• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

DomCR / ACadSharp / 16379028536

18 Jul 2025 07:45PM UTC coverage: 74.905% (-0.1%) from 75.043%
16379028536

Pull #715

github

web-flow
Merge 9090edde3 into 402a39408
Pull Request #715: Issue 712 pdfunderlay writer

5876 of 8627 branches covered (68.11%)

Branch coverage included in aggregate %.

118 of 209 new or added lines in 14 files covered. (56.46%)

14 existing lines in 3 files now uncovered.

23420 of 30484 relevant lines covered (76.83%)

80920.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.03
/src/ACadSharp/Objects/CadDictionary.cs
1
using ACadSharp.Attributes;
2
using CSUtilities.Extensions;
3
using System;
4
using System.Collections;
5
using System.Collections.Generic;
6
using System.Linq;
7

8
namespace ACadSharp.Objects
9
{
10
        /// <summary>
11
        /// Represents a <see cref="CadDictionary"/> object.
12
        /// </summary>
13
        /// <remarks>
14
        /// Object name <see cref="DxfFileToken.ObjectDictionary"/> <br/>
15
        /// Dxf class name <see cref="DxfSubclassMarker.Dictionary"/>
16
        /// </remarks>
17
        [DxfName(DxfFileToken.ObjectDictionary)]
18
        [DxfSubClass(DxfSubclassMarker.Dictionary)]
19
        public class CadDictionary : NonGraphicalObject, IObservableCadCollection<NonGraphicalObject>
20
        {
21
                public event EventHandler<CollectionChangedEventArgs> OnAdd;
22

23
                public event EventHandler<CollectionChangedEventArgs> OnRemove;
24

25
                /// <summary>
26
                /// Duplicate record cloning flag (determines how to merge duplicate entries)
27
                /// </summary>
28
                [DxfCodeValue(281)]
29
                public DictionaryCloningFlags ClonningFlags { get; set; }
35,926✔
30

31
                /// <summary>
32
                /// Soft-owner ID/handle to entry object
33
                /// </summary>
34
                [DxfCodeValue(350)]
NEW
35
                public ulong[] EntryHandles { get { return this._entries.Values.Select(c => c.Handle).ToArray(); } }
×
36

37
                /// <summary>
38
                /// Entry names
39
                /// </summary>
40
                [DxfCodeValue(3)]
NEW
41
                public string[] EntryNames { get { return this._entries.Keys.ToArray(); } }
×
42

43
                /// <summary>
44
                /// indicates that elements of the dictionary are to be treated as hard-owned.
45
                /// </summary>
46
                [DxfCodeValue(280)]
47
                public bool HardOwnerFlag { get; set; }
28,799✔
48

49
                /// <inheritdoc/>
50
                public override string ObjectName => DxfFileToken.ObjectDictionary;
87,658✔
51

52
                /// <inheritdoc/>
53
                public override ObjectType ObjectType => ObjectType.DICTIONARY;
1,216✔
54

55
                /// <inheritdoc/>
NEW
56
                public override string SubclassMarker => DxfSubclassMarker.Dictionary;
×
57

58
                /// <summary>
59
                /// ACAD_COLOR dictionary entry.
60
                /// </summary>
61
                public const string AcadColor = "ACAD_COLOR";
62

63
                /// <summary>
64
                /// ACAD_FIELDLIST dictionary entry.
65
                /// </summary>
66
                public const string AcadFieldList = "ACAD_FIELDLIST";
67

68
                /// <summary>
69
                /// ACAD_GROUP dictionary entry.
70
                /// </summary>
71
                public const string AcadGroup = "ACAD_GROUP";
72

73
                /// <summary>
74
                /// ACAD_IMAGE_DICT dictionary entry.
75
                /// </summary>
76
                public const string AcadImageDict = "ACAD_IMAGE_DICT";
77

78
                /// <summary>
79
                /// ACAD_LAYOUT dictionary entry.
80
                /// </summary>
81
                public const string AcadLayout = "ACAD_LAYOUT";
82

83
                /// <summary>
84
                /// ACAD_MATERIAL dictionary entry.
85
                /// </summary>
86
                public const string AcadMaterial = "ACAD_MATERIAL";
87

88
                /// <summary>
89
                /// ACAD_MLEADERSTYLE dictionary entry.
90
                /// </summary>
91
                public const string AcadMLeaderStyle = "ACAD_MLEADERSTYLE";
92

93
                /// <summary>
94
                /// ACAD_MLINESTYLE dictionary entry.
95
                /// </summary>
96
                public const string AcadMLineStyle = "ACAD_MLINESTYLE";
97

98
                /// <summary>
99
                /// ACAD_PDFDEFINITIONS dictionary entry.
100
                /// </summary>
101
                public const string AcadPdfDefinitions = "ACAD_PDFDEFINITIONS";
102

103
                /// <summary>
104
                /// ACAD_PLOTSETTINGS dictionary entry.
105
                /// </summary>
106
                public const string AcadPlotSettings = "ACAD_PLOTSETTINGS";
107

108
                /// <summary>
109
                /// ACAD_PLOTSTYLENAME dictionary entry.
110
                /// </summary>
111
                public const string AcadPlotStyleName = "ACAD_PLOTSTYLENAME";
112

113
                /// <summary>
114
                /// scales dictionary
115
                /// </summary>
116
                public const string AcadScaleList = "ACAD_SCALELIST";
117

118
                /// <summary>
119
                /// ACAD_SORTENTS dictionary entry.
120
                /// </summary>
121
                public const string AcadSortEnts = "ACAD_SORTENTS";
122

123
                /// <summary>
124
                /// ACAD_TABLESTYLE dictionary entry.
125
                /// </summary>
126
                public const string AcadTableStyle = "ACAD_TABLESTYLE";
127

128
                /// <summary>
129
                /// ACAD_VISUALSTYLE dictionary entry.
130
                /// </summary>
131
                public const string AcadVisualStyle = "ACAD_VISUALSTYLE";
132

133
                /// <summary>
134
                /// ACAD_GEOGRAPHICDATA dictionary entry.
135
                /// </summary>
136
                public const string GeographicData = "ACAD_GEOGRAPHICDATA";
137

138
                /// <summary>
139
                /// ROOT dictionary, only used in the top level dictionary.
140
                /// </summary>
141
                public const string Root = "ROOT";
142

143
                /// <summary>
144
                /// AcDbVariableDictionary dictionary entry.
145
                /// </summary>
146
                public const string VariableDictionary = "AcDbVariableDictionary";
147

148
                private readonly Dictionary<string, NonGraphicalObject> _entries = new(StringComparer.OrdinalIgnoreCase);
41,963✔
149

150
                /// <summary>
151
                /// Default constructor.
152
                /// </summary>
153
                public CadDictionary()
37,848✔
154
                { }
75,696✔
155

156
                /// <summary>
157
                /// Constructor for a named dictionary.
158
                /// </summary>
159
                /// <param name="name">Dictionary name.</param>
160
                public CadDictionary(string name)
4,115✔
161
                {
4,115✔
162
                        this.Name = name;
4,115✔
163
                }
4,115✔
164

165
                /// <summary>
166
                /// Create the default entries for the root dictionary.
167
                /// </summary>
168
                public static void CreateDefaultEntries(CadDictionary root)
169
                {
235✔
170
                        root.TryAdd(new CadDictionary(AcadColor));
235✔
171
                        root.TryAdd(new CadDictionary(AcadGroup));
235✔
172

173
                        CadDictionary layouts = root.ensureCadDictionaryExist(AcadLayout);
235✔
174

175
                        root.TryAdd(new CadDictionary(AcadMaterial));
235✔
176
                        root.TryAdd(new CadDictionary(AcadSortEnts));
235✔
177

178
                        CadDictionary mLeaderStyles = root.ensureCadDictionaryExist(AcadMLeaderStyle);
235✔
179
                        mLeaderStyles.TryAdd(MultiLeaderStyle.Default);
235✔
180

181
                        CadDictionary mLineStyles = root.ensureCadDictionaryExist(AcadMLineStyle);
235✔
182
                        mLineStyles.TryAdd(MLineStyle.Default);
235✔
183

184
                        root.TryAdd(new CadDictionary(AcadTableStyle));
235✔
185
                        root.TryAdd(new CadDictionary(AcadPlotSettings));
235✔
186
                        // { AcadPlotStyleName, new CadDictionaryWithDefault() },        //Add default entry "Normal"        PlaceHolder        ??
187

188
                        root.TryAdd(new CadDictionary(VariableDictionary));
235✔
189
                        //DictionaryVars Entry DIMASSOC and HIDETEXT ??
190

191
                        CadDictionary scales = root.ensureCadDictionaryExist(AcadScaleList);
235✔
192
                        scales.TryAdd(new Scale { Name = "A0", PaperUnits = 1.0, DrawingUnits = 1.0, IsUnitScale = true });
235✔
193
                        scales.TryAdd(new Scale { Name = "A1", PaperUnits = 1.0, DrawingUnits = 2.0, IsUnitScale = false });
235✔
194
                        scales.TryAdd(new Scale { Name = "A2", PaperUnits = 1.0, DrawingUnits = 4.0, IsUnitScale = false });
235✔
195
                        scales.TryAdd(new Scale { Name = "A3", PaperUnits = 1.0, DrawingUnits = 5.0, IsUnitScale = false });
235✔
196
                        scales.TryAdd(new Scale { Name = "A4", PaperUnits = 1.0, DrawingUnits = 8.0, IsUnitScale = false });
235✔
197
                        scales.TryAdd(new Scale { Name = "A5", PaperUnits = 1.0, DrawingUnits = 10.0, IsUnitScale = false });
235✔
198
                        scales.TryAdd(new Scale { Name = "A6", PaperUnits = 1.0, DrawingUnits = 16.0, IsUnitScale = false });
235✔
199
                        scales.TryAdd(new Scale { Name = "A7", PaperUnits = 1.0, DrawingUnits = 20.0, IsUnitScale = false });
235✔
200
                        scales.TryAdd(new Scale { Name = "A8", PaperUnits = 1.0, DrawingUnits = 30.0, IsUnitScale = false });
235✔
201
                        scales.TryAdd(new Scale { Name = "A9", PaperUnits = 1.0, DrawingUnits = 40.0, IsUnitScale = false });
235✔
202
                        scales.TryAdd(new Scale { Name = "B0", PaperUnits = 1.0, DrawingUnits = 50.0, IsUnitScale = false });
235✔
203
                        scales.TryAdd(new Scale { Name = "B1", PaperUnits = 1.0, DrawingUnits = 100.0, IsUnitScale = false });
235✔
204
                        scales.TryAdd(new Scale { Name = "B2", PaperUnits = 2.0, DrawingUnits = 1.0, IsUnitScale = false });
235✔
205
                        scales.TryAdd(new Scale { Name = "B3", PaperUnits = 4.0, DrawingUnits = 1.0, IsUnitScale = false });
235✔
206
                        scales.TryAdd(new Scale { Name = "B4", PaperUnits = 8.0, DrawingUnits = 1.0, IsUnitScale = false });
235✔
207
                        scales.TryAdd(new Scale { Name = "B5", PaperUnits = 10.0, DrawingUnits = 1.0, IsUnitScale = false });
235✔
208
                        scales.TryAdd(new Scale { Name = "B6", PaperUnits = 100.0, DrawingUnits = 1.0, IsUnitScale = false });
235✔
209

210
                        root.TryAdd(new CadDictionary(AcadVisualStyle));
235✔
211
                        root.TryAdd(new CadDictionary(AcadFieldList));
235✔
212
                        root.TryAdd(new CadDictionary(AcadImageDict));
235✔
213
                }
235✔
214

215
                /// <summary>
216
                /// Creates the root dictionary with the default entries.
217
                /// </summary>
218
                /// <returns></returns>
219
                public static CadDictionary CreateRoot()
220
                {
234✔
221
                        CadDictionary root = new CadDictionary(Root);
234✔
222

223
                        CreateDefaultEntries(root);
234✔
224

225
                        return root;
234✔
226
                }
234✔
227

228
                /// <summary>
229
                /// Add a <see cref="NonGraphicalObject"/> to the collection, this method triggers <see cref="OnAdd"/>
230
                /// </summary>
231
                /// <param name="key">key for the entry in the dictionary</param>
232
                /// <param name="value"></param>
233
                public void Add(string key, NonGraphicalObject value)
234
                {
77,972✔
235
                        if (string.IsNullOrEmpty(key))
77,972!
236
                        {
×
237
                                throw new ArgumentNullException(nameof(value), $"NonGraphicalObject [{this.GetType().FullName}] must have a name");
×
238
                        }
239

240
                        this._entries.Add(key, value);
77,972✔
241
                        value.Owner = this;
77,970✔
242

243
                        value.OnNameChanged += this.onEntryNameChanged;
77,970✔
244

245
                        OnAdd?.Invoke(this, new CollectionChangedEventArgs(value));
77,970✔
246
                }
77,970✔
247

248
                /// <summary>
249
                /// Add a <see cref="NonGraphicalObject"/> to the collection, this method triggers <see cref="OnAdd"/>
250
                /// </summary>
251
                /// <param name="value">the name of the NonGraphicalObject will be used as a key for the dictionary</param>
252
                /// <exception cref="ArgumentException"></exception>
253
                public void Add(NonGraphicalObject value)
254
                {
2,216✔
255
                        this.Add(value.Name, value);
2,216✔
256
                }
2,214✔
257

258
                /// <summary>
259
                /// Removes all keys and values from the <see cref="CadDictionary"/>.
260
                /// </summary>
261
                public void Clear()
UNCOV
262
                {
×
NEW
263
                        foreach (var item in this._entries)
×
UNCOV
264
                        {
×
NEW
265
                                this.Remove(item.Key, out _);
×
UNCOV
266
                        }
×
UNCOV
267
                }
×
268

269
                /// <summary>
270
                /// Determines whether the <see cref="CadDictionary"/> contains the specified key.
271
                /// </summary>
272
                /// <param name="key">The key to locate in the <see cref="CadDictionary"/></param>
273
                /// <returns></returns>
274
                public bool ContainsKey(string key)
275
                {
23✔
276
                        return this._entries.ContainsKey(key);
23✔
277
                }
23✔
278

279
                /// <summary>
280
                /// Gets the value associated with the specific key
281
                /// </summary>
282
                /// <typeparam name="T"></typeparam>
283
                /// <param name="name"></param>
284
                /// <returns>The value with Type T or null if not found or different type</returns>
285
                public T GetEntry<T>(string name)
286
                        where T : NonGraphicalObject
287
                {
16✔
288
                        this.TryGetEntry<T>(name, out T value);
16✔
289
                        return value;
16✔
290
                }
16✔
291

292
                /// <inheritdoc/>
293
                public IEnumerator<NonGraphicalObject> GetEnumerator()
294
                {
36,683✔
295
                        return this._entries.Values.GetEnumerator();
36,683✔
296
                }
36,683✔
297

298
                /// <inheritdoc/>
299
                IEnumerator IEnumerable.GetEnumerator()
300
                {
27✔
301
                        return this._entries.Values.GetEnumerator();
27✔
302
                }
27✔
303

304
                /// <summary>
305
                /// Removes a <see cref="NonGraphicalObject"/> from the collection, this method triggers <see cref="OnRemove"/>
306
                /// </summary>
307
                /// <param name="key"></param>
308
                /// <param name="item"></param>
309
                /// <returns>true if the element is successfully removed; otherwise, false.</returns>
310
                public bool Remove(string key, out NonGraphicalObject item)
311
                {
2✔
312
                        if (this._entries.Remove(key, out item))
2!
313
                        {
2✔
314
                                item.Owner = null;
2✔
315
                                OnRemove?.Invoke(this, new CollectionChangedEventArgs(item));
2!
316
                                item.OnNameChanged -= this.onEntryNameChanged;
2✔
317
                                return true;
2✔
318
                        }
319

320
                        return false;
×
321
                }
2✔
322

323
                /// <summary>
324
                /// Removes a <see cref="NonGraphicalObject"/> from the collection, this method triggers <see cref="OnRemove"/>
325
                /// </summary>
326
                /// <param name="key"></param>
327
                /// <returns>true if the element is successfully removed; otherwise, false.</returns>
328
                public bool Remove(string key)
329
                {
×
330
                        return this.Remove(key, out _);
×
331
                }
×
332

333
                /// <summary>
334
                /// Tries to add the <see cref="NonGraphicalObject"/> entry using the name as key.
335
                /// </summary>
336
                /// <param name="value"></param>
337
                /// <returns>true if the element is successfully added; otherwise, false.</returns>
338
                public bool TryAdd(NonGraphicalObject value)
339
                {
6,817✔
340
                        if (!this._entries.ContainsKey(value.Name))
6,817✔
341
                        {
6,787✔
342
                                this.Add(value.Name, value);
6,787✔
343
                                return true;
6,787✔
344
                        }
345

346
                        return false;
30✔
347
                }
6,817✔
348

349
                /// <summary>
350
                /// Gets the value associated with the specific key
351
                /// </summary>
352
                /// <typeparam name="T"></typeparam>
353
                /// <param name="name"></param>
354
                /// <param name="value"></param>
355
                /// <returns>true if the value is found or false if not found or different type</returns>
356
                public bool TryGetEntry<T>(string name, out T value)
357
                        where T : NonGraphicalObject
358
                {
17,591✔
359
                        if (this._entries.TryGetValue(name, out NonGraphicalObject obj))
17,591✔
360
                        {
15,623✔
361
                                if (obj is T t)
15,623!
362
                                {
15,623✔
363
                                        value = t;
15,623✔
364
                                        return true;
15,623✔
365
                                }
366
                        }
×
367

368
                        value = null;
1,968✔
369
                        return false;
1,968✔
370
                }
17,591✔
371

372
                private CadDictionary ensureCadDictionaryExist(string name)
373
                {
940✔
374
                        if (!this.TryGetEntry(name, out CadDictionary entry))
940✔
375
                        {
936✔
376
                                entry = new CadDictionary(name);
936✔
377
                                this.Add(entry);
936✔
378
                        }
936✔
379

380
                        return entry;
940✔
381
                }
940✔
382

383
                private void onEntryNameChanged(object sender, OnNameChangedArgs e)
384
                {
1✔
385
                        var entry = this._entries[e.OldName];
1✔
386
                        this._entries.Add(e.NewName, entry);
1✔
387
                        this._entries.Remove(e.OldName);
1✔
388
                }
1✔
389

390
                public CadObject this[string key] { get { return this._entries[key]; } }
51✔
391
        }
392
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc