~ubuntu-branches/ubuntu/natty/electric/natty

« back to all changes in this revision

Viewing changes to com/sun/electric/database/hierarchy/Cell.java

  • Committer: Bazaar Package Importer
  • Author(s): Onkar Shinde
  • Date: 2010-01-09 16:26:04 UTC
  • mfrom: (1.1.4 upstream) (3.1.6 sid)
  • Revision ID: james.westby@ubuntu.com-20100109162604-1ypvmy8ijmlc6oq7
Tags: 8.10-1
* New upstream version.
* debian/control
  - Add libjava3d-java and quilt build dependencies.
  - Update standards version to 3.8.3.
  - Add libjava3d-java as recommends to binary package.
* debian/rules
  - Use quilt patch system instead of simple patchsys.
  - Add java3d related jar files to DEB_JARS.
* debian/patches/*
  - Update as per current upstream source. Convert to quilt.
* debian/ant.properties
  - Do not disable 3D plugin anymore.
  - Use new property to disable compilation of OS X related classes.
* debian/wrappers/electric
  - Add java3d related jar files to runtime classpath.
* debian/README.source
  - Change text to the appropriate one for quilt.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
 
26
26
import com.sun.electric.database.CellBackup;
27
27
import com.sun.electric.database.CellRevision;
 
28
import com.sun.electric.database.CellTree;
28
29
import com.sun.electric.database.EObjectInputStream;
29
30
import com.sun.electric.database.EObjectOutputStream;
30
31
import com.sun.electric.database.IdMapper;
34
35
import com.sun.electric.database.ImmutableNodeInst;
35
36
import com.sun.electric.database.Snapshot;
36
37
import com.sun.electric.database.constraint.Constraints;
37
 
import com.sun.electric.database.geometry.DBMath;
38
38
import com.sun.electric.database.geometry.ERectangle;
39
39
import com.sun.electric.database.geometry.Poly;
40
40
import com.sun.electric.database.id.CellId;
41
41
import com.sun.electric.database.id.CellUsage;
42
42
import com.sun.electric.database.id.PortProtoId;
43
43
import com.sun.electric.database.id.TechId;
 
44
import com.sun.electric.database.network.NetCell;
44
45
import com.sun.electric.database.network.Netlist;
45
46
import com.sun.electric.database.network.NetworkTool;
46
47
import com.sun.electric.database.prototype.NodeProto;
83
84
import java.io.IOException;
84
85
import java.io.InvalidObjectException;
85
86
import java.io.NotSerializableException;
 
87
import java.lang.ref.Reference;
 
88
import java.lang.ref.SoftReference;
 
89
import java.lang.ref.WeakReference;
86
90
import java.util.ArrayList;
87
91
import java.util.BitSet;
88
92
import java.util.Collections;
119
123
 * <P>
120
124
 * <CENTER><IMG SRC="doc-files/Cell-1.gif"></CENTER>
121
125
 */
122
 
public class Cell extends ElectricObject implements NodeProto, Comparable<Cell>
123
 
{
124
 
        // ------------------------- private classes -----------------------------
125
 
 
126
 
        /**
127
 
         * A CellGroup contains a list of cells that are related.
128
 
         * This includes different Views of a cell (e.g. the schematic, layout, and icon Views),
129
 
         * alternative icons, all the parts of a multi-part icon.
130
 
         */
131
 
        public static class CellGroup
132
 
        {
133
 
                // private data
 
126
public class Cell extends ElectricObject implements NodeProto, Comparable<Cell> {
 
127
 
 
128
    private static final boolean USE_WEAK_REFERENCES = false;
 
129
    private static final boolean LAZY_TOPOLOGY = true;
 
130
    // ------------------------- private classes -----------------------------
 
131
 
 
132
    /**
 
133
     * A CellGroup contains a list of cells that are related.
 
134
     * This includes different Views of a cell (e.g. the schematic, layout, and icon Views),
 
135
     * alternative icons, all the parts of a multi-part icon.
 
136
     */
 
137
    public static class CellGroup {
 
138
        // private data
 
139
 
134
140
        private final Library lib;
135
 
                private TreeSet<Cell> cells;
136
 
                private Cell mainSchematic;
137
 
                private CellName groupName;
138
 
 
139
 
                // ------------------------- public methods -----------------------------
140
 
 
141
 
                /**
142
 
                 * Constructs a CellGroup.
143
 
                 */
144
 
                private CellGroup(Library lib)
145
 
                {
 
141
        private TreeSet<Cell> cells;
 
142
        private Cell mainSchematic;
 
143
        private CellName groupName;
 
144
 
 
145
        // ------------------------- public methods -----------------------------
 
146
        /**
 
147
         * Constructs a CellGroup.
 
148
         */
 
149
        private CellGroup(Library lib) {
146
150
            this.lib = lib;
147
151
            cells = new TreeSet<Cell>();
148
 
                }
 
152
        }
149
153
 
150
154
        /**
151
155
         * Constructor for Undo.
154
158
            lib = cells.first().getLibrary();
155
159
            this.cells = cells;
156
160
            setMainSchematics(true);
157
 
            for (Cell cell: cells) {
 
161
            for (Cell cell : cells) {
158
162
                assert cell.getLibrary() == lib;
159
163
                cell.cellGroup = this;
160
164
            }
161
165
        }
162
166
 
163
 
                /**
164
 
                 * Method to add a Cell to this CellGroup.
165
 
                 * @param cell the cell to add to this CellGroup.
166
 
                 */
167
 
                private void add(Cell cell)
168
 
                {
 
167
        /**
 
168
         * Method to add a Cell to this CellGroup.
 
169
         * @param cell the cell to add to this CellGroup.
 
170
         */
 
171
        private void add(Cell cell) {
169
172
            lib.checkChanging();
170
173
            Cell paramOwner = getParameterOwner();
171
 
                        synchronized(cells)
172
 
                        {
173
 
                if (!cells.contains(cell))
174
 
                                    cells.add(cell);
 
174
            synchronized (cells) {
 
175
                if (!cells.contains(cell)) {
 
176
                    cells.add(cell);
 
177
                }
175
178
                setMainSchematics(false);
176
 
                        }
177
 
                        cell.cellGroup = this;
178
 
            if (cell.getD().paramsAllowed() && paramOwner != null)
 
179
            }
 
180
            cell.cellGroup = this;
 
181
            if (cell.getD().paramsAllowed() && paramOwner != null) {
179
182
                cell.setParams(paramOwner);
180
 
                }
 
183
            }
 
184
        }
181
185
 
182
 
                /**
183
 
                 * Method to remove a Cell from this CellGroup.
184
 
                 * @param f the cell to remove from this CellGroup.
185
 
                 */
186
 
                private void remove(Cell f)
187
 
                {
 
186
        /**
 
187
         * Method to remove a Cell from this CellGroup.
 
188
         * @param f the cell to remove from this CellGroup.
 
189
         */
 
190
        private void remove(Cell f) {
188
191
            lib.checkChanging();
189
 
                        synchronized (cells)
190
 
                        {
191
 
                                cells.remove(f);
 
192
            synchronized (cells) {
 
193
                cells.remove(f);
192
194
                setMainSchematics(false);
193
 
                        }
 
195
            }
194
196
            f.cellGroup = null;
195
 
                }
196
 
 
197
 
                /**
198
 
                 * Method to return an Iterator over all the Cells that are in this CellGroup.
199
 
                 * @return an Iterator over all the Cells that are in this CellGroup.
200
 
                 */
201
 
                public Iterator<Cell> getCells() { return cells.iterator(); }
202
 
 
203
 
                /**
204
 
                 * Method to return the number of Cells that are in this CellGroup.
205
 
                 * @return the number of Cells that are in this CellGroup.
206
 
                 */
207
 
                public int getNumCells() { return cells.size(); }
208
 
 
209
 
                /**
210
 
                 * Method to return a List of all cells in this Group, sorted by View.
211
 
                 * @return a List of all cells in this Group, sorted by View.
212
 
                 */
213
 
                public List<Cell> getCellsSortedByView()
214
 
                {
215
 
                        synchronized(cells)
216
 
                        {
217
 
                                List<Cell> sortedList = new ArrayList<Cell>(cells);
218
 
                                Collections.sort(sortedList, new TextUtils.CellsByView());
219
 
                                return sortedList;
220
 
                        }
221
 
                }
222
 
 
223
 
                /**
224
 
                 * Method to return main schematics Cell in this CellGroup.
225
 
                 * The main schematic is the one that is shown when descending into an icon.
226
 
                 * Other schematic views may exist in the group, but they are "alternates".
227
 
                 * @return main schematics Cell in this CellGroup.
228
 
                 */
229
 
                public Cell getMainSchematics()
230
 
                {
231
 
                        return mainSchematic;
232
 
                }
233
 
 
234
 
                /**
235
 
                 * Method to return parameter owner Cell in this CellGroup.
236
 
                 * The param owner Cell is icon or schematic Cell whose parameters
 
197
        }
 
198
 
 
199
        /**
 
200
         * Method to return an Iterator over all the Cells that are in this CellGroup.
 
201
         * @return an Iterator over all the Cells that are in this CellGroup.
 
202
         */
 
203
        public Iterator<Cell> getCells() {
 
204
            return cells.iterator();
 
205
        }
 
206
 
 
207
        /**
 
208
         * Method to return the number of Cells that are in this CellGroup.
 
209
         * @return the number of Cells that are in this CellGroup.
 
210
         */
 
211
        public int getNumCells() {
 
212
            return cells.size();
 
213
        }
 
214
 
 
215
        /**
 
216
         * Method to return a List of all cells in this Group, sorted by View.
 
217
         * @return a List of all cells in this Group, sorted by View.
 
218
         */
 
219
        public List<Cell> getCellsSortedByView() {
 
220
            synchronized (cells) {
 
221
                List<Cell> sortedList = new ArrayList<Cell>(cells);
 
222
                Collections.sort(sortedList, new TextUtils.CellsByView());
 
223
                return sortedList;
 
224
            }
 
225
        }
 
226
 
 
227
        /**
 
228
         * Method to return main schematics Cell in this CellGroup.
 
229
         * The main schematic is the one that is shown when descending into an icon.
 
230
         * Other schematic views may exist in the group, but they are "alternates".
 
231
         * @return main schematics Cell in this CellGroup.
 
232
         */
 
233
        public Cell getMainSchematics() {
 
234
            return mainSchematic;
 
235
        }
 
236
 
 
237
        /**
 
238
         * Method to return parameter owner Cell in this CellGroup.
 
239
         * The param owner Cell is icon or schematic Cell whose parameters
237
240
         * are used as reference when reconcilating parameters of other icon/schematic
238
241
         * Cells in the group.
239
 
                 * Param owner Cell is either main schematic Cell or first icon in alphanumeric
 
242
         * Param owner Cell is either main schematic Cell or first icon in alphanumeric
240
243
         * order in CellGroups without schematic Cells
241
 
                 * @return parameter owner Cell in this CellGroup.
242
 
                 */
243
 
                public Cell getParameterOwner() {
244
 
            if (mainSchematic != null)
 
244
         * @return parameter owner Cell in this CellGroup.
 
245
         */
 
246
        public Cell getParameterOwner() {
 
247
            if (mainSchematic != null) {
245
248
                return mainSchematic;
246
 
            for (Cell cell: cells) {
247
 
                if (cell.isIcon())
 
249
            }
 
250
            for (Cell cell : cells) {
 
251
                if (cell.isIcon()) {
248
252
                    return cell;
 
253
                }
249
254
            }
250
255
            return null;
251
 
                }
 
256
        }
252
257
 
253
258
        /**
254
259
         * Method to add a parameter on icons/schematics of this CellGroup.
256
261
         * @param param parameter to add.
257
262
         */
258
263
        public void addParam(Variable param) {
259
 
            for (Cell cell: cells) {
260
 
                if (!(cell.isIcon() || cell.isSchematic())) continue;
 
264
            for (Cell cell : cells) {
 
265
                if (!(cell.isIcon() || cell.isSchematic())) {
 
266
                    continue;
 
267
                }
261
268
 
262
 
                // find nonconflicting location of this cell attribute
263
 
                Point2D offset = cell.newVarOffset();
 
269
                // find nonconflicting location of this cell attribute
 
270
                Point2D offset = cell.newVarOffset();
264
271
                cell.addParam(param.withOff(offset.getX(), offset.getY()));
265
272
            }
266
273
        }
270
277
         * @param key the key of the parameter to delete.
271
278
         */
272
279
        public void delParam(Variable.AttrKey key) {
273
 
            for (Cell cell: cells) {
274
 
                if (!(cell.isIcon() || cell.isSchematic())) continue;
 
280
            for (Cell cell : cells) {
 
281
                if (!(cell.isIcon() || cell.isSchematic())) {
 
282
                    continue;
 
283
                }
275
284
                cell.delParam(key);
276
285
            }
277
286
        }
284
293
         * @param newName the new name of the parameter
285
294
         */
286
295
        public void renameParam(Variable.AttrKey key, Variable.AttrKey newName) {
287
 
            if (newName == key) return;
288
 
            for (Cell cell: cells) {
289
 
                if (!(cell.isIcon() || cell.isSchematic())) continue;
 
296
            if (newName == key) {
 
297
                return;
 
298
            }
 
299
            for (Cell cell : cells) {
 
300
                if (!(cell.isIcon() || cell.isSchematic())) {
 
301
                    continue;
 
302
                }
290
303
                cell.renameParam(key, newName);
291
304
            }
292
305
        }
299
312
         */
300
313
        public void updateParam(Variable.AttrKey key, Object value) {
301
314
            assert cells.iterator().next().isParam(key);
302
 
            for (Cell cell: cells) {
303
 
                if (!(cell.isIcon() || cell.isSchematic())) continue;
304
 
                        Variable oldParam = cell.getParameter(key);
 
315
            for (Cell cell : cells) {
 
316
                if (!(cell.isIcon() || cell.isSchematic())) {
 
317
                    continue;
 
318
                }
 
319
                Variable oldParam = cell.getParameter(key);
305
320
                cell.addParam(oldParam.withObject(value));
306
321
            }
307
322
        }
315
330
         */
316
331
        public void updateParamText(Variable.AttrKey key, String text) {
317
332
            assert cells.iterator().next().isParam(key);
318
 
            for (Cell cell: cells) {
319
 
                if (!(cell.isIcon() || cell.isSchematic())) continue;
320
 
                        Variable oldParam = cell.getParameter(key);
 
333
            for (Cell cell : cells) {
 
334
                if (!(cell.isIcon() || cell.isSchematic())) {
 
335
                    continue;
 
336
                }
 
337
                Variable oldParam = cell.getParameter(key);
321
338
                cell.addParam(oldParam.withText(text));
322
339
            }
323
340
        }
327
344
         * @param cell the Cell in question.
328
345
         * @return true if the Cell is in this CellGroup.
329
346
         */
330
 
        public boolean containsCell(Cell cell) { return cell != null && cells.contains(cell); }
331
 
 
332
 
                /**
333
 
                 * Returns a printable version of this CellGroup.
334
 
                 * @return a printable version of this CellGroup.
335
 
                 */
336
 
                public String toString() { return "CellGroup " + getName(); }
337
 
 
338
 
                /**
339
 
                 * Method to compare two CellGroups.
340
 
                 * Because CellGroups seem to be ephemeral, and are created dynamically,
341
 
                 * it is not possible to compare them by equating the object.
342
 
                 * Therefore, this override compares the group names.
343
 
                 * Although not accurate, it is better than simple object equality.
344
 
                 */
345
 
                public boolean equals(Object obj)
346
 
                {
347
 
                        if (obj instanceof CellGroup && groupName != null)
348
 
                        {
349
 
                                return groupName.equals(((CellGroup)obj).groupName);
350
 
                        }
351
 
                        return this == obj;
352
 
                }
353
 
 
354
 
                /**
 
347
        public boolean containsCell(Cell cell) {
 
348
            return cell != null && cells.contains(cell);
 
349
        }
 
350
 
 
351
        /**
 
352
         * Returns a printable version of this CellGroup.
 
353
         * @return a printable version of this CellGroup.
 
354
         */
 
355
        public String toString() {
 
356
            return "CellGroup " + getName();
 
357
        }
 
358
 
 
359
        /**
 
360
         * Method to compare two CellGroups.
 
361
         * Because CellGroups seem to be ephemeral, and are created dynamically,
 
362
         * it is not possible to compare them by equating the object.
 
363
         * Therefore, this override compares the group names.
 
364
         * Although not accurate, it is better than simple object equality.
 
365
         */
 
366
        public boolean equals(Object obj) {
 
367
            if (obj instanceof CellGroup && groupName != null) {
 
368
                return groupName.equals(((CellGroup) obj).groupName);
 
369
            }
 
370
            return this == obj;
 
371
        }
 
372
 
 
373
        /**
355
374
         * Returns a string representing the name of the cell group
356
 
                 */
357
 
                public String getName() { return groupName != null ? groupName.getName() : null; }
358
 
 
359
 
        public EDatabase getDatabase() { return lib.getDatabase(); }
360
 
 
361
 
                /**
362
 
                 * Method to check invariants in this CellGroup.
363
 
                 * @exception AssertionError if invariants are not valid
364
 
                 */
365
 
                void check()
366
 
                {
367
 
                        for (Cell cell : cells)
368
 
                        {
369
 
                                assert lib.cells.get(cell.getCellName()) == cell;
370
 
                                assert cell.cellGroup == this;
 
375
         */
 
376
        public String getName() {
 
377
            return groupName != null ? groupName.getName() : null;
 
378
        }
 
379
 
 
380
        public EDatabase getDatabase() {
 
381
            return lib.getDatabase();
 
382
        }
 
383
 
 
384
        /**
 
385
         * Method to check invariants in this CellGroup.
 
386
         * @exception AssertionError if invariants are not valid
 
387
         */
 
388
        void check() {
 
389
            for (Cell cell : cells) {
 
390
                assert lib.cells.get(cell.getCellName()) == cell;
 
391
                assert cell.cellGroup == this;
371
392
                assert cell.d.groupName.equals(groupName);
372
 
                        }
373
 
                        if (mainSchematic != null)
374
 
                        {
375
 
                                assert containsCell(mainSchematic);
376
 
                                assert mainSchematic.getNewestVersion() == mainSchematic;
377
 
                        }
378
 
                }
379
 
                /**
380
 
                 * Method to set the main schematics Cell in ths CellGroup.
381
 
                 * The main schematic is the one that is shown when descending into an icon.
382
 
                 * Other schematic views may exist in the group, but they are "alternates".
 
393
            }
 
394
            if (mainSchematic != null) {
 
395
                assert containsCell(mainSchematic);
 
396
                assert mainSchematic.getNewestVersion() == mainSchematic;
 
397
            }
 
398
        }
 
399
 
 
400
        /**
 
401
         * Method to set the main schematics Cell in ths CellGroup.
 
402
         * The main schematic is the one that is shown when descending into an icon.
 
403
         * Other schematic views may exist in the group, but they are "alternates".
383
404
         * Only one schematic view should be in cell group.
384
405
         * If many schematic views exists then main schematics is the newest version of first in alpahabetical order schematic cell.
385
 
                 */
386
 
                private void setMainSchematics(boolean undo)
387
 
                {
 
406
         */
 
407
        private void setMainSchematics(boolean undo) {
388
408
            if (cells.isEmpty()) {
389
409
                groupName = null;
390
410
                mainSchematic = null;
391
411
                return;
392
412
            }
393
 
                        // not set: see if it is obvious
 
413
            // not set: see if it is obvious
394
414
            List<CellName> cellNames = new ArrayList<CellName>();
395
415
//            String bestName = null;
396
416
            Cell mainSchematic = null;
397
 
                        for (Cell cell: cells) {
398
 
                                if (cell.isSchematic() && mainSchematic == null)
 
417
            for (Cell cell : cells) {
 
418
                if (cell.isSchematic() && mainSchematic == null) {
399
419
                    mainSchematic = cell;
 
420
                }
400
421
                cellNames.add(cell.getCellName());
401
 
                        }
 
422
            }
402
423
            groupName = Snapshot.makeCellGroupName(cellNames);
403
424
            this.mainSchematic = mainSchematic;
404
 
                        for (Cell cell: cells) {
 
425
            for (Cell cell : cells) {
405
426
                if (undo) {
406
427
                    assert cell.d.groupName.equals(groupName);
407
428
                } else {
408
429
                    cell.setD(cell.d.withGroupName(groupName));
409
430
                }
410
431
            }
411
 
                }
412
 
        }
413
 
 
414
 
        private class MaxSuffix { int v = 0; }
415
 
 
416
 
        // -------------------------- private data ---------------------------------
417
 
 
418
 
        /** Variable key for characteristic spacing for a cell. */              public static final Variable.Key CHARACTERISTIC_SPACING = Variable.newKey("FACET_characteristic_spacing");
419
 
        /** Variable key for text cell contents. */                                             public static final Variable.Key CELL_TEXT_KEY = Variable.newKey("FACET_message");
420
 
        /** Variable key for number of multipage pages. */                              public static final Variable.Key MULTIPAGE_COUNT_KEY = Variable.newKey("CELL_page_count");
421
 
        /** Variable key for font of text in textual cells. */                  public static final Variable.Key TEXT_CELL_FONT_NAME = Variable.newKey("CELL_text_font");
422
 
        /** Variable key for size of text in textual cells. */                  public static final Variable.Key TEXT_CELL_FONT_SIZE = Variable.newKey("CELL_text_size");
423
 
 
 
432
        }
 
433
    }
 
434
 
 
435
    private class MaxSuffix {
 
436
 
 
437
        int v = 0;
 
438
    }
 
439
    // -------------------------- private data ---------------------------------
 
440
    /** Variable key for characteristic spacing for a cell. */
 
441
    public static final Variable.Key CHARACTERISTIC_SPACING = Variable.newKey("FACET_characteristic_spacing");
 
442
    /** Variable key for text cell contents. */
 
443
    public static final Variable.Key CELL_TEXT_KEY = Variable.newKey("FACET_message");
 
444
    /** Variable key for number of multipage pages. */
 
445
    public static final Variable.Key MULTIPAGE_COUNT_KEY = Variable.newKey("CELL_page_count");
 
446
    /** Variable key for font of text in textual cells. */
 
447
    public static final Variable.Key TEXT_CELL_FONT_NAME = Variable.newKey("CELL_text_font");
 
448
    /** Variable key for size of text in textual cells. */
 
449
    public static final Variable.Key TEXT_CELL_FONT_SIZE = Variable.newKey("CELL_text_size");
424
450
    private static final int[] NULL_INT_ARRAY = {};
425
 
        private static final Export[] NULL_EXPORT_ARRAY = {};
426
 
 
427
 
        /** set if instances should be expanded */                                              public static final int WANTNEXPAND   =           02;
428
 
//      /** set if cell is modified */                                                      private static final int MODIFIED      =     01000000;
429
 
        /** set if everything in cell is locked */                                              public static final int NPLOCKED      =     04000000;
430
 
        /** set if instances in cell are locked */                                              public static final int NPILOCKED     =    010000000;
431
 
        /** set if cell is part of a "cell library" */                                  public static final int INCELLLIBRARY =    020000000;
432
 
        /** set if cell is from a technology-library */                                 public static final int TECEDITCELL   =    040000000;
433
 
        /** set if cell is a multi-page schematic */                                    private static final int MULTIPAGE     = 017600000000;
434
 
 
435
 
        /** Length of base name for autonaming. */                                              private static final int ABBREVLEN = 8;
436
 
        /** zero rectangle */                                                                                   private static final Rectangle2D CENTERRECT = new Rectangle2D.Double(0, 0, 0, 0);
437
 
 
438
 
    /** Bounds are correct */                                       private static final byte BOUNDS_CORRECT = 0;
439
 
    /** Bounds are correct if all subcells have correct bounds. */  private static final byte BOUNDS_CORRECT_SUB = 1;
440
 
    /** Bounds are correct if all geoms have correct bounds. */     private static final byte BOUNDS_CORRECT_GEOM = 2;
441
 
    /** Bounds need to be recomputed. */                            private static final byte BOUNDS_RECOMPUTE = 3;
442
 
 
443
 
    /** Database to which this Library belongs. */                  private final EDatabase database;
444
 
    /** Persistent data of this Cell. */                            private ImmutableCell d;
445
 
        /** The CellGroup this Cell belongs to. */                                              private CellGroup cellGroup;
446
 
        /** The library this Cell belongs to. */                                                private Library lib;
447
 
    /** The technology of this Cell. */                             private Technology tech;
448
 
    /** The newest version of this Cell. */                         Cell newestVersion;
449
 
    /** An array of Exports on the Cell by chronological index. */  private Export[] chronExports = new Export[2];
450
 
        /** A sorted array of Exports on the Cell. */                                   private Export[] exports = NULL_EXPORT_ARRAY;
451
 
    /** Cell's topology. */                                         private final Topology topology = new Topology(this, false);
452
 
        /** The Cell's essential-bounds. */                                                             private final List<NodeInst> essenBounds = new ArrayList<NodeInst>();
453
 
    /** Chronological list of NodeInsts in this Cell. */            private final List<NodeInst> chronNodes = new ArrayList<NodeInst>();
454
 
    /** Set containing nodeIds of expanded cells. */                private final BitSet expandedNodes = new BitSet();
455
 
        /** A list of NodeInsts in this Cell. */                                                private final List<NodeInst> nodes = new ArrayList<NodeInst>();
456
 
    /** Counts of NodeInsts for each CellUsage. */                  private int[] cellUsages = NULL_INT_ARRAY;
457
 
        /** A map from canonic String to Integer maximal numeric suffix */private final Map<String,MaxSuffix> maxSuffix = new HashMap<String,MaxSuffix>();
458
 
        /** The bounds of the Cell. */                                                                  private ERectangle cellBounds;
459
 
        /** Whether the bounds need to be recomputed.
460
 
     * BOUNDS_CORRECT - bounds are correct.
461
 
     * BOUNDS_CORRECT_SUB - bounds are correct provided that bounds of subcells are correct.
462
 
     * BOUNDS_CORRECT_GEOM - bounds are correct proveded that bounds of nodes and arcs are correct.
463
 
     * BOUNDS_RECOMPUTE - bounds need to be recomputed. */          private byte boundsDirty = BOUNDS_RECOMPUTE;
464
 
        /** The temporary integer value. */                                                             private int tempInt;
465
 
    /** Set if expanded status of subcell instances is modified. */ private boolean expandStatusModified;
466
 
    /** Last backup of this Cell */                                 CellBackup backup;
467
 
    /** True if cell together with contents matches cell backup. */ boolean cellBackupFresh;
468
 
    /** True if cell contents matches cell backup. */               private boolean cellContentsFresh;
469
 
    /** True if cell revision date is just set by lowLevelSetRevisionDate*/private boolean revisionDateFresh;
470
 
 
471
 
 
472
 
        // ------------------ protected and private methods -----------------------
473
 
 
474
 
        /**
475
 
         * This constructor should not be called.
476
 
         * Use the factory "newInstance" to create a Cell.
477
 
         */
478
 
        Cell(EDatabase database, ImmutableCell d) {
 
451
    private static final Export[] NULL_EXPORT_ARRAY = {};
 
452
    /** set if instances should be expanded */
 
453
    public static final int WANTNEXPAND = 02;
 
454
//  /** set if cell is modified */                                  private static final int MODIFIED      =     01000000;
 
455
    /** set if everything in cell is locked */
 
456
    public static final int NPLOCKED = 04000000;
 
457
    /** set if instances in cell are locked */
 
458
    public static final int NPILOCKED = 010000000;
 
459
    /** set if cell is part of a "cell library" */
 
460
    public static final int INCELLLIBRARY = 020000000;
 
461
    /** set if cell is from a technology-library */
 
462
    public static final int TECEDITCELL = 040000000;
 
463
    /** set if cell is a multi-page schematic */
 
464
    private static final int MULTIPAGE = 017600000000;
 
465
    /** Length of base name for autonaming. */
 
466
    private static final int ABBREVLEN = 8;
 
467
    /** zero rectangle */
 
468
    private static final Rectangle2D CENTERRECT = new Rectangle2D.Double(0, 0, 0, 0);
 
469
    /** Database to which this Library belongs. */
 
470
    private final EDatabase database;
 
471
    /** Persistent data of this Cell. */
 
472
    private ImmutableCell d;
 
473
    /** The CellGroup this Cell belongs to. */
 
474
    private CellGroup cellGroup;
 
475
    /** The library this Cell belongs to. */
 
476
    private Library lib;
 
477
    /** The technology of this Cell. */
 
478
    private Technology tech;
 
479
    /** The newest version of this Cell. */
 
480
    Cell newestVersion;
 
481
    /** An array of Exports on the Cell by chronological index. */
 
482
    private Export[] chronExports = new Export[2];
 
483
    /** A sorted array of Exports on the Cell. */
 
484
    private Export[] exports = NULL_EXPORT_ARRAY;
 
485
    /** Cell's topology. */
 
486
    private Reference<Topology> topologyRef;
 
487
    /** Cell's topology. */
 
488
    private Topology strongTopology;
 
489
    /** Set containing nodeIds of expanded cells. */
 
490
    private final BitSet expandedNodes = new BitSet();
 
491
    /** Counts of NodeInsts for each CellUsage. */
 
492
    private int[] cellUsages = NULL_INT_ARRAY;
 
493
    /** A map from canonic String to Integer maximal numeric suffix */
 
494
    private final Map<String, MaxSuffix> maxSuffix = new HashMap<String, MaxSuffix>();
 
495
    /** The temporary integer value. */
 
496
    private int tempInt;
 
497
    /** Set if expanded status of subcell instances is modified. */
 
498
    private boolean expandStatusModified;
 
499
    /** Last CellTree of this Cell */
 
500
    CellTree tree;
 
501
    /** True if cell together with subcells matches cell tree. */
 
502
    boolean cellTreeFresh;
 
503
    /** Last backup of this Cell */
 
504
    CellBackup backup;
 
505
    /** True if cell together with contents matches cell backup. */
 
506
    boolean cellBackupFresh;
 
507
    /** True if cell contents matches cell backup. */
 
508
    private boolean cellContentsFresh;
 
509
    /** True if cell revision date is just set by lowLevelSetRevisionDate*/
 
510
    private boolean revisionDateFresh;
 
511
    /** A weak reference to NetCell object with Netlists */
 
512
    private Reference<NetCell> netCellRef;
 
513
 
 
514
    // ------------------ protected and private methods -----------------------
 
515
    /**
 
516
     * This constructor should not be called.
 
517
     * Use the factory "newInstance" to create a Cell.
 
518
     */
 
519
    Cell(EDatabase database, ImmutableCell d) {
479
520
        this.database = database;
480
521
        this.d = d;
481
522
        lib = database.getLib(d.getLibId());
482
523
        assert lib != null;
483
 
        if (d.techId != null)
 
524
        if (d.techId != null) {
484
525
            tech = database.getTech(d.techId);
485
 
        }
 
526
        }
 
527
        if (!LAZY_TOPOLOGY || !Job.isThreadSafe()) {
 
528
            strongTopology = new Topology(this, false);
 
529
        }
 
530
        setTopologyRef(strongTopology);
 
531
        if (NetworkTool.isLazy()) {
 
532
            setNetCellRef(null);
 
533
        }
 
534
    }
486
535
 
487
 
    private Object writeReplace() { return new CellKey(this); }
 
536
    private Object writeReplace() {
 
537
        return new CellKey(this);
 
538
    }
488
539
 
489
540
    private static class CellKey extends EObjectInputStream.Key<Cell> {
490
 
        public CellKey() {}
491
 
        private CellKey(Cell cell) { super(cell); }
 
541
 
 
542
        public CellKey() {
 
543
        }
 
544
 
 
545
        private CellKey(Cell cell) {
 
546
            super(cell);
 
547
        }
492
548
 
493
549
        @Override
494
550
        public void writeExternal(EObjectOutputStream out, Cell cell) throws IOException {
495
551
            CellId cellId = cell.getId();
496
 
            if (cell.getDatabase() != out.getDatabase() || !cell.isLinked())
 
552
            if (cell.getDatabase() != out.getDatabase() || !cell.isLinked()) {
497
553
                throw new NotSerializableException(cell + " not linked");
 
554
            }
498
555
            out.writeObject(cellId);
499
556
        }
500
557
 
501
558
        @Override
502
559
        public Cell readExternal(EObjectInputStream in) throws IOException, ClassNotFoundException {
503
 
            CellId cellId = (CellId)in.readObject();
 
560
            CellId cellId = (CellId) in.readObject();
504
561
            Cell cell = cellId.inDatabase(in.getDatabase());
505
 
            if (cell == null)
 
562
            if (cell == null) {
506
563
                throw new InvalidObjectException(cellId + " not linked");
 
564
            }
507
565
            return cell;
508
566
        }
509
567
    }
510
568
 
511
 
        /****************************** CREATE, DELETE ******************************/
512
 
 
513
 
        /**
514
 
         * Factory method to create a new Cell.
515
 
         * Also does auxiliary things to create the Cell, such as placing a cell-center if requested.
516
 
         * @param lib the Library in which to place this cell.
517
 
         * @param name the name of this cell.
518
 
         * Cell names may not contain unprintable characters, spaces, tabs, a colon (:), semicolon (;) or curly braces ({}).
519
 
         * However, the name can be fully qualified with version and view information.
520
 
         * For example, "foo;2{sch}".
521
 
         * @return the newly created cell (null on error).
522
 
         */
523
 
        public static Cell makeInstance(Library lib, String name)
524
 
        {
525
 
                Cell cell = newInstance(lib, name);
526
 
 
527
 
                // add cell-center if requested
528
 
                if (User.isPlaceCellCenter())
529
 
                {
530
 
                        NodeProto cellCenterProto = Generic.tech().cellCenterNode;
531
 
                        NodeInst cellCenter = NodeInst.newInstance(cellCenterProto, new Point2D.Double(0, 0),
532
 
                                cellCenterProto.getDefWidth(), cellCenterProto.getDefHeight(), cell);
533
 
            if (cellCenter != null)
534
 
            {
 
569
    /****************************** CREATE, DELETE ******************************/
 
570
    /**
 
571
     * Factory method to create a new Cell.
 
572
     * Also does auxiliary things to create the Cell, such as placing a cell-center if requested.
 
573
     * @param lib the Library in which to place this cell.
 
574
     * @param name the name of this cell.
 
575
     * Cell names may not contain unprintable characters, spaces, tabs, a colon (:), semicolon (;) or curly braces ({}).
 
576
     * However, the name can be fully qualified with version and view information.
 
577
     * For example, "foo;2{sch}".
 
578
     * @return the newly created cell (null on error).
 
579
     */
 
580
    public static Cell makeInstance(Library lib, String name) {
 
581
        Cell cell = newInstance(lib, name);
 
582
 
 
583
        // add cell-center if requested
 
584
        if (User.isPlaceCellCenter()) {
 
585
            NodeProto cellCenterProto = Generic.tech().cellCenterNode;
 
586
            NodeInst cellCenter = NodeInst.newInstance(cellCenterProto, new Point2D.Double(0, 0),
 
587
                    cellCenterProto.getDefWidth(), cellCenterProto.getDefHeight(), cell);
 
588
            if (cellCenter != null) {
535
589
                cellCenter.setVisInside();
536
 
                            cellCenter.setHardSelect();
 
590
                cellCenter.setHardSelect();
537
591
            }
538
 
                }
539
 
                return cell;
540
 
        }
 
592
        }
 
593
        return cell;
 
594
    }
541
595
 
542
 
        /**
543
 
         * Factory method to create a new Cell.
544
 
         * @param lib the Library in which to place this cell.
545
 
         * @param name the name of this cell.
546
 
         * Cell names may not contain unprintable characters, spaces, tabs, a colon (:), semicolon (;) or curly braces ({}).
547
 
         * However, the name can be fully qualified with version and view information.
548
 
         * For example, "foo;2{sch}".
549
 
         * @return the newly created cell (null on error).
550
 
         */
551
 
        public static Cell newInstance(Library lib, String name)
552
 
        {
553
 
                lib.checkChanging();
 
596
    /**
 
597
     * Factory method to create a new Cell.
 
598
     * @param lib the Library in which to place this cell.
 
599
     * @param name the name of this cell.
 
600
     * Cell names may not contain unprintable characters, spaces, tabs, a colon (:), semicolon (;) or curly braces ({}).
 
601
     * However, the name can be fully qualified with version and view information.
 
602
     * For example, "foo;2{sch}".
 
603
     * @return the newly created cell (null on error).
 
604
     */
 
605
    public static Cell newInstance(Library lib, String name) {
 
606
        lib.checkChanging();
554
607
        EDatabase database = lib.getDatabase();
555
608
 
556
 
                CellName cellName = CellName.parseName(name);
557
 
                if (cellName == null) return null;
 
609
        CellName cellName = CellName.parseName(name);
 
610
        if (cellName == null) {
 
611
            return null;
 
612
        }
558
613
 
559
 
                // check name for legal characters
560
 
                String protoName = cellName.getName();
561
 
                String original = null;
562
 
                for(int i=0; i<protoName.length(); i++)
563
 
                {
564
 
                        char chr = protoName.charAt(i);
565
 
                        if (Character.isWhitespace(chr) || chr == ':' || chr == ';' || chr == '{' || chr == '}')
566
 
                        {
567
 
                                if (original == null) original = protoName;
568
 
                                protoName = protoName.substring(0, i) + '_' + protoName.substring(i+1);
569
 
                        }
570
 
                }
571
 
                if (original != null)
572
 
                {
573
 
                        System.out.println("Cell name changed from '" + original + "' to '" + protoName + "'");
574
 
                        cellName = CellName.newName(protoName, cellName.getView(), cellName.getVersion());
575
 
                }
 
614
        // check name for legal characters
 
615
        String protoName = cellName.getName();
 
616
        String original = null;
 
617
        for (int i = 0; i < protoName.length(); i++) {
 
618
            char chr = protoName.charAt(i);
 
619
            if (Character.isWhitespace(chr) || chr == ':' || chr == ';' || chr == '{' || chr == '}') {
 
620
                if (original == null) {
 
621
                    original = protoName;
 
622
                }
 
623
                protoName = protoName.substring(0, i) + '_' + protoName.substring(i + 1);
 
624
            }
 
625
        }
 
626
        if (original != null) {
 
627
            System.out.println("Cell name changed from '" + original + "' to '" + protoName + "'");
 
628
            cellName = CellName.newName(protoName, cellName.getView(), cellName.getVersion());
 
629
        }
576
630
        cellName = makeUnique(lib, cellName);
577
631
 
578
632
        Date creationDate = new Date();
579
633
        CellId cellId = lib.getId().newCellId(cellName);
580
 
                Cell cell = new Cell(lib.getDatabase(), ImmutableCell.newInstance(cellId, creationDate.getTime()));
 
634
        Cell cell = new Cell(lib.getDatabase(), ImmutableCell.newInstance(cellId, creationDate.getTime()));
581
635
 
582
 
                // success
 
636
        // success
583
637
        database.addCell(cell);
584
 
                // add ourselves to the library
 
638
        // add ourselves to the library
585
639
        lib.addCell(cell);
586
640
 
587
 
                // add ourselves to cell group
588
 
                cell.lowLevelLinkCellName();
 
641
        // add ourselves to cell group
 
642
        cell.lowLevelLinkCellName();
589
643
 
590
 
                // handle change control, constraint, and broadcast
 
644
        // handle change control, constraint, and broadcast
591
645
        database.unfreshSnapshot();
592
 
                Constraints.getCurrent().newObject(cell);
593
 
                return cell;
594
 
        }
595
 
 
596
 
        private void lowLevelLinkCellName()
597
 
        {
598
 
                // determine the cell group
599
 
                for (Iterator<Cell> it = getViewsTail(); it.hasNext(); )
600
 
                {
601
 
                        Cell c = it.next();
602
 
                        if (c.getName().equals(getName()))
603
 
                                cellGroup = c.cellGroup;
604
 
                }
605
 
                // still none: make a new one
606
 
                if (cellGroup == null) cellGroup = new CellGroup(lib);
607
 
 
608
 
                // add ourselves to cell group
609
 
                cellGroup.add(this);
610
 
        }
611
 
 
612
 
        /**
613
 
         * Method to remove this node from all lists.
614
 
         */
615
 
        public void kill()
616
 
        {
617
 
                if (!isLinked())
618
 
                {
619
 
                        System.out.println("Cell already killed");
620
 
                        return;
621
 
                }
622
 
                checkChanging();
623
 
 
624
 
                // remove ourselves from the cellGroup.
625
 
                lib.removeCell(this);
626
 
                cellGroup.remove(this);
 
646
        Constraints.getCurrent().newObject(cell);
 
647
        return cell;
 
648
    }
 
649
 
 
650
    private void lowLevelLinkCellName() {
 
651
        // determine the cell group
 
652
        for (Iterator<Cell> it = getViewsTail(); it.hasNext();) {
 
653
            Cell c = it.next();
 
654
            if (c.getName().equals(getName())) {
 
655
                cellGroup = c.cellGroup;
 
656
            }
 
657
        }
 
658
        // still none: make a new one
 
659
        if (cellGroup == null) {
 
660
            cellGroup = new CellGroup(lib);
 
661
        }
 
662
 
 
663
        // add ourselves to cell group
 
664
        cellGroup.add(this);
 
665
    }
 
666
 
 
667
    /**
 
668
     * Method to remove this node from all lists.
 
669
     */
 
670
    public void kill() {
 
671
        if (!isLinked()) {
 
672
            System.out.println("Cell already killed");
 
673
            return;
 
674
        }
 
675
        checkChanging();
 
676
 
 
677
        List<NodeInst> nodesToKill = new ArrayList<NodeInst>();
 
678
        for (Iterator<NodeInst> it = getInstancesOf(); it.hasNext();) {
 
679
            nodesToKill.add(it.next());
 
680
        }
 
681
        for (NodeInst ni : nodesToKill) {
 
682
            ni.kill();
 
683
        }
 
684
        assert !getUsagesOf().hasNext();
 
685
 
 
686
        // remove ourselves from the cellGroup.
 
687
        lib.removeCell(this);
 
688
        cellGroup.remove(this);
627
689
        database.removeCell(getId());
628
690
 
629
 
                // handle change control, constraint, and broadcast
 
691
        // handle change control, constraint, and broadcast
630
692
        database.unfreshSnapshot();
631
693
//        lib.setChanged();
632
 
                Constraints.getCurrent().killObject(this);
633
 
        }
634
 
 
635
 
        /**
636
 
         * Method to copy a Cell to any Library.
637
 
         * @param fromCell the Cell to copy.
638
 
         * @param toLib the Library to copy it to.
639
 
         * @param toName the name of the Cell in the destination Library.
640
 
         * If the destination library is the same as the original Cell's library and the new name is the same
641
 
         * as the old name, a new version is made.
642
 
         * @param useExisting true to use existing subcell instances if they exist in the destination Library.
643
 
         * @return the new Cell in the destination Library.
644
 
         */
645
 
        public static Cell copyNodeProto(Cell fromCell, Library toLib, String toName, boolean useExisting)
646
 
        {
647
 
                return copyNodeProto(fromCell, toLib, toName, useExisting, null);
648
 
        }
649
 
 
650
 
        /**
651
 
         * Method to copy a Cell to any Library.
652
 
         * @param fromCell the Cell to copy.
653
 
         * @param toLib the Library to copy it to.
654
 
         * @param toName the name of the Cell in the destination Library.
655
 
         * If the destination library is the same as the original Cell's library and the new name is the same
656
 
         * as the old name, a new version is made.
657
 
         * @param useExisting true to use existing subcell instances if they exist in the destination Library.
658
 
         * @param cellNamesToUse a map that disambiguates cell names when they clash in different original libraries.
659
 
         * The main key is an old cell name, and the value for that key is a map of library names to new cell names.
660
 
         * So, for example, if libraries "A" and "B" both have a cell called "X", then existing.get("X").get("A") is "X" but
661
 
         * existing.get(X").get("B") is "X_1" which disambiguates the cell names in the destination library.  The map may be null.
662
 
         * @return the new Cell in the destination Library.
663
 
         */
664
 
        public static Cell copyNodeProto(Cell fromCell, Library toLib, String toName, boolean useExisting,
665
 
                Map<String,Map<String,String>> cellNamesToUse)
666
 
        {
667
 
                // check for validity
668
 
                if (fromCell == null) return null;
669
 
                if (toLib == null) return null;
670
 
 
671
 
                // make sure name of new cell is valid
672
 
                for(int i=0; i<toName.length(); i++)
673
 
                {
674
 
                        char ch = toName.charAt(i);
675
 
                        if (ch <= ' ' || ch == ':' || ch >= 0177)
676
 
            {
 
694
        Constraints.getCurrent().killObject(this);
 
695
    }
 
696
 
 
697
    /**
 
698
     * Method to copy a Cell to any Library.
 
699
     * @param fromCell the Cell to copy.
 
700
     * @param toLib the Library to copy it to.
 
701
     * @param toName the name of the Cell in the destination Library.
 
702
     * If the destination library is the same as the original Cell's library and the new name is the same
 
703
     * as the old name, a new version is made.
 
704
     * @param useExisting true to use existing subcell instances if they exist in the destination Library.
 
705
     * @return the new Cell in the destination Library.
 
706
     */
 
707
    public static Cell copyNodeProto(Cell fromCell, Library toLib, String toName, boolean useExisting) {
 
708
        return copyNodeProto(fromCell, toLib, toName, useExisting, null);
 
709
    }
 
710
 
 
711
    /**
 
712
     * Method to copy a Cell to any Library.
 
713
     * @param fromCell the Cell to copy.
 
714
     * @param toLib the Library to copy it to.
 
715
     * @param toName the name of the Cell in the destination Library.
 
716
     * If the destination library is the same as the original Cell's library and the new name is the same
 
717
     * as the old name, a new version is made.
 
718
     * @param useExisting true to use existing subcell instances if they exist in the destination Library.
 
719
     * @param cellNamesToUse a map that disambiguates cell names when they clash in different original libraries.
 
720
     * The main key is an old cell name, and the value for that key is a map of library names to new cell names.
 
721
     * So, for example, if libraries "A" and "B" both have a cell called "X", then existing.get("X").get("A") is "X" but
 
722
     * existing.get(X").get("B") is "X_1" which disambiguates the cell names in the destination library.  The map may be null.
 
723
     * @return the new Cell in the destination Library.
 
724
     */
 
725
    public static Cell copyNodeProto(Cell fromCell, Library toLib, String toName, boolean useExisting,
 
726
            Map<String, Map<String, String>> cellNamesToUse) {
 
727
        // check for validity
 
728
        if (fromCell == null) {
 
729
            return null;
 
730
        }
 
731
        if (toLib == null) {
 
732
            return null;
 
733
        }
 
734
 
 
735
        // make sure name of new cell is valid
 
736
        for (int i = 0; i < toName.length(); i++) {
 
737
            char ch = toName.charAt(i);
 
738
            if (ch <= ' ' || ch == ':' || ch >= 0177) {
677
739
                System.out.println("invalid name of new cell");
678
740
                return null;
679
741
            }
680
 
                }
681
 
 
682
 
                // determine whether this copy is to a different library
683
 
                Library destLib = toLib;
684
 
                if (toLib == fromCell.getLibrary()) destLib = null;
685
 
 
686
 
                // mark the proper prototype to use for each node
687
 
                Map<NodeInst,NodeProto> nodePrototypes = new HashMap<NodeInst,NodeProto>();
688
 
 
689
 
                // if doing a cross-library copy and can use existing ones from new library, do it
690
 
                if (destLib != null)
691
 
                {
692
 
                        // scan all subcells to see if they are found in the new library
693
 
                        for(Iterator<NodeInst> it = fromCell.getNodes(); it.hasNext(); )
694
 
                        {
695
 
                                NodeInst ni = it.next();
696
 
                                if (!ni.isCellInstance()) continue;
697
 
                                Cell niProto = (Cell)ni.getProto();
698
 
 
699
 
                                boolean maySubstitute = useExisting;
700
 
                                if (!maySubstitute)
701
 
                                {
702
 
                                        // force substitution for documentation icons
703
 
                                        if (niProto.isIcon())
704
 
                                        {
705
 
                                                if (niProto.isIconOf(fromCell)) maySubstitute = true;
706
 
                                        }
707
 
                                }
708
 
                                if (!maySubstitute) continue;
709
 
 
710
 
                                // switch cell names if disambiguating
711
 
                                String oldCellName = niProto.getName();
712
 
                                if (cellNamesToUse != null)
713
 
                                {
714
 
                                        Map<String,String> libToNameMap = cellNamesToUse.get(oldCellName);
715
 
                                        if (libToNameMap != null)
716
 
                                        {
717
 
                                                String newCellName = libToNameMap.get(niProto.getLibrary().getName());
718
 
                                                if (newCellName != null) oldCellName = newCellName;
719
 
                                        }
720
 
                                }
721
 
 
722
 
                                // search for cell with same name and view in new library
723
 
                                Cell lnt = null;
724
 
                                for(Iterator<Cell> cIt = toLib.getCells(); cIt.hasNext(); )
725
 
                                {
726
 
                                        lnt = cIt.next();
727
 
                                        if (lnt.getName().equals(oldCellName) &&
728
 
//                                      if (lnt.getName().equalsIgnoreCase(oldCellName) &&
729
 
                                                lnt.getView() == niProto.getView()) break;
730
 
                                        lnt = null;
731
 
                                }
732
 
                                if (lnt == null) continue;
733
 
 
734
 
                                // make sure all used ports can be found on the uncopied cell
735
 
                                boolean validPorts = true;
736
 
                                for(Iterator<PortInst> pIt = ni.getPortInsts(); pIt.hasNext(); )
737
 
                                {
738
 
                                        PortInst pi = pIt.next();
739
 
                                        PortProto pp = pi.getPortProto();
740
 
                                        PortProto ppt = lnt.findPortProto(pp.getName());
 
742
        }
 
743
 
 
744
        // determine whether this copy is to a different library
 
745
        Library destLib = toLib;
 
746
        if (toLib == fromCell.getLibrary()) {
 
747
            destLib = null;
 
748
        }
 
749
 
 
750
        // mark the proper prototype to use for each node
 
751
        Map<NodeInst, NodeProto> nodePrototypes = new HashMap<NodeInst, NodeProto>();
 
752
 
 
753
        // if doing a cross-library copy and can use existing ones from new library, do it
 
754
        if (destLib != null) {
 
755
            // scan all subcells to see if they are found in the new library
 
756
            for (Iterator<NodeInst> it = fromCell.getNodes(); it.hasNext();) {
 
757
                NodeInst ni = it.next();
 
758
                if (!ni.isCellInstance()) {
 
759
                    continue;
 
760
                }
 
761
                Cell niProto = (Cell) ni.getProto();
 
762
 
 
763
                boolean maySubstitute = useExisting;
 
764
                if (!maySubstitute) {
 
765
                    // force substitution for documentation icons
 
766
                    if (niProto.isIcon()) {
 
767
                        if (niProto.isIconOf(fromCell)) {
 
768
                            maySubstitute = true;
 
769
                        }
 
770
                    }
 
771
                }
 
772
                if (!maySubstitute) {
 
773
                    continue;
 
774
                }
 
775
 
 
776
                // switch cell names if disambiguating
 
777
                String oldCellName = niProto.getName();
 
778
                if (cellNamesToUse != null) {
 
779
                    Map<String, String> libToNameMap = cellNamesToUse.get(oldCellName);
 
780
                    if (libToNameMap != null) {
 
781
                        String newCellName = libToNameMap.get(niProto.getLibrary().getName());
 
782
                        if (newCellName != null) {
 
783
                            oldCellName = newCellName;
 
784
                        }
 
785
                    }
 
786
                }
 
787
 
 
788
                // search for cell with same name and view in new library
 
789
                Cell lnt = null;
 
790
                for (Iterator<Cell> cIt = toLib.getCells(); cIt.hasNext();) {
 
791
                    lnt = cIt.next();
 
792
                    if (lnt.getName().equals(oldCellName)
 
793
                            && //                                       if (lnt.getName().equalsIgnoreCase(oldCellName) &&
 
794
                            lnt.getView() == niProto.getView()) {
 
795
                        break;
 
796
                    }
 
797
                    lnt = null;
 
798
                }
 
799
                if (lnt == null) {
 
800
                    continue;
 
801
                }
 
802
 
 
803
                // make sure all used ports can be found on the uncopied cell
 
804
                boolean validPorts = true;
 
805
                for (Iterator<PortInst> pIt = ni.getPortInsts(); pIt.hasNext();) {
 
806
                    PortInst pi = pIt.next();
 
807
                    PortProto pp = pi.getPortProto();
 
808
                    PortProto ppt = lnt.findPortProto(pp.getName());
741
809
//                                      if (ppt != null)
742
810
//                                      {
743
811
//                                              // the connections must match, too
744
812
//                                              if (pp->connects != ppt->connects) ppt = null;
745
813
//                                      }
746
 
                                        if (ppt == null)
747
 
                                        {
748
 
                                                System.out.println("Cannot use subcell " + lnt.noLibDescribe() + " in " + destLib +
749
 
                                                        ": exports don't match");
750
 
                                                validPorts = false;
751
 
                                                break;
752
 
                                        }
753
 
                                }
754
 
                                if (!validPorts) continue;
755
 
 
756
 
                                // match found: use the prototype from the destination library
757
 
                                nodePrototypes.put(ni, lnt);
758
 
                        }
759
 
                }
760
 
                return copyNodeProtoUsingMapping(fromCell, toLib, toName, nodePrototypes);
761
 
        }
762
 
 
763
 
        /**
764
 
         * Method to copy a Cell to any Library, using a preset mapping of node prototypes.
765
 
         * @param fromCell the Cell to copy.
766
 
         * @param toLib the Library to copy it to.
767
 
         * If the destination library is the same as the original Cell's library, a new version is made.
768
 
         * @param toName the name of the Cell in the destination Library.
769
 
         * @param nodePrototypes a HashMap from NodeInsts in the source Cell to proper NodeProtos to use in the new Cell.
770
 
         * @return the new Cell in the destination Library.
771
 
         */
772
 
        public static Cell copyNodeProtoUsingMapping(Cell fromCell, Library toLib, String toName,
773
 
                Map<NodeInst,NodeProto> nodePrototypes)
774
 
        {
775
 
                // create the nodeproto
776
 
                String cellName = toName;
777
 
                if (toName.indexOf('{') < 0 && fromCell.getView() != View.UNKNOWN)
778
 
                {
779
 
                        cellName = toName + fromCell.getView().getAbbreviationExtension();
780
 
                }
781
 
                Cell newCell = Cell.newInstance(toLib, cellName);
782
 
                if (newCell == null) return(null);
783
 
                newCell.lowLevelSetUserbits(fromCell.lowLevelGetUserbits());
784
 
 
785
 
                // copy nodes
786
 
                Map<NodeInst,NodeInst> newNodes = new HashMap<NodeInst,NodeInst>();
787
 
                for(Iterator<NodeInst> it = fromCell.getNodes(); it.hasNext(); )
788
 
                {
789
 
                        // create the new nodeinst
790
 
                        NodeInst ni = it.next();
791
 
                        NodeProto lnt = nodePrototypes.get(ni);
792
 
                        if (lnt == null) lnt = ni.getProto();
793
 
                        double scaleX = ni.getXSize();   //if (ni.isXMirrored()) scaleX = -scaleX;
794
 
                        double scaleY = ni.getYSize();   //if (ni.isYMirrored()) scaleY = -scaleY;
795
 
                        NodeInst toNi = NodeInst.newInstance(lnt, new Point2D.Double(ni.getAnchorCenterX(), ni.getAnchorCenterY()),
796
 
                                scaleX, scaleY, newCell, ni.getOrient(), ni.getName());
797
 
                        if (toNi == null) return null;
798
 
 
799
 
                        // save the new nodeinst address in the old nodeinst
800
 
                        newNodes.put(ni, toNi);
801
 
 
802
 
                        // copy miscellaneous information
803
 
                        toNi.copyTextDescriptorFrom(ni, NodeInst.NODE_PROTO);
804
 
                        toNi.copyTextDescriptorFrom(ni, NodeInst.NODE_NAME);
805
 
                        toNi.copyStateBits(ni);
806
 
                }
807
 
 
808
 
                // now copy the variables on the nodes
809
 
                for(Iterator<NodeInst> it = fromCell.getNodes(); it.hasNext(); )
810
 
                {
811
 
                        NodeInst ni = it.next();
812
 
                        NodeInst toNi = newNodes.get(ni);
813
 
                        toNi.copyVarsFrom(ni);
 
814
                    if (ppt == null) {
 
815
                        System.out.println("Cannot use subcell " + lnt.noLibDescribe() + " in " + destLib
 
816
                                + ": exports don't match");
 
817
                        validPorts = false;
 
818
                        break;
 
819
                    }
 
820
                }
 
821
                if (!validPorts) {
 
822
                    continue;
 
823
                }
 
824
 
 
825
                // match found: use the prototype from the destination library
 
826
                nodePrototypes.put(ni, lnt);
 
827
            }
 
828
        }
 
829
        return copyNodeProtoUsingMapping(fromCell, toLib, toName, nodePrototypes);
 
830
    }
 
831
 
 
832
    /**
 
833
     * Method to copy a Cell to any Library, using a preset mapping of node prototypes.
 
834
     * @param fromCell the Cell to copy.
 
835
     * @param toLib the Library to copy it to.
 
836
     * If the destination library is the same as the original Cell's library, a new version is made.
 
837
     * @param toName the name of the Cell in the destination Library.
 
838
     * @param nodePrototypes a HashMap from NodeInsts in the source Cell to proper NodeProtos to use in the new Cell.
 
839
     * @return the new Cell in the destination Library.
 
840
     */
 
841
    public static Cell copyNodeProtoUsingMapping(Cell fromCell, Library toLib, String toName,
 
842
            Map<NodeInst, NodeProto> nodePrototypes) {
 
843
        // create the nodeproto
 
844
        String cellName = toName;
 
845
        if (toName.indexOf('{') < 0 && fromCell.getView() != View.UNKNOWN) {
 
846
            cellName = toName + fromCell.getView().getAbbreviationExtension();
 
847
        }
 
848
        Cell newCell = Cell.newInstance(toLib, cellName);
 
849
        if (newCell == null) {
 
850
            return (null);
 
851
        }
 
852
        newCell.lowLevelSetUserbits(fromCell.lowLevelGetUserbits());
 
853
 
 
854
        // copy nodes
 
855
        Map<NodeInst, NodeInst> newNodes = new HashMap<NodeInst, NodeInst>();
 
856
        for (Iterator<NodeInst> it = fromCell.getNodes(); it.hasNext();) {
 
857
            // create the new nodeinst
 
858
            NodeInst ni = it.next();
 
859
            NodeProto lnt = nodePrototypes.get(ni);
 
860
            if (lnt == null) {
 
861
                lnt = ni.getProto();
 
862
            }
 
863
            double scaleX = ni.getXSize();   //if (ni.isXMirrored()) scaleX = -scaleX;
 
864
            double scaleY = ni.getYSize();   //if (ni.isYMirrored()) scaleY = -scaleY;
 
865
            NodeInst toNi = NodeInst.newInstance(lnt, new Point2D.Double(ni.getAnchorCenterX(), ni.getAnchorCenterY()),
 
866
                    scaleX, scaleY, newCell, ni.getOrient(), ni.getName());
 
867
            if (toNi == null) {
 
868
                return null;
 
869
            }
 
870
 
 
871
            // save the new nodeinst address in the old nodeinst
 
872
            newNodes.put(ni, toNi);
 
873
 
 
874
            // copy miscellaneous information
 
875
            toNi.copyTextDescriptorFrom(ni, NodeInst.NODE_PROTO);
 
876
            toNi.copyTextDescriptorFrom(ni, NodeInst.NODE_NAME);
 
877
            toNi.copyStateBitsAndExpandedFlag(ni);
 
878
        }
 
879
 
 
880
        // now copy the variables on the nodes
 
881
        for (Iterator<NodeInst> it = fromCell.getNodes(); it.hasNext();) {
 
882
            NodeInst ni = it.next();
 
883
            NodeInst toNi = newNodes.get(ni);
 
884
            toNi.copyVarsFrom(ni);
814
885
 
815
886
            // if this is an icon, and this nodeinst is the box with the name of the cell on it,
816
887
            // then change the name from the old to the new
817
888
            if (newCell.isIcon()) {
818
889
                String name = toNi.getVarValue(Schematics.SCHEM_FUNCTION, String.class);
819
 
                if (fromCell.getName().equals(name))
 
890
                if (fromCell.getName().equals(name)) {
820
891
                    toNi.updateVar(Schematics.SCHEM_FUNCTION, newCell.getName());
821
 
            }
822
 
                }
823
 
 
824
 
                // copy arcs
825
 
                for(Iterator<ArcInst> it = fromCell.getArcs(); it.hasNext(); )
826
 
                {
827
 
                        ArcInst ai = it.next();
828
 
 
829
 
                        // find the nodeinst and portinst connections for this arcinst
830
 
                        PortInst [] opi = new PortInst[2];
831
 
                        Point2D [] oLoc = new Point2D[2];
832
 
                        for(int i=0; i<2; i++)
833
 
                        {
834
 
                                opi[i] = null;
835
 
                                NodeInst ono = newNodes.get(ai.getPortInst(i).getNodeInst());
836
 
                                PortProto pp = ai.getPortInst(i).getPortProto();
837
 
                                if (!ono.isCellInstance())
838
 
                                {
839
 
                                        // primitives associate ports directly
840
 
                                        opi[i] = ono.findPortInstFromProto(pp);
841
 
                                } else
842
 
                                {
843
 
                                        // cells associate ports by name
844
 
                                        PortProto ppt = ono.getProto().findPortProto(pp.getName());
845
 
                                        if (ppt != null) opi[i] = ono.findPortInstFromProto(ppt);
846
 
                                }
847
 
                                if (opi[i] == null)
848
 
                                        System.out.println("Error: no port for " + ai.getProto() +
849
 
                                                " arc on " + ono.getProto());
850
 
                                oLoc[i] = ai.getLocation(i);
851
 
                        Poly poly = opi[i].getPoly();
852
 
                        if (!poly.isInside(oLoc[i])) oLoc[i] = poly.getCenter();
853
 
                        }
854
 
                        if (opi[0] == null || opi[1] == null) return null;
855
 
 
856
 
                        // create the arcinst
857
 
                        ArcInst toAi = ArcInst.newInstanceBase(ai.getProto(), ai.getLambdaBaseWidth(), opi[ArcInst.HEADEND], opi[ArcInst.TAILEND],
858
 
                                oLoc[ArcInst.HEADEND], oLoc[ArcInst.TAILEND], ai.getName(), ai.getAngle());
859
 
                        if (toAi == null) return null;
860
 
 
861
 
                        // copy arcinst information
862
 
                        toAi.copyPropertiesFrom(ai);
863
 
                }
864
 
 
865
 
                // copy the Exports
866
 
                for(Iterator<Export> it = fromCell.getExports(); it.hasNext(); )
867
 
                {
868
 
                        Export pp = it.next();
869
 
 
870
 
                        // match sub-portproto in old nodeinst to sub-portproto in new one
871
 
                        NodeInst ni = newNodes.get(pp.getOriginalPort().getNodeInst());
872
 
                        PortInst pi = ni.findPortInst(pp.getOriginalPort().getPortProto().getName());
873
 
                        if (pi == null)
874
 
                        {
875
 
                                System.out.println("Error: no port on " + pp.getOriginalPort().getNodeInst().getProto());
876
 
                                return null;
877
 
                        }
878
 
 
879
 
                        // create the nodeinst portinst
880
 
                        Export ppt = Export.newInstance(newCell, pi, pp.getName());
881
 
                        if (ppt == null) return null;
882
 
 
883
 
                        // copy portproto variables
884
 
                        ppt.copyVarsFrom(pp);
885
 
 
886
 
                        // copy miscellaneous information
887
 
                        ppt.copyStateBits(pp);
888
 
                        ppt.copyTextDescriptorFrom(pp, Export.EXPORT_NAME);
889
 
                }
890
 
 
891
 
                // copy cell variables
892
 
        for (Iterator<Variable> it = fromCell.getParametersAndVariables(); it.hasNext(); ) {
 
892
                }
 
893
            }
 
894
        }
 
895
 
 
896
        // copy arcs
 
897
        for (Iterator<ArcInst> it = fromCell.getArcs(); it.hasNext();) {
 
898
            ArcInst ai = it.next();
 
899
 
 
900
            // find the nodeinst and portinst connections for this arcinst
 
901
            PortInst[] opi = new PortInst[2];
 
902
            Point2D[] oLoc = new Point2D[2];
 
903
            for (int i = 0; i < 2; i++) {
 
904
                opi[i] = null;
 
905
                NodeInst ono = newNodes.get(ai.getPortInst(i).getNodeInst());
 
906
                PortProto pp = ai.getPortInst(i).getPortProto();
 
907
                if (!ono.isCellInstance()) {
 
908
                    // primitives associate ports directly
 
909
                    opi[i] = ono.findPortInstFromProto(pp);
 
910
                } else {
 
911
                    // cells associate ports by name
 
912
                    PortProto ppt = ono.getProto().findPortProto(pp.getName());
 
913
                    if (ppt != null) {
 
914
                        opi[i] = ono.findPortInstFromProto(ppt);
 
915
                    }
 
916
                }
 
917
                if (opi[i] == null) {
 
918
                    System.out.println("Error: no port for " + ai.getProto()
 
919
                            + " arc on " + ono.getProto());
 
920
                }
 
921
                oLoc[i] = ai.getLocation(i);
 
922
                Poly poly = opi[i].getPoly();
 
923
                if (!poly.isInside(oLoc[i])) {
 
924
                    oLoc[i] = poly.getCenter();
 
925
                }
 
926
            }
 
927
            if (opi[0] == null || opi[1] == null) {
 
928
                return null;
 
929
            }
 
930
 
 
931
            // create the arcinst
 
932
            ArcInst toAi = ArcInst.newInstanceBase(ai.getProto(), ai.getLambdaBaseWidth(), opi[ArcInst.HEADEND], opi[ArcInst.TAILEND],
 
933
                    oLoc[ArcInst.HEADEND], oLoc[ArcInst.TAILEND], ai.getName(), ai.getAngle());
 
934
            if (toAi == null) {
 
935
                return null;
 
936
            }
 
937
 
 
938
            // copy arcinst information
 
939
            toAi.copyPropertiesFrom(ai);
 
940
        }
 
941
 
 
942
        // copy the Exports
 
943
        for (Iterator<Export> it = fromCell.getExports(); it.hasNext();) {
 
944
            Export pp = it.next();
 
945
 
 
946
            // match sub-portproto in old nodeinst to sub-portproto in new one
 
947
            NodeInst ni = newNodes.get(pp.getOriginalPort().getNodeInst());
 
948
            PortInst pi = ni.findPortInst(pp.getOriginalPort().getPortProto().getName());
 
949
            if (pi == null) {
 
950
                System.out.println("Error: no port on " + pp.getOriginalPort().getNodeInst().getProto());
 
951
                return null;
 
952
            }
 
953
 
 
954
            // create the nodeinst portinst
 
955
            Export ppt = Export.newInstance(newCell, pi, pp.getName());
 
956
            if (ppt == null) {
 
957
                return null;
 
958
            }
 
959
 
 
960
            // copy portproto variables
 
961
            ppt.copyVarsFrom(pp);
 
962
 
 
963
            // copy miscellaneous information
 
964
            ppt.copyStateBits(pp);
 
965
            ppt.copyTextDescriptorFrom(pp, Export.EXPORT_NAME);
 
966
        }
 
967
 
 
968
        // copy cell variables
 
969
        for (Iterator<Variable> it = fromCell.getParametersAndVariables(); it.hasNext();) {
893
970
            Variable fromVar = it.next();
894
971
            if (newCell.isParam(fromVar.getKey())) {
895
972
                newCell.setTextDescriptor(fromVar.getKey(), fromVar.getTextDescriptor());
901
978
            }
902
979
        }
903
980
 
904
 
                // reset (copy) date information
905
 
                newCell.lowLevelSetCreationDate(fromCell.getCreationDate());
906
 
                newCell.lowLevelSetRevisionDate(fromCell.getRevisionDate());
907
 
 
908
 
                return newCell;
909
 
        }
910
 
 
911
 
        /**
912
 
         * Method to replace subcells of a Cell by cells with similar name in Cell's     */
 
981
        // reset (copy) date information
 
982
        newCell.lowLevelSetCreationDate(fromCell.getCreationDate());
 
983
        newCell.lowLevelSetRevisionDate(fromCell.getRevisionDate());
 
984
 
 
985
        return newCell;
 
986
    }
 
987
 
 
988
    /**
 
989
     * Method to replace subcells of a Cell by cells with similar name in Cell's         */
913
990
    public void replaceSubcellsByExisting() {
914
991
        // scan all subcells to see if they are found in the new library
915
 
                Map<NodeInst,Cell> nodePrototypes = new HashMap<NodeInst,Cell>();
916
 
        for(Iterator<NodeInst> it = getNodes(); it.hasNext(); ) {
 
992
        Map<NodeInst, Cell> nodePrototypes = new HashMap<NodeInst, Cell>();
 
993
        for (Iterator<NodeInst> it = getNodes(); it.hasNext();) {
917
994
            NodeInst ni = it.next();
918
 
            if (!ni.isCellInstance()) continue;
919
 
            Cell niProto = (Cell)ni.getProto();
920
 
            if (niProto.lib == lib) continue;
 
995
            if (!ni.isCellInstance()) {
 
996
                continue;
 
997
            }
 
998
            Cell niProto = (Cell) ni.getProto();
 
999
            if (niProto.lib == lib) {
 
1000
                continue;
 
1001
            }
921
1002
 
922
1003
            // search for cell with same name and view in new library
923
1004
            Cell lnt = null;
924
 
            for(Iterator<Cell> cIt = lib.getCells(); cIt.hasNext(); ) {
 
1005
            for (Iterator<Cell> cIt = lib.getCells(); cIt.hasNext();) {
925
1006
                lnt = cIt.next();
926
 
                if (lnt.getName().equals(niProto.getName()) &&
927
 
//                if (lnt.getName().equalsIgnoreCase(niProto.getName()) &&
928
 
                        lnt.getView() == niProto.getView()) break;
 
1007
                if (lnt.getName().equals(niProto.getName())
 
1008
                        && //                if (lnt.getName().equalsIgnoreCase(niProto.getName()) &&
 
1009
                        lnt.getView() == niProto.getView()) {
 
1010
                    break;
 
1011
                }
929
1012
                lnt = null;
930
1013
            }
931
 
            if (lnt == null) continue;
 
1014
            if (lnt == null) {
 
1015
                continue;
 
1016
            }
932
1017
 
933
1018
            // make sure all used ports can be found on the uncopied cell
934
1019
            boolean validPorts = true;
935
 
            for(Iterator<PortInst> pIt = ni.getPortInsts(); pIt.hasNext(); ) {
 
1020
            for (Iterator<PortInst> pIt = ni.getPortInsts(); pIt.hasNext();) {
936
1021
                PortInst pi = pIt.next();
937
1022
                PortProto pp = pi.getPortProto();
938
1023
                PortProto ppt = lnt.findPortProto(pp.getName());
941
1026
//                                              if (pp->connects != ppt->connects) ppt = null;
942
1027
//                }
943
1028
                if (ppt == null) {
944
 
                    System.out.println("Cannot use subcell " + lnt.noLibDescribe() + " in " + lib +
945
 
                            ": exports don't match");
 
1029
                    System.out.println("Cannot use subcell " + lnt.noLibDescribe() + " in " + lib
 
1030
                            + ": exports don't match");
946
1031
                    validPorts = false;
947
1032
                    break;
948
1033
                }
949
1034
            }
950
 
            if (!validPorts) continue;
 
1035
            if (!validPorts) {
 
1036
                continue;
 
1037
            }
951
1038
 
952
1039
            // match found: use the prototype from the destination library
953
1040
            nodePrototypes.put(ni, lnt);
954
1041
        }
955
 
        for (Map.Entry<NodeInst,Cell> e: nodePrototypes.entrySet()) {
 
1042
        for (Map.Entry<NodeInst, Cell> e : nodePrototypes.entrySet()) {
956
1043
            NodeInst ni = e.getKey();
957
1044
            Cell newProto = e.getValue();
958
1045
            ni.replace(newProto, false, false);
959
1046
        }
960
1047
    }
961
1048
 
962
 
        /**
963
 
         * Method to rename this Cell.
964
 
         * @param newName the new name of this cell.
 
1049
    /**
 
1050
     * Method to rename this Cell.
 
1051
     * @param newName the new name of this cell.
965
1052
     * @param newGroupName the name of cell in a group to put the rename cell to.
966
 
         */
967
 
        public IdMapper rename(String newName, String newGroupName)
968
 
        {
969
 
                return rename(CellName.parseName(newName + ";" + getVersion() + getView().getAbbreviationExtension()), newGroupName);
970
 
        }
 
1053
     */
 
1054
    public IdMapper rename(String newName, String newGroupName) {
 
1055
        return rename(CellName.parseName(newName + ";" + getVersion() + getView().getAbbreviationExtension()), newGroupName);
 
1056
    }
971
1057
 
972
 
        /**
973
 
         * Method to rename this Cell.
974
 
         * @param cellName the new name of this cell.
975
 
         */
976
 
        private IdMapper rename(CellName cellName, String newGroupName)
977
 
        {
978
 
                checkChanging();
979
 
                assert isLinked();
980
 
                if (cellName == null) return null;
981
 
                if (getCellName().equals(cellName)) return null;
 
1058
    /**
 
1059
     * Method to rename this Cell.
 
1060
     * @param cellName the new name of this cell.
 
1061
     */
 
1062
    private IdMapper rename(CellName cellName, String newGroupName) {
 
1063
        checkChanging();
 
1064
        assert isLinked();
 
1065
        if (cellName == null) {
 
1066
            return null;
 
1067
        }
 
1068
        if (getCellName().equals(cellName)) {
 
1069
            return null;
 
1070
        }
982
1071
 
983
1072
//              // remove temporarily from the library and from cell group
984
1073
//              lib.removeCell(this);
985
1074
//              cellGroup.remove(this);
986
1075
 
987
 
                // remember the expansion state of instances of the cell
988
 
                Map<CellId,Map<Name,Boolean>> expansionRemap = new HashMap<CellId,Map<Name,Boolean>>();
989
 
                for(Iterator<NodeInst> it = getInstancesOf(); it.hasNext(); )
990
 
                {
991
 
                        NodeInst ni = it.next();
992
 
                        Cell cell = ni.getParent();
993
 
                        Map<Name,Boolean> cellExpansionRemap = expansionRemap.get(cell.getId());
994
 
                        if (cellExpansionRemap == null)
995
 
                        {
996
 
                                cellExpansionRemap = new HashMap<Name,Boolean>();
997
 
                                expansionRemap.put(cell.getId(), cellExpansionRemap);
998
 
                        }
999
 
                        Boolean isExpanded = new Boolean(ni.isExpanded());
1000
 
                        cellExpansionRemap.put(ni.getNameKey(), isExpanded);
1001
 
                }
 
1076
        // remember the expansion state of instances of the cell
 
1077
        Map<CellId, Map<Name, Boolean>> expansionRemap = new HashMap<CellId, Map<Name, Boolean>>();
 
1078
        for (Iterator<NodeInst> it = getInstancesOf(); it.hasNext();) {
 
1079
            NodeInst ni = it.next();
 
1080
            Cell cell = ni.getParent();
 
1081
            Map<Name, Boolean> cellExpansionRemap = expansionRemap.get(cell.getId());
 
1082
            if (cellExpansionRemap == null) {
 
1083
                cellExpansionRemap = new HashMap<Name, Boolean>();
 
1084
                expansionRemap.put(cell.getId(), cellExpansionRemap);
 
1085
            }
 
1086
            Boolean isExpanded = new Boolean(ni.isExpanded());
 
1087
            cellExpansionRemap.put(ni.getNameKey(), isExpanded);
 
1088
        }
1002
1089
 
1003
 
                // do the rename
 
1090
        // do the rename
1004
1091
        cellName = makeUnique(lib, cellName);
1005
1092
//        setD(getD().withCellName(cellName));
1006
1093
        EDatabase database = getDatabase();
1015
1102
        Constraints.getCurrent().renameIds(idMapper);
1016
1103
        lib.setChanged();
1017
1104
 
1018
 
                // restore the expansion state of instances of the cell
1019
 
        for(CellId cid : expansionRemap.keySet())
1020
 
        {
1021
 
                        Map<Name,Boolean> cellExpansionRemap = expansionRemap.get(cid);
1022
 
                        Cell cell = cid.inDatabase(database);
1023
 
                for(Name name : cellExpansionRemap.keySet())
1024
 
                {
1025
 
                        NodeInst ni = cell.findNode(name.toString());
1026
 
                        if (ni != null)
1027
 
                                ni.setExpanded(cellExpansionRemap.get(name).booleanValue());
1028
 
                }
 
1105
        // restore the expansion state of instances of the cell
 
1106
        for (CellId cid : expansionRemap.keySet()) {
 
1107
            Map<Name, Boolean> cellExpansionRemap = expansionRemap.get(cid);
 
1108
            Cell cell = cid.inDatabase(database);
 
1109
            for (Name name : cellExpansionRemap.keySet()) {
 
1110
                NodeInst ni = cell.findNode(name.toString());
 
1111
                if (ni != null) {
 
1112
                    ni.setExpanded(cellExpansionRemap.get(name).booleanValue());
 
1113
                }
 
1114
            }
1029
1115
        }
1030
1116
 
1031
1117
        return idMapper;
1032
 
        }
1033
 
 
1034
 
        /****************************** LOW-LEVEL IMPLEMENTATION ******************************/
1035
 
 
 
1118
    }
 
1119
 
 
1120
    /****************************** LOW-LEVEL IMPLEMENTATION ******************************/
1036
1121
    private static CellName makeUnique(Library lib, CellName cellName) {
1037
 
                // ensure unique cell name
1038
 
                String protoName = cellName.getName();
1039
 
                View view = cellName.getView();
1040
 
                int version = cellName.getVersion();
1041
 
                int greatestVersion = 0;
1042
 
                boolean conflict = version <= 0;
1043
 
                for (Iterator<Cell> it = lib.getCells(); it.hasNext(); )
1044
 
                {
1045
 
                        Cell c = it.next();
1046
 
                        if (c.getName().equals(protoName) && c.getView() == view)
1047
 
//                      if (c.getName().equalsIgnoreCase(protoName) && c.getView() == view)
1048
 
                        {
1049
 
                                if (c.getVersion() == version) conflict = true;
1050
 
                                if (c.getVersion() > greatestVersion)
1051
 
                                        greatestVersion = c.getVersion();
1052
 
                        }
1053
 
                }
1054
 
                if (conflict)
1055
 
                {
1056
 
                        if (version > 0)
1057
 
                                System.out.println("Already have cell " + cellName + " with version " + version + ", generating a new version");
 
1122
        // ensure unique cell name
 
1123
        String protoName = cellName.getName();
 
1124
        View view = cellName.getView();
 
1125
        int version = cellName.getVersion();
 
1126
        int greatestVersion = 0;
 
1127
        boolean conflict = version <= 0;
 
1128
        for (Iterator<Cell> it = lib.getCells(); it.hasNext();) {
 
1129
            Cell c = it.next();
 
1130
            if (c.getName().equals(protoName) && c.getView() == view) //                        if (c.getName().equalsIgnoreCase(protoName) && c.getView() == view)
 
1131
            {
 
1132
                if (c.getVersion() == version) {
 
1133
                    conflict = true;
 
1134
                }
 
1135
                if (c.getVersion() > greatestVersion) {
 
1136
                    greatestVersion = c.getVersion();
 
1137
                }
 
1138
            }
 
1139
        }
 
1140
        if (conflict) {
 
1141
            if (version > 0) {
 
1142
                System.out.println("Already have cell " + cellName + " with version " + version + ", generating a new version");
 
1143
            }
1058
1144
            int newVersion = greatestVersion + 1;
1059
 
                        cellName = CellName.newName(protoName, view, newVersion);
1060
 
                }
 
1145
            cellName = CellName.newName(protoName, view, newVersion);
 
1146
        }
1061
1147
        return cellName;
1062
1148
    }
1063
1149
 
1064
 
        /**
1065
 
         * Low-level method to get the user bits.
1066
 
         * The "user bits" are a collection of flags that are more sensibly accessed
1067
 
         * through special methods.
1068
 
         * This general access to the bits is required because the ELIB
1069
 
         * file format stores it as a full integer.
1070
 
         * This should not normally be called by any other part of the system.
1071
 
         * @return the "user bits".
1072
 
         */
1073
 
        public int lowLevelGetUserbits() { return getD().flags; }
1074
 
 
1075
 
        /**
1076
 
         * Low-level method to set the user bits.
1077
 
         * The "user bits" are a collection of flags that are more sensibly accessed
1078
 
         * through special methods.
1079
 
         * This general access to the bits is required because the ELIB
1080
 
         * file format stores it as a full integer.
1081
 
         * This should not normally be called by any other part of the system.
1082
 
         * @param userBits the new "user bits".
1083
 
         */
1084
 
        public void lowLevelSetUserbits(int userBits) { setD(getD().withFlags(userBits)); }
1085
 
 
1086
 
        /*
1087
 
         * Low-level method to backup this Cell to CellBackup.
 
1150
    /**
 
1151
     * Low-level method to get the user bits.
 
1152
     * The "user bits" are a collection of flags that are more sensibly accessed
 
1153
     * through special methods.
 
1154
     * This general access to the bits is required because the ELIB
 
1155
     * file format stores it as a full integer.
 
1156
     * This should not normally be called by any other part of the system.
 
1157
     * @return the "user bits".
 
1158
     */
 
1159
    public int lowLevelGetUserbits() {
 
1160
        return getD().flags;
 
1161
    }
 
1162
 
 
1163
    /**
 
1164
     * Low-level method to set the user bits.
 
1165
     * The "user bits" are a collection of flags that are more sensibly accessed
 
1166
     * through special methods.
 
1167
     * This general access to the bits is required because the ELIB
 
1168
     * file format stores it as a full integer.
 
1169
     * This should not normally be called by any other part of the system.
 
1170
     * @param userBits the new "user bits".
 
1171
     */
 
1172
    public void lowLevelSetUserbits(int userBits) {
 
1173
        setD(getD().withFlags(userBits));
 
1174
    }
 
1175
 
 
1176
    /*
 
1177
     * Low-level method to backup this Cell to CellTree.
 
1178
     * @return CellTree which is the backup of this Cell.
 
1179
     * @throws IllegalStateException if recalculation of Snapshot is requred in thread which is not enabled to do it.
 
1180
     */
 
1181
    public CellTree tree() {
 
1182
        if (cellTreeFresh) {
 
1183
            return tree;
 
1184
        }
 
1185
        if (Job.isThreadSafe()) {
 
1186
            checkChanging();
 
1187
        } else {
 
1188
            if (!database.canComputeBounds()) {
 
1189
                throw new IllegalStateException();
 
1190
            }
 
1191
        }
 
1192
        return doTree();
 
1193
    }
 
1194
 
 
1195
    /*
 
1196
     * Low-level method to backup this Cell to CellBackup.
1088
1197
     * @return CellBackup which is the backup of this Cell.
1089
1198
     * @throws IllegalStateException if recalculation of Snapshot is requred in thread which is not enabled to do it.
1090
 
         */
 
1199
     */
1091
1200
    public CellBackup backup() {
1092
 
        if (cellBackupFresh) return backup;
1093
 
        if (!database.canComputeBounds())
1094
 
            throw new IllegalStateException();
 
1201
        if (cellBackupFresh) {
 
1202
            return backup;
 
1203
        }
 
1204
        if (Job.isThreadSafe()) {
 
1205
            checkChanging();
 
1206
        } else {
 
1207
            if (!database.canComputeBounds()) {
 
1208
                throw new IllegalStateException();
 
1209
            }
 
1210
        }
1095
1211
        return doBackup();
1096
1212
    }
1097
1213
 
1098
 
        /*
1099
 
         * Low-level method to backup this Cell to CellBackup.
 
1214
    /*
 
1215
     * Low-level method to backup this Cell to CellTree.
 
1216
     * If there is no fresh tree for this database and thread is not enabled to calculate snspshot, returns the latest tree.
 
1217
     * @return CellTrrr which is the backup of this Cell.
 
1218
     * @throws IllegalStateException if recalculation of Snapshot is requred in thread which is not enabled to do it.
 
1219
     */
 
1220
    public CellTree treeUnsafe() {
 
1221
        if (cellTreeFresh) {
 
1222
            return tree;
 
1223
        }
 
1224
        if (Job.isThreadSafe()) {
 
1225
            checkChanging();
 
1226
        } else {
 
1227
            if (!database.canComputeBounds()) {
 
1228
                return tree;
 
1229
            }
 
1230
        }
 
1231
        return doTree();
 
1232
    }
 
1233
 
 
1234
    /*
 
1235
     * Low-level method to backup this Cell to CellBackup.
1100
1236
     * If there is no fresh backup for this database and thread is not enabled to calculate snspshot, returns the latest backup.
1101
1237
     * @return CellBackup which is the backup of this Cell.
1102
1238
     * @throws IllegalStateException if recalculation of Snapshot is requred in thread which is not enabled to do it.
1103
 
         */
 
1239
     */
1104
1240
    public CellBackup backupUnsafe() {
1105
 
        if (cellBackupFresh || !database.canComputeBounds()) return backup;
 
1241
        if (cellBackupFresh) {
 
1242
            return backup;
 
1243
        }
 
1244
        if (Job.isThreadSafe()) {
 
1245
            checkChanging();
 
1246
        } else {
 
1247
            if (!database.canComputeBounds()) {
 
1248
                return backup;
 
1249
            }
 
1250
        }
1106
1251
        return doBackup();
1107
1252
    }
1108
1253
 
1122
1267
        return backupUnsafe().getShrinkage();
1123
1268
    }
1124
1269
 
1125
 
    public Topology getTopology() { return topology; }
 
1270
    public Topology getTopology() {
 
1271
        Topology topology = topologyRef.get();
 
1272
        if (topology != null) {
 
1273
            return topology;
 
1274
        }
 
1275
        return createTopology();
 
1276
    }
 
1277
 
 
1278
    private synchronized Topology createTopology() {
 
1279
        assert strongTopology == null;
 
1280
        assert LAZY_TOPOLOGY && Job.isThreadSafe();
 
1281
        Topology topology = new Topology(this, backup != null);
 
1282
        setTopologyRef(topology);
 
1283
//        System.out.println("Created topology "+database+":"+this);
 
1284
        return topology;
 
1285
    }
 
1286
 
 
1287
    private void setTopologyRef(Topology topology) {
 
1288
        topologyRef = USE_WEAK_REFERENCES ? new WeakReference(topology) : new SoftReference(topology);
 
1289
    }
 
1290
 
 
1291
    Topology getTopologyOptional() {
 
1292
        return topologyRef.get();
 
1293
    }
 
1294
 
 
1295
    private CellTree doTree() {
 
1296
        CellBackup top = backup();
 
1297
        CellTree[] subTrees = new CellTree[cellUsages.length];
 
1298
        for (int i = 0; i < cellUsages.length; i++) {
 
1299
            if (cellUsages[i] == 0) {
 
1300
                continue;
 
1301
            }
 
1302
            CellId subCellId = getId().getUsageIn(i).protoId;
 
1303
            subTrees[i] = database.getCell(subCellId).tree();
 
1304
        }
 
1305
        tree = tree.with(top, subTrees, getTechPool());
 
1306
        cellTreeFresh = true;
 
1307
        return tree;
 
1308
    }
1126
1309
 
1127
1310
    private CellBackup doBackup() {
1128
1311
        TechPool techPool = getTechPool();
1129
1312
        if (backup == null) {
1130
1313
            getTechnology();
1131
1314
            backup = CellBackup.newInstance(getD().withoutVariables(), techPool);
1132
 
            assert !cellBackupFresh && !cellContentsFresh && !revisionDateFresh;
 
1315
            tree = CellTree.newInstance(backup.cellRevision.d, techPool).with(backup, CellTree.NULL_ARRAY, techPool);
 
1316
            assert !cellTreeFresh && !cellBackupFresh && !cellContentsFresh && !revisionDateFresh;
1133
1317
        }
1134
1318
        ImmutableNodeInst[] nodes = null;
1135
1319
        ImmutableArcInst[] arcs = null;
1136
1320
        ImmutableExport[] exports = null;
1137
1321
        if (!cellContentsFresh) {
1138
1322
//            System.out.println("Refresh contents of " + this);
1139
 
            nodes = backupNodes();
1140
 
            arcs = topology.backupArcs(backup.cellRevision.arcs);
 
1323
            Topology topology = getTopologyOptional();
 
1324
            nodes = topology != null ? topology.backupNodes(backup.cellRevision.nodes) : null;
 
1325
            arcs = topology != null ? topology.backupArcs(backup.cellRevision.arcs) : null;
1141
1326
            exports = backupExports();
1142
1327
        }
1143
1328
        backup = backup.with(getD(), nodes, arcs, exports, techPool);
1144
1329
        cellBackupFresh = true;
1145
1330
        cellContentsFresh = true;
1146
 
        if (backup.modified)
 
1331
        if (LAZY_TOPOLOGY && Job.isThreadSafe()) {
 
1332
            strongTopology = null;
 
1333
        }
 
1334
        if (backup.modified) {
1147
1335
            lib.setChanged();
 
1336
        }
1148
1337
        return backup;
1149
1338
    }
1150
1339
 
1151
 
    private ImmutableNodeInst[] backupNodes() {
1152
 
        ImmutableNodeInst[] newNodes = new ImmutableNodeInst[nodes.size()];
1153
 
        ImmutableArrayList<ImmutableNodeInst> oldNodes = backup.cellRevision.nodes;
1154
 
        boolean changed = nodes.size() != oldNodes.size();
1155
 
        for (int i = 0; i < nodes.size(); i++) {
1156
 
            NodeInst ni = nodes.get(i);
1157
 
            ImmutableNodeInst d = ni.getD();
1158
 
            changed = changed || oldNodes.get(i) != d;
1159
 
            newNodes[i] = d;
1160
 
        }
1161
 
        return changed ? newNodes : null;
1162
 
    }
1163
 
 
1164
1340
    private ImmutableExport[] backupExports() {
1165
1341
        ImmutableExport[] newExports = new ImmutableExport[exports.length];
1166
1342
        ImmutableArrayList<ImmutableExport> oldExports = backup.cellRevision.exports;
1174
1350
        return changed ? newExports : null;
1175
1351
    }
1176
1352
 
1177
 
    void recover(CellBackup newBackup, ERectangle cellBounds) {
1178
 
        assert cellBounds != null;
1179
 
        this.cellBounds = cellBounds;
1180
 
        update(true, newBackup, null);
 
1353
    void recover(CellTree newTree) {
 
1354
        update(true, newTree, null);
 
1355
        if (!Job.isThreadSafe()) {
 
1356
            getTopology().getRTree();
 
1357
        }
1181
1358
    }
1182
1359
 
1183
 
    void undo(CellBackup newBackup, ERectangle cellBounds, BitSet exportsModified, BitSet boundsModified) {
 
1360
    void undo(CellTree newTree, BitSet exportsModified, BitSet boundsModified) {
1184
1361
        if (backup == null) {
1185
 
            recover(newBackup, cellBounds);
 
1362
            recover(newTree);
1186
1363
            return;
1187
1364
        }
1188
1365
        assert cellBackupFresh;
1189
 
        assert boundsDirty == BOUNDS_CORRECT;
1190
 
        this.cellBounds = cellBounds;
1191
 
        if (backup != newBackup) {
1192
 
            update(false, newBackup, exportsModified);
1193
 
        } else if (exportsModified != null || boundsModified != null) {
1194
 
            updateSubCells(exportsModified, boundsModified);
1195
 
        }
1196
 
    }
1197
 
 
1198
 
    void resize() {
1199
 
        assert cellBackupFresh;
1200
 
        update(false, null, null);
1201
 
    }
1202
 
 
1203
 
    private void update(boolean full, CellBackup newBackup, BitSet exportsModified) {
 
1366
        if (backup != newTree.top) {
 
1367
            update(false, newTree, exportsModified);
 
1368
        } else {
 
1369
            if (exportsModified != null || boundsModified != null) {
 
1370
                checkUndoing();
 
1371
                Topology topology = getTopologyOptional();
 
1372
                if (topology != null) {
 
1373
                    topology.updateSubCells(exportsModified, boundsModified);
 
1374
                }
 
1375
            }
 
1376
            cellTreeFresh = true;
 
1377
            tree = newTree;
 
1378
        }
 
1379
        if (!Job.isThreadSafe()) {
 
1380
            getTopology().getRTree();
 
1381
        }
 
1382
    }
 
1383
 
 
1384
    private void update(boolean full, CellTree newTree, BitSet exportsModified) {
1204
1385
        checkUndoing();
1205
 
        boundsDirty = BOUNDS_RECOMPUTE;
1206
1386
        unfreshRTree();
1207
 
        CellRevision newRevision;
1208
 
        if (newBackup != null) {
1209
 
            newRevision = newBackup.cellRevision;
1210
 
        } else {
1211
 
            newRevision = backup.cellRevision;
1212
 
            cellBounds = null;
1213
 
        }
1214
 
        this.d = newRevision.d;
 
1387
        CellBackup newBackup = newTree.top;
 
1388
        CellRevision newRevision = newBackup.cellRevision;
 
1389
        this.d = newRevision.d;
1215
1390
        lib = database.getLib(newRevision.d.getLibId());
1216
1391
        tech = database.getTech(newRevision.d.techId);
1217
 
       // Update NodeInsts
1218
 
        nodes.clear();
1219
 
        essenBounds.clear();
1220
 
        maxSuffix.clear();
1221
1392
        cellUsages = newRevision.getInstCounts();
1222
 
        for (int i = 0; i < newRevision.nodes.size(); i++) {
1223
 
            ImmutableNodeInst d = newRevision.nodes.get(i);
1224
 
            while (d.nodeId >= chronNodes.size()) chronNodes.add(null);
1225
 
            NodeInst ni = chronNodes.get(d.nodeId);
1226
 
            if (ni != null && ni.getProto().getId().isIcon() == d.protoId.isIcon()) {
1227
 
                NodeProto oldProto = ni.getProto();
1228
 
                ni.setDInUndo(d);
1229
 
                if (ni.isCellInstance()) {
1230
 
                    int subCellIndex = ((Cell)ni.getProto()).getCellIndex();
1231
 
                    if (full || exportsModified != null && exportsModified.get(subCellIndex))
1232
 
                        ni.updatePortInsts(full || ni.getProto() != oldProto);
1233
 
                } else if (ni.getProto() != oldProto) {
1234
 
                    ni.updatePortInsts(true);
1235
 
                }
1236
 
            } else {
1237
 
                ni = NodeInst.lowLevelNewInstance(this, d);
1238
 
                chronNodes.set(d.nodeId, ni);
1239
 
                if (ni.isCellInstance()) {
1240
 
                    Cell subCell = (Cell)ni.getProto();
1241
 
                    expandedNodes.set(d.nodeId, subCell.isWantExpanded());
1242
 
                    expandStatusModified = true;
1243
 
                }
1244
 
            }
1245
 
            ni.setNodeIndex(i);
1246
 
            nodes.add(ni);
1247
 
            updateMaxSuffix(ni);
1248
 
            NodeProto np = ni.getProto();
1249
 
            if (np == Generic.tech().essentialBoundsNode)
1250
 
                essenBounds.add(ni);
1251
 
//            ni.check();
1252
 
        }
1253
 
        assert nodes.size() == newRevision.nodes.size();
1254
 
 
1255
 
        int nodeCount = 0;
1256
 
        for (int i = 0; i < chronNodes.size(); i++) {
1257
 
            NodeInst ni = chronNodes.get(i);
1258
 
            if (ni == null) continue;
1259
 
            int nodeIndex = ni.getNodeIndex();
1260
 
            if (nodeIndex >= nodes.size() || ni != nodes.get(nodeIndex)) {
1261
 
                ni.setNodeIndex(-1);
1262
 
                chronNodes.set(i, null);
1263
 
                continue;
1264
 
            }
1265
 
            nodeCount++;
1266
 
        }
1267
 
        assert nodeCount == nodes.size();
1268
 
 
1269
 
        topology.updateArcs(newRevision);
 
1393
        // Update NodeInsts
 
1394
 
 
1395
        Topology topology = getTopologyOptional();
 
1396
        if (topology != null) {
 
1397
            if (topology.updateNodes(full, newRevision, exportsModified, expandedNodes)) {
 
1398
                expandStatusModified = true;
 
1399
            }
 
1400
            topology.updateArcs(newRevision);
 
1401
        }
1270
1402
 
1271
1403
        exports = new Export[newRevision.exports.size()];
1272
1404
        for (int i = 0; i < newRevision.exports.size(); i++) {
1274
1406
            // Add to chronExports
1275
1407
            int chronIndex = d.exportId.getChronIndex();
1276
1408
            if (chronExports.length <= chronIndex) {
1277
 
                Export[] newChronExports = new Export[Math.max(chronIndex + 1, chronExports.length*2)];
 
1409
                Export[] newChronExports = new Export[Math.max(chronIndex + 1, chronExports.length * 2)];
1278
1410
                System.arraycopy(chronExports, 0, newChronExports, 0, chronExports.length);
1279
1411
                chronExports = newChronExports;
1280
1412
            }
1292
1424
        int exportCount = 0;
1293
1425
        for (int i = 0; i < chronExports.length; i++) {
1294
1426
            Export e = chronExports[i];
1295
 
            if (e == null) continue;
 
1427
            if (e == null) {
 
1428
                continue;
 
1429
            }
1296
1430
            int portIndex = e.getPortIndex();
1297
1431
            if (portIndex >= exports.length || e != exports[portIndex]) {
1298
1432
                e.setPortIndex(-1);
1303
1437
        }
1304
1438
        assert exportCount == exports.length;
1305
1439
 
1306
 
        if (newBackup != null) {
1307
 
            backup = newBackup;
1308
 
        } else {
1309
 
            backup = backup.withTechPool(getTechPool());
1310
 
        }
 
1440
        tree = newTree;
 
1441
        backup = newBackup;
 
1442
        cellTreeFresh = true;
1311
1443
        cellBackupFresh = true;
1312
1444
        cellContentsFresh = true;
 
1445
        if (LAZY_TOPOLOGY && Job.isThreadSafe()) {
 
1446
            strongTopology = null;
 
1447
        }
1313
1448
        revisionDateFresh = true;
1314
 
 
1315
 
        getMemoization();
1316
 
        boundsDirty = BOUNDS_RECOMPUTE;
1317
 
        if (newBackup != null) {
1318
 
            ERectangle newBounds = computeBounds();
1319
 
            assert newBounds == cellBounds;
1320
 
        } else {
1321
 
            cellBounds = computeBounds();
1322
 
        }
1323
 
        boundsDirty = BOUNDS_CORRECT;
1324
 
        topology.rebuildRTree();
1325
 
        assert boundsDirty == BOUNDS_CORRECT;
1326
 
    }
1327
 
 
1328
 
    private void updateSubCells(BitSet exportsModified, BitSet boundsModified) {
1329
 
        checkUndoing();
1330
 
        unfreshRTree();
1331
 
        if (boundsModified != null)
1332
 
            boundsDirty = BOUNDS_RECOMPUTE;
1333
 
        for (int i = 0; i < nodes.size(); i++) {
1334
 
            NodeInst ni = nodes.get(i);
1335
 
            if (!ni.isCellInstance()) continue;
1336
 
            int subCellIndex = ((Cell)ni.getProto()).getCellIndex();
1337
 
            if (exportsModified != null && exportsModified.get(subCellIndex)) {
1338
 
                ni.updatePortInsts(false);
1339
 
            }
1340
 
            if (boundsModified != null && boundsModified.get(subCellIndex))
1341
 
                ni.redoGeometric();
1342
 
        }
1343
 
        if (boundsModified != null) {
1344
 
            assert boundsDirty == BOUNDS_RECOMPUTE;
1345
 
            ERectangle newBounds = computeBounds();
1346
 
            assert newBounds == cellBounds;
1347
 
            boundsDirty = BOUNDS_CORRECT;
1348
 
        }
1349
 
        assert boundsDirty == BOUNDS_CORRECT;
1350
 
        topology.rebuildRTree();
1351
 
        assert boundsDirty == BOUNDS_CORRECT;
1352
 
    }
1353
 
 
1354
 
        /****************************** GRAPHICS ******************************/
1355
 
 
1356
 
        /**
1357
 
         * Method to get the width of this Cell.
1358
 
         * @return the width of this Cell.
1359
 
         */
1360
 
        public double getDefWidth() { return getBounds().getWidth(); }
1361
 
 
1362
 
        /**
1363
 
         * Method to the height of this Cell.
1364
 
         * @return the height of this Cell.
1365
 
         */
1366
 
        public double getDefHeight() { return getBounds().getHeight(); }
1367
 
 
1368
 
        /**
1369
 
         * Method to get the size offset of this Cell.
1370
 
         * @return the size offset of this Cell.  It is always zero for cells.
1371
 
         */
1372
 
        public SizeOffset getProtoSizeOffset() { return SizeOffset.ZERO_OFFSET; }
1373
 
 
1374
 
        /**
1375
 
         * Method to get the characteristic spacing for this Cell.
1376
 
         * The characteristic spacing is used by the Array command to space these cells sensibly.
1377
 
         * @return a dimension that is the characteristic spacing for this cell.
1378
 
         * Returns null if there is no spacing defined.
1379
 
         */
1380
 
//      public Dimension2D getCharacteristicSpacing()
1381
 
//      {
1382
 
//              Variable var = getVar(CHARACTERISTIC_SPACING);
1383
 
//              if (var != null)
1384
 
//              {
1385
 
//                      Object obj = var.getObject();
1386
 
//                      if (obj instanceof Integer[])
1387
 
//                      {
1388
 
//                              Integer [] iSpac = (Integer [])obj;
1389
 
//                              Dimension2D spacing = new Dimension2D.Double(iSpac[0].intValue(), iSpac[1].intValue());
1390
 
//                              return spacing;
1391
 
//                      } else if (obj instanceof Double[])
1392
 
//                      {
1393
 
//                              Double [] dSpac = (Double [])obj;
1394
 
//                              Dimension2D spacing = new Dimension2D.Double(dSpac[0].doubleValue(), dSpac[1].doubleValue());
1395
 
//                              return spacing;
1396
 
//                      }
1397
 
//              }
1398
 
//              return null;
1399
 
//      }
1400
 
 
1401
 
        /**
1402
 
         * Method to set the characteristic spacing for this Cell.
1403
 
         * The characteristic spacing is used by the Array command to space these cells sensibly.
1404
 
         * @param x the characteristic width.
1405
 
         * @param y the characteristic height.
1406
 
         */
1407
 
//      public void setCharacteristicSpacing(double x, double y)
1408
 
//      {
1409
 
//              Double [] newVals = new Double[2];
1410
 
//              newVals[0] = new Double(x);
1411
 
//              newVals[1] = new Double(y);
1412
 
//              newVar(CHARACTERISTIC_SPACING, newVals);
1413
 
//      }
1414
 
 
1415
 
        /**
1416
 
         * Method to indicate that the bounds of this Cell are incorrect because
1417
 
         * a node or arc has been created, deleted, or modified.
1418
 
         */
1419
 
        public void setDirty() { setDirty(BOUNDS_RECOMPUTE); }
1420
 
 
1421
 
        /**
1422
 
         * Method to indicate that the bounds of this Cell are incorrect because
1423
 
         * a node or arc may have been modified.
1424
 
         */
1425
 
        public void setGeomDirty() { setDirty(BOUNDS_CORRECT_GEOM); }
1426
 
 
1427
 
    /**
1428
 
     * Debug method to check that bound dirty flag is clear
1429
 
     */
1430
 
    void checkBoundsCorrect() {
1431
 
        assert boundsDirty == BOUNDS_CORRECT;
1432
 
        for (NodeInst ni: nodes) {
1433
 
            if (ni.isCellInstance()) {
1434
 
                Cell subCell = (Cell)ni.getProto();
1435
 
                assert subCell.boundsDirty == BOUNDS_CORRECT;
1436
 
            }
1437
 
        }
1438
 
    }
1439
 
 
1440
 
        /**
1441
 
         * Method to indicate that the bounds of this Cell are incorrect because
1442
 
         * a node or arc has been created, deleted, or modified.
1443
 
         */
1444
 
        private void setDirty(byte boundsLevel)
1445
 
        {
1446
 
        unfreshRTree();
1447
 
        if (boundsDirty == BOUNDS_CORRECT) {
1448
 
            boundsDirty = boundsLevel;
1449
 
            for (Iterator<CellUsage> it = getUsagesOf(); it.hasNext(); ) {
1450
 
                CellUsage u = it.next();
1451
 
                u.getParent(database).setDirty(BOUNDS_CORRECT_SUB);
1452
 
            }
1453
 
        } else if (boundsDirty < boundsLevel)
1454
 
            boundsDirty = boundsLevel;
1455
 
        }
1456
 
 
1457
 
        /**
1458
 
         * Method to return an interator over all RTBounds objects in a given area of this Cell.
1459
 
         * @param bounds the specified area to search.
1460
 
         * @return an iterator over all of the RTBounds objects in that area.
1461
 
         */
1462
 
        public Iterator<RTBounds> searchIterator(Rectangle2D bounds) { return searchIterator(bounds, true); }
1463
 
 
1464
 
    /**
1465
 
         * Method to return an interator over all RTBounds objects in a given area of this Cell that allows
 
1449
    }
 
1450
 
 
1451
    /****************************** GRAPHICS ******************************/
 
1452
    /**
 
1453
     * Method to get the width of this Cell.
 
1454
     * @return the width of this Cell.
 
1455
     */
 
1456
    public double getDefWidth() {
 
1457
        return getBounds().getWidth();
 
1458
    }
 
1459
 
 
1460
    /**
 
1461
     * Method to the height of this Cell.
 
1462
     * @return the height of this Cell.
 
1463
     */
 
1464
    public double getDefHeight() {
 
1465
        return getBounds().getHeight();
 
1466
    }
 
1467
 
 
1468
    /**
 
1469
     * Method to get the size offset of this Cell.
 
1470
     * @return the size offset of this Cell.  It is always zero for cells.
 
1471
     */
 
1472
    public SizeOffset getProtoSizeOffset() {
 
1473
        return SizeOffset.ZERO_OFFSET;
 
1474
    }
 
1475
 
 
1476
    /**
 
1477
     * Method to return an interator over all RTBounds objects in a given area of this Cell.
 
1478
     * @param bounds the specified area to search.
 
1479
     * @return an iterator over all of the RTBounds objects in that area.
 
1480
     */
 
1481
    public Iterator<RTBounds> searchIterator(Rectangle2D bounds) {
 
1482
        return searchIterator(bounds, true);
 
1483
    }
 
1484
 
 
1485
    /**
 
1486
     * Method to return an interator over all RTBounds objects in a given area of this Cell that allows
1466
1487
     * to ignore elements touching the area.
1467
 
         * @param bounds the specified area to search.
 
1488
     * @param bounds the specified area to search.
1468
1489
     * @param includeEdges true if RTBounds objects along edges are considered in.
1469
 
         * @return an iterator over all of the RTBounds objects in that area.
1470
 
         */
 
1490
     * @return an iterator over all of the RTBounds objects in that area.
 
1491
     */
1471
1492
    public Iterator<RTBounds> searchIterator(Rectangle2D bounds, boolean includeEdges) {
1472
 
        return topology.searchIterator(bounds, includeEdges);
1473
 
    }
1474
 
 
1475
 
        /**
1476
 
         * Method to return the bounds of this Cell.
1477
 
         * @return an ERectangle with the bounds of this cell's contents
1478
 
         */
1479
 
        public ERectangle getBounds()
1480
 
        {
1481
 
        if (boundsDirty == BOUNDS_CORRECT || !database.canComputeBounds())
1482
 
            return cellBounds;
1483
 
 
1484
 
                checkChanging();
1485
 
        if (boundsDirty == BOUNDS_CORRECT_SUB) {
1486
 
            boundsDirty = BOUNDS_CORRECT;
1487
 
            // Recalculate bounds of subcells.
1488
 
            for (Iterator<CellUsage> it = getUsagesIn(); it.hasNext(); ) {
1489
 
                CellUsage u = it.next();
1490
 
                u.getProto(database).getBounds();
1491
 
            }
1492
 
            if (boundsDirty == BOUNDS_CORRECT)
1493
 
                return cellBounds;
1494
 
        }
1495
 
        if (boundsDirty == BOUNDS_CORRECT_GEOM) {
1496
 
            boundsDirty = BOUNDS_CORRECT;
1497
 
            for (NodeInst ni: nodes)
1498
 
                ni.getBounds();
1499
 
            for (Iterator<ArcInst> it = topology.getArcs(); it.hasNext(); )
1500
 
                it.next().getBounds();
1501
 
            if (boundsDirty == BOUNDS_CORRECT)
1502
 
                return cellBounds;
1503
 
        }
1504
 
 
1505
 
        // recompute bounds
1506
 
        unfreshRTree();
1507
 
        assert boundsDirty != BOUNDS_CORRECT;
1508
 
        ERectangle newBounds = computeBounds();
1509
 
        if (newBounds != cellBounds) {
1510
 
            cellBounds = newBounds;
1511
 
            for (Iterator<NodeInst> it = getInstancesOf(); it.hasNext(); ) {
1512
 
                NodeInst ni = it.next();
1513
 
                // Fake modify to recalcualte bounds and RTree
1514
 
                                ni.redoGeometric();
1515
 
            }
1516
 
        }
1517
 
        boundsDirty = BOUNDS_CORRECT;
1518
 
                return cellBounds;
1519
 
        }
1520
 
 
1521
 
    ERectangle computeBounds() {
1522
 
        double cellLowX, cellHighX, cellLowY, cellHighY;
1523
 
        boolean boundsEmpty = true;
1524
 
        cellLowX = cellHighX = cellLowY = cellHighY = 0;
1525
 
 
1526
 
        // Ensure that all subcells have correct bounds
1527
 
        for (Iterator<CellUsage> it = getUsagesIn(); it.hasNext(); ) {
1528
 
            CellUsage u = it.next();
1529
 
            u.getProto(database).getBounds();
1530
 
        }
1531
 
 
1532
 
        for(int i = 0; i < nodes.size(); i++ ) {
1533
 
            NodeInst ni = nodes.get(i);
1534
 
            NodeProto np = ni.getProto();
1535
 
            Rectangle2D bounds = ni.getBounds();
1536
 
 
1537
 
            // special case: do not include "cell center" primitives from Generic
1538
 
            if (np == Generic.tech().cellCenterNode) continue;
1539
 
 
1540
 
            // special case for invisible pins: do not include if inheritable or interior-only
1541
 
            if (np == Generic.tech().invisiblePinNode) {
1542
 
                boolean found = false;
1543
 
                for(Iterator<Variable> it = ni.getVariables(); it.hasNext(); ) {
1544
 
                    Variable var = it.next();
1545
 
                    if (var.isDisplay()) {
1546
 
                        TextDescriptor td = var.getTextDescriptor();
1547
 
                        if (td.isInterior() || td.isInherit()) { found = true;   break; }
1548
 
                    }
1549
 
                }
1550
 
                if (found) continue;
1551
 
            }
1552
 
 
1553
 
            double lowx = bounds.getMinX();
1554
 
            double highx = bounds.getMaxX();
1555
 
            double lowy = bounds.getMinY();
1556
 
            double highy = bounds.getMaxY();
1557
 
            if (boundsEmpty) {
1558
 
                boundsEmpty = false;
1559
 
                cellLowX = lowx;   cellHighX = highx;
1560
 
                cellLowY = lowy;   cellHighY = highy;
1561
 
            } else {
1562
 
                if (lowx < cellLowX) cellLowX = lowx;
1563
 
                if (highx > cellHighX) cellHighX = highx;
1564
 
                if (lowy < cellLowY) cellLowY = lowy;
1565
 
                if (highy > cellHighY) cellHighY = highy;
1566
 
            }
1567
 
        }
1568
 
        long gridMinX = DBMath.lambdaToGrid(cellLowX);
1569
 
        long gridMinY = DBMath.lambdaToGrid(cellLowY);
1570
 
        long gridMaxX = DBMath.lambdaToGrid(cellHighX);
1571
 
        long gridMaxY = DBMath.lambdaToGrid(cellHighY);
1572
 
 
1573
 
        topology.computeArcBounds();
1574
 
        ERectangle primitiveBounds = backup().getPrimitiveBounds();
1575
 
        if (primitiveBounds != null) {
1576
 
            assert !boundsEmpty;
1577
 
            gridMinX = Math.min(gridMinX, primitiveBounds.getGridMinX());
1578
 
            gridMaxX = Math.max(gridMaxX, primitiveBounds.getGridMaxX());
1579
 
            gridMinY = Math.min(gridMinY, primitiveBounds.getGridMinY());
1580
 
            gridMaxY = Math.max(gridMaxY, primitiveBounds.getGridMaxY());
1581
 
        }
1582
 
        if (cellBounds != null && gridMinX == cellBounds.getGridMinX() && gridMinY == cellBounds.getGridMinY() &&
1583
 
                gridMaxX == cellBounds.getGridMaxX() && gridMaxY == cellBounds.getGridMaxY())
1584
 
            return cellBounds;
1585
 
        return ERectangle.fromGrid(gridMinX, gridMinY, gridMaxX - gridMinX, gridMaxY - gridMinY);
1586
 
    }
1587
 
 
1588
 
        /**
1589
 
         * Method to compute the "essential bounds" of this Cell.
1590
 
         * It looks for NodeInst objects in the cell that are of the type
1591
 
         * "generic:Essential-Bounds" and builds a rectangle from their locations.
1592
 
         * @return the bounding area of the essential bounds.
1593
 
         * Returns null if an essential bounds cannot be determined.
1594
 
         */
1595
 
        public Rectangle2D findEssentialBounds()
1596
 
        {
1597
 
                if (essenBounds.size() < 2)
1598
 
                        return null;
1599
 
                double minX = Double.MAX_VALUE;
1600
 
                double maxX = Double.MIN_VALUE;
1601
 
                double minY = Double.MAX_VALUE;
1602
 
                double maxY = Double.MIN_VALUE;
1603
 
 
1604
 
                for (int i = 0; i < essenBounds.size(); i++)
1605
 
                {
1606
 
                        NodeInst ni = essenBounds.get(i);
1607
 
                        minX = Math.min(minX, ni.getTrueCenterX());
1608
 
                        maxX = Math.max(maxX, ni.getTrueCenterX());
1609
 
                        minY = Math.min(minY, ni.getTrueCenterY());
1610
 
                        maxY = Math.max(maxY, ni.getTrueCenterY());
1611
 
                }
1612
 
 
1613
 
                return new Rectangle2D.Double(minX, minY, maxX - minX, maxY - minY);
1614
 
        }
 
1493
        return getTopology().searchIterator(bounds, includeEdges);
 
1494
    }
 
1495
 
 
1496
    /**
 
1497
     * Method to return the bounds of this Cell.
 
1498
     * @return an ERectangle with the bounds of this cell's contents
 
1499
     */
 
1500
    public ERectangle getBounds() {
 
1501
        return treeUnsafe().getBounds();
 
1502
    }
 
1503
 
 
1504
    /**
 
1505
     * Method to compute the "essential bounds" of this Cell.
 
1506
     * It looks for NodeInst objects in the cell that are of the type
 
1507
     * "generic:Essential-Bounds" and builds a rectangle from their locations.
 
1508
     * @return the bounding area of the essential bounds.
 
1509
     * Returns null if an essential bounds cannot be determined.
 
1510
     */
 
1511
    public Rectangle2D findEssentialBounds() {
 
1512
        return getTopology().findEssentialBounds();
 
1513
    }
1615
1514
 
1616
1515
    /**
1617
1516
     * Method to determine whether this Cell has a cell center in it.
1618
1517
     * @return true if this Cell has a Cell-center node in it.
1619
1518
     */
1620
 
    public boolean alreadyCellCenter()
1621
 
    {
1622
 
        for(Iterator<NodeInst> it = getNodes(); it.hasNext(); )
1623
 
        {
 
1519
    public boolean alreadyCellCenter() {
 
1520
        for (Iterator<NodeInst> it = getNodes(); it.hasNext();) {
1624
1521
            NodeInst ni = it.next();
1625
 
            if (ni.getProto() == Generic.tech().cellCenterNode) return true;
 
1522
            if (ni.getProto() == Generic.tech().cellCenterNode) {
 
1523
                return true;
 
1524
            }
1626
1525
        }
1627
1526
        return false;
1628
1527
    }
1629
1528
 
1630
 
        /**
1631
 
         * Method adjust this cell when the reference point moves.
1632
 
         * This requires renumbering all coordinate values in the Cell.
1633
 
         * @param cX coordinate X of new center.
 
1529
    /**
 
1530
     * Method adjust this cell when the reference point moves.
 
1531
     * This requires renumbering all coordinate values in the Cell.
 
1532
     * @param cX coordinate X of new center.
1634
1533
     * @param cY coordinate Y of new center.
1635
 
         */
1636
 
        public void adjustReferencePoint(double cX, double cY)
1637
 
        {
1638
 
                checkChanging();
1639
 
 
1640
 
                // if there is no change, stop now
1641
 
                if (cX == 0 && cY == 0) return;
1642
 
 
1643
 
                // move reference point by (dx,dy)
 
1534
     */
 
1535
    public void adjustReferencePoint(double cX, double cY) {
 
1536
        checkChanging();
 
1537
 
 
1538
        // if there is no change, stop now
 
1539
        if (cX == 0 && cY == 0) {
 
1540
            return;
 
1541
        }
 
1542
 
 
1543
        // move reference point by (dx,dy)
1644
1544
//              referencePointNode.modifyInstance(-cX, -cY, 0, 0, 0);
1645
1545
 
1646
 
                // must adjust all nodes by (dx,dy)
1647
 
                for(Iterator<NodeInst> it = getNodes(); it.hasNext(); )
1648
 
                {
1649
 
                        NodeInst ni = it.next();
1650
 
                        if (ni.getProto() == Generic.tech().cellCenterNode) continue;
1651
 
 
1652
 
                        // move NodeInst "ni" by (dx,dy)
1653
 
                        ni.move(-cX, -cY);
1654
 
                }
1655
 
                for(Iterator<ArcInst> it = getArcs(); it.hasNext(); )
1656
 
                {
1657
 
                        ArcInst ai = it.next();
1658
 
 
1659
 
                        // move NodeInst "ni" by (dx,dy)
1660
 
                        ai.modify(-cX, -cY, -cX, -cY);
1661
 
                }
1662
 
 
1663
 
                // adjust all instances of this cell
1664
 
                for(Iterator<NodeInst> it = getInstancesOf(); it.hasNext(); )
1665
 
                {
1666
 
                        NodeInst ni = it.next();
 
1546
        // must adjust all nodes by (dx,dy)
 
1547
        for (Iterator<NodeInst> it = getNodes(); it.hasNext();) {
 
1548
            NodeInst ni = it.next();
 
1549
            if (ni.getProto() == Generic.tech().cellCenterNode) {
 
1550
                continue;
 
1551
            }
 
1552
 
 
1553
            // move NodeInst "ni" by (dx,dy)
 
1554
            ni.move(-cX, -cY);
 
1555
        }
 
1556
        for (Iterator<ArcInst> it = getArcs(); it.hasNext();) {
 
1557
            ArcInst ai = it.next();
 
1558
 
 
1559
            // move NodeInst "ni" by (dx,dy)
 
1560
            ai.modify(-cX, -cY, -cX, -cY);
 
1561
        }
 
1562
 
 
1563
        // adjust all instances of this cell
 
1564
        for (Iterator<NodeInst> it = getInstancesOf(); it.hasNext();) {
 
1565
            NodeInst ni = it.next();
1667
1566
//                      Undo.redrawObject(ni);
1668
1567
            AffineTransform trans = ni.getOrient().pureRotate();
1669
1568
//                      AffineTransform trans = NodeInst.pureRotate(ni.getAngle(), ni.isMirroredAboutXAxis(), ni.isMirroredAboutYAxis());
1670
 
                        Point2D in = new Point2D.Double(cX, cY);
1671
 
                        trans.transform(in, in);
1672
 
                        ni.move(in.getX(), in.getY());
1673
 
                }
 
1569
            Point2D in = new Point2D.Double(cX, cY);
 
1570
            trans.transform(in, in);
 
1571
            ni.move(in.getX(), in.getY());
 
1572
        }
1674
1573
 
1675
1574
        Job.getUserInterface().adjustReferencePoint(this, cX, cY);
1676
1575
//              // adjust all windows showing this cell
1686
1585
//                      off.setLocation(off.getX()-cX, off.getY()-cY);
1687
1586
//                      wnd.setOffset(off);
1688
1587
//              }
1689
 
        }
1690
 
 
1691
 
        /**
1692
 
         * Class for creating a description of a frame around a schematic cell.
1693
 
         */
1694
 
        public static class FrameDescription
1695
 
        {
1696
 
                public static final double MULTIPAGESEPARATION = 1000;
1697
 
 
1698
 
                private static final double FRAMESCALE = 18.0;
1699
 
                private static final double HASCHXSIZE = ( 8.5  * FRAMESCALE);
1700
 
                private static final double HASCHYSIZE = ( 5.5  * FRAMESCALE);
1701
 
                private static final double ASCHXSIZE  = (11.0  * FRAMESCALE);
1702
 
                private static final double ASCHYSIZE  = ( 8.5  * FRAMESCALE);
1703
 
                private static final double BSCHXSIZE  = (17.0  * FRAMESCALE);
1704
 
                private static final double BSCHYSIZE  = (11.0  * FRAMESCALE);
1705
 
                private static final double CSCHXSIZE  = (24.0  * FRAMESCALE);
1706
 
                private static final double CSCHYSIZE  = (17.0  * FRAMESCALE);
1707
 
                private static final double DSCHXSIZE  = (36.0  * FRAMESCALE);
1708
 
                private static final double DSCHYSIZE  = (24.0  * FRAMESCALE);
1709
 
                private static final double ESCHXSIZE  = (48.0  * FRAMESCALE);
1710
 
                private static final double ESCHYSIZE  = (36.0  * FRAMESCALE);
1711
 
                private static final double FRAMEWID   = ( 0.15 * FRAMESCALE);
1712
 
                private static final double XLOGOBOX   = ( 2.0  * FRAMESCALE);
1713
 
                private static final double YLOGOBOX   = ( 1.0  * FRAMESCALE);
1714
 
 
1715
 
                private Cell cell;
1716
 
                private List<Point2D> lineFromEnd;
1717
 
                private List<Point2D> lineToEnd;
1718
 
                private List<Point2D> textPoint;
1719
 
                private List<Double> textSize;
1720
 
                private List<Point2D> textBox;
1721
 
                private List<String> textMessage;
1722
 
                private int pageNo;
1723
 
 
1724
 
                /**
1725
 
                 * Constructor for cell frame descriptions.
1726
 
                 * @param cell the Cell that is having a frame drawn.
1727
 
                 */
1728
 
                public FrameDescription(Cell cell, int pageNo)
1729
 
                {
1730
 
                        this.cell = cell;
1731
 
                        this.pageNo = pageNo;
1732
 
                        lineFromEnd = new ArrayList<Point2D>();
1733
 
                        lineToEnd = new ArrayList<Point2D>();
1734
 
                        textPoint = new ArrayList<Point2D>();
1735
 
                        textSize = new ArrayList<Double>();
1736
 
                        textBox = new ArrayList<Point2D>();
1737
 
                        textMessage = new ArrayList<String>();
1738
 
                        loadFrame();
1739
 
                }
1740
 
 
1741
 
                /**
1742
 
                 * Method to draw a line in a frame.
1743
 
                 * This method is overridden by subclasses that know how to do the function.
1744
 
                 * @param from the starting point of the line (in database units).
1745
 
                 * @param to the ending point of the line (in database units).
1746
 
                 */
1747
 
                public void showFrameLine(Point2D from, Point2D to) {}
1748
 
 
1749
 
                /**
1750
 
                 * Method to draw text in a frame.
1751
 
                 * This method is overridden by subclasses that know how to do the function.
1752
 
                 * @param ctr the anchor point of the text.
1753
 
                 * @param size the size of the text (in database units).
1754
 
                 * @param maxWid the maximum width of the text (ignored if zero).
1755
 
                 * @param maxHei the maximum height of the text (ignored if zero).
1756
 
                 * @param string the text to be displayed.
1757
 
                 */
1758
 
                public void showFrameText(Point2D ctr, double size, double maxWid, double maxHei, String string) {}
1759
 
 
1760
 
                /**
1761
 
                 * Method called to render the frame information.
1762
 
                 * It makes calls to "renderInit()", "showFrameLine()", and "showFrameText()".
1763
 
                 */
1764
 
                public void renderFrame()
1765
 
                {
1766
 
                        double offY = 0;
1767
 
                        if (cell.isMultiPage())
1768
 
                        {
1769
 
                                offY = pageNo * MULTIPAGESEPARATION;
1770
 
                        }
1771
 
                        for(int i=0; i<lineFromEnd.size(); i++)
1772
 
                        {
1773
 
                                Point2D from = lineFromEnd.get(i);
1774
 
                                Point2D to = lineToEnd.get(i);
1775
 
                                if (offY != 0)
1776
 
                                {
1777
 
                                        from = new Point2D.Double(from.getX(), from.getY() + offY);
1778
 
                                        to = new Point2D.Double(to.getX(), to.getY() + offY);
1779
 
                                }
1780
 
                                showFrameLine(from, to);
1781
 
                        }
1782
 
                        for(int i=0; i<textPoint.size(); i++)
1783
 
                        {
1784
 
                                Point2D at = textPoint.get(i);
1785
 
                                if (offY != 0)
1786
 
                                        at = new Point2D.Double(at.getX(), at.getY() + offY);
1787
 
                                double size = textSize.get(i).doubleValue();
1788
 
                                Point2D box = textBox.get(i);
1789
 
                                double width = box.getX();
1790
 
                                double height = box.getY();
1791
 
                                String msg = textMessage.get(i);
1792
 
                                showFrameText(at, size, width, height, msg);
1793
 
                        }
1794
 
                }
1795
 
 
1796
 
                /**
1797
 
                 * Method to determine the size of the schematic frame in the current Cell.
1798
 
                 * @param d a Dimension in which the size (database units) will be placed.
1799
 
                 * @return 0: there should be a frame whose size is absolute;
1800
 
                 * 1: there should be a frame but it combines with other stuff in the cell;
1801
 
                 * 2: there is no frame.
1802
 
                 */
1803
 
                public static int getCellFrameInfo(Cell cell, Dimension d)
1804
 
                {
1805
 
                        String frameInfo = cell.getVarValue(User.FRAME_SIZE, String.class);
1806
 
                        if (frameInfo == null) return 2;
1807
 
                        if (frameInfo.length() == 0) return 2;
1808
 
                        int retval = 0;
1809
 
                        char chr = frameInfo.charAt(0);
1810
 
                        double wid = 0, hei = 0;
1811
 
                        if (chr == 'x')
1812
 
                        {
1813
 
                                wid = XLOGOBOX + FRAMEWID;   hei = YLOGOBOX + FRAMEWID;
1814
 
                                retval = 1;
1815
 
                        } else
1816
 
                        {
1817
 
                                switch (chr)
1818
 
                                {
1819
 
                                        case 'h': wid = HASCHXSIZE;  hei = HASCHYSIZE;  break;
1820
 
                                        case 'a': wid = ASCHXSIZE;   hei = ASCHYSIZE;   break;
1821
 
                                        case 'b': wid = BSCHXSIZE;   hei = BSCHYSIZE;   break;
1822
 
                                        case 'c': wid = CSCHXSIZE;   hei = CSCHYSIZE;   break;
1823
 
                                        case 'd': wid = DSCHXSIZE;   hei = DSCHYSIZE;   break;
1824
 
                                        case 'e': wid = ESCHXSIZE;   hei = ESCHYSIZE;   break;
1825
 
                                }
1826
 
                        }
1827
 
                        if (frameInfo.indexOf("v") >= 0)
1828
 
                        {
1829
 
                                d.setSize(hei, wid);
1830
 
                        } else
1831
 
                        {
1832
 
                                d.setSize(wid, hei);
1833
 
                        }
1834
 
                        return retval;
1835
 
                }
1836
 
 
1837
 
                private void loadFrame()
1838
 
                {
1839
 
                        Dimension d = new Dimension();
1840
 
                        int frameFactor = getCellFrameInfo(cell, d);
1841
 
                        if (frameFactor == 2) return;
1842
 
 
1843
 
                        String frameInfo = cell.getVarValue(User.FRAME_SIZE, String.class);
1844
 
                        if (frameInfo == null) return;
1845
 
                        double schXSize = d.getWidth();
1846
 
                        double schYSize = d.getHeight();
1847
 
 
1848
 
                        boolean drawTitleBox = true;
1849
 
                        int xSections = 8;
1850
 
                        int ySections = 4;
1851
 
                        if (frameFactor == 1)
1852
 
                        {
1853
 
                                xSections = ySections = 0;
1854
 
                        } else
1855
 
                        {
1856
 
                                if (frameInfo.indexOf("v") >= 0)
1857
 
                                {
1858
 
                                        xSections = 4;
1859
 
                                        ySections = 8;
1860
 
                                }
1861
 
                                if (frameInfo.indexOf("n") >= 0) drawTitleBox = false;
1862
 
                        }
1863
 
 
1864
 
                        double xLogoBox = XLOGOBOX;
1865
 
                        double yLogoBox = YLOGOBOX;
1866
 
                        double frameWid = FRAMEWID;
1867
 
 
1868
 
                        // draw the frame
1869
 
                        if (xSections > 0)
1870
 
                        {
1871
 
                                double xSecSize = (schXSize - frameWid*2) / xSections;
1872
 
                                double ySecSize = (schYSize - frameWid*2) / ySections;
1873
 
 
1874
 
                                // draw the outer frame
1875
 
                                Point2D point0 = new Point2D.Double(-schXSize/2, -schYSize/2);
1876
 
                                Point2D point1 = new Point2D.Double(-schXSize/2,  schYSize/2);
1877
 
                                Point2D point2 = new Point2D.Double( schXSize/2,  schYSize/2);
1878
 
                                Point2D point3 = new Point2D.Double( schXSize/2, -schYSize/2);
1879
 
                                addLine(point0, point1);
1880
 
                                addLine(point1, point2);
1881
 
                                addLine(point2, point3);
1882
 
                                addLine(point3, point0);
1883
 
 
1884
 
                                // draw the inner frame
1885
 
                                point0 = new Point2D.Double(-schXSize/2 + frameWid, -schYSize/2 + frameWid);
1886
 
                                point1 = new Point2D.Double(-schXSize/2 + frameWid,  schYSize/2 - frameWid);
1887
 
                                point2 = new Point2D.Double( schXSize/2 - frameWid,  schYSize/2 - frameWid);
1888
 
                                point3 = new Point2D.Double( schXSize/2 - frameWid, -schYSize/2 + frameWid);
1889
 
                                addLine(point0, point1);
1890
 
                                addLine(point1, point2);
1891
 
                                addLine(point2, point3);
1892
 
                                addLine(point3, point0);
1893
 
 
1894
 
                                // tick marks along the top and bottom sides
1895
 
                                for(int i=0; i<xSections; i++)
1896
 
                                {
1897
 
                                        double x = i * xSecSize - (schXSize/2 - frameWid);
1898
 
                                        if (i > 0)
1899
 
                                        {
1900
 
                                                point0 = new Point2D.Double(x, schYSize/2 - frameWid);
1901
 
                                                point1 = new Point2D.Double(x, schYSize/2 - frameWid/2);
1902
 
                                                addLine(point0, point1);
1903
 
                                                point0 = new Point2D.Double(x, -schYSize/2 + frameWid);
1904
 
                                                point1 = new Point2D.Double(x, -schYSize/2 + frameWid/2);
1905
 
                                                addLine(point0, point1);
1906
 
                                        }
1907
 
 
1908
 
                                        char chr = (char)('1' + xSections - i - 1);
1909
 
                                        point0 = new Point2D.Double(x + xSecSize/2, schYSize/2 - frameWid/2);
1910
 
                                        addText(point0, frameWid, 0, 0, String.valueOf(chr));
1911
 
 
1912
 
                                        point0 = new Point2D.Double(x + xSecSize/2, -schYSize/2 + frameWid/2);
1913
 
                                        addText(point0, frameWid, 0, 0, String.valueOf(chr));
1914
 
                                }
1915
 
 
1916
 
                                // tick marks along the left and right sides
1917
 
                                for(int i=0; i<ySections; i++)
1918
 
                                {
1919
 
                                        double y = i * ySecSize - (schYSize/2 - frameWid);
1920
 
                                        if (i > 0)
1921
 
                                        {
1922
 
                                                point0 = new Point2D.Double(schXSize/2 - frameWid, y);
1923
 
                                                point1 = new Point2D.Double(schXSize/2 - frameWid/2, y);
1924
 
                                                addLine(point0, point1);
1925
 
                                                point0 = new Point2D.Double(-schXSize/2 + frameWid, y);
1926
 
                                                point1 = new Point2D.Double(-schXSize/2 + frameWid/2, y);
1927
 
                                                addLine(point0, point1);
1928
 
                                        }
1929
 
                                        char chr = (char)('A' + i);
1930
 
                                        point0 = new Point2D.Double(schXSize/2 - frameWid/2, y + ySecSize/2);
1931
 
                                        addText(point0, frameWid, 0, 0, String.valueOf(chr));
1932
 
 
1933
 
                                        point0 = new Point2D.Double(-schXSize/2 + frameWid/2, y + ySecSize/2);
1934
 
                                        addText(point0, frameWid, 0, 0, String.valueOf(chr));
1935
 
                                }
1936
 
                        }
1937
 
                        if (drawTitleBox)
1938
 
                        {
1939
 
                                Point2D point0 = new Point2D.Double(schXSize/2 - frameWid - xLogoBox, -schYSize/2 + frameWid + yLogoBox);
1940
 
                                Point2D point1 = new Point2D.Double(schXSize/2 - frameWid, -schYSize/2 + frameWid + yLogoBox);
1941
 
                                Point2D point2 = new Point2D.Double(schXSize/2 - frameWid, -schYSize/2 + frameWid);
1942
 
                                Point2D point3 = new Point2D.Double(schXSize/2 - frameWid - xLogoBox, -schYSize/2 + frameWid);
1943
 
                                addLine(point0, point1);
1944
 
                                addLine(point1, point2);
1945
 
                                addLine(point2, point3);
1946
 
                                addLine(point3, point0);
1947
 
 
1948
 
                                point0 = new Point2D.Double(schXSize/2 - frameWid - xLogoBox, -schYSize/2 + frameWid + yLogoBox*2/15);
1949
 
                                point1 = new Point2D.Double(schXSize/2 - frameWid,            -schYSize/2 + frameWid + yLogoBox*2/15);
1950
 
                                addLine(point0, point1);
1951
 
 
1952
 
                                point0 = new Point2D.Double(schXSize/2 - frameWid - xLogoBox, -schYSize/2 + frameWid + yLogoBox*4/15);
1953
 
                                point1 = new Point2D.Double(schXSize/2 - frameWid,            -schYSize/2 + frameWid + yLogoBox*4/15);
1954
 
                                addLine(point0, point1);
1955
 
 
1956
 
                                point0 = new Point2D.Double(schXSize/2 - frameWid - xLogoBox, -schYSize/2 + frameWid + yLogoBox*6/15);
1957
 
                                point1 = new Point2D.Double(schXSize/2 - frameWid,            -schYSize/2 + frameWid + yLogoBox*6/15);
1958
 
                                addLine(point0, point1);
1959
 
 
1960
 
                                point0 = new Point2D.Double(schXSize/2 - frameWid - xLogoBox, -schYSize/2 + frameWid + yLogoBox*8/15);
1961
 
                                point1 = new Point2D.Double(schXSize/2 - frameWid,            -schYSize/2 + frameWid + yLogoBox*8/15);
1962
 
                                addLine(point0, point1);
1963
 
 
1964
 
                                point0 = new Point2D.Double(schXSize/2 - frameWid - xLogoBox, -schYSize/2 + frameWid + yLogoBox*10/15);
1965
 
                                point1 = new Point2D.Double(schXSize/2 - frameWid,            -schYSize/2 + frameWid + yLogoBox*10/15);
1966
 
                                addLine(point0, point1);
1967
 
 
1968
 
                                point0 = new Point2D.Double(schXSize/2 - frameWid - xLogoBox, -schYSize/2 + frameWid + yLogoBox*12/15);
1969
 
                                point1 = new Point2D.Double(schXSize/2 - frameWid,            -schYSize/2 + frameWid + yLogoBox*12/15);
1970
 
                                addLine(point0, point1);
1971
 
 
1972
 
                                point0 = new Point2D.Double(schXSize/2 - frameWid - xLogoBox/2, -schYSize/2 + frameWid + yLogoBox*13.5/15);
1973
 
                                addText(point0, yLogoBox*2/15, xLogoBox, yLogoBox*3/15, "Cell: " + cell.describe(false) + (cell.isMultiPage() ? " Page " + (pageNo+1) : ""));
1974
 
 
1975
 
                                String projectName = cell.getLibrary().getVarValue(User.FRAME_PROJECT_NAME, String.class, User.getFrameProjectName());
1976
 
                                if (projectName.length() > 0)
1977
 
                                {
1978
 
                                        point0 = new Point2D.Double(schXSize/2 - frameWid - xLogoBox/2, -schYSize/2 + frameWid + yLogoBox*11/15);
1979
 
                                        addText(point0, yLogoBox*2/15, xLogoBox, yLogoBox*2/15, "Project: " + projectName);
1980
 
                                }
 
1588
    }
 
1589
 
 
1590
    /**
 
1591
     * Class for creating a description of a frame around a schematic cell.
 
1592
     */
 
1593
    public static class FrameDescription {
 
1594
 
 
1595
        public static final double MULTIPAGESEPARATION = 1000;
 
1596
        private static final double FRAMESCALE = 18.0;
 
1597
        private static final double HASCHXSIZE = (8.5 * FRAMESCALE);
 
1598
        private static final double HASCHYSIZE = (5.5 * FRAMESCALE);
 
1599
        private static final double ASCHXSIZE = (11.0 * FRAMESCALE);
 
1600
        private static final double ASCHYSIZE = (8.5 * FRAMESCALE);
 
1601
        private static final double BSCHXSIZE = (17.0 * FRAMESCALE);
 
1602
        private static final double BSCHYSIZE = (11.0 * FRAMESCALE);
 
1603
        private static final double CSCHXSIZE = (24.0 * FRAMESCALE);
 
1604
        private static final double CSCHYSIZE = (17.0 * FRAMESCALE);
 
1605
        private static final double DSCHXSIZE = (36.0 * FRAMESCALE);
 
1606
        private static final double DSCHYSIZE = (24.0 * FRAMESCALE);
 
1607
        private static final double ESCHXSIZE = (48.0 * FRAMESCALE);
 
1608
        private static final double ESCHYSIZE = (36.0 * FRAMESCALE);
 
1609
        private static final double FRAMEWID = (0.15 * FRAMESCALE);
 
1610
        private static final double XLOGOBOX = (2.0 * FRAMESCALE);
 
1611
        private static final double YLOGOBOX = (1.0 * FRAMESCALE);
 
1612
        private Cell cell;
 
1613
        private List<Point2D> lineFromEnd;
 
1614
        private List<Point2D> lineToEnd;
 
1615
        private List<Point2D> textPoint;
 
1616
        private List<Double> textSize;
 
1617
        private List<Point2D> textBox;
 
1618
        private List<String> textMessage;
 
1619
        private int pageNo;
 
1620
 
 
1621
        /**
 
1622
         * Constructor for cell frame descriptions.
 
1623
         * @param cell the Cell that is having a frame drawn.
 
1624
         */
 
1625
        public FrameDescription(Cell cell, int pageNo) {
 
1626
            this.cell = cell;
 
1627
            this.pageNo = pageNo;
 
1628
            lineFromEnd = new ArrayList<Point2D>();
 
1629
            lineToEnd = new ArrayList<Point2D>();
 
1630
            textPoint = new ArrayList<Point2D>();
 
1631
            textSize = new ArrayList<Double>();
 
1632
            textBox = new ArrayList<Point2D>();
 
1633
            textMessage = new ArrayList<String>();
 
1634
            loadFrame();
 
1635
        }
 
1636
 
 
1637
        /**
 
1638
         * Method to draw a line in a frame.
 
1639
         * This method is overridden by subclasses that know how to do the function.
 
1640
         * @param from the starting point of the line (in database units).
 
1641
         * @param to the ending point of the line (in database units).
 
1642
         */
 
1643
        public void showFrameLine(Point2D from, Point2D to) {
 
1644
        }
 
1645
 
 
1646
        /**
 
1647
         * Method to draw text in a frame.
 
1648
         * This method is overridden by subclasses that know how to do the function.
 
1649
         * @param ctr the anchor point of the text.
 
1650
         * @param size the size of the text (in database units).
 
1651
         * @param maxWid the maximum width of the text (ignored if zero).
 
1652
         * @param maxHei the maximum height of the text (ignored if zero).
 
1653
         * @param string the text to be displayed.
 
1654
         */
 
1655
        public void showFrameText(Point2D ctr, double size, double maxWid, double maxHei, String string) {
 
1656
        }
 
1657
 
 
1658
        /**
 
1659
         * Method called to render the frame information.
 
1660
         * It makes calls to "renderInit()", "showFrameLine()", and "showFrameText()".
 
1661
         */
 
1662
        public void renderFrame() {
 
1663
            double offY = 0;
 
1664
            if (cell.isMultiPage()) {
 
1665
                offY = pageNo * MULTIPAGESEPARATION;
 
1666
            }
 
1667
            for (int i = 0; i < lineFromEnd.size(); i++) {
 
1668
                Point2D from = lineFromEnd.get(i);
 
1669
                Point2D to = lineToEnd.get(i);
 
1670
                if (offY != 0) {
 
1671
                    from = new Point2D.Double(from.getX(), from.getY() + offY);
 
1672
                    to = new Point2D.Double(to.getX(), to.getY() + offY);
 
1673
                }
 
1674
                showFrameLine(from, to);
 
1675
            }
 
1676
            for (int i = 0; i < textPoint.size(); i++) {
 
1677
                Point2D at = textPoint.get(i);
 
1678
                if (offY != 0) {
 
1679
                    at = new Point2D.Double(at.getX(), at.getY() + offY);
 
1680
                }
 
1681
                double size = textSize.get(i).doubleValue();
 
1682
                Point2D box = textBox.get(i);
 
1683
                double width = box.getX();
 
1684
                double height = box.getY();
 
1685
                String msg = textMessage.get(i);
 
1686
                showFrameText(at, size, width, height, msg);
 
1687
            }
 
1688
        }
 
1689
 
 
1690
        /**
 
1691
         * Method to determine the size of the schematic frame in the current Cell.
 
1692
         * @param d a Dimension in which the size (database units) will be placed.
 
1693
         * @return 0: there should be a frame whose size is absolute;
 
1694
         * 1: there should be a frame but it combines with other stuff in the cell;
 
1695
         * 2: there is no frame.
 
1696
         */
 
1697
        public static int getCellFrameInfo(Cell cell, Dimension d) {
 
1698
            String frameInfo = cell.getVarValue(User.FRAME_SIZE, String.class);
 
1699
            if (frameInfo == null) {
 
1700
                return 2;
 
1701
            }
 
1702
            if (frameInfo.length() == 0) {
 
1703
                return 2;
 
1704
            }
 
1705
            int retval = 0;
 
1706
            char chr = frameInfo.charAt(0);
 
1707
            double wid = 0, hei = 0;
 
1708
            if (chr == 'x') {
 
1709
                wid = XLOGOBOX + FRAMEWID;
 
1710
                hei = YLOGOBOX + FRAMEWID;
 
1711
                retval = 1;
 
1712
            } else {
 
1713
                switch (chr) {
 
1714
                    case 'h':
 
1715
                        wid = HASCHXSIZE;
 
1716
                        hei = HASCHYSIZE;
 
1717
                        break;
 
1718
                    case 'a':
 
1719
                        wid = ASCHXSIZE;
 
1720
                        hei = ASCHYSIZE;
 
1721
                        break;
 
1722
                    case 'b':
 
1723
                        wid = BSCHXSIZE;
 
1724
                        hei = BSCHYSIZE;
 
1725
                        break;
 
1726
                    case 'c':
 
1727
                        wid = CSCHXSIZE;
 
1728
                        hei = CSCHYSIZE;
 
1729
                        break;
 
1730
                    case 'd':
 
1731
                        wid = DSCHXSIZE;
 
1732
                        hei = DSCHYSIZE;
 
1733
                        break;
 
1734
                    case 'e':
 
1735
                        wid = ESCHXSIZE;
 
1736
                        hei = ESCHYSIZE;
 
1737
                        break;
 
1738
                }
 
1739
            }
 
1740
            if (frameInfo.indexOf("v") >= 0) {
 
1741
                d.setSize(hei, wid);
 
1742
            } else {
 
1743
                d.setSize(wid, hei);
 
1744
            }
 
1745
            return retval;
 
1746
        }
 
1747
 
 
1748
        private void loadFrame() {
 
1749
            Dimension d = new Dimension();
 
1750
            int frameFactor = getCellFrameInfo(cell, d);
 
1751
            if (frameFactor == 2) {
 
1752
                return;
 
1753
            }
 
1754
 
 
1755
            String frameInfo = cell.getVarValue(User.FRAME_SIZE, String.class);
 
1756
            if (frameInfo == null) {
 
1757
                return;
 
1758
            }
 
1759
            double schXSize = d.getWidth();
 
1760
            double schYSize = d.getHeight();
 
1761
 
 
1762
            boolean drawTitleBox = true;
 
1763
            int xSections = 8;
 
1764
            int ySections = 4;
 
1765
            if (frameFactor == 1) {
 
1766
                xSections = ySections = 0;
 
1767
            } else {
 
1768
                if (frameInfo.indexOf("v") >= 0) {
 
1769
                    xSections = 4;
 
1770
                    ySections = 8;
 
1771
                }
 
1772
                if (frameInfo.indexOf("n") >= 0) {
 
1773
                    drawTitleBox = false;
 
1774
                }
 
1775
            }
 
1776
 
 
1777
            double xLogoBox = XLOGOBOX;
 
1778
            double yLogoBox = YLOGOBOX;
 
1779
            double frameWid = FRAMEWID;
 
1780
 
 
1781
            // draw the frame
 
1782
            if (xSections > 0) {
 
1783
                double xSecSize = (schXSize - frameWid * 2) / xSections;
 
1784
                double ySecSize = (schYSize - frameWid * 2) / ySections;
 
1785
 
 
1786
                // draw the outer frame
 
1787
                Point2D point0 = new Point2D.Double(-schXSize / 2, -schYSize / 2);
 
1788
                Point2D point1 = new Point2D.Double(-schXSize / 2, schYSize / 2);
 
1789
                Point2D point2 = new Point2D.Double(schXSize / 2, schYSize / 2);
 
1790
                Point2D point3 = new Point2D.Double(schXSize / 2, -schYSize / 2);
 
1791
                addLine(point0, point1);
 
1792
                addLine(point1, point2);
 
1793
                addLine(point2, point3);
 
1794
                addLine(point3, point0);
 
1795
 
 
1796
                // draw the inner frame
 
1797
                point0 = new Point2D.Double(-schXSize / 2 + frameWid, -schYSize / 2 + frameWid);
 
1798
                point1 = new Point2D.Double(-schXSize / 2 + frameWid, schYSize / 2 - frameWid);
 
1799
                point2 = new Point2D.Double(schXSize / 2 - frameWid, schYSize / 2 - frameWid);
 
1800
                point3 = new Point2D.Double(schXSize / 2 - frameWid, -schYSize / 2 + frameWid);
 
1801
                addLine(point0, point1);
 
1802
                addLine(point1, point2);
 
1803
                addLine(point2, point3);
 
1804
                addLine(point3, point0);
 
1805
 
 
1806
                // tick marks along the top and bottom sides
 
1807
                for (int i = 0; i < xSections; i++) {
 
1808
                    double x = i * xSecSize - (schXSize / 2 - frameWid);
 
1809
                    if (i > 0) {
 
1810
                        point0 = new Point2D.Double(x, schYSize / 2 - frameWid);
 
1811
                        point1 = new Point2D.Double(x, schYSize / 2 - frameWid / 2);
 
1812
                        addLine(point0, point1);
 
1813
                        point0 = new Point2D.Double(x, -schYSize / 2 + frameWid);
 
1814
                        point1 = new Point2D.Double(x, -schYSize / 2 + frameWid / 2);
 
1815
                        addLine(point0, point1);
 
1816
                    }
 
1817
 
 
1818
                    char chr = (char) ('1' + xSections - i - 1);
 
1819
                    point0 = new Point2D.Double(x + xSecSize / 2, schYSize / 2 - frameWid / 2);
 
1820
                    addText(point0, frameWid, 0, 0, String.valueOf(chr));
 
1821
 
 
1822
                    point0 = new Point2D.Double(x + xSecSize / 2, -schYSize / 2 + frameWid / 2);
 
1823
                    addText(point0, frameWid, 0, 0, String.valueOf(chr));
 
1824
                }
 
1825
 
 
1826
                // tick marks along the left and right sides
 
1827
                for (int i = 0; i < ySections; i++) {
 
1828
                    double y = i * ySecSize - (schYSize / 2 - frameWid);
 
1829
                    if (i > 0) {
 
1830
                        point0 = new Point2D.Double(schXSize / 2 - frameWid, y);
 
1831
                        point1 = new Point2D.Double(schXSize / 2 - frameWid / 2, y);
 
1832
                        addLine(point0, point1);
 
1833
                        point0 = new Point2D.Double(-schXSize / 2 + frameWid, y);
 
1834
                        point1 = new Point2D.Double(-schXSize / 2 + frameWid / 2, y);
 
1835
                        addLine(point0, point1);
 
1836
                    }
 
1837
                    char chr = (char) ('A' + i);
 
1838
                    point0 = new Point2D.Double(schXSize / 2 - frameWid / 2, y + ySecSize / 2);
 
1839
                    addText(point0, frameWid, 0, 0, String.valueOf(chr));
 
1840
 
 
1841
                    point0 = new Point2D.Double(-schXSize / 2 + frameWid / 2, y + ySecSize / 2);
 
1842
                    addText(point0, frameWid, 0, 0, String.valueOf(chr));
 
1843
                }
 
1844
            }
 
1845
            if (drawTitleBox) {
 
1846
                Point2D point0 = new Point2D.Double(schXSize / 2 - frameWid - xLogoBox, -schYSize / 2 + frameWid + yLogoBox);
 
1847
                Point2D point1 = new Point2D.Double(schXSize / 2 - frameWid, -schYSize / 2 + frameWid + yLogoBox);
 
1848
                Point2D point2 = new Point2D.Double(schXSize / 2 - frameWid, -schYSize / 2 + frameWid);
 
1849
                Point2D point3 = new Point2D.Double(schXSize / 2 - frameWid - xLogoBox, -schYSize / 2 + frameWid);
 
1850
                addLine(point0, point1);
 
1851
                addLine(point1, point2);
 
1852
                addLine(point2, point3);
 
1853
                addLine(point3, point0);
 
1854
 
 
1855
                point0 = new Point2D.Double(schXSize / 2 - frameWid - xLogoBox, -schYSize / 2 + frameWid + yLogoBox * 2 / 15);
 
1856
                point1 = new Point2D.Double(schXSize / 2 - frameWid, -schYSize / 2 + frameWid + yLogoBox * 2 / 15);
 
1857
                addLine(point0, point1);
 
1858
 
 
1859
                point0 = new Point2D.Double(schXSize / 2 - frameWid - xLogoBox, -schYSize / 2 + frameWid + yLogoBox * 4 / 15);
 
1860
                point1 = new Point2D.Double(schXSize / 2 - frameWid, -schYSize / 2 + frameWid + yLogoBox * 4 / 15);
 
1861
                addLine(point0, point1);
 
1862
 
 
1863
                point0 = new Point2D.Double(schXSize / 2 - frameWid - xLogoBox, -schYSize / 2 + frameWid + yLogoBox * 6 / 15);
 
1864
                point1 = new Point2D.Double(schXSize / 2 - frameWid, -schYSize / 2 + frameWid + yLogoBox * 6 / 15);
 
1865
                addLine(point0, point1);
 
1866
 
 
1867
                point0 = new Point2D.Double(schXSize / 2 - frameWid - xLogoBox, -schYSize / 2 + frameWid + yLogoBox * 8 / 15);
 
1868
                point1 = new Point2D.Double(schXSize / 2 - frameWid, -schYSize / 2 + frameWid + yLogoBox * 8 / 15);
 
1869
                addLine(point0, point1);
 
1870
 
 
1871
                point0 = new Point2D.Double(schXSize / 2 - frameWid - xLogoBox, -schYSize / 2 + frameWid + yLogoBox * 10 / 15);
 
1872
                point1 = new Point2D.Double(schXSize / 2 - frameWid, -schYSize / 2 + frameWid + yLogoBox * 10 / 15);
 
1873
                addLine(point0, point1);
 
1874
 
 
1875
                point0 = new Point2D.Double(schXSize / 2 - frameWid - xLogoBox, -schYSize / 2 + frameWid + yLogoBox * 12 / 15);
 
1876
                point1 = new Point2D.Double(schXSize / 2 - frameWid, -schYSize / 2 + frameWid + yLogoBox * 12 / 15);
 
1877
                addLine(point0, point1);
 
1878
 
 
1879
                point0 = new Point2D.Double(schXSize / 2 - frameWid - xLogoBox / 2, -schYSize / 2 + frameWid + yLogoBox * 13.5 / 15);
 
1880
                addText(point0, yLogoBox * 2 / 15, xLogoBox, yLogoBox * 3 / 15, "Cell: " + cell.describe(false) + (cell.isMultiPage() ? " Page " + (pageNo + 1) : ""));
 
1881
 
 
1882
                String projectName = cell.getLibrary().getVarValue(User.FRAME_PROJECT_NAME, String.class, User.getFrameProjectName());
 
1883
                if (projectName.length() > 0) {
 
1884
                    point0 = new Point2D.Double(schXSize / 2 - frameWid - xLogoBox / 2, -schYSize / 2 + frameWid + yLogoBox * 11 / 15);
 
1885
                    addText(point0, yLogoBox * 2 / 15, xLogoBox, yLogoBox * 2 / 15, "Project: " + projectName);
 
1886
                }
1981
1887
 
1982
1888
                String designerName = cell.getVarValue(User.FRAME_DESIGNER_NAME, String.class);
1983
 
                if (designerName == null)
 
1889
                if (designerName == null) {
1984
1890
                    designerName = cell.getLibrary().getVarValue(User.FRAME_DESIGNER_NAME, String.class, User.getFrameDesignerName());
1985
 
                                if (designerName.length() > 0)
1986
 
                                {
1987
 
                                        point0 = new Point2D.Double(schXSize/2 - frameWid - xLogoBox/2, -schYSize/2 + frameWid + yLogoBox*9/15);
1988
 
                                        addText(point0, yLogoBox*2/15, xLogoBox, yLogoBox*2/15, "Designer: " + designerName);
1989
 
                                }
1990
 
 
1991
 
                                String lastChangeByName = cell.getVarValue(User.FRAME_LAST_CHANGED_BY, String.class);
1992
 
                                if (lastChangeByName != null)
1993
 
                                {
1994
 
                                        point0 = new Point2D.Double(schXSize/2 - frameWid - xLogoBox/2, -schYSize/2 + frameWid + yLogoBox*7/15);
1995
 
                                        addText(point0, yLogoBox*2/15, xLogoBox, yLogoBox*2/15, "Last Changed By: " + lastChangeByName);
1996
 
                                }
1997
 
 
1998
 
                                String companyName = cell.getLibrary().getVarValue(User.FRAME_COMPANY_NAME, String.class, User.getFrameCompanyName());
1999
 
                                if (companyName.length() > 0)
2000
 
                                {
2001
 
                                        point0 = new Point2D.Double(schXSize/2 - frameWid - xLogoBox/2, -schYSize/2 + frameWid + yLogoBox*5/15);
2002
 
                                        addText(point0, yLogoBox*2/15, xLogoBox, yLogoBox*2/15, "Company: " + companyName);
2003
 
                                }
2004
 
 
2005
 
                                point0 = new Point2D.Double(schXSize/2 - frameWid - xLogoBox/2, -schYSize/2 + frameWid + yLogoBox*3/15);
2006
 
                                addText(point0, yLogoBox*2/15, xLogoBox, yLogoBox*2/15, "Created: " + TextUtils.formatDate(cell.getCreationDate()));
2007
 
 
2008
 
                                point0 = new Point2D.Double(schXSize/2 - frameWid - xLogoBox/2, -schYSize/2 + frameWid + yLogoBox*1/15);
2009
 
                                addText(point0, yLogoBox*2/15, xLogoBox, yLogoBox*2/15, "Revised: " + TextUtils.formatDate(cell.getRevisionDate()));
2010
 
                        }
2011
 
                }
2012
 
 
2013
 
                private void addLine(Point2D from, Point2D to)
2014
 
                {
2015
 
                        lineFromEnd.add(from);
2016
 
                        lineToEnd.add(to);
2017
 
                }
2018
 
 
2019
 
                private void addText(Point2D at, double size, double width, double height, String msg)
2020
 
                {
2021
 
                        textPoint.add(at);
2022
 
                        textSize.add(new Double(size));
2023
 
                        textBox.add(new Point2D.Double(width, height));
2024
 
                        textMessage.add(msg);
2025
 
                }
2026
 
        }
2027
 
 
2028
 
        /****************************** NODES ******************************/
2029
 
 
2030
 
        /**
2031
 
         * Method to return an Iterator over all NodeInst objects in this Cell.
2032
 
         * @return an Iterator over all NodeInst objects in this Cell.
2033
 
         */
2034
 
        public synchronized Iterator<NodeInst> getNodes()
2035
 
        {
2036
 
        List<NodeInst> nodesCopy = new ArrayList<NodeInst>(nodes);
2037
 
                return nodesCopy.iterator();
2038
 
        }
2039
 
 
2040
 
        /**
2041
 
         * Method to return an Iterator over all NodeInst objects in this Cell.
2042
 
         * @return an Iterator over all NodeInst objects in this Cell.
2043
 
         */
2044
 
        public synchronized Iterator<Nodable> getNodables()
2045
 
        {
2046
 
        List<Nodable> nodesCopy = new ArrayList<Nodable>(nodes);
2047
 
                return nodesCopy.iterator();
2048
 
        }
2049
 
 
2050
 
        /**
2051
 
         * Method to return the number of NodeInst objects in this Cell.
2052
 
         * @return the number of NodeInst objects in this Cell.
2053
 
         */
2054
 
        public int getNumNodes()
2055
 
        {
2056
 
                return nodes.size();
2057
 
        }
2058
 
 
2059
 
        /**
2060
 
         * Method to return the NodeInst at specified position.
2061
 
         * @param nodeIndex specified position of NodeInst.
2062
 
         * @return the NodeInst at specified position.
2063
 
         */
2064
 
        public final NodeInst getNode(int nodeIndex)
2065
 
        {
2066
 
                return nodes.get(nodeIndex);
2067
 
        }
2068
 
 
2069
 
        /**
2070
 
         * Method to return the NodeInst by its chronological index.
2071
 
         * @param nodeId chronological index of NodeInst.
2072
 
         * @return the NodeInst with specified chronological index.
2073
 
         */
2074
 
        public NodeInst getNodeById(int nodeId)
2075
 
        {
2076
 
                return nodeId < chronNodes.size() ? chronNodes.get(nodeId) : null;
2077
 
        }
 
1891
                }
 
1892
                if (designerName.length() > 0) {
 
1893
                    point0 = new Point2D.Double(schXSize / 2 - frameWid - xLogoBox / 2, -schYSize / 2 + frameWid + yLogoBox * 9 / 15);
 
1894
                    addText(point0, yLogoBox * 2 / 15, xLogoBox, yLogoBox * 2 / 15, "Designer: " + designerName);
 
1895
                }
 
1896
 
 
1897
                String lastChangeByName = cell.getVarValue(User.FRAME_LAST_CHANGED_BY, String.class);
 
1898
                if (lastChangeByName != null) {
 
1899
                    point0 = new Point2D.Double(schXSize / 2 - frameWid - xLogoBox / 2, -schYSize / 2 + frameWid + yLogoBox * 7 / 15);
 
1900
                    addText(point0, yLogoBox * 2 / 15, xLogoBox, yLogoBox * 2 / 15, "Last Changed By: " + lastChangeByName);
 
1901
                }
 
1902
 
 
1903
                String companyName = cell.getLibrary().getVarValue(User.FRAME_COMPANY_NAME, String.class, User.getFrameCompanyName());
 
1904
                if (companyName.length() > 0) {
 
1905
                    point0 = new Point2D.Double(schXSize / 2 - frameWid - xLogoBox / 2, -schYSize / 2 + frameWid + yLogoBox * 5 / 15);
 
1906
                    addText(point0, yLogoBox * 2 / 15, xLogoBox, yLogoBox * 2 / 15, "Company: " + companyName);
 
1907
                }
 
1908
 
 
1909
                point0 = new Point2D.Double(schXSize / 2 - frameWid - xLogoBox / 2, -schYSize / 2 + frameWid + yLogoBox * 3 / 15);
 
1910
                addText(point0, yLogoBox * 2 / 15, xLogoBox, yLogoBox * 2 / 15, "Created: " + TextUtils.formatDate(cell.getCreationDate()));
 
1911
 
 
1912
                point0 = new Point2D.Double(schXSize / 2 - frameWid - xLogoBox / 2, -schYSize / 2 + frameWid + yLogoBox * 1 / 15);
 
1913
                addText(point0, yLogoBox * 2 / 15, xLogoBox, yLogoBox * 2 / 15, "Revised: " + TextUtils.formatDate(cell.getRevisionDate()));
 
1914
            }
 
1915
        }
 
1916
 
 
1917
        private void addLine(Point2D from, Point2D to) {
 
1918
            lineFromEnd.add(from);
 
1919
            lineToEnd.add(to);
 
1920
        }
 
1921
 
 
1922
        private void addText(Point2D at, double size, double width, double height, String msg) {
 
1923
            textPoint.add(at);
 
1924
            textSize.add(new Double(size));
 
1925
            textBox.add(new Point2D.Double(width, height));
 
1926
            textMessage.add(msg);
 
1927
        }
 
1928
    }
 
1929
 
 
1930
    /****************************** NODES ******************************/
 
1931
    /**
 
1932
     * Method to return an Iterator over all NodeInst objects in this Cell.
 
1933
     * @return an Iterator over all NodeInst objects in this Cell.
 
1934
     */
 
1935
    public synchronized Iterator<NodeInst> getNodes() {
 
1936
        return getTopology().getNodes();
 
1937
    }
 
1938
 
 
1939
    /**
 
1940
     * Method to return an Iterator over all NodeInst objects in this Cell.
 
1941
     * @return an Iterator over all NodeInst objects in this Cell.
 
1942
     */
 
1943
    public synchronized Iterator<Nodable> getNodables() {
 
1944
        return getTopology().getNodables();
 
1945
    }
 
1946
 
 
1947
    /**
 
1948
     * Method to return the number of NodeInst objects in this Cell.
 
1949
     * @return the number of NodeInst objects in this Cell.
 
1950
     */
 
1951
    public int getNumNodes() {
 
1952
        Topology topology = getTopologyOptional();
 
1953
        return topology != null ? topology.getNumNodes() : backup().cellRevision.nodes.size();
 
1954
    }
 
1955
 
 
1956
    /**
 
1957
     * Method to return the NodeInst at specified position.
 
1958
     * @param nodeIndex specified position of NodeInst.
 
1959
     * @return the NodeInst at specified position.
 
1960
     */
 
1961
    public final NodeInst getNode(int nodeIndex) {
 
1962
        return getTopology().getNode(nodeIndex);
 
1963
    }
 
1964
 
 
1965
    /**
 
1966
     * Method to return the NodeInst by its chronological index.
 
1967
     * @param nodeId chronological index of NodeInst.
 
1968
     * @return the NodeInst with specified chronological index.
 
1969
     */
 
1970
    public NodeInst getNodeById(int nodeId) {
 
1971
        return getTopology().getNodeById(nodeId);
 
1972
    }
2078
1973
 
2079
1974
    /**
2080
1975
     * Tells expanded status of NodeInst with specified nodeId.
2084
1979
        return expandedNodes.get(nodeId);
2085
1980
    }
2086
1981
 
 
1982
    public BitSet lowLevelExpandedNodes() {
 
1983
        return expandedNodes;
 
1984
    }
 
1985
 
2087
1986
    /**
2088
 
         * Method to set expanded status of specified NodeInst.
2089
 
         * Expanded NodeInsts are instances of Cells that show their contents.
2090
 
         * Unexpanded Cell instances are shown as boxes with the node prototype names in them.
2091
 
         * The state has no meaning for instances of primitive node prototypes.
 
1987
     * Method to set expanded status of specified NodeInst.
 
1988
     * Expanded NodeInsts are instances of Cells that show their contents.
 
1989
     * Unexpanded Cell instances are shown as boxes with the node prototype names in them.
 
1990
     * The state has no meaning for instances of primitive node prototypes.
2092
1991
     * @param nodeId specified nodeId
2093
1992
     * @param value true if NodeInst is expanded.
2094
 
         */
 
1993
     */
2095
1994
    public void setExpanded(int nodeId, boolean value) {
2096
 
        NodeInst ni = getNodeById(nodeId);
2097
 
        if (ni == null) return;
2098
 
        NodeProto protoType = ni.getProto();
2099
 
        if (!(protoType instanceof Cell) || ((Cell)protoType).isIcon()) return;
 
1995
        ImmutableNodeInst n = backupUnsafe().getMemoization().getNodeById(nodeId);
 
1996
        if (n == null) {
 
1997
            return;
 
1998
        }
 
1999
        if (!(n.protoId instanceof CellId) || ((CellId) n.protoId).isIcon()) {
 
2000
            return;
 
2001
        }
2100
2002
        boolean oldValue = expandedNodes.get(nodeId);
2101
 
        if (oldValue == value) return;
 
2003
        if (oldValue == value) {
 
2004
            return;
 
2005
        }
2102
2006
        expandedNodes.set(nodeId, value);
2103
2007
        expandStatusModified = true;
2104
2008
    }
2105
2009
 
2106
 
        /**
2107
 
         * Method to return the PortInst by nodeId and PortProtoId.
2108
 
         * @param nodeId specified NodeId.
 
2010
    /**
 
2011
     * Method to set expand specified subcells.
 
2012
     * Expanded NodeInsts are instances of Cells that show their contents.
 
2013
     * @param subCells nodeIds of subCells to expand
 
2014
     */
 
2015
    void expand(BitSet subCells) {
 
2016
        for (int nodeId = subCells.nextSetBit(0); nodeId >= 0; nodeId = subCells.nextSetBit(nodeId + 1)) {
 
2017
            setExpanded(nodeId, true);
 
2018
        }
 
2019
    }
 
2020
 
 
2021
    /**
 
2022
     * Method to return the PortInst by nodeId and PortProtoId.
 
2023
     * @param nodeId specified NodeId.
2109
2024
     * @param portProtoId
2110
 
         * @return the PortInst at specified position..
2111
 
         */
 
2025
     * @return the PortInst at specified position..
 
2026
     */
2112
2027
    public PortInst getPortInst(int nodeId, PortProtoId portProtoId) {
2113
 
        NodeInst ni = chronNodes.get(nodeId);
2114
 
        assert ni.getD().protoId == portProtoId.getParentId();
2115
 
        NodeProto np = ni.getProto();
2116
 
        PortProto pp = np.getPort(portProtoId);
2117
 
        PortInst pi = ni.getPortInst(pp.getPortIndex());
2118
 
        assert pi.getNodeInst().getD().nodeId == nodeId;
2119
 
        assert pi.getPortProto().getId() == portProtoId;
2120
 
        return pi;
 
2028
        return getTopology().getPortInst(nodeId, portProtoId);
2121
2029
    }
2122
2030
 
2123
2031
    /**
2126
2034
     */
2127
2035
    public synchronized Iterator<CellUsage> getUsagesIn() {
2128
2036
        return new Iterator<CellUsage>() {
 
2037
 
2129
2038
            private int i = 0;
2130
2039
            CellUsage nextU = findNext();
2131
2040
 
2132
 
            public boolean hasNext() { return nextU != null; }
 
2041
            public boolean hasNext() {
 
2042
                return nextU != null;
 
2043
            }
2133
2044
 
2134
 
                        public CellUsage next() {
2135
 
                if (nextU == null) throw new NoSuchElementException();
 
2045
            public CellUsage next() {
 
2046
                if (nextU == null) {
 
2047
                    throw new NoSuchElementException();
 
2048
                }
2136
2049
                CellUsage u = nextU;
2137
2050
                nextU = findNext();
2138
2051
                return u;
2139
2052
            }
2140
2053
 
2141
 
            public void remove() { throw new UnsupportedOperationException(); };
 
2054
            public void remove() {
 
2055
                throw new UnsupportedOperationException();
 
2056
            }
 
2057
 
 
2058
            ;
2142
2059
 
2143
2060
            private CellUsage findNext() {
2144
2061
                while (i < cellUsages.length) {
2145
 
                    if (cellUsages[i] != 0)
 
2062
                    if (cellUsages[i] != 0) {
2146
2063
                        return getId().getUsageIn(i++);
 
2064
                    }
2147
2065
                    i++;
2148
2066
                }
2149
2067
                return null;
2158
2076
    public int getNumUsagesIn() {
2159
2077
        int numUsages = 0;
2160
2078
        for (int i = 0; i < cellUsages.length; i++) {
2161
 
            if (cellUsages[i] != 0)
 
2079
            if (cellUsages[i] != 0) {
2162
2080
                numUsages++;
 
2081
            }
2163
2082
        }
2164
2083
        return numUsages;
2165
2084
    }
2166
2085
 
2167
 
        /**
2168
 
         * Method to find a named NodeInst on this Cell.
2169
 
         * @param name the name of the NodeInst.
2170
 
         * @return the NodeInst.  Returns null if none with that name are found.
2171
 
         */
2172
 
        public NodeInst findNode(String name)
2173
 
        {
2174
 
                int nodeIndex = searchNode(name);
2175
 
                return nodeIndex >= 0 ? nodes.get(nodeIndex) : null;
2176
 
        }
 
2086
    /**
 
2087
     * Method to find a named NodeInst on this Cell.
 
2088
     * @param name the name of the NodeInst.
 
2089
     * @return the NodeInst.  Returns null if none with that name are found.
 
2090
     */
 
2091
    public NodeInst findNode(String name) {
 
2092
        return getTopology().findNode(name);
 
2093
    }
2177
2094
 
2178
 
        /**
2179
 
         * Method to unlink a set of these NodeInsts from this Cell.
 
2095
    /**
 
2096
     * Method to unlink a set of these NodeInsts from this Cell.
2180
2097
     * @param killedNodes a set of NodeInsts to kill.
2181
 
         */
2182
 
        public void killNodes(Set<NodeInst> killedNodes) {
2183
 
        if (killedNodes.isEmpty()) return;
2184
 
                for(NodeInst ni : killedNodes) {
2185
 
            if (ni.getParent() != this)
 
2098
     */
 
2099
    public void killNodes(Set<NodeInst> killedNodes) {
 
2100
        if (killedNodes.isEmpty()) {
 
2101
            return;
 
2102
        }
 
2103
        for (NodeInst ni : killedNodes) {
 
2104
            if (ni.getParent() != this) {
2186
2105
                throw new IllegalArgumentException("parent");
2187
 
                }
 
2106
            }
 
2107
        }
2188
2108
        Set<ArcInst> arcsToKill = new HashSet<ArcInst>();
2189
 
        for (Iterator<ArcInst> it = getArcs(); it.hasNext(); ) {
 
2109
        for (Iterator<ArcInst> it = getArcs(); it.hasNext();) {
2190
2110
            ArcInst ai = it.next();
2191
 
            if (killedNodes.contains(ai.getTailPortInst().getNodeInst()) || killedNodes.contains(ai.getHeadPortInst().getNodeInst()))
 
2111
            if (killedNodes.contains(ai.getTailPortInst().getNodeInst()) || killedNodes.contains(ai.getHeadPortInst().getNodeInst())) {
2192
2112
                arcsToKill.add(ai);
 
2113
            }
2193
2114
 
2194
2115
        }
2195
2116
        Set<Export> exportsToKill = new HashSet<Export>();
2196
 
        for (Iterator<Export> it = getExports(); it.hasNext(); ) {
 
2117
        for (Iterator<Export> it = getExports(); it.hasNext();) {
2197
2118
            Export export = it.next();
2198
 
            if (killedNodes.contains(export.getOriginalPort().getNodeInst()))
 
2119
            if (killedNodes.contains(export.getOriginalPort().getNodeInst())) {
2199
2120
                exportsToKill.add(export);
 
2121
            }
2200
2122
        }
2201
2123
 
2202
 
        for (ArcInst ai: arcsToKill)
 
2124
        for (ArcInst ai : arcsToKill) {
2203
2125
            ai.kill();
 
2126
        }
2204
2127
        killExports(exportsToKill);
2205
2128
 
2206
 
                for(NodeInst ni : killedNodes)
2207
 
                {
2208
 
            if (!ni.isLinked()) continue;
2209
 
                        // remove this node from the cell
2210
 
                        removeNode(ni);
2211
 
 
2212
 
                        // handle change control, constraint, and broadcast
2213
 
                        Constraints.getCurrent().killObject(ni);
2214
 
                }
2215
 
    }
2216
 
 
2217
 
        private static boolean allowCirDep = false;
2218
 
 
2219
 
        /**
2220
 
         * Method to allow temporarily circular library dependences
2221
 
         * (for example to read legacy libraries).
2222
 
         * It is called only from synchronyzed method Input.readLibrary.
2223
 
         * @param val true allows circular dependencies.
2224
 
         */
2225
 
        public static void setAllowCircularLibraryDependences(boolean val)
2226
 
        {
2227
 
                allowCirDep = val;
2228
 
        }
2229
 
 
2230
 
        /**
2231
 
         * Method to add a new NodeInst to the cell.
2232
 
         * @param ni the NodeInst to be included in the cell.
2233
 
         * @return true on failure
2234
 
         */
2235
 
        public boolean addNode(NodeInst ni)
2236
 
        {
2237
 
                checkChanging();
2238
 
 
2239
 
                // check to see if this instantiation would create a circular library dependency
2240
 
                if (ni.isCellInstance()) {
2241
 
                        Cell instProto = (Cell)ni.getProto();
2242
 
                        if (instProto.getLibrary() != getLibrary()) {
2243
 
                                // a reference will be created, check it
2244
 
                                Library.LibraryDependency libDep = getLibrary().addReferencedLib(instProto.getLibrary());
2245
 
                                if (libDep != null) {
2246
 
                                        // addition would create circular dependency
2247
 
                                        if (!allowCirDep) {
2248
 
                                                System.out.println("ERROR: "+ libDescribe() + " cannot instantiate " +
2249
 
                                                        instProto.libDescribe() + " because it would create a circular library dependence: ");
2250
 
                                                System.out.println(libDep.toString());
2251
 
                                                return true;
2252
 
                                        }
2253
 
                                        System.out.println("WARNING: "+ libDescribe() + " instantiates " +
2254
 
                                                instProto.libDescribe() + " which causes a circular library dependence: ");
2255
 
                                        System.out.println(libDep.toString());
2256
 
                                }
2257
 
                        }
2258
 
                }
2259
 
 
2260
 
        setContentsModified();
2261
 
                addNodeName(ni);
2262
 
        int nodeId = ni.getD().nodeId;
2263
 
        while (chronNodes.size() <= nodeId) chronNodes.add(null);
2264
 
        assert chronNodes.get(nodeId) == null;
2265
 
        chronNodes.set(nodeId, ni);
 
2129
        for (NodeInst ni : killedNodes) {
 
2130
            if (!ni.isLinked()) {
 
2131
                continue;
 
2132
            }
 
2133
            // remove this node from the cell
 
2134
            removeNode(ni);
 
2135
 
 
2136
            // handle change control, constraint, and broadcast
 
2137
            Constraints.getCurrent().killObject(ni);
 
2138
        }
 
2139
    }
 
2140
    private static boolean allowCirDep = false;
 
2141
 
 
2142
    /**
 
2143
     * Method to allow temporarily circular library dependences
 
2144
     * (for example to read legacy libraries).
 
2145
     * It is called only from synchronyzed method Input.readLibrary.
 
2146
     * @param val true allows circular dependencies.
 
2147
     */
 
2148
    public static void setAllowCircularLibraryDependences(boolean val) {
 
2149
        allowCirDep = val;
 
2150
    }
 
2151
 
 
2152
    /**
 
2153
     * Method to add a new NodeInst to the cell.
 
2154
     * @param ni the NodeInst to be included in the cell.
 
2155
     * @return true on failure
 
2156
     */
 
2157
    public boolean addNode(NodeInst ni) {
 
2158
        checkChanging();
 
2159
 
 
2160
        // check to see if this instantiation would create a circular library dependency
 
2161
        if (ni.isCellInstance()) {
 
2162
            Cell instProto = (Cell) ni.getProto();
 
2163
            if (instProto.getLibrary() != getLibrary()) {
 
2164
                // a reference will be created, check it
 
2165
                Library.LibraryDependency libDep = getLibrary().addReferencedLib(instProto.getLibrary());
 
2166
                if (libDep != null) {
 
2167
                    // addition would create circular dependency
 
2168
                    if (!allowCirDep) {
 
2169
                        System.out.println("ERROR: " + libDescribe() + " cannot instantiate "
 
2170
                                + instProto.libDescribe() + " because it would create a circular library dependence: ");
 
2171
                        System.out.println(libDep.toString());
 
2172
                        return true;
 
2173
                    }
 
2174
                    System.out.println("WARNING: " + libDescribe() + " instantiates "
 
2175
                            + instProto.libDescribe() + " which causes a circular library dependence: ");
 
2176
                    System.out.println(libDep.toString());
 
2177
                }
 
2178
            }
 
2179
        }
 
2180
 
 
2181
        setTopologyModified();
 
2182
        int nodeId = getTopology().addNode(ni);
 
2183
//        addNodeName(ni);
 
2184
//        int nodeId = ni.getD().nodeId;
 
2185
//        while (chronNodes.size() <= nodeId) {
 
2186
//            chronNodes.add(null);
 
2187
//        }
 
2188
//        assert chronNodes.get(nodeId) == null;
 
2189
//        chronNodes.set(nodeId, ni);
2266
2190
 
2267
2191
        // expand status and count usage
2268
2192
        if (ni.isCellInstance()) {
2269
 
            Cell subCell = (Cell)ni.getProto();
 
2193
            Cell subCell = (Cell) ni.getProto();
2270
2194
            expandedNodes.set(nodeId, subCell.isWantExpanded());
2271
2195
            expandStatusModified = true;
2272
2196
 
2279
2203
            cellUsages[u.indexInParent]++;
2280
2204
        }
2281
2205
 
2282
 
                // make additional checks to keep circuit up-to-date
2283
 
                if (ni.getProto() == Generic.tech().essentialBoundsNode)
2284
 
                        essenBounds.add(ni);
2285
 
        setDirty();
2286
 
 
2287
 
                return false;
2288
 
        }
2289
 
 
2290
 
        /**
2291
 
         * Method to add a new NodeInst to the name index of this cell.
2292
 
         * @param ni the NodeInst to be included tp the name index in the cell.
2293
 
         */
2294
 
        public void addNodeName(NodeInst ni)
2295
 
        {
2296
 
                // Gilda's test
2297
 
//        int nodeIndex = nodes.size();
2298
 
//        nodes.add(ni);
2299
 
//        ni.setNodeIndex(nodeIndex);
2300
 
        int nodeIndex = searchNode(ni.getName());
2301
 
                assert nodeIndex < 0;
2302
 
                nodeIndex = - nodeIndex - 1;
2303
 
                nodes.add(nodeIndex, ni);
2304
 
                for (; nodeIndex < nodes.size(); nodeIndex++)
2305
 
                {
2306
 
                        NodeInst n = nodes.get(nodeIndex);
2307
 
                        n.setNodeIndex(nodeIndex);
2308
 
                }
2309
 
        updateMaxSuffix(ni);
2310
 
        }
 
2206
//        // make additional checks to keep circuit up-to-date
 
2207
//        if (ni.getProto() == Generic.tech().essentialBoundsNode) {
 
2208
//            essenBounds.add(ni);
 
2209
//        }
 
2210
 
 
2211
        return false;
 
2212
    }
2311
2213
 
2312
2214
    /**
2313
2215
     * add temp name of NodeInst to maxSuffix map.
2314
2216
     * @param ni NodeInst.
2315
2217
     */
2316
2218
    private void updateMaxSuffix(NodeInst ni) {
2317
 
                Name name = ni.getNameKey();
2318
 
                if (!name.isTempname()) return;
 
2219
        Name name = ni.getNameKey();
 
2220
        if (!name.isTempname()) {
 
2221
            return;
 
2222
        }
2319
2223
 
2320
 
                Name basename = name.getBasename();
 
2224
        Name basename = name.getBasename();
2321
2225
        String basenameString = basename.toString();
2322
2226
//        String basenameString = basename.canonicString();
2323
2227
        MaxSuffix ms = maxSuffix.get(basenameString);
2331
2235
        }
2332
2236
    }
2333
2237
 
2334
 
        /**
2335
 
         * Method to return unique autoname for NodeInst in this cell.
2336
 
         * @param basename base name of autoname
2337
 
         * @return autoname
2338
 
         */
2339
 
        public Name getNodeAutoname(Name basename)
2340
 
        {
2341
 
        String basenameString = basename.toString();
2342
 
//        String basenameString = basename.canonicString();
2343
 
                MaxSuffix ms = maxSuffix.get(basenameString);
2344
 
        Name name;
2345
 
                if (ms == null)
2346
 
                {
2347
 
                        ms = new MaxSuffix();
2348
 
                        maxSuffix.put(basenameString, ms);
2349
 
                        name = basename.findSuffixed(0);
2350
 
                } else
2351
 
                {
2352
 
                        ms.v++;
2353
 
                        name = basename.findSuffixed(ms.v);
2354
 
                }
2355
 
        assert searchNode(name.toString()) < 0;
2356
 
        return name;
2357
 
        }
2358
 
 
2359
 
        /**
2360
 
         * Method to remove an NodeInst from the cell.
2361
 
         * @param ni the NodeInst to be removed from the cell.
2362
 
         */
2363
 
        private void removeNode(NodeInst ni)
2364
 
        {
2365
 
                checkChanging();
2366
 
                assert ni.isLinked();
2367
 
 
2368
 
                essenBounds.remove(ni);
 
2238
    /**
 
2239
     * Method to remove an NodeInst from the cell.
 
2240
     * @param ni the NodeInst to be removed from the cell.
 
2241
     */
 
2242
    private void removeNode(NodeInst ni) {
 
2243
        checkChanging();
 
2244
        assert ni.isLinked();
 
2245
        getTopology().removeNode(ni);
 
2246
 
 
2247
//        essenBounds.remove(ni);
2369
2248
 
2370
2249
        // remove usage count
2371
2250
        if (ni.isCellInstance()) {
2372
 
            Cell subCell = (Cell)ni.getProto();
 
2251
            Cell subCell = (Cell) ni.getProto();
2373
2252
            CellUsage u = getId().getUsageIn(subCell.getId());
2374
2253
            cellUsages[u.indexInParent]--;
2375
2254
            if (cellUsages[u.indexInParent] <= 0) {
2376
2255
                assert cellUsages[u.indexInParent] == 0;
2377
2256
                // remove library dependency, if possible
2378
 
                getLibrary().removeReferencedLib(((Cell)ni.getProto()).getLibrary());
2379
 
             }
 
2257
                getLibrary().removeReferencedLib(((Cell) ni.getProto()).getLibrary());
 
2258
            }
2380
2259
        }
2381
2260
 
2382
 
        setContentsModified();
2383
 
                removeNodeName(ni);
2384
 
        int nodeId = ni.getD().nodeId;
2385
 
        assert chronNodes.get(nodeId) == ni;
2386
 
        chronNodes.set(nodeId, null);
2387
 
        setDirty();
2388
 
        }
2389
 
 
2390
 
        /**
2391
 
         * Method to remove an NodeInst from the name index of this cell.
2392
 
         * @param ni the NodeInst to be removed from the cell.
2393
 
         */
2394
 
        public void removeNodeName(NodeInst ni)
2395
 
        {
2396
 
                int nodeIndex = ni.getNodeIndex();
2397
 
                NodeInst removedNi = nodes.remove(nodeIndex);
2398
 
                assert removedNi == ni;
2399
 
                for (int i = nodeIndex; i < nodes.size(); i++)
2400
 
                {
2401
 
                        NodeInst n = nodes.get(i);
2402
 
                        n.setNodeIndex(i);
2403
 
                }
2404
 
                ni.setNodeIndex(-1);
2405
 
        }
2406
 
 
2407
 
    /**
2408
 
     * Searches the nodes for the specified name using the binary
2409
 
     * search algorithm.
2410
 
     * @param name the name to be searched.
2411
 
     * @return index of the search name, if it is contained in the nodes;
2412
 
     *         otherwise, <tt>(-(<i>insertion point</i>) - 1)</tt>.  The
2413
 
     *         <i>insertion point</i> is defined as the point at which the
2414
 
     *         NodeInst would be inserted into the list: the index of the first
2415
 
     *         element greater than the name, or <tt>nodes.size()</tt>, if all
2416
 
     *         elements in the list are less than the specified name.  Note
2417
 
     *         that this guarantees that the return value will be &gt;= 0 if
2418
 
     *         and only if the NodeInst is found.
2419
 
     */
2420
 
        private int searchNode(String name)
2421
 
        {
2422
 
        int low = 0;
2423
 
        int high = nodes.size()-1;
2424
 
        int pick = high; // initially try the last postition
2425
 
                while (low <= high) {
2426
 
                        NodeInst ni = nodes.get(pick);
2427
 
                        int cmp = TextUtils.STRING_NUMBER_ORDER.compare(ni.getName(), name);
2428
 
 
2429
 
                        if (cmp < 0)
2430
 
                                low = pick + 1;
2431
 
                        else if (cmp > 0)
2432
 
                                high = pick - 1;
2433
 
                        else
2434
 
                                return pick; // NodeInst found
2435
 
                        pick = (low + high) >> 1; // try in a middle
2436
 
                }
2437
 
                return -(low + 1);  // NodeInst not found.
2438
 
    }
2439
 
 
2440
 
        /****************************** ARCS ******************************/
2441
 
 
2442
 
        /**
2443
 
         * Method to return an Iterator over all ArcInst objects in this Cell.
2444
 
         * @return an Iterator over all ArcInst objects in this Cell.
2445
 
         */
2446
 
        public synchronized Iterator<ArcInst> getArcs() { return getTopology().getArcs(); }
2447
 
 
2448
 
        /**
2449
 
         * Method to return the number of ArcInst objects in this Cell.
2450
 
         * @return the number of ArcInst objects in this Cell.
2451
 
         */
2452
 
        public int getNumArcs() { return topology.getNumArcs(); }
2453
 
 
2454
 
        /**
2455
 
         * Method to return the ArcInst at specified position.
2456
 
         * @param arcIndex specified position of ArcInst.
2457
 
         * @return the ArcInst at specified position..
2458
 
         */
2459
 
        public final ArcInst getArc(int arcIndex) { return getTopology().getArc(arcIndex); }
2460
 
 
2461
 
        /**
2462
 
         * Method to return the ArcInst by its chronological index.
2463
 
         * @param arcId chronological index of ArcInst.
2464
 
         * @return the ArcInst with specified chronological index.
2465
 
         */
2466
 
        public ArcInst getArcById(int arcId) { return getTopology().getArcById(arcId); }
2467
 
 
2468
 
        /**
2469
 
         * Method to find a named ArcInst on this Cell.
2470
 
         * @param name the name of the ArcInst.
2471
 
         * @return the ArcInst.  Returns null if none with that name are found.
2472
 
         */
2473
 
        public ArcInst findArc(String name) { return getTopology().findArc(name); }
2474
 
 
2475
 
        /**
2476
 
         * Method to unlink a set of these ArcInsts from this Cell.
 
2261
        setTopologyModified();
 
2262
//        removeNodeName(ni);
 
2263
//        int nodeId = ni.getD().nodeId;
 
2264
//        assert chronNodes.get(nodeId) == ni;
 
2265
//        chronNodes.set(nodeId, null);
 
2266
//        setDirty();
 
2267
    }
 
2268
 
 
2269
//    /**
 
2270
//     * Method to remove an NodeInst from the name index of this cell.
 
2271
//     * @param ni the NodeInst to be removed from the cell.
 
2272
//     */
 
2273
//    public void removeNodeName(NodeInst ni) {
 
2274
//        int nodeIndex = ni.getNodeIndex();
 
2275
//        NodeInst removedNi = nodes.remove(nodeIndex);
 
2276
//        assert removedNi == ni;
 
2277
//        for (int i = nodeIndex; i < nodes.size(); i++) {
 
2278
//            NodeInst n = nodes.get(i);
 
2279
//            n.setNodeIndex(i);
 
2280
//        }
 
2281
//        ni.setNodeIndex(-1);
 
2282
//    }
 
2283
    /****************************** ARCS ******************************/
 
2284
    /**
 
2285
     * Method to return an Iterator over all ArcInst objects in this Cell.
 
2286
     * @return an Iterator over all ArcInst objects in this Cell.
 
2287
     */
 
2288
    public synchronized Iterator<ArcInst> getArcs() {
 
2289
        return getTopology().getArcs();
 
2290
    }
 
2291
 
 
2292
    /**
 
2293
     * Method to return the number of ArcInst objects in this Cell.
 
2294
     * @return the number of ArcInst objects in this Cell.
 
2295
     */
 
2296
    public int getNumArcs() {
 
2297
        Topology topology = getTopologyOptional();
 
2298
        return topology != null ? topology.getNumArcs() : backup().cellRevision.arcs.size();
 
2299
    }
 
2300
 
 
2301
    /**
 
2302
     * Method to return the ArcInst at specified position.
 
2303
     * @param arcIndex specified position of ArcInst.
 
2304
     * @return the ArcInst at specified position..
 
2305
     */
 
2306
    public final ArcInst getArc(int arcIndex) {
 
2307
        return getTopology().getArc(arcIndex);
 
2308
    }
 
2309
 
 
2310
    /**
 
2311
     * Method to return the ArcInst by its chronological index.
 
2312
     * @param arcId chronological index of ArcInst.
 
2313
     * @return the ArcInst with specified chronological index.
 
2314
     */
 
2315
    public ArcInst getArcById(int arcId) {
 
2316
        return getTopology().getArcById(arcId);
 
2317
    }
 
2318
 
 
2319
    /**
 
2320
     * Method to return a map from arcId of arcs in the Cell to their arcIndex in alphanumerical order.
 
2321
     * @return a map from arcId to arcIndex.
 
2322
     */
 
2323
    public int[] getArcIndexByArcIdMap() {
 
2324
        return backup().getArcIndexByArcIdMap();
 
2325
    }
 
2326
 
 
2327
    /**
 
2328
     * Method to find a named ArcInst on this Cell.
 
2329
     * @param name the name of the ArcInst.
 
2330
     * @return the ArcInst.  Returns null if none with that name are found.
 
2331
     */
 
2332
    public ArcInst findArc(String name) {
 
2333
        return getTopology().findArc(name);
 
2334
    }
 
2335
 
 
2336
    /**
 
2337
     * Method to unlink a set of these ArcInsts from this Cell.
2477
2338
     * @param killedArcs a set of ArcInsts to kill.
2478
 
         */
2479
 
        public void killArcs(Set<ArcInst> killedArcs) {
2480
 
        if (killedArcs.isEmpty()) return;
2481
 
                for(ArcInst ai : killedArcs) {
2482
 
            if (ai.getParent() != this)
 
2339
     */
 
2340
    public void killArcs(Set<ArcInst> killedArcs) {
 
2341
        if (killedArcs.isEmpty()) {
 
2342
            return;
 
2343
        }
 
2344
        for (ArcInst ai : killedArcs) {
 
2345
            if (ai.getParent() != this) {
2483
2346
                throw new IllegalArgumentException("parent");
2484
 
                }
 
2347
            }
 
2348
        }
2485
2349
        for (int arcIndex = getNumArcs() - 1; arcIndex >= 0; arcIndex--) {
2486
2350
            ArcInst ai = getArc(arcIndex);
2487
 
            if (killedArcs.contains(ai))
 
2351
            if (killedArcs.contains(ai)) {
2488
2352
                ai.kill();
 
2353
            }
2489
2354
        }
2490
2355
    }
2491
2356
 
2492
 
        /****************************** EXPORTS ******************************/
2493
 
 
2494
 
        /**
2495
 
         * Add a PortProto to this NodeProto.
2496
 
         * Adds Exports for Cells, PrimitivePorts for PrimitiveNodes.
2497
 
         * @param export the PortProto to add to this NodeProto.
2498
 
         */
2499
 
         void addExport(Export export)
2500
 
        {
2501
 
                checkChanging();
 
2357
    /****************************** EXPORTS ******************************/
 
2358
    /**
 
2359
     * Add a PortProto to this NodeProto.
 
2360
     * Adds Exports for Cells, PrimitivePorts for PrimitiveNodes.
 
2361
     * @param export the PortProto to add to this NodeProto.
 
2362
     */
 
2363
    void addExport(Export export) {
 
2364
        checkChanging();
2502
2365
        setContentsModified();
2503
2366
 
2504
 
                int portIndex = - searchExport(export.getName()) - 1;
2505
 
                assert portIndex >= 0;
2506
 
                export.setPortIndex(portIndex);
 
2367
        int portIndex = -searchExport(export.getName()) - 1;
 
2368
        assert portIndex >= 0;
 
2369
        export.setPortIndex(portIndex);
2507
2370
 
2508
2371
        // Add to chronExprots
2509
2372
        int chronIndex = export.getId().getChronIndex();
2510
2373
        if (chronExports.length <= chronIndex) {
2511
 
            Export[] newChronExports = new Export[Math.max(chronIndex + 1, chronExports.length*2)];
 
2374
            Export[] newChronExports = new Export[Math.max(chronIndex + 1, chronExports.length * 2)];
2512
2375
            System.arraycopy(chronExports, 0, newChronExports, 0, chronExports.length);
2513
2376
            chronExports = newChronExports;
2514
2377
        }
2515
2378
        chronExports[chronIndex] = export;
2516
2379
 
2517
 
                Export[] newExports = new Export[exports.length + 1];
2518
 
                System.arraycopy(exports, 0, newExports, 0, portIndex);
2519
 
                newExports[portIndex] = export;
2520
 
                for (int i = portIndex; i < exports.length; i++)
2521
 
                {
2522
 
                        Export e = exports[i];
2523
 
                        e.setPortIndex(i + 1);
2524
 
                        newExports[i + 1] = e;
2525
 
                }
2526
 
                exports = newExports;
 
2380
        Export[] newExports = new Export[exports.length + 1];
 
2381
        System.arraycopy(exports, 0, newExports, 0, portIndex);
 
2382
        newExports[portIndex] = export;
 
2383
        for (int i = portIndex; i < exports.length; i++) {
 
2384
            Export e = exports[i];
 
2385
            e.setPortIndex(i + 1);
 
2386
            newExports[i + 1] = e;
 
2387
        }
 
2388
        exports = newExports;
2527
2389
 
2528
 
                // create a PortInst for every instance of this Cell
2529
 
        if (getId().numUsagesOf() == 0) return;
 
2390
        // create a PortInst for every instance of this Cell
 
2391
        if (getId().numUsagesOf() == 0) {
 
2392
            return;
 
2393
        }
2530
2394
        int[] pattern = new int[exports.length];
2531
 
        for (int i = 0; i < portIndex; i++) pattern[i] = i;
 
2395
        for (int i = 0; i < portIndex; i++) {
 
2396
            pattern[i] = i;
 
2397
        }
2532
2398
        pattern[portIndex] = -1;
2533
 
        for (int i = portIndex + 1; i < exports.length; i++) pattern[i] = i - 1;
 
2399
        for (int i = portIndex + 1; i < exports.length; i++) {
 
2400
            pattern[i] = i - 1;
 
2401
        }
2534
2402
        updatePortInsts(pattern);
2535
2403
//        for(Iterator<NodeInst> it = getInstancesOf(); it.hasNext(); ) {
2536
2404
//            NodeInst ni = it.next();
2537
2405
//            ni.addPortInst(export);
2538
2406
//            assert ni.getNumPortInsts() == exports.length;
2539
2407
//        }
2540
 
        }
 
2408
    }
2541
2409
 
2542
 
        /**
2543
 
         * Removes an Export from this Cell.
2544
 
         * @param export the Export to remove from this Cell.
2545
 
         */
2546
 
        void removeExport(Export export)
2547
 
        {
2548
 
                checkChanging();
 
2410
    /**
 
2411
     * Removes an Export from this Cell.
 
2412
     * @param export the Export to remove from this Cell.
 
2413
     */
 
2414
    void removeExport(Export export) {
 
2415
        checkChanging();
2549
2416
        setContentsModified();
2550
 
                int portIndex = export.getPortIndex();
 
2417
        int portIndex = export.getPortIndex();
2551
2418
 
2552
 
                Export[] newExports = exports.length > 1 ? new Export[exports.length - 1] : NULL_EXPORT_ARRAY;
2553
 
                System.arraycopy(exports, 0, newExports, 0, portIndex);
2554
 
                for (int i = portIndex; i < newExports.length; i++)
2555
 
                {
2556
 
                        Export e = exports[i + 1];
2557
 
                        e.setPortIndex(i);
2558
 
                        newExports[i] = e;
2559
 
                }
2560
 
                exports = newExports;
 
2419
        Export[] newExports = exports.length > 1 ? new Export[exports.length - 1] : NULL_EXPORT_ARRAY;
 
2420
        System.arraycopy(exports, 0, newExports, 0, portIndex);
 
2421
        for (int i = portIndex; i < newExports.length; i++) {
 
2422
            Export e = exports[i + 1];
 
2423
            e.setPortIndex(i);
 
2424
            newExports[i] = e;
 
2425
        }
 
2426
        exports = newExports;
2561
2427
        chronExports[export.getId().getChronIndex()] = null;
2562
 
                export.setPortIndex(-1);
 
2428
        export.setPortIndex(-1);
2563
2429
 
2564
 
                // remove the PortInst from every instance of this Cell
2565
 
        if (getId().numUsagesOf() == 0) return;
 
2430
        // remove the PortInst from every instance of this Cell
 
2431
        if (getId().numUsagesOf() == 0) {
 
2432
            return;
 
2433
        }
2566
2434
        int[] pattern = new int[exports.length];
2567
 
        for (int i = 0; i < portIndex; i++) pattern[i] = i;
2568
 
        for (int i = portIndex; i < exports.length; i++) pattern[i] = i + 1;
 
2435
        for (int i = 0; i < portIndex; i++) {
 
2436
            pattern[i] = i;
 
2437
        }
 
2438
        for (int i = portIndex; i < exports.length; i++) {
 
2439
            pattern[i] = i + 1;
 
2440
        }
2569
2441
        updatePortInsts(pattern);
2570
2442
//              for(Iterator<NodeInst> it = getInstancesOf(); it.hasNext(); )
2571
2443
//              {
2572
2444
//                      NodeInst ni = it.next();
2573
2445
//                      ni.removePortInst(export);
2574
2446
//              }
2575
 
        }
2576
 
 
2577
 
        /**
2578
 
         * Move renamed Export in sorted exports array.
2579
 
         * @param oldPortIndex old position of the Export in exports array.
2580
 
         */
2581
 
        void moveExport(int oldPortIndex, String newName)
2582
 
        {
2583
 
                Export export = exports[oldPortIndex];
2584
 
                int newPortIndex = - searchExport(newName) - 1;
2585
 
                if (newPortIndex < 0) return;
2586
 
                if (newPortIndex > oldPortIndex)
2587
 
                        newPortIndex--;
2588
 
                if (newPortIndex == oldPortIndex) return;
2589
 
 
2590
 
                if (newPortIndex > oldPortIndex)
2591
 
                {
2592
 
                        for (int i = oldPortIndex; i < newPortIndex; i++)
2593
 
                        {
2594
 
                                Export e = exports[i + 1];
2595
 
                                e.setPortIndex(i);
2596
 
                                exports[i] = e;
2597
 
                        }
2598
 
                } else
2599
 
                {
2600
 
                        for (int i = oldPortIndex; i > newPortIndex; i--)
2601
 
                        {
2602
 
                                Export e = exports[i - 1];
2603
 
                                e.setPortIndex(i);
2604
 
                                exports[i] = e;
2605
 
                        }
2606
 
                }
2607
 
                export.setPortIndex(newPortIndex);
2608
 
                exports[newPortIndex] = export;
 
2447
    }
 
2448
 
 
2449
    /**
 
2450
     * Move renamed Export in sorted exports array.
 
2451
     * @param oldPortIndex old position of the Export in exports array.
 
2452
     */
 
2453
    void moveExport(int oldPortIndex, String newName) {
 
2454
        Export export = exports[oldPortIndex];
 
2455
        int newPortIndex = -searchExport(newName) - 1;
 
2456
        if (newPortIndex < 0) {
 
2457
            return;
 
2458
        }
 
2459
        if (newPortIndex > oldPortIndex) {
 
2460
            newPortIndex--;
 
2461
        }
 
2462
        if (newPortIndex == oldPortIndex) {
 
2463
            return;
 
2464
        }
 
2465
 
 
2466
        if (newPortIndex > oldPortIndex) {
 
2467
            for (int i = oldPortIndex; i < newPortIndex; i++) {
 
2468
                Export e = exports[i + 1];
 
2469
                e.setPortIndex(i);
 
2470
                exports[i] = e;
 
2471
            }
 
2472
        } else {
 
2473
            for (int i = oldPortIndex; i > newPortIndex; i--) {
 
2474
                Export e = exports[i - 1];
 
2475
                e.setPortIndex(i);
 
2476
                exports[i] = e;
 
2477
            }
 
2478
        }
 
2479
        export.setPortIndex(newPortIndex);
 
2480
        exports[newPortIndex] = export;
2609
2481
 
2610
2482
        // move PortInst for every instance of this Cell.
2611
 
        if (getId().numUsagesOf() == 0) return;
 
2483
        if (getId().numUsagesOf() == 0) {
 
2484
            return;
 
2485
        }
2612
2486
        int[] pattern = new int[exports.length];
2613
 
        for (int i = 0; i < pattern.length; i++) pattern[i] = i;
 
2487
        for (int i = 0; i < pattern.length; i++) {
 
2488
            pattern[i] = i;
 
2489
        }
2614
2490
        pattern[newPortIndex] = oldPortIndex;
2615
 
        if (newPortIndex > oldPortIndex)
2616
 
            for (int i = oldPortIndex; i < newPortIndex; i++) pattern[i] = i + 1;
2617
 
        else
2618
 
            for (int i = oldPortIndex; i > newPortIndex; i--) pattern[i] = i - 1;
 
2491
        if (newPortIndex > oldPortIndex) {
 
2492
            for (int i = oldPortIndex; i < newPortIndex; i++) {
 
2493
                pattern[i] = i + 1;
 
2494
            }
 
2495
        } else {
 
2496
            for (int i = oldPortIndex; i > newPortIndex; i--) {
 
2497
                pattern[i] = i - 1;
 
2498
            }
 
2499
        }
2619
2500
        updatePortInsts(pattern);
2620
 
        }
 
2501
    }
2621
2502
 
2622
 
        /**
2623
 
         * Update PortInsts of all instances of this Cell accoding to pattern.
 
2503
    /**
 
2504
     * Update PortInsts of all instances of this Cell accoding to pattern.
2624
2505
     * Pattern contains an element for each Export.
2625
2506
     * If Export was just created, the element contains -1.
2626
2507
     * For old Exports the element contains old index of the Export.
2627
 
         * @param pattern array with elements describing new PortInsts.
2628
 
         */
 
2508
     * @param pattern array with elements describing new PortInsts.
 
2509
     */
2629
2510
    public void updatePortInsts(int[] pattern) {
2630
 
                for(Iterator<NodeInst> it = getInstancesOf(); it.hasNext(); ) {
2631
 
                        NodeInst ni = it.next();
2632
 
                        ni.updatePortInsts(pattern);
2633
 
                }
 
2511
        for (Iterator<CellUsage> it = getUsagesOf(); it.hasNext(); ) {
 
2512
            CellUsage cu = it.next();
 
2513
            Cell parentCell = cu.getParent(database);
 
2514
            Topology topology = parentCell.getTopologyOptional();
 
2515
            if (topology != null) {
 
2516
                topology.updatePortInsts(this, pattern);
 
2517
            }
 
2518
        }
2634
2519
    }
2635
2520
 
2636
 
        /**
2637
 
         * Method to unlink a set of these Export from this Cell.
 
2521
    /**
 
2522
     * Method to unlink a set of these Export from this Cell.
2638
2523
     * @param killedExports a set of Exports to kill.
2639
 
         */
2640
 
        public void killExports(Set<Export> killedExports) {
2641
 
                checkChanging();
2642
 
        if (killedExports.isEmpty()) return;
2643
 
        for (Export export: killedExports) {
2644
 
            if (export.getParent() != this)
 
2524
     */
 
2525
    public void killExports(Set<Export> killedExports) {
 
2526
        checkChanging();
 
2527
        if (killedExports.isEmpty()) {
 
2528
            return;
 
2529
        }
 
2530
        for (Export export : killedExports) {
 
2531
            if (export.getParent() != this) {
2645
2532
                throw new IllegalArgumentException("parent");
 
2533
            }
2646
2534
        }
2647
2535
 
2648
2536
        Export[] killedExportsArray = killedExports.toArray(new Export[killedExports.size()]);
2649
 
        for (Iterator<CellUsage> uit = getUsagesOf(); uit.hasNext(); ) {
 
2537
        for (Iterator<CellUsage> uit = getUsagesOf(); uit.hasNext();) {
2650
2538
            CellUsage u = uit.next();
2651
2539
            Cell higherCell = database.getCell(u.parentId);
2652
2540
 
2653
2541
            // collect the arcs attached to the connections to these port instance.
2654
2542
            List<ArcInst> arcsToKill = new ArrayList<ArcInst>();
2655
 
            for (Iterator<ArcInst> ait = higherCell.getArcs(); ait.hasNext(); ) {
 
2543
            for (Iterator<ArcInst> ait = higherCell.getArcs(); ait.hasNext();) {
2656
2544
                ArcInst ai = ait.next();
2657
2545
                PortInst tail = ai.getTailPortInst();
2658
2546
                PortInst head = ai.getHeadPortInst();
2659
 
                if (tail.getNodeInst().getProto() == this && killedExports.contains(tail.getPortProto()) ||
2660
 
                        head.getNodeInst().getProto() == this && killedExports.contains(head.getPortProto()))
 
2547
                if (tail.getNodeInst().getProto() == this && killedExports.contains(tail.getPortProto())
 
2548
                        || head.getNodeInst().getProto() == this && killedExports.contains(head.getPortProto())) {
2661
2549
                    arcsToKill.add(ai);
 
2550
                }
2662
2551
            }
2663
2552
            // collect reexports
2664
2553
            Set<Export> higherExportsToKill = null;
2665
 
            for (Export higherExport: higherCell.exports) {
 
2554
            for (Export higherExport : higherCell.exports) {
2666
2555
                PortInst pi = higherExport.getOriginalPort();
2667
 
                if (pi.getNodeInst().getProto() != this) continue;
2668
 
                Export lowerExport = (Export)pi.getPortProto();
 
2556
                if (pi.getNodeInst().getProto() != this) {
 
2557
                    continue;
 
2558
                }
 
2559
                Export lowerExport = (Export) pi.getPortProto();
2669
2560
                assert lowerExport.getParent() == this;
2670
 
                if (!killedExports.contains(lowerExport)) continue;
2671
 
                if (higherExportsToKill == null) higherExportsToKill = new HashSet<Export>();
 
2561
                if (!killedExports.contains(lowerExport)) {
 
2562
                    continue;
 
2563
                }
 
2564
                if (higherExportsToKill == null) {
 
2565
                    higherExportsToKill = new HashSet<Export>();
 
2566
                }
2672
2567
                higherExportsToKill.add(higherExport);
2673
2568
            }
2674
2569
 
2675
2570
            // delete variables on port instances
2676
 
            for (NodeInst ni: higherCell.nodes) {
2677
 
                if (ni.getProto() != this) continue;
2678
 
                for (Export e: killedExportsArray)
 
2571
            for (Iterator<NodeInst> it = higherCell.getNodes(); it.hasNext();) {
 
2572
                NodeInst ni = it.next();
 
2573
                if (ni.getProto() != this) {
 
2574
                    continue;
 
2575
                }
 
2576
                for (Export e : killedExportsArray) {
2679
2577
                    ni.findPortInstFromProto(e).delVars();
 
2578
                }
2680
2579
            }
2681
2580
            // delete connected arcs
2682
 
            for (ArcInst ai: arcsToKill)
 
2581
            for (ArcInst ai : arcsToKill) {
2683
2582
                ai.kill();
2684
 
                        // recurse up the hierarchy deleting rexports
2685
 
            if (higherExportsToKill != null)
 
2583
            }
 
2584
            // recurse up the hierarchy deleting rexports
 
2585
            if (higherExportsToKill != null) {
2686
2586
                higherCell.killExports(higherExportsToKill);
 
2587
            }
2687
2588
        }
2688
2589
 
2689
2590
        // kill exports themselves
2690
 
        for (Export e: killedExports) {
 
2591
        for (Export e : killedExports) {
2691
2592
            assert e.isLinked();
2692
2593
            NodeInst originalNode = e.getOriginalPort().getNodeInst();
2693
2594
            originalNode.redoGeometric();
2694
2595
            removeExport(e);
2695
 
                // handle change control, constraint, and broadcast
2696
 
                Constraints.getCurrent().killObject(e);
 
2596
            // handle change control, constraint, and broadcast
 
2597
            Constraints.getCurrent().killObject(e);
2697
2598
        }
2698
 
        }
 
2599
    }
2699
2600
 
2700
 
        /**
2701
 
         * Method to recursively alter the state bit fields of these Exports.
 
2601
    /**
 
2602
     * Method to recursively alter the state bit fields of these Exports.
2702
2603
     * @param changedExports changed exports of this Cell.
2703
 
         */
2704
 
        void recursivelyChangeAllPorts(Set<Export> changedExports) {
2705
 
                // look at all usages of this cell
2706
 
        for (Iterator<CellUsage> cit = getUsagesOf(); cit.hasNext(); ) {
 
2604
     */
 
2605
    void recursivelyChangeAllPorts(Set<Export> changedExports) {
 
2606
        // look at all usages of this cell
 
2607
        for (Iterator<CellUsage> cit = getUsagesOf(); cit.hasNext();) {
2707
2608
            CellUsage u = cit.next();
2708
2609
            Cell higherCell = database.getCell(u.parentId);
2709
2610
            Set<Export> changedHigherExports = null;
2710
2611
            // see reexports of these ports
2711
 
            for (Export higherExport: higherCell.exports) {
 
2612
            for (Export higherExport : higherCell.exports) {
2712
2613
                PortInst pi = higherExport.getOriginalPort();
2713
 
                if (pi.getNodeInst().getProto() != this) continue;
2714
 
                Export lowerExport = (Export)pi.getPortProto();
 
2614
                if (pi.getNodeInst().getProto() != this) {
 
2615
                    continue;
 
2616
                }
 
2617
                Export lowerExport = (Export) pi.getPortProto();
2715
2618
                assert lowerExport.getParent() == this;
2716
 
                if (!changedExports.contains(lowerExport)) continue;
2717
 
                if (changedHigherExports == null) changedHigherExports = new HashSet<Export>();
 
2619
                if (!changedExports.contains(lowerExport)) {
 
2620
                    continue;
 
2621
                }
 
2622
                if (changedHigherExports == null) {
 
2623
                    changedHigherExports = new HashSet<Export>();
 
2624
                }
2718
2625
                changedHigherExports.add(higherExport);
2719
 
                                // change this port
 
2626
                // change this port
2720
2627
                higherExport.copyStateBits(lowerExport);
2721
2628
            }
2722
 
                        // recurse up the hierarchy
2723
 
            if (changedHigherExports != null)
 
2629
            // recurse up the hierarchy
 
2630
            if (changedHigherExports != null) {
2724
2631
                higherCell.recursivelyChangeAllPorts(changedHigherExports);
2725
 
        }
2726
 
        }
2727
 
 
2728
 
        /**
2729
 
         * Method to find the PortProto that has a particular name.
2730
 
         * @return the PortProto, or null if there is no PortProto with that name.
2731
 
         */
2732
 
        public PortProto findPortProto(String name)
2733
 
        {
2734
 
        if (name == null) return null;
2735
 
                return findPortProto(Name.findName(name));
2736
 
        }
2737
 
 
2738
 
        /**
2739
 
         * Method to find the PortProto that has a particular Name.
2740
 
         * @return the PortProto, or null if there is no PortProto with that name.
2741
 
         */
 
2632
            }
 
2633
        }
 
2634
    }
 
2635
 
 
2636
    /**
 
2637
     * Method to find the PortProto that has a particular name.
 
2638
     * @return the PortProto, or null if there is no PortProto with that name.
 
2639
     */
 
2640
    public PortProto findPortProto(String name) {
 
2641
        if (name == null) {
 
2642
            return null;
 
2643
        }
 
2644
        return findPortProto(Name.findName(name));
 
2645
    }
 
2646
 
 
2647
    /**
 
2648
     * Method to find the PortProto that has a particular Name.
 
2649
     * @return the PortProto, or null if there is no PortProto with that name.
 
2650
     */
2742
2651
    public PortProto findPortProto(Name name) {
2743
 
        if (name == null) return null;
 
2652
        if (name == null) {
 
2653
            return null;
 
2654
        }
2744
2655
        int portIndex = searchExport(name.toString());
2745
 
        if (portIndex >= 0) return exports[portIndex];
 
2656
        if (portIndex >= 0) {
 
2657
            return exports[portIndex];
 
2658
        }
2746
2659
//        String nameString = name.canonicString();
2747
2660
//        for (int i = 0; i < exports.length; i++) {
2748
2661
//            Export e = exports[i];
2752
2665
        return null;
2753
2666
    }
2754
2667
 
2755
 
        /**
2756
 
         * Method to determine if a given PortProto is considered as export
2757
 
         * @param port the PortProto in question.
2758
 
         * @return true if the PortProto is an export.
2759
 
         */
 
2668
    /**
 
2669
     * Method to determine if a given PortProto is considered as export
 
2670
     * @param port the PortProto in question.
 
2671
     * @return true if the PortProto is an export.
 
2672
     */
2760
2673
//      public boolean findPortProto(PortProto port)
2761
2674
//      {
2762
2675
//              for (int i = 0; i < exports.length; i++)
2766
2679
//              }
2767
2680
//              return false;
2768
2681
//      }
2769
 
 
2770
 
        /**
2771
 
         * Method to return an iterator over all PortProtos of this NodeProto.
2772
 
         * @return an iterator over all PortProtos of this NodeProto.
2773
 
         */
2774
 
        public Iterator<PortProto> getPorts() { return ArrayIterator.iterator((PortProto[])exports); }
2775
 
 
2776
 
        /**
2777
 
         * Method to return an iterator over all Exports of this NodeProto.
2778
 
         * @return an iterator over all Exports of this NodeProto.
2779
 
         */
2780
 
        public Iterator<Export> getExports() { return ArrayIterator.iterator(exports); }
2781
 
 
2782
 
        /**
2783
 
         * Method to return the number of PortProtos on this NodeProto.
2784
 
         * @return the number of PortProtos on this NodeProto.
2785
 
         */
2786
 
        public int getNumPorts() { return exports.length; }
2787
 
 
2788
 
        /**
2789
 
         * Method to return the PortProto at specified position.
2790
 
         * @param portIndex specified position of PortProto.
2791
 
         * @return the PortProto at specified position..
2792
 
         */
2793
 
        public Export getPort(int portIndex) { return exports[portIndex]; }
2794
 
 
2795
 
        /**
2796
 
         * Method to return the PortProto by thread-independent PortProtoId.
2797
 
         * @param portProtoId thread-independent PortProtoId.
2798
 
         * @return the PortProto.
2799
 
         */
2800
 
        public Export getPort(PortProtoId portProtoId) {
2801
 
        if (portProtoId.getParentId() != getId())
 
2682
    /**
 
2683
     * Method to return an iterator over all PortProtos of this NodeProto.
 
2684
     * @return an iterator over all PortProtos of this NodeProto.
 
2685
     */
 
2686
    public Iterator<PortProto> getPorts() {
 
2687
        return ArrayIterator.iterator((PortProto[]) exports);
 
2688
    }
 
2689
 
 
2690
    /**
 
2691
     * Method to return an iterator over all Exports of this NodeProto.
 
2692
     * @return an iterator over all Exports of this NodeProto.
 
2693
     */
 
2694
    public Iterator<Export> getExports() {
 
2695
        return ArrayIterator.iterator(exports);
 
2696
    }
 
2697
 
 
2698
    /**
 
2699
     * Method to return the number of PortProtos on this NodeProto.
 
2700
     * @return the number of PortProtos on this NodeProto.
 
2701
     */
 
2702
    public int getNumPorts() {
 
2703
        return exports.length;
 
2704
    }
 
2705
 
 
2706
    /**
 
2707
     * Method to return the PortProto at specified position.
 
2708
     * @param portIndex specified position of PortProto.
 
2709
     * @return the PortProto at specified position..
 
2710
     */
 
2711
    public Export getPort(int portIndex) {
 
2712
        return exports[portIndex];
 
2713
    }
 
2714
 
 
2715
    /**
 
2716
     * Method to return the PortProto by thread-independent PortProtoId.
 
2717
     * @param portProtoId thread-independent PortProtoId.
 
2718
     * @return the PortProto.
 
2719
     */
 
2720
    public Export getPort(PortProtoId portProtoId) {
 
2721
        if (portProtoId.getParentId() != getId()) {
2802
2722
            throw new IllegalArgumentException();
 
2723
        }
2803
2724
        return getExportChron(portProtoId.getChronIndex());
2804
2725
    }
2805
2726
 
2806
 
        /**
2807
 
         * Method to return the Export at specified chronological index.
2808
 
         * @param chronIndex specified chronological index of Export.
2809
 
         * @return the Export at specified chronological index or null.
2810
 
         */
2811
 
        public Export getExportChron(int chronIndex) {
 
2727
    /**
 
2728
     * Method to return the Export at specified chronological index.
 
2729
     * @param chronIndex specified chronological index of Export.
 
2730
     * @return the Export at specified chronological index or null.
 
2731
     */
 
2732
    public Export getExportChron(int chronIndex) {
2812
2733
        return chronIndex < chronExports.length ? chronExports[chronIndex] : null;
2813
2734
    }
2814
2735
 
2815
 
        /**
2816
 
         * Method to find a named Export on this Cell.
2817
 
         * @param name the name of the export.
2818
 
         * @return the export.  Returns null if that name was not found.
2819
 
         */
2820
 
        public Export findExport(String name)
2821
 
        {
2822
 
                return (Export) findPortProto(name);
2823
 
        }
 
2736
    /**
 
2737
     * Method to find a named Export on this Cell.
 
2738
     * @param name the name of the export.
 
2739
     * @return the export.  Returns null if that name was not found.
 
2740
     */
 
2741
    public Export findExport(String name) {
 
2742
        return (Export) findPortProto(name);
 
2743
    }
2824
2744
 
2825
 
        /**
2826
 
         * Method to find a named Export on this Cell.
2827
 
         * @param name the Name of the export.
2828
 
         * @return the export.  Returns null if that name was not found.
2829
 
         */
2830
 
        public Export findExport(Name name)
2831
 
        {
2832
 
                return (Export) findPortProto(name);
2833
 
        }
 
2745
    /**
 
2746
     * Method to find a named Export on this Cell.
 
2747
     * @param name the Name of the export.
 
2748
     * @return the export.  Returns null if that name was not found.
 
2749
     */
 
2750
    public Export findExport(Name name) {
 
2751
        return (Export) findPortProto(name);
 
2752
    }
2834
2753
 
2835
2754
    /**
2836
2755
     * Searches the exports for the specified name using the binary
2845
2764
     *         that this guarantees that the return value will be &gt;= 0 if
2846
2765
     *         and only if the Export is found.
2847
2766
     */
2848
 
        private int searchExport(String name)
2849
 
        {
2850
 
                int low = 0;
2851
 
                int high = exports.length-1;
2852
 
 
2853
 
                while (low <= high) {
2854
 
                        int mid = (low + high) >> 1;
2855
 
                        Export e = exports[mid];
2856
 
                        int cmp = TextUtils.STRING_NUMBER_ORDER.compare(e.getName(), name);
2857
 
 
2858
 
                        if (cmp < 0)
2859
 
                                low = mid + 1;
2860
 
                        else if (cmp > 0)
2861
 
                                high = mid - 1;
2862
 
                        else
2863
 
                                return mid; // Export found
2864
 
                }
2865
 
                return -(low + 1);  // Export not found.
2866
 
    }
2867
 
 
2868
 
        /****************************** TEXT ******************************/
2869
 
 
2870
 
        /**
2871
 
         * Method to return the CellName object describing this Cell.
2872
 
         * @return the CellName object describing this Cell.
2873
 
         */
2874
 
        public CellName getCellName() { return getD().cellId.cellName; }
2875
 
 
2876
 
        /**
2877
 
         * Method to return the pure name of this Cell, without
2878
 
         * any view or version information.
2879
 
         * @return the pure name of this Cell.
2880
 
         */
2881
 
        public String getName() { return getCellName().getName(); }
2882
 
 
2883
 
        /**
2884
 
         * Method to describe this cell.
2885
 
         * The description has the form: cell;version{view}
2886
 
         * If the cell is not from the current library, prepend the library name.
 
2767
    private int searchExport(String name) {
 
2768
        int low = 0;
 
2769
        int high = exports.length - 1;
 
2770
 
 
2771
        while (low <= high) {
 
2772
            int mid = (low + high) >> 1;
 
2773
            Export e = exports[mid];
 
2774
            int cmp = TextUtils.STRING_NUMBER_ORDER.compare(e.getName(), name);
 
2775
 
 
2776
            if (cmp < 0) {
 
2777
                low = mid + 1;
 
2778
            } else if (cmp > 0) {
 
2779
                high = mid - 1;
 
2780
            } else {
 
2781
                return mid; // Export found
 
2782
            }
 
2783
        }
 
2784
        return -(low + 1);  // Export not found.
 
2785
    }
 
2786
 
 
2787
    /****************************** TEXT ******************************/
 
2788
    /**
 
2789
     * Method to return the CellName object describing this Cell.
 
2790
     * @return the CellName object describing this Cell.
 
2791
     */
 
2792
    public CellName getCellName() {
 
2793
        return getD().cellId.cellName;
 
2794
    }
 
2795
 
 
2796
    /**
 
2797
     * Method to return the pure name of this Cell, without
 
2798
     * any view or version information.
 
2799
     * @return the pure name of this Cell.
 
2800
     */
 
2801
    public String getName() {
 
2802
        return getCellName().getName();
 
2803
    }
 
2804
 
 
2805
    /**
 
2806
     * Method to describe this cell.
 
2807
     * The description has the form: cell;version{view}
 
2808
     * If the cell is not from the current library, prepend the library name.
2887
2809
     * @param withQuotes to wrap description between quotes
2888
 
         * @return a String that describes this cell.
2889
 
         */
2890
 
        public String describe(boolean withQuotes)
2891
 
        {
2892
 
                String name = "";
2893
 
                if (lib != Library.getCurrent())
2894
 
                        name += lib.getName() + ":";
2895
 
                name += noLibDescribe();
2896
 
                return (withQuotes) ? "'"+name+"'" : name;
2897
 
        }
 
2810
     * @return a String that describes this cell.
 
2811
     */
 
2812
    public String describe(boolean withQuotes) {
 
2813
        String name = "";
 
2814
        if (lib != Library.getCurrent()) {
 
2815
            name += lib.getName() + ":";
 
2816
        }
 
2817
        name += noLibDescribe();
 
2818
        return (withQuotes) ? "'" + name + "'" : name;
 
2819
    }
2898
2820
 
2899
2821
    /**
2900
2822
     * Method to describe this cell.
2901
2823
     * The description has the form: Library:cell;version{view}
2902
2824
     * @return a String that describes this cell.
2903
2825
     */
2904
 
    public String libDescribe()
2905
 
    {
 
2826
    public String libDescribe() {
2906
2827
        return (lib.getName() + ":" + noLibDescribe());
2907
2828
    }
2908
2829
 
2909
 
        /**
2910
 
         * Method to describe this cell.
2911
 
         * The description has the form: cell;version{view}
2912
 
         * Unlike "describe()", this method never prepends the library name.
2913
 
         * @return a String that describes this cell.
2914
 
         */
2915
 
        public String noLibDescribe()
2916
 
        {
2917
 
                String name = getName();
2918
 
                if (getNewestVersion() != this)
2919
 
                        name += ";" + getVersion();
2920
 
                name += getView().getAbbreviationExtension();
2921
 
                return name;
2922
 
        }
2923
 
 
2924
 
        /**
2925
 
         * Method to find the NodeProto with the given name.
2926
 
         * This can be a PrimitiveNode (and can be prefixed by a Technology name),
2927
 
         * or it can be a Cell (and be prefixed by a Library name).
2928
 
         * @param line the name of the NodeProto.
2929
 
         * @return the specified NodeProto, or null if none can be found.
2930
 
         */
2931
 
        public static NodeProto findNodeProto(String line)
2932
 
        {
2933
 
                Technology tech = Technology.getCurrent();
2934
 
                Library lib = Library.getCurrent();
2935
 
                boolean saidtech = false;
2936
 
                boolean saidlib = false;
2937
 
                int colon = line.indexOf(':');
2938
 
                String withoutPrefix;
2939
 
                if (colon == -1) withoutPrefix = line; else
2940
 
                {
2941
 
                        String prefix = line.substring(0, colon);
2942
 
                        Technology t = Technology.findTechnology(prefix);
2943
 
                        if (t != null)
2944
 
                        {
2945
 
                                tech = t;
2946
 
                                saidtech = true;
2947
 
                        }
2948
 
                        Library l = Library.findLibrary(prefix);
2949
 
                        if (l != null)
2950
 
                        {
2951
 
                                lib = l;
2952
 
                                saidlib = true;
2953
 
                        }
2954
 
                        withoutPrefix = line.substring(colon+1);
2955
 
                }
2956
 
 
2957
 
                /* try primitives in the technology */
2958
 
                if (!saidlib)
2959
 
                {
2960
 
                        PrimitiveNode np = tech.findNodeProto(withoutPrefix);
2961
 
                        if (np != null) return np;
2962
 
                }
2963
 
 
2964
 
                if (!saidtech && lib != null)
2965
 
                {
2966
 
                        Cell np = lib.findNodeProto(withoutPrefix);
2967
 
                        if (np != null) return np;
2968
 
                }
2969
 
                return null;
2970
 
        }
2971
 
 
2972
 
        /**
2973
 
         * Method to get the strings in this Cell.
2974
 
         * It is only valid for cells with "text" views (documentation, vhdl, netlist, etc.)
2975
 
         * @return the strings in this Cell.
2976
 
         * Returns null if there are no strings.
2977
 
         */
2978
 
        public String [] getTextViewContents()
2979
 
        {
2980
 
                // look on the cell for its text
2981
 
                Variable var = getVar(Cell.CELL_TEXT_KEY);
2982
 
                if (var == null) return null;
2983
 
                Object obj = var.getObject();
2984
 
                if (!(obj instanceof String[])) return null;
2985
 
                return (String [])obj;
2986
 
        }
2987
 
 
2988
 
        /**
2989
 
         * Method to set the strings in this Cell.
2990
 
         * It is only valid for cells with "text" views (documentation, vhdl, netlist, etc.)
2991
 
         * The call needs to be wrapped inside of a Job.
2992
 
         * @param strings an array of Strings that define this Cell.
2993
 
         */
2994
 
        public void setTextViewContents(String [] strings)
2995
 
        {
2996
 
                checkChanging();
2997
 
                newVar(Cell.CELL_TEXT_KEY, strings);
2998
 
        }
 
2830
    /**
 
2831
     * Method to describe this cell.
 
2832
     * The description has the form: cell;version{view}
 
2833
     * Unlike "describe()", this method never prepends the library name.
 
2834
     * @return a String that describes this cell.
 
2835
     */
 
2836
    public String noLibDescribe() {
 
2837
        String name = getName();
 
2838
        if (getNewestVersion() != this) {
 
2839
            name += ";" + getVersion();
 
2840
        }
 
2841
        name += getView().getAbbreviationExtension();
 
2842
        return name;
 
2843
    }
 
2844
 
 
2845
    /**
 
2846
     * Method to find the NodeProto with the given name.
 
2847
     * This can be a PrimitiveNode (and can be prefixed by a Technology name),
 
2848
     * or it can be a Cell (and be prefixed by a Library name).
 
2849
     * @param line the name of the NodeProto.
 
2850
     * @return the specified NodeProto, or null if none can be found.
 
2851
     */
 
2852
    public static NodeProto findNodeProto(String line) {
 
2853
        Technology tech = Technology.getCurrent();
 
2854
        Library lib = Library.getCurrent();
 
2855
        boolean saidtech = false;
 
2856
        boolean saidlib = false;
 
2857
        int colon = line.indexOf(':');
 
2858
        String withoutPrefix;
 
2859
        if (colon == -1) {
 
2860
            withoutPrefix = line;
 
2861
        } else {
 
2862
            String prefix = line.substring(0, colon);
 
2863
            Technology t = Technology.findTechnology(prefix);
 
2864
            if (t != null) {
 
2865
                tech = t;
 
2866
                saidtech = true;
 
2867
            }
 
2868
            Library l = Library.findLibrary(prefix);
 
2869
            if (l != null) {
 
2870
                lib = l;
 
2871
                saidlib = true;
 
2872
            }
 
2873
            withoutPrefix = line.substring(colon + 1);
 
2874
        }
 
2875
 
 
2876
        /* try primitives in the technology */
 
2877
        if (!saidlib) {
 
2878
            PrimitiveNode np = tech.findNodeProto(withoutPrefix);
 
2879
            if (np != null) {
 
2880
                return np;
 
2881
            }
 
2882
        }
 
2883
 
 
2884
        if (!saidtech && lib != null) {
 
2885
            Cell np = lib.findNodeProto(withoutPrefix);
 
2886
            if (np != null) {
 
2887
                return np;
 
2888
            }
 
2889
        }
 
2890
        return null;
 
2891
    }
 
2892
 
 
2893
    /**
 
2894
     * Method to get the strings in this Cell.
 
2895
     * It is only valid for cells with "text" views (documentation, vhdl, netlist, etc.)
 
2896
     * @return the strings in this Cell.
 
2897
     * Returns null if there are no strings.
 
2898
     */
 
2899
    public String[] getTextViewContents() {
 
2900
        // look on the cell for its text
 
2901
        Variable var = getVar(Cell.CELL_TEXT_KEY);
 
2902
        if (var == null) {
 
2903
            return null;
 
2904
        }
 
2905
        Object obj = var.getObject();
 
2906
        if (!(obj instanceof String[])) {
 
2907
            return null;
 
2908
        }
 
2909
        return (String[]) obj;
 
2910
    }
 
2911
 
 
2912
    /**
 
2913
     * Method to set the strings in this Cell.
 
2914
     * It is only valid for cells with "text" views (documentation, vhdl, netlist, etc.)
 
2915
     * The call needs to be wrapped inside of a Job.
 
2916
     * @param strings an array of Strings that define this Cell.
 
2917
     */
 
2918
    public void setTextViewContents(String[] strings) {
 
2919
        checkChanging();
 
2920
        newVar(Cell.CELL_TEXT_KEY, strings);
 
2921
    }
2999
2922
 
3000
2923
    /**
3001
2924
     * Method to return the Variable on this Cell with the given key
3004
2927
     * @return the Variable with that key, that is parameter. Returns null if none found.
3005
2928
     */
3006
2929
    public Variable getParameter(Variable.Key key) {
3007
 
        return key instanceof Variable.AttrKey ? getD().getParameter((Variable.AttrKey)key) : null;
 
2930
        return key instanceof Variable.AttrKey ? getD().getParameter((Variable.AttrKey) key) : null;
3008
2931
    }
3009
2932
 
3010
2933
    /**
3023
2946
        return getNumParameters() > 0;
3024
2947
    }
3025
2948
 
3026
 
        /**
3027
 
         * Method to return the number of Parameters on this Cell.
3028
 
         * @return the number of Parametes on this ImmutableCell.
3029
 
         */
3030
 
        public int getNumParameters() { return getD().getNumParameters(); }
 
2949
    /**
 
2950
     * Method to return the number of Parameters on this Cell.
 
2951
     * @return the number of Parametes on this ImmutableCell.
 
2952
     */
 
2953
    public int getNumParameters() {
 
2954
        return getD().getNumParameters();
 
2955
    }
3031
2956
 
3032
 
        /**
3033
 
         * Method to return the Parameter by its paramIndex.
 
2957
    /**
 
2958
     * Method to return the Parameter by its paramIndex.
3034
2959
     * @param paramIndex index of Parameter.
3035
 
         * @return the Parameter with given paramIndex.
 
2960
     * @return the Parameter with given paramIndex.
3036
2961
     * @throws ArrayIndexOutOfBoundesException if paramIndex out of bounds.
3037
 
         */
3038
 
        public Variable getParameter(int paramIndex) { return getD().getParameter(paramIndex); }
 
2962
     */
 
2963
    public Variable getParameter(int paramIndex) {
 
2964
        return getD().getParameter(paramIndex);
 
2965
    }
3039
2966
 
3040
 
        /**
3041
 
         * Method to return true if the Variable on this ElectricObject with given key is a parameter.
3042
 
         * Parameters are those Variables that have values on instances which are
3043
 
         * passed down the hierarchy into the contents.
3044
 
         * Parameters can only exist on NodeInst objects.
 
2967
    /**
 
2968
     * Method to return true if the Variable on this ElectricObject with given key is a parameter.
 
2969
     * Parameters are those Variables that have values on instances which are
 
2970
     * passed down the hierarchy into the contents.
 
2971
     * Parameters can only exist on NodeInst objects.
3045
2972
     * @param varKey key to test
3046
 
         * @return true if the Variable with given key is a parameter.
3047
 
         */
 
2973
     * @return true if the Variable with given key is a parameter.
 
2974
     */
3048
2975
    public boolean isParam(Variable.Key varKey) {
3049
 
        return varKey instanceof Variable.AttrKey && getD().getParameter((Variable.AttrKey)varKey) != null;
 
2976
        return varKey instanceof Variable.AttrKey && getD().getParameter((Variable.AttrKey) varKey) != null;
3050
2977
    }
3051
2978
 
3052
2979
    private void addParam(Variable var) {
3053
2980
        assert var.getTextDescriptor().isParam() && var.isInherit();
3054
2981
        if (isIcon()) {
3055
2982
            // Remove variables with the same name as new parameter
3056
 
            for (Iterator<NodeInst> it = getInstancesOf(); it.hasNext(); ) {
 
2983
            for (Iterator<NodeInst> it = getInstancesOf(); it.hasNext();) {
3057
2984
                NodeInst ni = it.next();
3058
 
                if (!ni.isParam(var.getKey()))
 
2985
                if (!ni.isParam(var.getKey())) {
3059
2986
                    ni.delVar(var.getKey());
 
2987
                }
3060
2988
            }
3061
2989
        }
3062
2990
        setD(getD().withoutVariable(var.getKey()).withParam(var));
3066
2994
        assert isParam(key);
3067
2995
        if (isIcon()) {
3068
2996
            // Remove instance parameters
3069
 
            for (Iterator<NodeInst> it = getInstancesOf(); it.hasNext(); ) {
 
2997
            for (Iterator<NodeInst> it = getInstancesOf(); it.hasNext();) {
3070
2998
                NodeInst ni = it.next();
3071
2999
                ni.delParameter(key);
3072
3000
            }
3081
3009
        addParam(Variable.newInstance(newName, oldParam.getObject(), oldParam.getTextDescriptor()));
3082
3010
        if (isIcon()) {
3083
3011
            // Rename instance parameters
3084
 
            for (Iterator<NodeInst> it = getInstancesOf(); it.hasNext(); ) {
 
3012
            for (Iterator<NodeInst> it = getInstancesOf(); it.hasNext();) {
3085
3013
                NodeInst ni = it.next();
3086
 
                if (!ni.isDefinedParameter(key)) continue;
 
3014
                if (!ni.isDefinedParameter(key)) {
 
3015
                    continue;
 
3016
                }
3087
3017
                Variable param = ni.getParameter(key);
3088
3018
                ni.addParameter(Variable.newInstance(newName, param.getObject(), param.getTextDescriptor()));
3089
3019
                ni.delParameter(key);
3093
3023
    }
3094
3024
 
3095
3025
    private void setParams(Cell paramOwner) {
3096
 
        for (Iterator<Variable> it = getParameters(); it.hasNext(); ) {
3097
 
            delParam((Variable.AttrKey)it.next().getKey());
 
3026
        for (Iterator<Variable> it = getParameters(); it.hasNext();) {
 
3027
            delParam((Variable.AttrKey) it.next().getKey());
3098
3028
        }
3099
 
        for (Iterator<Variable> it = paramOwner.getParameters(); it.hasNext(); ) {
 
3029
        for (Iterator<Variable> it = paramOwner.getParameters(); it.hasNext();) {
3100
3030
            Variable param = it.next();
3101
3031
            addParam(param);
3102
3032
        }
3103
3033
    }
3104
3034
 
3105
 
        /**
3106
 
         * Method to return a list of Polys that describes all text on this Cell.
3107
 
         * @param hardToSelect is true if considering hard-to-select text.
3108
 
         * @param wnd the window in which the text will be drawn.
3109
 
         * @return an array of Polys that describes the text.
3110
 
         */
3111
 
        public Poly [] getAllText(boolean hardToSelect, EditWindow0 wnd) {
3112
 
                return getDisplayableVariables(CENTERRECT, wnd, false);
3113
 
        }
3114
 
 
3115
 
        /**
3116
 
         * Method to return the bounds of all relative text in this Cell.
3117
 
         * This is used when displaying "full screen" because the text may grow to
3118
 
         * be larger than the actual cell contents.
3119
 
         * Only relative (scalable) text is considered, since it is not possible
3120
 
         * to change the size of absolute text.
3121
 
         * @param wnd the EditWindow0 in which this Cell is being displayed.
3122
 
         * @return the bounds of the relative (scalable) text.
3123
 
         */
3124
 
        public Rectangle2D getRelativeTextBounds(EditWindow0 wnd)
3125
 
        {
3126
 
                Rectangle2D bounds = null;
3127
 
                for(Iterator<NodeInst> it = this.getNodes(); it.hasNext(); )
3128
 
                {
3129
 
                        NodeInst ni = it.next();
3130
 
                        bounds = accumulateTextBoundsOnObject(ni, bounds, wnd);
3131
 
                        for(Iterator<PortInst> pIt = ni.getPortInsts(); pIt.hasNext(); )
3132
 
                        {
3133
 
                                PortInst pi = pIt.next();
3134
 
                                bounds = accumulateTextBoundsOnObject(pi, bounds, wnd);
3135
 
                        }
3136
 
                }
3137
 
                for(Iterator<ArcInst> it = this.getArcs(); it.hasNext(); )
3138
 
                {
3139
 
                        ArcInst ai = it.next();
3140
 
                        bounds = accumulateTextBoundsOnObject(ai, bounds, wnd);
3141
 
                }
3142
 
                for(Iterator<Export> it = this.getExports(); it.hasNext(); )
3143
 
                {
3144
 
                        Export pp = it.next();
3145
 
                        bounds = accumulateTextBoundsOnObject(pp, bounds, wnd);
3146
 
                }
3147
 
                bounds = accumulateTextBoundsOnObject(this, bounds, wnd);
3148
 
                return bounds;
3149
 
        }
3150
 
 
3151
 
        private Rectangle2D accumulateTextBoundsOnObject(ElectricObject eObj, Rectangle2D bounds, EditWindow0 wnd)
3152
 
        {
3153
 
                Rectangle2D objBounds = eObj.getTextBounds(wnd);
3154
 
                if (objBounds == null) return bounds;
3155
 
                if (bounds == null) return objBounds;
3156
 
                Rectangle2D.union(bounds, objBounds, bounds);
3157
 
                return bounds;
3158
 
        }
3159
 
 
3160
 
        /**
3161
 
         * Method to return the basename for autonaming instances of this Cell.
3162
 
         * @return the basename for autonaming instances of this Cell.
3163
 
         */
3164
 
        public Name getBasename() {
3165
 
                String protoName = getName();
3166
 
                Name basename = Name.findName(protoName.substring(0,Math.min(ABBREVLEN,protoName.length()))+"@0").getBasename();
3167
 
                if (basename == null)
3168
 
                        basename = PrimitiveNode.Function.UNKNOWN.getBasename();
 
3035
    /**
 
3036
     * Method to return a list of Polys that describes all text on this Cell.
 
3037
     * @param hardToSelect is true if considering hard-to-select text.
 
3038
     * @param wnd the window in which the text will be drawn.
 
3039
     * @return an array of Polys that describes the text.
 
3040
     */
 
3041
    public Poly[] getAllText(boolean hardToSelect, EditWindow0 wnd) {
 
3042
        return getDisplayableVariables(CENTERRECT, wnd, false);
 
3043
    }
 
3044
 
 
3045
    /**
 
3046
     * Method to return the bounds of all relative text in this Cell.
 
3047
     * This is used when displaying "full screen" because the text may grow to
 
3048
     * be larger than the actual cell contents.
 
3049
     * Only relative (scalable) text is considered, since it is not possible
 
3050
     * to change the size of absolute text.
 
3051
     * @param wnd the EditWindow0 in which this Cell is being displayed.
 
3052
     * @return the bounds of the relative (scalable) text.
 
3053
     */
 
3054
    public Rectangle2D getRelativeTextBounds(EditWindow0 wnd) {
 
3055
        Rectangle2D bounds = null;
 
3056
        for (Iterator<NodeInst> it = this.getNodes(); it.hasNext();) {
 
3057
            NodeInst ni = it.next();
 
3058
            bounds = accumulateTextBoundsOnObject(ni, bounds, wnd);
 
3059
            for (Iterator<PortInst> pIt = ni.getPortInsts(); pIt.hasNext();) {
 
3060
                PortInst pi = pIt.next();
 
3061
                bounds = accumulateTextBoundsOnObject(pi, bounds, wnd);
 
3062
            }
 
3063
        }
 
3064
        for (Iterator<ArcInst> it = this.getArcs(); it.hasNext();) {
 
3065
            ArcInst ai = it.next();
 
3066
            bounds = accumulateTextBoundsOnObject(ai, bounds, wnd);
 
3067
        }
 
3068
        for (Iterator<Export> it = this.getExports(); it.hasNext();) {
 
3069
            Export pp = it.next();
 
3070
            bounds = accumulateTextBoundsOnObject(pp, bounds, wnd);
 
3071
        }
 
3072
        bounds = accumulateTextBoundsOnObject(this, bounds, wnd);
 
3073
        return bounds;
 
3074
    }
 
3075
 
 
3076
    private Rectangle2D accumulateTextBoundsOnObject(ElectricObject eObj, Rectangle2D bounds, EditWindow0 wnd) {
 
3077
        Rectangle2D objBounds = eObj.getTextBounds(wnd);
 
3078
        if (objBounds == null) {
 
3079
            return bounds;
 
3080
        }
 
3081
        if (bounds == null) {
 
3082
            return objBounds;
 
3083
        }
 
3084
        Rectangle2D.union(bounds, objBounds, bounds);
 
3085
        return bounds;
 
3086
    }
 
3087
 
 
3088
    /**
 
3089
     * Method to return the basename for autonaming instances of this Cell.
 
3090
     * @return the basename for autonaming instances of this Cell.
 
3091
     */
 
3092
    public Name getBasename() {
 
3093
        String protoName = getName();
 
3094
        Name basename = Name.findName(protoName.substring(0, Math.min(ABBREVLEN, protoName.length())) + "@0").getBasename();
 
3095
        if (basename == null) {
 
3096
            basename = PrimitiveNode.Function.UNKNOWN.getBasename();
 
3097
        }
3169
3098
        return basename;
3170
3099
    }
3171
3100
 
3172
 
        /**
3173
 
         * Method to determine the index value which, when appended to a given string,
3174
 
         * will generate a unique name in this Cell.
3175
 
         * @param prefix the start of the string.
3176
 
         * @param cls the type of object being examined.
3177
 
         * @param startingIndex the starting value to append to the string.
3178
 
         * @return a value that, when appended to the prefix, forms a unique name in the cell.
3179
 
         */
3180
 
        public int getUniqueNameIndex(String prefix, Class cls, int startingIndex)
3181
 
        {
3182
 
                int len = prefix.length();
3183
 
                int uniqueIndex = startingIndex;
3184
 
                if (cls == PortProto.class)
3185
 
                {
3186
 
                        for(Iterator<PortProto> it = getPorts(); it.hasNext(); )
3187
 
                        {
3188
 
                                PortProto pp = it.next();
3189
 
                                if (pp.getName().startsWith(prefix))
3190
 
//                              if (TextUtils.startsWithIgnoreCase(pp.getName(), prefix))
3191
 
                                {
3192
 
                                        String restOfName = pp.getName().substring(len);
3193
 
                                        if (TextUtils.isANumber(restOfName))
3194
 
                                        {
3195
 
                                                int indexVal = TextUtils.atoi(restOfName);
3196
 
                                                if (indexVal >= uniqueIndex) uniqueIndex = indexVal + 1;
3197
 
                                        }
3198
 
                                }
3199
 
                        }
3200
 
                } else if (cls == NodeInst.class)
3201
 
                {
3202
 
                        for(Iterator<NodeInst> it = getNodes(); it.hasNext(); )
3203
 
                        {
3204
 
                                NodeInst ni = it.next();
3205
 
                                if (ni.getName().startsWith(prefix))
3206
 
//                              if (TextUtils.startsWithIgnoreCase(ni.getName(), prefix))
3207
 
                                {
3208
 
                                        String restOfName = ni.getName().substring(len);
3209
 
                                        if (TextUtils.isANumber(restOfName))
3210
 
                                        {
3211
 
                                                int indexVal = TextUtils.atoi(restOfName);
3212
 
                                                if (indexVal >= uniqueIndex) uniqueIndex = indexVal + 1;
3213
 
                                        }
3214
 
                                }
3215
 
                        }
3216
 
                } else if (cls == ArcInst.class)
3217
 
                {
3218
 
                        for(Iterator<ArcInst> it = getArcs(); it.hasNext(); )
3219
 
                        {
3220
 
                                ArcInst ai = it.next();
3221
 
                                if (ai.getName().startsWith(prefix))
3222
 
//                              if (TextUtils.startsWithIgnoreCase(ai.getName(), prefix))
3223
 
                                {
3224
 
                                        String restOfName = ai.getName().substring(len);
3225
 
                                        if (TextUtils.isANumber(restOfName))
3226
 
                                        {
3227
 
                                                int indexVal = TextUtils.atoi(restOfName);
3228
 
                                                if (indexVal >= uniqueIndex) uniqueIndex = indexVal + 1;
3229
 
                                        }
3230
 
                                }
3231
 
                        }
3232
 
                }
3233
 
                return uniqueIndex;
3234
 
        }
3235
 
 
3236
 
        /**
3237
 
         * Method to determine whether a name is unique in this Cell.
3238
 
         * @param name the Name being tested to see if it is unique.
3239
 
         * @param cls the type of object being examined.
3240
 
         * The only classes that can be examined are PortProto, NodeInst, and ArcInst.
3241
 
         * @param exclude an object that should not be considered in this test (null to ignore the exclusion).
3242
 
         * @return true if the name is unique in the Cell.  False if it already exists.
3243
 
         */
3244
 
        public boolean isUniqueName(String name, Class cls, ElectricObject exclude)
3245
 
        {
3246
 
                return isUniqueName(Name.findName(name), cls, exclude);
3247
 
        }
3248
 
 
3249
 
        /**
3250
 
         * Method to determine whether a name is unique in this Cell.
3251
 
         * @param name the Name being tested to see if it is unique.
3252
 
         * @param cls the type of object being examined.
3253
 
         * The only classes that can be examined are PortProto, NodeInst, and ArcInst.
3254
 
         * @param exclude an object that should not be considered in this test (null to ignore the exclusion).
3255
 
         * @return true if the name is unique in the Cell.  False if it already exists.
3256
 
         */
3257
 
        public boolean isUniqueName(Name name, Class cls, ElectricObject exclude)
3258
 
        {
 
3101
    /**
 
3102
     * Method to determine the index value which, when appended to a given string,
 
3103
     * will generate a unique name in this Cell.
 
3104
     * @param prefix the start of the string.
 
3105
     * @param cls the type of object being examined.
 
3106
     * @param startingIndex the starting value to append to the string.
 
3107
     * @return a value that, when appended to the prefix, forms a unique name in the cell.
 
3108
     */
 
3109
    public int getUniqueNameIndex(String prefix, Class cls, int startingIndex) {
 
3110
        int len = prefix.length();
 
3111
        int uniqueIndex = startingIndex;
 
3112
        if (cls == PortProto.class) {
 
3113
            for (Iterator<PortProto> it = getPorts(); it.hasNext();) {
 
3114
                PortProto pp = it.next();
 
3115
                if (pp.getName().startsWith(prefix)) //                         if (TextUtils.startsWithIgnoreCase(pp.getName(), prefix))
 
3116
                {
 
3117
                    String restOfName = pp.getName().substring(len);
 
3118
                    if (TextUtils.isANumber(restOfName)) {
 
3119
                        int indexVal = TextUtils.atoi(restOfName);
 
3120
                        if (indexVal >= uniqueIndex) {
 
3121
                            uniqueIndex = indexVal + 1;
 
3122
                        }
 
3123
                    }
 
3124
                }
 
3125
            }
 
3126
        } else if (cls == NodeInst.class) {
 
3127
            for (Iterator<NodeInst> it = getNodes(); it.hasNext();) {
 
3128
                NodeInst ni = it.next();
 
3129
                if (ni.getName().startsWith(prefix)) //                         if (TextUtils.startsWithIgnoreCase(ni.getName(), prefix))
 
3130
                {
 
3131
                    String restOfName = ni.getName().substring(len);
 
3132
                    if (TextUtils.isANumber(restOfName)) {
 
3133
                        int indexVal = TextUtils.atoi(restOfName);
 
3134
                        if (indexVal >= uniqueIndex) {
 
3135
                            uniqueIndex = indexVal + 1;
 
3136
                        }
 
3137
                    }
 
3138
                }
 
3139
            }
 
3140
        } else if (cls == ArcInst.class) {
 
3141
            for (Iterator<ArcInst> it = getArcs(); it.hasNext();) {
 
3142
                ArcInst ai = it.next();
 
3143
                if (ai.getName().startsWith(prefix)) //                         if (TextUtils.startsWithIgnoreCase(ai.getName(), prefix))
 
3144
                {
 
3145
                    String restOfName = ai.getName().substring(len);
 
3146
                    if (TextUtils.isANumber(restOfName)) {
 
3147
                        int indexVal = TextUtils.atoi(restOfName);
 
3148
                        if (indexVal >= uniqueIndex) {
 
3149
                            uniqueIndex = indexVal + 1;
 
3150
                        }
 
3151
                    }
 
3152
                }
 
3153
            }
 
3154
        }
 
3155
        return uniqueIndex;
 
3156
    }
 
3157
 
 
3158
    /**
 
3159
     * Method to determine whether a name is unique in this Cell.
 
3160
     * @param name the Name being tested to see if it is unique.
 
3161
     * @param cls the type of object being examined.
 
3162
     * The only classes that can be examined are PortProto, NodeInst, and ArcInst.
 
3163
     * @param exclude an object that should not be considered in this test (null to ignore the exclusion).
 
3164
     * @return true if the name is unique in the Cell.  False if it already exists.
 
3165
     */
 
3166
    public boolean isUniqueName(String name, Class cls, ElectricObject exclude) {
 
3167
        return isUniqueName(Name.findName(name), cls, exclude);
 
3168
    }
 
3169
 
 
3170
    /**
 
3171
     * Method to determine whether a name is unique in this Cell.
 
3172
     * @param name the Name being tested to see if it is unique.
 
3173
     * @param cls the type of object being examined.
 
3174
     * The only classes that can be examined are PortProto, NodeInst, and ArcInst.
 
3175
     * @param exclude an object that should not be considered in this test (null to ignore the exclusion).
 
3176
     * @return true if the name is unique in the Cell.  False if it already exists.
 
3177
     */
 
3178
    public boolean isUniqueName(Name name, Class cls, ElectricObject exclude) {
3259
3179
//              name = name.canonic();
3260
 
                if (cls == PortProto.class)
3261
 
                {
3262
 
                        PortProto pp = findExport(name);
3263
 
                        if (pp == null || exclude == pp) return true;
3264
 
                        return false;
3265
 
                }
3266
 
                if (cls == NodeInst.class)
3267
 
                {
 
3180
        if (cls == PortProto.class) {
 
3181
            PortProto pp = findExport(name);
 
3182
            if (pp == null || exclude == pp) {
 
3183
                return true;
 
3184
            }
 
3185
            return false;
 
3186
        }
 
3187
        if (cls == NodeInst.class) {
3268
3188
            NodeInst ni = findNode(name.toString());
3269
3189
            return (ni == null || exclude == ni);
3270
 
                }
3271
 
                if (cls == ArcInst.class)
3272
 
                {
 
3190
        }
 
3191
        if (cls == ArcInst.class) {
3273
3192
            ArcInst ai = findArc(name.toString());
3274
3193
            return ai == null || exclude == ai;
3275
3194
//            String nameString = name.canonicString();
3286
3205
//                              if (nameString == arcName.canonicString()) return false;
3287
3206
//                      }
3288
3207
//                      return true;
3289
 
                }
3290
 
                return true;
3291
 
        }
3292
 
 
3293
 
        /**
3294
 
         * Method to determine whether a variable key on Cell is deprecated.
3295
 
         * Deprecated variable keys are those that were used in old versions of Electric,
3296
 
         * but are no longer valid.
3297
 
         * @param key the key of the variable.
3298
 
         * @return true if the variable key is deprecated.
3299
 
         */
3300
 
        public boolean isDeprecatedVariable(Variable.Key key)
3301
 
        {
3302
 
                String name = key.getName();
3303
 
                if (name.equals("NET_last_good_ncc") ||
3304
 
                        name.equals("NET_last_good_ncc_facet") ||
3305
 
                        name.equals("SIM_window_signal_order") ||
3306
 
                        name.equals("SIM_window_signalorder")) return true;
3307
 
                return super.isDeprecatedVariable(key);
3308
 
        }
3309
 
 
3310
 
        /**
3311
 
         * Method to compute the location of a new Variable on this Cell.
3312
 
         * @return the offset of the new Variable.
3313
 
         */
3314
 
    public Point2D newVarOffset()
3315
 
    {
3316
 
        // find nonconflicting location of this cell attribute
3317
 
        int numVars = 0;
3318
 
        double xPosSum = 0;
3319
 
        double yPosBot = 0;
3320
 
        for(Iterator<Variable> it = getParametersAndVariables(); it.hasNext(); )
3321
 
        {
3322
 
                Variable eVar = it.next();
3323
 
                if (!eVar.isDisplay()) continue;
3324
 
                xPosSum += eVar.getXOff();
3325
 
                if (eVar.getYOff() < yPosBot) yPosBot = eVar.getYOff();
3326
 
                numVars++;
3327
 
        }
3328
 
        if (numVars == 0) return new Point2D.Double(0, 0);
3329
 
        return new Point2D.Double(xPosSum / numVars, yPosBot-2);
3330
 
    }
3331
 
 
3332
 
        /**
3333
 
         * Returns a printable version of this Cell.
3334
 
         * @return a printable version of this Cell.
3335
 
         */
3336
 
        public String toString()
3337
 
        {
3338
 
                return "cell " + describe(true);
3339
 
        }
3340
 
 
3341
 
        /****************************** HIERARCHY ******************************/
3342
 
 
 
3208
        }
 
3209
        return true;
 
3210
    }
 
3211
 
 
3212
    /**
 
3213
     * Method to determine whether a variable key on Cell is deprecated.
 
3214
     * Deprecated variable keys are those that were used in old versions of Electric,
 
3215
     * but are no longer valid.
 
3216
     * @param key the key of the variable.
 
3217
     * @return true if the variable key is deprecated.
 
3218
     */
 
3219
    public boolean isDeprecatedVariable(Variable.Key key) {
 
3220
        String name = key.getName();
 
3221
        if (name.equals("NET_last_good_ncc")
 
3222
                || name.equals("NET_last_good_ncc_facet")
 
3223
                || name.equals("SIM_window_signal_order")
 
3224
                || name.equals("SIM_window_signalorder")) {
 
3225
            return true;
 
3226
        }
 
3227
        return super.isDeprecatedVariable(key);
 
3228
    }
 
3229
 
 
3230
    /**
 
3231
     * Method to compute the location of a new Variable on this Cell.
 
3232
     * @return the offset of the new Variable.
 
3233
     */
 
3234
    public Point2D newVarOffset() {
 
3235
        // find nonconflicting location of this cell attribute
 
3236
        int numVars = 0;
 
3237
        double xPosSum = 0;
 
3238
        double yPosBot = 0;
 
3239
        for (Iterator<Variable> it = getParametersAndVariables(); it.hasNext();) {
 
3240
            Variable eVar = it.next();
 
3241
            if (!eVar.isDisplay()) {
 
3242
                continue;
 
3243
            }
 
3244
            xPosSum += eVar.getXOff();
 
3245
            if (eVar.getYOff() < yPosBot) {
 
3246
                yPosBot = eVar.getYOff();
 
3247
            }
 
3248
            numVars++;
 
3249
        }
 
3250
        if (numVars == 0) {
 
3251
            return new Point2D.Double(0, 0);
 
3252
        }
 
3253
        return new Point2D.Double(xPosSum / numVars, yPosBot - 2);
 
3254
    }
 
3255
 
 
3256
    /**
 
3257
     * Returns a printable version of this Cell.
 
3258
     * @return a printable version of this Cell.
 
3259
     */
 
3260
    public String toString() {
 
3261
        return "cell " + describe(true);
 
3262
    }
 
3263
 
 
3264
    /****************************** HIERARCHY ******************************/
3343
3265
    /**
3344
3266
     * Returns persistent data of this Cell.
3345
3267
     * @return persistent data of this Cell.
3346
3268
     */
3347
3269
    @Override
3348
 
    public ImmutableCell getD() { return d; }
 
3270
    public ImmutableCell getD() {
 
3271
        return d;
 
3272
    }
3349
3273
 
3350
3274
    /**
3351
3275
     * Modifies persistend data of this Cell.
3355
3279
        assert isLinked();
3356
3280
        checkChanging();
3357
3281
        ImmutableCell oldD = getD();
3358
 
        if (newD == oldD) return;
 
3282
        if (newD == oldD) {
 
3283
            return;
 
3284
        }
3359
3285
        d = newD;
3360
3286
        unfreshBackup();
3361
3287
        Constraints.getCurrent().modifyCell(this, oldD);
3367
3293
     * @param var Variable to add.
3368
3294
     */
3369
3295
    public void addVar(Variable var) {
3370
 
        if (var.getTextDescriptor().isParam() || isParam(var.getKey()))
 
3296
        if (var.getTextDescriptor().isParam() || isParam(var.getKey())) {
3371
3297
            throw new IllegalArgumentException("Parameters should be added by CellGroup.addParam");
 
3298
        }
3372
3299
        setD(getD().withVariable(var));
3373
3300
    }
3374
3301
 
3375
 
        /**
3376
 
         * Method to delete a Variable from this Cell.
3377
 
         * @param key the key of the Variable to delete.
3378
 
         */
3379
 
        public void delVar(Variable.Key key)
3380
 
        {
3381
 
        if (isParam(key))
 
3302
    /**
 
3303
     * Method to delete a Variable from this Cell.
 
3304
     * @param key the key of the Variable to delete.
 
3305
     */
 
3306
    public void delVar(Variable.Key key) {
 
3307
        if (isParam(key)) {
3382
3308
            throw new IllegalArgumentException("Parameters should be deleted by CellGroup.delParam");
 
3309
        }
3383
3310
        setD(getD().withoutVariable(key));
3384
 
        }
 
3311
    }
3385
3312
 
3386
 
        /**
3387
 
         * Method to return the Parameter or Variable on this Cell with a given key.
3388
 
         * @param key the key of the Parameter or Variable.
3389
 
         * @return the Parameter or Variable with that key, or null if there is no such Parameter or Variable Variable.
 
3313
    /**
 
3314
     * Method to return the Parameter or Variable on this Cell with a given key.
 
3315
     * @param key the key of the Parameter or Variable.
 
3316
     * @return the Parameter or Variable with that key, or null if there is no such Parameter or Variable Variable.
3390
3317
     * @throws NullPointerException if key is null
3391
 
         */
 
3318
     */
3392
3319
    @Override
3393
 
        public Variable getParameterOrVariable(Variable.Key key) {
3394
 
                checkExamine();
 
3320
    public Variable getParameterOrVariable(Variable.Key key) {
 
3321
        checkExamine();
3395
3322
        if (key instanceof Variable.AttrKey) {
3396
3323
            Variable param = getParameter(key);
3397
 
            if (param != null)
 
3324
            if (param != null) {
3398
3325
                return param;
 
3326
            }
3399
3327
        }
3400
 
                return getVar(key);
3401
 
        }
 
3328
        return getVar(key);
 
3329
    }
3402
3330
 
3403
 
        /**
3404
 
         * Method to return an Iterator over all Parameters and Variables on this Cell.
3405
 
         * @return an Iterator over all Parameters and Variables on this Cell.
3406
 
         */
 
3331
    /**
 
3332
     * Method to return an Iterator over all Parameters and Variables on this Cell.
 
3333
     * @return an Iterator over all Parameters and Variables on this Cell.
 
3334
     */
3407
3335
    @Override
3408
 
        public Iterator<Variable> getParametersAndVariables() {
3409
 
        if (getNumParameters() == 0)
 
3336
    public Iterator<Variable> getParametersAndVariables() {
 
3337
        if (getNumParameters() == 0) {
3410
3338
            return getVariables();
 
3339
        }
3411
3340
        List<Variable> allVars = new ArrayList<Variable>();
3412
 
        for (Iterator<Variable> it = getParameters(); it.hasNext(); )
3413
 
            allVars.add(it.next());
3414
 
        for (Iterator<Variable> it = getVariables(); it.hasNext(); )
3415
 
            allVars.add(it.next());
 
3341
        for (Iterator<Variable> it = getParameters(); it.hasNext();) {
 
3342
            allVars.add(it.next());
 
3343
        }
 
3344
        for (Iterator<Variable> it = getVariables(); it.hasNext();) {
 
3345
            allVars.add(it.next());
 
3346
        }
3416
3347
        return allVars.iterator();
3417
3348
    }
3418
3349
 
3419
 
        /**
3420
 
         * Updates the TextDescriptor on this Cell selected by varKey.
3421
 
         * The varKey may be a key of parameter or variable on this Cell.
3422
 
         * If varKey doesn't select any text descriptor, no action is performed.
3423
 
         * The TextDescriptor gives information for displaying the Variable.
3424
 
         * @param varKey key of variable or special key.
3425
 
         * @param td new value TextDescriptor
3426
 
         */
 
3350
    /**
 
3351
     * Updates the TextDescriptor on this Cell selected by varKey.
 
3352
     * The varKey may be a key of parameter or variable on this Cell.
 
3353
     * If varKey doesn't select any text descriptor, no action is performed.
 
3354
     * The TextDescriptor gives information for displaying the Variable.
 
3355
     * @param varKey key of variable or special key.
 
3356
     * @param td new value TextDescriptor
 
3357
     */
3427
3358
    @Override
3428
 
        public void setTextDescriptor(Variable.Key varKey, TextDescriptor td) {
 
3359
    public void setTextDescriptor(Variable.Key varKey, TextDescriptor td) {
3429
3360
        Variable param = getParameter(varKey);
3430
3361
        if (param != null) {
3431
3362
            td = td.withParam(true).withInherit(true).withUnit(param.getUnit());
3432
3363
            addParam(param.withTextDescriptor(td));
3433
3364
            return;
3434
3365
        }
3435
 
                Variable var = getVar(varKey);
3436
 
                if (var != null)
 
3366
        Variable var = getVar(varKey);
 
3367
        if (var != null) {
3437
3368
            addVar(var.withTextDescriptor(td.withParam(false)));
3438
 
        }
 
3369
        }
 
3370
    }
3439
3371
 
3440
3372
    /**
3441
3373
     * Method to return NodeProtoId of this NodeProto.
3442
3374
     * NodeProtoId identifies NodeProto independently of threads.
3443
3375
     * @return NodeProtoId of this NodeProto.
3444
3376
     */
3445
 
    public CellId getId() { return d.cellId; }
 
3377
    public CellId getId() {
 
3378
        return d.cellId;
 
3379
    }
3446
3380
 
3447
3381
    /**
3448
3382
     * Returns a Cell by CellId.
3450
3384
     * @param cellId CellId to find.
3451
3385
     * @return Cell or null.
3452
3386
     */
3453
 
    public static Cell inCurrentThread(CellId cellId) { return EDatabase.currentDatabase().getCell(cellId); }
 
3387
    public static Cell inCurrentThread(CellId cellId) {
 
3388
        return EDatabase.currentDatabase().getCell(cellId);
 
3389
    }
3454
3390
 
3455
 
        /**
3456
 
         * Method to return an iterator over all usages of this NodeProto.
3457
 
         * @return an iterator over all usages of this NodeProto.
3458
 
         */
3459
 
        public Iterator<CellUsage> getUsagesOf()
3460
 
        {
 
3391
    /**
 
3392
     * Method to return an iterator over all usages of this NodeProto.
 
3393
     * @return an iterator over all usages of this NodeProto.
 
3394
     */
 
3395
    public Iterator<CellUsage> getUsagesOf() {
3461
3396
        return new Iterator<CellUsage>() {
 
3397
 
3462
3398
            int i;
3463
3399
            CellUsage nextU = findNext();
3464
3400
 
3465
 
            public boolean hasNext() { return nextU != null; }
 
3401
            public boolean hasNext() {
 
3402
                return nextU != null;
 
3403
            }
3466
3404
 
3467
 
                        public CellUsage next() {
3468
 
                if (nextU == null) throw new NoSuchElementException();
 
3405
            public CellUsage next() {
 
3406
                if (nextU == null) {
 
3407
                    throw new NoSuchElementException();
 
3408
                }
3469
3409
                CellUsage u = nextU;
3470
3410
                nextU = findNext();
3471
3411
                return u;
3472
3412
            }
3473
3413
 
3474
 
            public void remove() { throw new UnsupportedOperationException(); };
 
3414
            public void remove() {
 
3415
                throw new UnsupportedOperationException();
 
3416
            }
 
3417
 
 
3418
            ;
3475
3419
 
3476
3420
            private CellUsage findNext() {
3477
3421
                CellId cellId = getId();
3478
3422
                while (i < cellId.numUsagesOf()) {
3479
3423
                    CellUsage u = cellId.getUsageOf(i++);
3480
3424
                    Cell parent = u.getParent(database);
3481
 
                    if (parent == null) continue;
3482
 
                    if (u.indexInParent >= parent.cellUsages.length) continue;
3483
 
                    if (parent.cellUsages[u.indexInParent] > 0) return u;
 
3425
                    if (parent == null) {
 
3426
                        continue;
 
3427
                    }
 
3428
                    if (u.indexInParent >= parent.cellUsages.length) {
 
3429
                        continue;
 
3430
                    }
 
3431
                    if (parent.cellUsages[u.indexInParent] > 0) {
 
3432
                        return u;
 
3433
                    }
3484
3434
                }
3485
3435
                return null;
3486
3436
            }
3487
3437
        };
3488
 
        }
3489
 
 
3490
 
        /**
3491
 
         * Method to return an iterator over all instances of this NodeProto.
3492
 
         * @return an iterator over all instances of this NodeProto.
3493
 
         */
3494
 
        public Iterator<NodeInst> getInstancesOf()
3495
 
        {
3496
 
                return new NodeInstsIterator();
3497
 
        }
3498
 
 
3499
 
        private class NodeInstsIterator implements Iterator<NodeInst>
3500
 
        {
3501
 
                private Iterator<CellUsage> uit;
 
3438
    }
 
3439
 
 
3440
    /**
 
3441
     * Method to return an iterator over all instances of this NodeProto.
 
3442
     * @return an iterator over all instances of this NodeProto.
 
3443
     */
 
3444
    public Iterator<NodeInst> getInstancesOf() {
 
3445
        return new NodeInstsIterator();
 
3446
    }
 
3447
 
 
3448
    private class NodeInstsIterator implements Iterator<NodeInst> {
 
3449
 
 
3450
        private Iterator<CellUsage> uit;
3502
3451
        private Cell cell;
3503
 
                private int i, n;
 
3452
        private int i, n;
3504
3453
        private NodeInst ni;
3505
3454
 
3506
 
                NodeInstsIterator()
3507
 
                {
3508
 
                        uit = getUsagesOf();
 
3455
        NodeInstsIterator() {
 
3456
            uit = getUsagesOf();
3509
3457
            findNext();
3510
 
                }
3511
 
 
3512
 
                public boolean hasNext() { return ni != null; }
3513
 
 
3514
 
                public NodeInst next()
3515
 
                {
 
3458
        }
 
3459
 
 
3460
        public boolean hasNext() {
 
3461
            return ni != null;
 
3462
        }
 
3463
 
 
3464
        public NodeInst next() {
3516
3465
            NodeInst ni = this.ni;
3517
 
            if (ni == null) throw new NoSuchElementException();
 
3466
            if (ni == null) {
 
3467
                throw new NoSuchElementException();
 
3468
            }
3518
3469
            findNext();
3519
3470
            return ni;
3520
 
                }
3521
 
 
3522
 
                public void remove() { throw new UnsupportedOperationException("NodeInstsIterator.remove()"); };
 
3471
        }
 
3472
 
 
3473
        public void remove() {
 
3474
            throw new UnsupportedOperationException("NodeInstsIterator.remove()");
 
3475
        }
 
3476
 
 
3477
        ;
3523
3478
 
3524
3479
        private void findNext() {
3525
3480
            for (;;) {
3526
3481
                while (i < n) {
3527
3482
                    ni = cell.getNode(i++);
3528
 
                    if (ni.getProto() == Cell.this)
 
3483
                    if (ni.getProto() == Cell.this) {
3529
3484
                        return;
 
3485
                    }
3530
3486
                }
3531
3487
                if (!uit.hasNext()) {
3532
3488
                    ni = null;
3534
3490
                }
3535
3491
                CellUsage u = uit.next();
3536
3492
                cell = u.getParent(database);
3537
 
                if (cell == null) continue;
 
3493
                if (cell == null) {
 
3494
                    continue;
 
3495
                }
3538
3496
                i = 0;
3539
3497
                n = cell.getNumNodes();
3540
3498
            }
3550
3508
     */
3551
3509
    public static boolean isInstantiationRecursive(Cell toInstantiate, Cell parent) {
3552
3510
        // if they are equal, this is recursive
3553
 
        if (toInstantiate == parent)
 
3511
        if (toInstantiate == parent) {
3554
3512
            return true;
 
3513
        }
3555
3514
        // Icons shouldn't contain cell instances
3556
 
        if (parent.isIcon())
 
3515
        if (parent.isIcon()) {
3557
3516
            return true;
 
3517
        }
3558
3518
 
3559
3519
        // special case: allow instance of icon inside of the contents for illustration
3560
3520
        if (toInstantiate.isIconOf(parent)) {
3565
3525
 
3566
3526
        // if the parent is a child of the cell to instantiate, that would be a
3567
3527
        // recursive operation
3568
 
        if (parent.isAChildOf(toInstantiate))
 
3528
        if (parent.isAChildOf(toInstantiate)) {
3569
3529
            return true;
 
3530
        }
3570
3531
 
3571
3532
        return false;
3572
3533
    }
3573
3534
 
3574
 
        /**
3575
 
         * Method to determine whether this Cell is a child of a given parent Cell.
3576
 
         * DO NOT use this method to determine whether an instantiation should be allowed
 
3535
    /**
 
3536
     * Method to determine whether this Cell is a child of a given parent Cell.
 
3537
     * DO NOT use this method to determine whether an instantiation should be allowed
3577
3538
     * (i.e. it is not a recursive instantation).  Use <code>isInstantiationRecursive</code>
3578
3539
     * instead.  This method *only* does what is it says it does: it checks if this cell
3579
3540
     * is currently instantiated as a child of 'parent' cell.
3580
 
         * @param parent the parent cell being examined.
3581
 
         * @return true if, somewhere above the hierarchy of this Cell is the parent Cell.
3582
 
         */
3583
 
        public boolean isAChildOf(Cell parent)
3584
 
        {
3585
 
                return getIsAChildOf(parent, new HashMap<Cell,Cell>());
3586
 
        }
 
3541
     * @param parent the parent cell being examined.
 
3542
     * @return true if, somewhere above the hierarchy of this Cell is the parent Cell.
 
3543
     */
 
3544
    public boolean isAChildOf(Cell parent) {
 
3545
        return getIsAChildOf(parent, new HashMap<Cell, Cell>());
 
3546
    }
3587
3547
 
3588
 
        private boolean getIsAChildOf(Cell parent, Map<Cell,Cell> checkedParents)
3589
 
        {
 
3548
    private boolean getIsAChildOf(Cell parent, Map<Cell, Cell> checkedParents) {
3590
3549
        // if parent is an icon view, also check contents view
3591
3550
        if (parent.isIcon()) {
3592
3551
            Cell c = parent.contentsView();
3593
3552
            if (c != null && c != parent) {
3594
 
                if (getIsAChildOf(c, checkedParents))
 
3553
                if (getIsAChildOf(c, checkedParents)) {
3595
3554
                    return true;
 
3555
                }
3596
3556
            }
3597
3557
        }
3598
3558
 
3599
3559
        // see if parent checked already
3600
 
        if (checkedParents.get(parent) != null) return false;
 
3560
        if (checkedParents.get(parent) != null) {
 
3561
            return false;
 
3562
        }
3601
3563
        // mark this parent as being checked so we don't recurse into it again
3602
3564
        checkedParents.put(parent, parent);
3603
3565
 
3607
3569
        // check both icon and content views
3608
3570
        // Note that contentView and iconView are the same for every recursion
3609
3571
        Cell contentView = contentsView();
3610
 
        if (contentView == null) contentView = this;
 
3572
        if (contentView == null) {
 
3573
            contentView = this;
 
3574
        }
3611
3575
        Cell iconView = iconView();
3612
3576
 
3613
 
        for (Iterator<NodeInst> it = parent.getNodes(); it.hasNext(); ) {
 
3577
        for (Iterator<NodeInst> it = parent.getNodes(); it.hasNext();) {
3614
3578
            NodeInst ni = it.next();
3615
3579
            if (ni.isCellInstance()) {
3616
 
                Cell c = (Cell)ni.getProto();
 
3580
                Cell c = (Cell) ni.getProto();
3617
3581
                // ignore instances of icon view inside content view
3618
 
                if (c.isIconOf(parent)) continue;
3619
 
                if (c == contentView) return true;
3620
 
                if (c == iconView) return true;
 
3582
                if (c.isIconOf(parent)) {
 
3583
                    continue;
 
3584
                }
 
3585
                if (c == contentView) {
 
3586
                    return true;
 
3587
                }
 
3588
                if (c == iconView) {
 
3589
                    return true;
 
3590
                }
3621
3591
                // recurse
3622
 
                if (getIsAChildOf(c, checkedParents))
 
3592
                if (getIsAChildOf(c, checkedParents)) {
3623
3593
                    return true;
 
3594
                }
3624
3595
            }
3625
3596
        }
3626
3597
        return false;
3672
3643
//              }
3673
3644
//              return false;
3674
3645
//      }
3675
 
 
3676
 
        /**
3677
 
         * Method to determine whether this Cell is in use anywhere.
3678
 
         * If it is, an error dialog is displayed.
3679
 
         * @param action a description of the intended action (i.e. "delete").
3680
 
         * @param quiet true not to warn the user of the cell being used.
3681
 
         * @param sameCellGroupAlso
 
3646
    /**
 
3647
     * Method to determine whether this Cell is in use anywhere.
 
3648
     * If it is, an error dialog is displayed.
 
3649
     * @param action a description of the intended action (i.e. "delete").
 
3650
     * @param quiet true not to warn the user of the cell being used.
 
3651
     * @param sameCellGroupAlso
3682
3652
     * @return true if this Cell is in use anywhere.
3683
 
         */
 
3653
     */
3684
3654
    public boolean isInUse(String action, boolean quiet, boolean sameCellGroupAlso) {
3685
3655
        String parents = isInUse(sameCellGroupAlso);
3686
3656
        if (parents != null) {
3687
 
            if (!quiet)
3688
 
                Job.getUserInterface().showErrorMessage("Cannot " + action + " " + this +
3689
 
                        " because it is used in " + parents, action + " failed");
 
3657
            if (!quiet) {
 
3658
                Job.getUserInterface().showErrorMessage("Cannot " + action + " " + this
 
3659
                        + " because it is used in " + parents, action + " failed");
 
3660
            }
3690
3661
            return true;
3691
3662
        }
3692
3663
        if (isSchematic() && this == getNewestVersion()) {
3693
 
            for (Cell cell: getCellGroup().cells) {
3694
 
                if (!cell.isIcon()) continue;
 
3664
            for (Cell cell : getCellGroup().cells) {
 
3665
                if (!cell.isIcon()) {
 
3666
                    continue;
 
3667
                }
3695
3668
                parents = cell.isInUse(false);
3696
3669
                if (parents != null) {
3697
 
                    if (!quiet)
3698
 
                        Job.getUserInterface().showErrorMessage("Cannot " + action + " " + this +
3699
 
                                " because icon " + cell + " is used in " + parents, action + " failed");
 
3670
                    if (!quiet) {
 
3671
                        Job.getUserInterface().showErrorMessage("Cannot " + action + " " + this
 
3672
                                + " because icon " + cell + " is used in " + parents, action + " failed");
 
3673
                    }
3700
3674
                    return true;
3701
3675
                }
3702
3676
            }
3712
3686
     */
3713
3687
    private String isInUse(boolean sameCellGroupAlso) {
3714
3688
        String parents = null;
3715
 
        for(Iterator<CellUsage> it = getUsagesOf(); it.hasNext(); ) {
 
3689
        for (Iterator<CellUsage> it = getUsagesOf(); it.hasNext();) {
3716
3690
            CellUsage u = it.next();
3717
3691
            Cell parent = u.getParent(database);
3718
 
            if (!sameCellGroupAlso && parent.getCellGroup() == getCellGroup()) continue;
3719
 
            if (parents == null) parents = parent.describe(true); else
 
3692
            if (!sameCellGroupAlso && parent.getCellGroup() == getCellGroup()) {
 
3693
                continue;
 
3694
            }
 
3695
            if (parents == null) {
 
3696
                parents = parent.describe(true);
 
3697
            } else {
3720
3698
                parents += ", " + parent.describe(true);
 
3699
            }
3721
3700
        }
3722
3701
        return parents;
3723
3702
    }
3724
3703
 
3725
 
        /****************************** VERSIONS ******************************/
3726
 
 
3727
 
        /**
3728
 
         * Method to create a new version of this Cell.
3729
 
         * @return a new Cell that is a new version of this Cell.
3730
 
         */
3731
 
        public Cell makeNewVersion()
3732
 
        {
3733
 
                Cell newVersion = Cell.copyNodeProto(this, lib, noLibDescribe(), false);
3734
 
                return newVersion;
3735
 
        }
3736
 
 
3737
 
        /**
3738
 
         * Method to return the version number of this Cell.
3739
 
         * @return the version number of this Cell.
3740
 
         */
3741
 
        public int getVersion() { return getCellName().getVersion(); }
3742
 
 
3743
 
        /**
3744
 
         * Method to return the number of different versions of this Cell.
3745
 
         * @return the number of different versions of this Cell.
3746
 
         */
3747
 
        public int getNumVersions()
3748
 
        {
3749
 
                int count = 0;
3750
 
                String protoName = getName();
3751
 
                View view = getView();
3752
 
                synchronized (lib.cells) {
3753
 
                        for (Iterator<Cell> it = getVersionsTail(); it.hasNext(); )
3754
 
                        {
3755
 
                                Cell c = it.next();
3756
 
                                if (!c.getName().equals(protoName) || c.getView() != view) break;
3757
 
                                count++;
3758
 
                        }
3759
 
                }
3760
 
                return count;
3761
 
        }
3762
 
 
3763
 
        /**
3764
 
         * Method to return an Iterator over the different versions of this Cell.
3765
 
         * @return an Iterator over the different versions of this Cell.
3766
 
         */
3767
 
        public Iterator<Cell> getVersions()
3768
 
        {
3769
 
                List<Cell> versions = new ArrayList<Cell>();
3770
 
                String protoName = getName();
3771
 
                View view = getView();
3772
 
                synchronized (lib.cells) {
3773
 
                        for (Iterator<Cell> it = getVersionsTail(); it.hasNext(); )
3774
 
                        {
3775
 
                                Cell c = it.next();
3776
 
                                if (!c.getName().equals(protoName) || c.getView() != view) break;
3777
 
                                versions.add(c);
3778
 
                        }
3779
 
                }
3780
 
                return versions.iterator();
3781
 
        }
3782
 
 
3783
 
        /**
3784
 
         * Method to return the most recent version of this Cell.
3785
 
         * @return he most recent version of this Cell.
3786
 
         */
 
3704
    /****************************** VERSIONS ******************************/
 
3705
    /**
 
3706
     * Method to create a new version of this Cell.
 
3707
     * @return a new Cell that is a new version of this Cell.
 
3708
     */
 
3709
    public Cell makeNewVersion() {
 
3710
        Cell newVersion = Cell.copyNodeProto(this, lib, noLibDescribe(), false);
 
3711
        return newVersion;
 
3712
    }
 
3713
 
 
3714
    /**
 
3715
     * Method to return the version number of this Cell.
 
3716
     * @return the version number of this Cell.
 
3717
     */
 
3718
    public int getVersion() {
 
3719
        return getCellName().getVersion();
 
3720
    }
 
3721
 
 
3722
    /**
 
3723
     * Method to return the number of different versions of this Cell.
 
3724
     * @return the number of different versions of this Cell.
 
3725
     */
 
3726
    public int getNumVersions() {
 
3727
        int count = 0;
 
3728
        String protoName = getName();
 
3729
        View view = getView();
 
3730
        synchronized (lib.cells) {
 
3731
            for (Iterator<Cell> it = getVersionsTail(); it.hasNext();) {
 
3732
                Cell c = it.next();
 
3733
                if (!c.getName().equals(protoName) || c.getView() != view) {
 
3734
                    break;
 
3735
                }
 
3736
                count++;
 
3737
            }
 
3738
        }
 
3739
        return count;
 
3740
    }
 
3741
 
 
3742
    /**
 
3743
     * Method to return an Iterator over the different versions of this Cell.
 
3744
     * @return an Iterator over the different versions of this Cell.
 
3745
     */
 
3746
    public Iterator<Cell> getVersions() {
 
3747
        List<Cell> versions = new ArrayList<Cell>();
 
3748
        String protoName = getName();
 
3749
        View view = getView();
 
3750
        synchronized (lib.cells) {
 
3751
            for (Iterator<Cell> it = getVersionsTail(); it.hasNext();) {
 
3752
                Cell c = it.next();
 
3753
                if (!c.getName().equals(protoName) || c.getView() != view) {
 
3754
                    break;
 
3755
                }
 
3756
                versions.add(c);
 
3757
            }
 
3758
        }
 
3759
        return versions.iterator();
 
3760
    }
 
3761
 
 
3762
    /**
 
3763
     * Method to return the most recent version of this Cell.
 
3764
     * @return he most recent version of this Cell.
 
3765
     */
3787
3766
    public Cell getNewestVersion() {
3788
3767
//        synchronized (lib.cells) {
3789
 
            return newestVersion;
 
3768
        return newestVersion;
3790
3769
//        }
3791
3770
    }
3792
3771
 
3793
 
        /*
3794
 
         * Return tail submap of library cells which starts from
3795
 
         * cells with same protoName and view as this Cell.
3796
 
         * @return tail submap with versions of this Cell.
3797
 
         */
 
3772
    /*
 
3773
     * Return tail submap of library cells which starts from
 
3774
     * cells with same protoName and view as this Cell.
 
3775
     * @return tail submap with versions of this Cell.
 
3776
     */
3798
3777
    private Iterator<Cell> getVersionsTail() {
3799
3778
        return lib.getCellsTail(newestVersion.getCellName());
3800
3779
    }
3801
3780
 
3802
 
        /*
3803
 
         * Return tail submap of library cells which starts from
3804
 
         * cells with same protoName as this Cell.
3805
 
         * @return tail submap with views of this Cell.
3806
 
         */
3807
 
        private Iterator<Cell> getViewsTail()
3808
 
        {
3809
 
                CellName cn = CellName.parseName(getName());
3810
 
                return lib.getCellsTail(cn);
3811
 
        }
3812
 
 
3813
 
        /****************************** GROUPS ******************************/
3814
 
 
3815
 
        /**
3816
 
         * Method to get the CellGroup that this Cell is part of.
3817
 
         * @return the CellGroup that this Cell is part of.
3818
 
         */
3819
 
        public CellGroup getCellGroup() { return cellGroup; }
3820
 
 
3821
 
        /**
3822
 
         * Method to move this Cell together with all its versions and views
3823
 
         * to the group of another Cell.
3824
 
         * @param otherCell the other cell whose group this Cell should join.
3825
 
         */
3826
 
        public void joinGroup(Cell otherCell)
3827
 
        {
3828
 
                setCellGroup(otherCell.getCellGroup());
3829
 
        }
 
3781
    /*
 
3782
     * Return tail submap of library cells which starts from
 
3783
     * cells with same protoName as this Cell.
 
3784
     * @return tail submap with views of this Cell.
 
3785
     */
 
3786
    private Iterator<Cell> getViewsTail() {
 
3787
        CellName cn = CellName.parseName(getName());
 
3788
        return lib.getCellsTail(cn);
 
3789
    }
 
3790
 
 
3791
    /****************************** GROUPS ******************************/
 
3792
    /**
 
3793
     * Method to get the CellGroup that this Cell is part of.
 
3794
     * @return the CellGroup that this Cell is part of.
 
3795
     */
 
3796
    public CellGroup getCellGroup() {
 
3797
        return cellGroup;
 
3798
    }
 
3799
 
 
3800
    /**
 
3801
     * Method to move this Cell together with all its versions and views
 
3802
     * to the group of another Cell.
 
3803
     * @param otherCell the other cell whose group this Cell should join.
 
3804
     */
 
3805
    public void joinGroup(Cell otherCell) {
 
3806
        setCellGroup(otherCell.getCellGroup());
 
3807
    }
3830
3808
 
3831
3809
//      /**
3832
3810
//       * Method to Cell together with all its versions and views into its own CellGroup.
3836
3814
//      {
3837
3815
//              setCellGroup(null);
3838
3816
//      }
3839
 
 
3840
 
        /**
3841
 
         * Method to put this Cell together with all its versions and views into the given CellGroup.
3842
 
         * @param cellGroup the CellGroup that this cell belongs to or null to put int own cell group
3843
 
         */
3844
 
        public void setCellGroup(CellGroup cellGroup)
3845
 
        {
3846
 
                if (!isLinked()) return;
 
3817
    /**
 
3818
     * Method to put this Cell together with all its versions and views into the given CellGroup.
 
3819
     * @param cellGroup the CellGroup that this cell belongs to or null to put int own cell group
 
3820
     */
 
3821
    public void setCellGroup(CellGroup cellGroup) {
 
3822
        if (!isLinked()) {
 
3823
            return;
 
3824
        }
3847
3825
//              CellGroup oldCellGroup = this.cellGroup;
3848
 
                if (cellGroup == null) cellGroup = new CellGroup(lib);
 
3826
        if (cellGroup == null) {
 
3827
            cellGroup = new CellGroup(lib);
 
3828
        }
3849
3829
        checkChanging();
3850
 
                if (cellGroup == this.cellGroup) return;
 
3830
        if (cellGroup == this.cellGroup) {
 
3831
            return;
 
3832
        }
3851
3833
        database.unfreshSnapshot();
3852
3834
        lib.setChanged();
3853
 
                String protoName = getName();
3854
 
                for (Iterator<Cell> it = getViewsTail(); it.hasNext(); )
3855
 
                {
3856
 
                        Cell cell = it.next();
3857
 
                        if (!cell.getName().equals(protoName)) break;
3858
 
                        cell.cellGroup.remove(cell);
3859
 
                        cellGroup.add(cell);
3860
 
                }
 
3835
        String protoName = getName();
 
3836
        for (Iterator<Cell> it = getViewsTail(); it.hasNext();) {
 
3837
            Cell cell = it.next();
 
3838
            if (!cell.getName().equals(protoName)) {
 
3839
                break;
 
3840
            }
 
3841
            cell.cellGroup.remove(cell);
 
3842
            cellGroup.add(cell);
 
3843
        }
3861
3844
//              Undo.modifyCellGroup(this, oldCellGroup);
3862
 
        }
3863
 
 
3864
 
        /****************************** VIEWS ******************************/
3865
 
 
3866
 
        /**
3867
 
         * Method to get this Cell's View.
3868
 
         * Views include "layout", "schematics", "icon", "netlist", etc.
3869
 
         * @return to get this Cell's View.
3870
 
         */
3871
 
        public View getView() { return getCellName().getView(); }
3872
 
 
3873
 
        /**
3874
 
         * Method to change the view of this Cell.
3875
 
         * @param newView the new View.
3876
 
         */
3877
 
        public IdMapper setView(View newView)
3878
 
        {
3879
 
                return rename(CellName.newName(getName(), newView, getVersion()), null);
3880
 
        }
3881
 
 
3882
 
        /**
3883
 
         * Method to determine whether this Cell is an icon Cell.
3884
 
         * @return true if this Cell is an icon  Cell.
3885
 
         */
3886
 
        public boolean isIcon() { return getId().isIcon(); }
3887
 
 
3888
 
        /**
3889
 
         * Method to determine whether this Cell is an icon of another Cell.
3890
 
         * @param cell the other cell which this may be an icon of.
3891
 
         * @return true if this Cell is an icon of that other Cell.
3892
 
         */
3893
 
        public boolean isIconOf(Cell cell)
3894
 
        {
3895
 
                return isIcon() && cellGroup == cell.cellGroup && cell.isSchematic();
3896
 
        }
3897
 
 
3898
 
        /**
3899
 
         * Method to return true if this Cell is a schematic Cell.
3900
 
         * @return true if this Cell is a schematic Cell.
3901
 
         */
3902
 
        public boolean isSchematic() { return getId().isSchematic(); }
 
3845
    }
 
3846
 
 
3847
    /****************************** VIEWS ******************************/
 
3848
    /**
 
3849
     * Method to get this Cell's View.
 
3850
     * Views include "layout", "schematics", "icon", "netlist", etc.
 
3851
     * @return to get this Cell's View.
 
3852
     */
 
3853
    public View getView() {
 
3854
        return getCellName().getView();
 
3855
    }
 
3856
 
 
3857
    /**
 
3858
     * Method to change the view of this Cell.
 
3859
     * @param newView the new View.
 
3860
     */
 
3861
    public IdMapper setView(View newView) {
 
3862
        return rename(CellName.newName(getName(), newView, getVersion()), null);
 
3863
    }
 
3864
 
 
3865
    /**
 
3866
     * Method to determine whether this Cell is an icon Cell.
 
3867
     * @return true if this Cell is an icon  Cell.
 
3868
     */
 
3869
    public boolean isIcon() {
 
3870
        return getId().isIcon();
 
3871
    }
 
3872
 
 
3873
    /**
 
3874
     * Method to determine whether this Cell is an icon of another Cell.
 
3875
     * @param cell the other cell which this may be an icon of.
 
3876
     * @return true if this Cell is an icon of that other Cell.
 
3877
     */
 
3878
    public boolean isIconOf(Cell cell) {
 
3879
        return isIcon() && cellGroup == cell.cellGroup && cell.isSchematic();
 
3880
    }
 
3881
 
 
3882
    /**
 
3883
     * Method to return true if this Cell is a schematic Cell.
 
3884
     * @return true if this Cell is a schematic Cell.
 
3885
     */
 
3886
    public boolean isSchematic() {
 
3887
        return getId().isSchematic();
 
3888
    }
3903
3889
 
3904
3890
    /**
3905
3891
     * Method to return true if bus names are allowed in this Cell
3906
3892
     * @return true if bus names are allowed in this Cell
3907
3893
     */
3908
 
    public boolean busNamesAllowed() { return getD().busNamesAllowed(); }
 
3894
    public boolean busNamesAllowed() {
 
3895
        return getD().busNamesAllowed();
 
3896
    }
3909
3897
 
3910
3898
    /**
3911
3899
     * Method to return true if this Cell is a layout Cell.
3912
3900
     * @return true if this Cell is a layout Cell
3913
3901
     */
3914
 
    public boolean isLayout()
3915
 
    {
 
3902
    public boolean isLayout() {
3916
3903
        View w = getView();
3917
3904
        return w == View.LAYOUT || w == View.LAYOUTCOMP || w == View.LAYOUTSKEL;
3918
3905
    }
3919
3906
 
3920
3907
    /**
3921
 
         * Method to return the number of pages in this multi-page Cell.
3922
 
         * @return the number of different pages.
3923
 
         */
3924
 
        public int getNumMultiPages()
3925
 
        {
3926
 
                if (!isMultiPage()) return 1;
3927
 
                Rectangle2D bounds = getBounds();
3928
 
                int numPages = (int)(bounds.getHeight() / FrameDescription.MULTIPAGESEPARATION) + 1;
3929
 
                Integer storedCount = getVarValue(MULTIPAGE_COUNT_KEY, Integer.class);
3930
 
                if (storedCount != null)
3931
 
                {
3932
 
                        if (storedCount.intValue() > numPages) numPages = storedCount.intValue();
3933
 
                }
3934
 
                return numPages;
3935
 
        }
3936
 
 
3937
 
        /**
3938
 
         * Method to find the contents Cell associated with this Cell.
3939
 
         * This only makes sense if the current Cell is an icon or skeleton Cell.
3940
 
         * @return the contents Cell associated with this Cell.
3941
 
         * Returns null if no such Cell can be found.
3942
 
         */
3943
 
        public Cell contentsView()
3944
 
        {
3945
 
                // can only consider contents if this cell is an icon
3946
 
                if (!isIcon() && getView() != View.LAYOUTSKEL)
3947
 
                        return null;
3948
 
 
3949
 
                // first check to see if there is a schematics link
3950
 
                for(Iterator<Cell> it = getCellGroup().getCells(); it.hasNext(); )
3951
 
                {
3952
 
                        Cell cellInGroup = it.next();
3953
 
                        if (cellInGroup.isSchematic()) return cellInGroup;
3954
 
                }
3955
 
 
3956
 
                // now check to see if there is any layout link
3957
 
                for(Iterator<Cell> it = getCellGroup().getCells(); it.hasNext(); )
3958
 
                {
3959
 
                        Cell cellInGroup = it.next();
3960
 
                        if (cellInGroup.getView() == View.LAYOUT) return cellInGroup;
3961
 
                }
3962
 
 
3963
 
                // finally check to see if there is any "unknown" link
3964
 
                for(Iterator<Cell> it = getCellGroup().getCells(); it.hasNext(); )
3965
 
                {
3966
 
                        Cell cellInGroup = it.next();
3967
 
                        if (cellInGroup.getView() == View.UNKNOWN) return cellInGroup;
3968
 
                }
3969
 
 
3970
 
                // no contents found
3971
 
                return null;
3972
 
        }
3973
 
 
3974
 
        /**
3975
 
         * Method to find the icon Cell associated with this Cell.
3976
 
         * @return the icon Cell associated with this Cell.
3977
 
         * Returns null if no such Cell can be found.
3978
 
         */
3979
 
        public Cell iconView()
3980
 
        {
3981
 
                // can only get icon view if this is a schematic
3982
 
                if (!isSchematic()) return null;
3983
 
 
3984
 
                // now look for views
3985
 
                for(Iterator<Cell> it = getCellGroup().getCells(); it.hasNext(); )
3986
 
                {
3987
 
                        Cell cellInGroup = it.next();
3988
 
                        if (cellInGroup.isIcon()) return cellInGroup;
3989
 
                }
3990
 
 
3991
 
                return null;
3992
 
        }
3993
 
 
3994
 
        /**
3995
 
         * Method to find the Cell of a given View that is in the same group as this Cell.
 
3908
     * Method to return the number of pages in this multi-page Cell.
 
3909
     * @return the number of different pages.
 
3910
     */
 
3911
    public int getNumMultiPages() {
 
3912
        if (!isMultiPage()) {
 
3913
            return 1;
 
3914
        }
 
3915
        Rectangle2D bounds = getBounds();
 
3916
        int numPages = (int) (bounds.getHeight() / FrameDescription.MULTIPAGESEPARATION) + 1;
 
3917
        Integer storedCount = getVarValue(MULTIPAGE_COUNT_KEY, Integer.class);
 
3918
        if (storedCount != null) {
 
3919
            if (storedCount.intValue() > numPages) {
 
3920
                numPages = storedCount.intValue();
 
3921
            }
 
3922
        }
 
3923
        return numPages;
 
3924
    }
 
3925
 
 
3926
    /**
 
3927
     * Method to find the contents Cell associated with this Cell.
 
3928
     * This only makes sense if the current Cell is an icon or skeleton Cell.
 
3929
     * @return the contents Cell associated with this Cell.
 
3930
     * Returns null if no such Cell can be found.
 
3931
     */
 
3932
    public Cell contentsView() {
 
3933
        // can only consider contents if this cell is an icon
 
3934
        if (!isIcon() && getView() != View.LAYOUTSKEL) {
 
3935
            return null;
 
3936
        }
 
3937
 
 
3938
        // first check to see if there is a schematics link
 
3939
        for (Iterator<Cell> it = getCellGroup().getCells(); it.hasNext();) {
 
3940
            Cell cellInGroup = it.next();
 
3941
            if (cellInGroup.isSchematic()) {
 
3942
                return cellInGroup;
 
3943
            }
 
3944
        }
 
3945
 
 
3946
        // now check to see if there is any layout link
 
3947
        for (Iterator<Cell> it = getCellGroup().getCells(); it.hasNext();) {
 
3948
            Cell cellInGroup = it.next();
 
3949
            if (cellInGroup.getView() == View.LAYOUT) {
 
3950
                return cellInGroup;
 
3951
            }
 
3952
        }
 
3953
 
 
3954
        // finally check to see if there is any "unknown" link
 
3955
        for (Iterator<Cell> it = getCellGroup().getCells(); it.hasNext();) {
 
3956
            Cell cellInGroup = it.next();
 
3957
            if (cellInGroup.getView() == View.UNKNOWN) {
 
3958
                return cellInGroup;
 
3959
            }
 
3960
        }
 
3961
 
 
3962
        // no contents found
 
3963
        return null;
 
3964
    }
 
3965
 
 
3966
    /**
 
3967
     * Method to find the icon Cell associated with this Cell.
 
3968
     * @return the icon Cell associated with this Cell.
 
3969
     * Returns null if no such Cell can be found.
 
3970
     */
 
3971
    public Cell iconView() {
 
3972
        // can only get icon view if this is a schematic
 
3973
        if (!isSchematic()) {
 
3974
            return null;
 
3975
        }
 
3976
 
 
3977
        // now look for views
 
3978
        for (Iterator<Cell> it = getCellGroup().getCells(); it.hasNext();) {
 
3979
            Cell cellInGroup = it.next();
 
3980
            if (cellInGroup.isIcon()) {
 
3981
                return cellInGroup;
 
3982
            }
 
3983
        }
 
3984
 
 
3985
        return null;
 
3986
    }
 
3987
 
 
3988
    /**
 
3989
     * Method to find the Cell of a given View that is in the same group as this Cell.
3996
3990
     * If there is more than one cell matching the View, it will do a name match.
3997
 
         * @param view the View of the other Cell.
3998
 
         * @return the Cell from this group with the specified View.
3999
 
         * Returns null if no such Cell can be found.
4000
 
         */
4001
 
        public Cell otherView(View view)
4002
 
        {
 
3991
     * @param view the View of the other Cell.
 
3992
     * @return the Cell from this group with the specified View.
 
3993
     * Returns null if no such Cell can be found.
 
3994
     */
 
3995
    public Cell otherView(View view) {
4003
3996
        Cell otherViewCell = null;
4004
3997
 
4005
 
                // look for views
4006
 
                for(Iterator<Cell> it = getCellGroup().getCells(); it.hasNext(); )
4007
 
                {
4008
 
                        Cell cellInGroup = it.next();
4009
 
                        if (cellInGroup.getView() == view)
4010
 
            {
 
3998
        // look for views
 
3999
        for (Iterator<Cell> it = getCellGroup().getCells(); it.hasNext();) {
 
4000
            Cell cellInGroup = it.next();
 
4001
            if (cellInGroup.getView() == view) {
4011
4002
                otherViewCell = cellInGroup.getNewestVersion();
4012
4003
                // Perfect match including name
4013
 
                if (cellInGroup.getName().equals(getName()))
4014
 
                // get latest version
 
4004
                if (cellInGroup.getName().equals(getName())) // get latest version
 
4005
                {
4015
4006
                    return otherViewCell;
 
4007
                }
4016
4008
            }
4017
 
                }
4018
 
 
4019
 
                return otherViewCell;
4020
 
        }
4021
 
 
4022
 
        /****************************** NETWORKS ******************************/
4023
 
 
4024
 
        /** Recompute the Netlist structure for this Cell whithout shortening resistors.
4025
 
         * @return the Netlist structure for this cell.
4026
 
         * @throws NetworkTool.NetlistNotReady if called from GUI thread and change Job hasn't prepared Netlist yet
 
4009
        }
 
4010
 
 
4011
        return otherViewCell;
 
4012
    }
 
4013
 
 
4014
    /****************************** NETWORKS ******************************/
 
4015
    /** Recompute the Netlist structure for this Cell whithout shortening resistors.
 
4016
     * @return the Netlist structure for this cell.
 
4017
     * @throws NetworkTool.NetlistNotReady if called from GUI thread and change Job hasn't prepared Netlist yet
4027
4018
     */
4028
 
        public Netlist getNetlist() { return getNetlist(Netlist.ShortResistors.NO); }
 
4019
    public Netlist getNetlist() {
 
4020
        return getNetlist(Netlist.ShortResistors.NO);
 
4021
    }
4029
4022
 
4030
 
        /** Recompute the Netlist structure for this Cell.
 
4023
    /** Recompute the Netlist structure for this Cell.
4031
4024
     * @param shortResistors short resistors mode of Netlist.
4032
 
         * @return the Netlist structure for this cell.
4033
 
         * @throws NetworkTool.NetlistNotReady if called from GUI thread and change Job hasn't prepared Netlist yet
4034
 
     */
4035
 
        public Netlist getNetlist(Netlist.ShortResistors shortResistors) { return NetworkTool.getNetlist(this, shortResistors); }
4036
 
 
4037
 
        /** Returns the Netlist structure for this Cell, using current network options.
4038
 
         * Waits for completion of change Job when called from GUI thread
4039
 
         * @return the Netlist structure for this cell.
4040
 
     */
4041
 
        public Netlist getUserNetlist() { return NetworkTool.getUserNetlist(this); }
4042
 
 
4043
 
        /** Returns the Netlist structure for this Cell, using current network options.
4044
 
         * Returns null if change Job hasn't prepared GUI Netlist
4045
 
         * @return the Netlist structure for this cell.
4046
 
     */
4047
 
        public Netlist acquireUserNetlist() { return NetworkTool.acquireUserNetlist(this); }
4048
 
 
4049
 
        /****************************** DATES ******************************/
4050
 
 
4051
 
        /**
4052
 
         * Method to get the creation date of this Cell.
4053
 
         * @return the creation date of this Cell.
4054
 
         */
4055
 
        public Date getCreationDate() { return new Date(getD().creationDate); }
4056
 
 
4057
 
        /**
4058
 
         * Method to set this Cell's creation date.
4059
 
         * This is a low-level method and should not be called unless you know what you are doing.
4060
 
         * @param creationDate the date of this Cell's creation.
4061
 
         */
4062
 
        public void lowLevelSetCreationDate(Date creationDate) { setD(getD().withCreationDate(creationDate.getTime())); }
4063
 
 
4064
 
        /**
4065
 
         * Method to return the revision date of this Cell.
4066
 
         * @return the revision date of this Cell.
4067
 
         */
4068
 
        public Date getRevisionDate() { return new Date(getD().revisionDate); }
4069
 
 
4070
 
        /**
4071
 
         * Method to set this Cell's last revision date.
4072
 
         * This is a low-level method and should not be called unless you know what you are doing.
4073
 
         * @param revisionDate the date of this Cell's last revision.
4074
 
         */
4075
 
        public void lowLevelSetRevisionDate(Date revisionDate) {
 
4025
     * @return the Netlist structure for this cell.
 
4026
     * @throws NetworkTool.NetlistNotReady if called from GUI thread and change Job hasn't prepared Netlist yet
 
4027
     */
 
4028
    public Netlist getNetlist(Netlist.ShortResistors shortResistors) {
 
4029
        if (NetworkTool.isLazy()) {
 
4030
            NetCell netCell = netCellRef.get();
 
4031
            if (netCell == null) {
 
4032
                netCell = NetCell.newInstance(this);
 
4033
                setNetCellRef(netCell);
 
4034
            }
 
4035
            return netCell.getNetlist(shortResistors);
 
4036
        } else {
 
4037
            return NetworkTool.getNetlist(this, shortResistors);
 
4038
        }
 
4039
    }
 
4040
 
 
4041
    private void setNetCellRef(NetCell netCell) {
 
4042
        netCellRef = USE_WEAK_REFERENCES ? new WeakReference<NetCell>(netCell) : new SoftReference<NetCell>(netCell);
 
4043
    }
 
4044
 
 
4045
    /** Returns the Netlist structure for this Cell, using current network options.
 
4046
     * Waits for completion of change Job when called from GUI thread
 
4047
     * @return the Netlist structure for this cell.
 
4048
     */
 
4049
    public Netlist getUserNetlist() {
 
4050
        return Job.isThreadSafe() ? getNetlist() : NetworkTool.getUserNetlist(this);
 
4051
    }
 
4052
 
 
4053
    /** Returns the Netlist structure for this Cell, using current network options.
 
4054
     * Returns null if change Job hasn't prepared GUI Netlist
 
4055
     * @return the Netlist structure for this cell.
 
4056
     */
 
4057
    public Netlist acquireUserNetlist() {
 
4058
        return Job.isThreadSafe() ? getNetlist() : NetworkTool.acquireUserNetlist(this);
 
4059
    }
 
4060
 
 
4061
    /****************************** DATES ******************************/
 
4062
    /**
 
4063
     * Method to get the creation date of this Cell.
 
4064
     * @return the creation date of this Cell.
 
4065
     */
 
4066
    public Date getCreationDate() {
 
4067
        return new Date(getD().creationDate);
 
4068
    }
 
4069
 
 
4070
    /**
 
4071
     * Method to set this Cell's creation date.
 
4072
     * This is a low-level method and should not be called unless you know what you are doing.
 
4073
     * @param creationDate the date of this Cell's creation.
 
4074
     */
 
4075
    public void lowLevelSetCreationDate(Date creationDate) {
 
4076
        setD(getD().withCreationDate(creationDate.getTime()));
 
4077
    }
 
4078
 
 
4079
    /**
 
4080
     * Method to return the revision date of this Cell.
 
4081
     * @return the revision date of this Cell.
 
4082
     */
 
4083
    public Date getRevisionDate() {
 
4084
        return new Date(getD().revisionDate);
 
4085
    }
 
4086
 
 
4087
    /**
 
4088
     * Method to set this Cell's last revision date.
 
4089
     * This is a low-level method and should not be called unless you know what you are doing.
 
4090
     * @param revisionDate the date of this Cell's last revision.
 
4091
     */
 
4092
    public void lowLevelSetRevisionDate(Date revisionDate) {
4076
4093
        lowLevelSetRevisionDate(revisionDate.getTime());
4077
4094
    }
4078
4095
 
4079
 
        /**
4080
 
         * Method to set this Cell's revision date and user name.
 
4096
    /**
 
4097
     * Method to set this Cell's revision date and user name.
4081
4098
     * Change system is not informed about this.
4082
 
         * This is a low-level method and should not be called unless you know what you are doing.
4083
 
         */
4084
 
        public void lowLevelMadeRevision(long revisionDate, String userName, CellRevision oldRevision) {
 
4099
     * This is a low-level method and should not be called unless you know what you are doing.
 
4100
     */
 
4101
    public void lowLevelMadeRevision(long revisionDate, String userName, CellRevision oldRevision) {
4085
4102
        backup();
4086
 
        if (!isModified() || backup.cellRevision == oldRevision || revisionDateFresh)
 
4103
        if (!isModified() || backup.cellRevision == oldRevision || revisionDateFresh) {
4087
4104
            return;
 
4105
        }
4088
4106
        lowLevelSetRevisionDate(revisionDate);
4089
 
        }
 
4107
    }
4090
4108
 
4091
 
        private void lowLevelSetRevisionDate(long revisionDate) {
 
4109
    private void lowLevelSetRevisionDate(long revisionDate) {
4092
4110
        backup = backup().withRevisionDate(revisionDate);
4093
4111
        d = backup.cellRevision.d;
4094
4112
        revisionDateFresh = true;
 
4113
        unfreshCellTree();
4095
4114
        database.unfreshSnapshot();
4096
4115
    }
4097
4116
 
4098
 
        /**
4099
 
         * Method to check the current cell to be sure that no subcells have a more recent date.
4100
 
         * This is invoked when the "Check cell dates" feature is enabled in the New Nodes tab of
4101
 
         * the Edit Options dialog.
4102
 
         */
4103
 
        public void checkCellDates()
4104
 
        {
4105
 
                Set<Cell> cellsChecked = new HashSet<Cell>();
4106
 
                checkCellDate(getRevisionDate(), cellsChecked);
4107
 
        }
4108
 
 
4109
 
        /**
4110
 
         * Recursive method to check sub-cell revision times.
4111
 
         * @param rev_time the revision date of the top-level cell.
4112
 
         * Nothing below it can be newer.
4113
 
         */
4114
 
        private void checkCellDate(Date rev_time, Set<Cell> cellsChecked)
4115
 
        {
4116
 
                for(Iterator<NodeInst> it = getNodes(); it.hasNext(); )
4117
 
                {
4118
 
                        NodeInst ni = it.next();
4119
 
                        if (!ni.isCellInstance()) continue;
4120
 
                        Cell subCell = (Cell)ni.getProto();
4121
 
 
4122
 
                        // ignore recursive references (showing icon in contents)
4123
 
                        if (subCell.isIconOf(this)) continue;
4124
 
                        if (!cellsChecked.contains(subCell))
4125
 
                        {
4126
 
                                subCell.checkCellDate(rev_time, cellsChecked); // recurse
4127
 
                        }
4128
 
 
4129
 
                        Cell contentsCell = subCell.contentsView();
4130
 
                        if (contentsCell != null)
4131
 
                        {
4132
 
                                if (!cellsChecked.contains(contentsCell))
4133
 
                                {
4134
 
                                        contentsCell.checkCellDate(rev_time, cellsChecked); // recurse
4135
 
                                }
4136
 
                        }
4137
 
                }
4138
 
 
4139
 
                // check this cell
4140
 
                cellsChecked.add(this); // flag that we have seen this one
4141
 
                if (!getRevisionDate().after(rev_time)) return;
4142
 
 
4143
 
                // possible error in hierarchy
4144
 
                System.out.println("WARNING: sub-cell " + this +
4145
 
                        " has been edited since the last revision to the current cell");
4146
 
        }
4147
 
 
4148
 
        /****************************** MISCELLANEOUS ******************************/
4149
 
 
4150
 
    private int getFlags() { return d.flags; }
4151
 
 
4152
 
    private boolean isFlag(int mask) { return (getFlags() & mask) != 0; }
4153
 
 
4154
 
    private void setFlag(int mask, boolean value) { lowLevelSetUserbits(value ? getFlags() | mask : getFlags() & ~mask); }
4155
 
 
4156
 
        /**
4157
 
         * Method to set this Cell so that instances of it are "expanded" by when created.
4158
 
         * Expanded NodeInsts are instances of Cells that show their contents.
4159
 
         */
4160
 
        public void setWantExpanded() { setFlag(WANTNEXPAND, true); }
4161
 
 
4162
 
        /**
4163
 
         * Method to set this Cell so that instances of it are "not expanded" by when created.
4164
 
         * Expanded NodeInsts are instances of Cells that show their contents.
4165
 
         */
4166
 
        public void clearWantExpanded() { setFlag(WANTNEXPAND, false); }
4167
 
 
4168
 
        /**
4169
 
         * Method to tell if instances of it are "expanded" by when created.
4170
 
         * Expanded NodeInsts are instances of Cells that show their contents.
4171
 
         * @return true if instances of it are "expanded" by when created.
4172
 
         */
4173
 
        public boolean isWantExpanded() { return isFlag(WANTNEXPAND) || isIcon(); }
4174
 
 
4175
 
        /**
4176
 
         * Method to return the function of this Cell.
4177
 
         * The Function of CELL is alway UNKNOWN.
4178
 
         * @return the function of this Cell.
4179
 
         */
4180
 
        public PrimitiveNode.Function getFunction() { return PrimitiveNode.Function.UNKNOWN; }
4181
 
 
4182
 
        /**
4183
 
         * Method to set this Cell so that everything inside of it is locked.
4184
 
         * Locked instances cannot be moved or deleted.
4185
 
         */
4186
 
        public void setAllLocked() { setFlag(NPLOCKED, true); }
4187
 
 
4188
 
        /**
4189
 
         * Method to set this Cell so that everything inside of it is not locked.
4190
 
         * Locked instances cannot be moved or deleted.
4191
 
         */
4192
 
        public void clearAllLocked() { setFlag(NPLOCKED, false); }
4193
 
 
4194
 
        /**
4195
 
         * Method to tell if the contents of this Cell are locked.
4196
 
         * Locked instances cannot be moved or deleted.
4197
 
         * @return true if the contents of this Cell are locked.
4198
 
         */
4199
 
        public boolean isAllLocked() { return isFlag(NPLOCKED); }
4200
 
 
4201
 
        /**
4202
 
         * Method to set this Cell so that all instances inside of it are locked.
4203
 
         * Locked instances cannot be moved or deleted.
4204
 
         */
4205
 
        public void setInstancesLocked() { setFlag(NPILOCKED, true); }
4206
 
 
4207
 
        /**
4208
 
         * Method to set this Cell so that all instances inside of it are not locked.
4209
 
         * Locked instances cannot be moved or deleted.
4210
 
         */
4211
 
        public void clearInstancesLocked() { setFlag(NPILOCKED, false); }
4212
 
 
4213
 
        /**
4214
 
         * Method to tell if the sub-instances in this Cell are locked.
4215
 
         * Locked instances cannot be moved or deleted.
4216
 
         * @return true if the sub-instances in this Cell are locked.
4217
 
         */
4218
 
        public boolean isInstancesLocked() { return isFlag(NPILOCKED); }
4219
 
 
4220
 
        /**
4221
 
         * Method to set this Cell so that it is part of a cell library.
4222
 
         * Cell libraries are simply libraries that contain standard cells but no hierarchy
4223
 
         * (as opposed to libraries that define a complete circuit).
4224
 
         * Certain commands exclude facets from cell libraries, so that the actual circuit hierarchy can be more clearly seen.
4225
 
         */
4226
 
        public void setInCellLibrary() { setFlag(INCELLLIBRARY, true); }
 
4117
    /**
 
4118
     * Method to check the current cell to be sure that no subcells have a more recent date.
 
4119
     * This is invoked when the "Check cell dates" feature is enabled in the New Nodes tab of
 
4120
     * the Edit Options dialog.
 
4121
     */
 
4122
    public void checkCellDates() {
 
4123
        Set<Cell> cellsChecked = new HashSet<Cell>();
 
4124
        checkCellDate(getRevisionDate(), cellsChecked);
 
4125
    }
 
4126
 
 
4127
    /**
 
4128
     * Recursive method to check sub-cell revision times.
 
4129
     * @param rev_time the revision date of the top-level cell.
 
4130
     * Nothing below it can be newer.
 
4131
     */
 
4132
    private void checkCellDate(Date rev_time, Set<Cell> cellsChecked) {
 
4133
        for (Iterator<NodeInst> it = getNodes(); it.hasNext();) {
 
4134
            NodeInst ni = it.next();
 
4135
            if (!ni.isCellInstance()) {
 
4136
                continue;
 
4137
            }
 
4138
            Cell subCell = (Cell) ni.getProto();
 
4139
 
 
4140
            // ignore recursive references (showing icon in contents)
 
4141
            if (subCell.isIconOf(this)) {
 
4142
                continue;
 
4143
            }
 
4144
            if (!cellsChecked.contains(subCell)) {
 
4145
                subCell.checkCellDate(rev_time, cellsChecked); // recurse
 
4146
            }
 
4147
 
 
4148
            Cell contentsCell = subCell.contentsView();
 
4149
            if (contentsCell != null) {
 
4150
                if (!cellsChecked.contains(contentsCell)) {
 
4151
                    contentsCell.checkCellDate(rev_time, cellsChecked); // recurse
 
4152
                }
 
4153
            }
 
4154
        }
 
4155
 
 
4156
        // check this cell
 
4157
        cellsChecked.add(this); // flag that we have seen this one
 
4158
        if (!getRevisionDate().after(rev_time)) {
 
4159
            return;
 
4160
        }
 
4161
 
 
4162
        // possible error in hierarchy
 
4163
        System.out.println("WARNING: sub-cell " + this
 
4164
                + " has been edited since the last revision to the current cell");
 
4165
    }
 
4166
 
 
4167
    /****************************** MISCELLANEOUS ******************************/
 
4168
    private int getFlags() {
 
4169
        return d.flags;
 
4170
    }
 
4171
 
 
4172
    private boolean isFlag(int mask) {
 
4173
        return (getFlags() & mask) != 0;
 
4174
    }
 
4175
 
 
4176
    private void setFlag(int mask, boolean value) {
 
4177
        lowLevelSetUserbits(value ? getFlags() | mask : getFlags() & ~mask);
 
4178
    }
 
4179
 
 
4180
    /**
 
4181
     * Method to set this Cell so that instances of it are "expanded" by when created.
 
4182
     * Expanded NodeInsts are instances of Cells that show their contents.
 
4183
     */
 
4184
    public void setWantExpanded() {
 
4185
        setFlag(WANTNEXPAND, true);
 
4186
    }
 
4187
 
 
4188
    /**
 
4189
     * Method to set this Cell so that instances of it are "not expanded" by when created.
 
4190
     * Expanded NodeInsts are instances of Cells that show their contents.
 
4191
     */
 
4192
    public void clearWantExpanded() {
 
4193
        setFlag(WANTNEXPAND, false);
 
4194
    }
 
4195
 
 
4196
    /**
 
4197
     * Method to tell if instances of it are "expanded" by when created.
 
4198
     * Expanded NodeInsts are instances of Cells that show their contents.
 
4199
     * @return true if instances of it are "expanded" by when created.
 
4200
     */
 
4201
    public boolean isWantExpanded() {
 
4202
        return isFlag(WANTNEXPAND) || isIcon();
 
4203
    }
 
4204
 
 
4205
    /**
 
4206
     * Method to return the function of this Cell.
 
4207
     * The Function of CELL is alway UNKNOWN.
 
4208
     * @return the function of this Cell.
 
4209
     */
 
4210
    public PrimitiveNode.Function getFunction() {
 
4211
        return PrimitiveNode.Function.UNKNOWN;
 
4212
    }
 
4213
 
 
4214
    /**
 
4215
     * Method to set this Cell so that everything inside of it is locked.
 
4216
     * Locked instances cannot be moved or deleted.
 
4217
     */
 
4218
    public void setAllLocked() {
 
4219
        setFlag(NPLOCKED, true);
 
4220
    }
 
4221
 
 
4222
    /**
 
4223
     * Method to set this Cell so that everything inside of it is not locked.
 
4224
     * Locked instances cannot be moved or deleted.
 
4225
     */
 
4226
    public void clearAllLocked() {
 
4227
        setFlag(NPLOCKED, false);
 
4228
    }
 
4229
 
 
4230
    /**
 
4231
     * Method to tell if the contents of this Cell are locked.
 
4232
     * Locked instances cannot be moved or deleted.
 
4233
     * @return true if the contents of this Cell are locked.
 
4234
     */
 
4235
    public boolean isAllLocked() {
 
4236
        return isFlag(NPLOCKED);
 
4237
    }
 
4238
 
 
4239
    /**
 
4240
     * Method to set this Cell so that all instances inside of it are locked.
 
4241
     * Locked instances cannot be moved or deleted.
 
4242
     */
 
4243
    public void setInstancesLocked() {
 
4244
        setFlag(NPILOCKED, true);
 
4245
    }
 
4246
 
 
4247
    /**
 
4248
     * Method to set this Cell so that all instances inside of it are not locked.
 
4249
     * Locked instances cannot be moved or deleted.
 
4250
     */
 
4251
    public void clearInstancesLocked() {
 
4252
        setFlag(NPILOCKED, false);
 
4253
    }
 
4254
 
 
4255
    /**
 
4256
     * Method to tell if the sub-instances in this Cell are locked.
 
4257
     * Locked instances cannot be moved or deleted.
 
4258
     * @return true if the sub-instances in this Cell are locked.
 
4259
     */
 
4260
    public boolean isInstancesLocked() {
 
4261
        return isFlag(NPILOCKED);
 
4262
    }
 
4263
 
 
4264
    /**
 
4265
     * Method to set this Cell so that it is part of a cell library.
 
4266
     * Cell libraries are simply libraries that contain standard cells but no hierarchy
 
4267
     * (as opposed to libraries that define a complete circuit).
 
4268
     * Certain commands exclude facets from cell libraries, so that the actual circuit hierarchy can be more clearly seen.
 
4269
     */
 
4270
    public void setInCellLibrary() {
 
4271
        setFlag(INCELLLIBRARY, true);
 
4272
    }
4227
4273
 
4228
4274
//      /**
4229
4275
//       * Method to set this Cell so that it is not part of a cell library.
4241
4287
//       * @return true if this Cell is part of a cell library.
4242
4288
//       */
4243
4289
//      public boolean isInCellLibrary() { return isFlag(INCELLLIBRARY); }
4244
 
 
4245
 
        /**
4246
 
         * Method to set this Cell so that it is part of a technology library.
4247
 
         * Technology libraries are those libraries that contain Cells with
4248
 
         * graphical descriptions of the nodes, arcs, and layers of a technology.
4249
 
         */
4250
 
        public void setInTechnologyLibrary() { setFlag(TECEDITCELL, true); }
4251
 
 
4252
 
        /**
4253
 
         * Method to set this Cell so that it is not part of a technology library.
4254
 
         * Technology libraries are those libraries that contain Cells with
4255
 
         * graphical descriptions of the nodes, arcs, and layers of a technology.
4256
 
         */
4257
 
        public void clearInTechnologyLibrary() { setFlag(TECEDITCELL, false); }
4258
 
 
4259
 
        /**
4260
 
         * Method to tell if this Cell is part of a Technology Library.
4261
 
         * Technology libraries are those libraries that contain Cells with
4262
 
         * graphical descriptions of the nodes, arcs, and layers of a technology.
4263
 
         * @return true if this Cell is part of a Technology Library.
4264
 
         */
4265
 
        public boolean isInTechnologyLibrary() { return isFlag(TECEDITCELL); }
4266
 
 
4267
 
        /**
4268
 
         * Method to clear this Cell modified bit since last save to disk. No need to call checkChanging().
 
4290
    /**
 
4291
     * Method to set this Cell so that it is part of a technology library.
 
4292
     * Technology libraries are those libraries that contain Cells with
 
4293
     * graphical descriptions of the nodes, arcs, and layers of a technology.
 
4294
     */
 
4295
    public void setInTechnologyLibrary() {
 
4296
        setFlag(TECEDITCELL, true);
 
4297
    }
 
4298
 
 
4299
    /**
 
4300
     * Method to set this Cell so that it is not part of a technology library.
 
4301
     * Technology libraries are those libraries that contain Cells with
 
4302
     * graphical descriptions of the nodes, arcs, and layers of a technology.
 
4303
     */
 
4304
    public void clearInTechnologyLibrary() {
 
4305
        setFlag(TECEDITCELL, false);
 
4306
    }
 
4307
 
 
4308
    /**
 
4309
     * Method to tell if this Cell is part of a Technology Library.
 
4310
     * Technology libraries are those libraries that contain Cells with
 
4311
     * graphical descriptions of the nodes, arcs, and layers of a technology.
 
4312
     * @return true if this Cell is part of a Technology Library.
 
4313
     */
 
4314
    public boolean isInTechnologyLibrary() {
 
4315
        return isFlag(TECEDITCELL);
 
4316
    }
 
4317
 
 
4318
    /**
 
4319
     * Method to clear this Cell modified bit since last save to disk. No need to call checkChanging().
4269
4320
     * This is done when the library contained this cell is saved to disk.
4270
 
         */
4271
 
        void clearModified() {
 
4321
     */
 
4322
    void clearModified() {
4272
4323
        if (isModified()) {
4273
4324
            backup = backup().withoutModified();
 
4325
            unfreshCellTree();
4274
4326
            database.unfreshSnapshot();
4275
4327
        }
4276
4328
        assert cellBackupFresh;
4277
4329
        revisionDateFresh = true;
4278
4330
    }
4279
4331
 
4280
 
        /**
4281
 
         * Method to tell if this Cell has been modified since last save to disk.
4282
 
         * @return true if cell has been modified.
4283
 
         */
4284
 
        public boolean isModified() {
 
4332
    /**
 
4333
     * Method to tell if this Cell has been modified since last save to disk.
 
4334
     * @return true if cell has been modified.
 
4335
     */
 
4336
    public boolean isModified() {
4285
4337
        return !cellBackupFresh || backup.modified;
4286
4338
    }
4287
4339
 
4288
4340
    public void setTopologyModified() {
 
4341
        strongTopology = getTopology();
4289
4342
        setContentsModified();
4290
4343
    }
4291
4344
 
4292
4345
    /**
4293
 
         * Method to set if cell has been modified in the batch job.
4294
 
         */
4295
 
        public void setContentsModified() {
 
4346
     * Method to set if cell has been modified in the batch job.
 
4347
     */
 
4348
    public void setContentsModified() {
4296
4349
        cellContentsFresh = false;
4297
4350
        unfreshBackup();
4298
4351
    }
4299
4352
 
 
4353
    private void unfreshCellTree() {
 
4354
        if (!cellTreeFresh) {
 
4355
            return;
 
4356
        }
 
4357
        unfreshRTree();
 
4358
        Topology topology = getTopologyOptional();
 
4359
        if (topology != null) {
 
4360
            for (Iterator<NodeInst> it = topology.getNodes(); it.hasNext();) {
 
4361
                NodeInst ni = it.next();
 
4362
                if (ni.isCellInstance()) {
 
4363
                    ni.redoGeometric();
 
4364
                }
 
4365
            }
 
4366
        }
 
4367
        cellTreeFresh = false;
 
4368
        for (Iterator<CellUsage> it = getUsagesOf(); it.hasNext();) {
 
4369
            CellUsage cu = it.next();
 
4370
            Cell cell = database.getCell(cu.parentId);
 
4371
            cell.unfreshCellTree();
 
4372
        }
 
4373
    }
 
4374
 
4300
4375
    private void unfreshBackup() {
4301
4376
        cellBackupFresh = false;
4302
4377
        revisionDateFresh = false;
 
4378
        unfreshCellTree();
4303
4379
        database.unfreshSnapshot();
4304
4380
    }
4305
4381
 
4306
 
    private void unfreshRTree() { topology.unfreshRTree(); }
 
4382
    public void unfreshRTree() {
 
4383
        Topology topology = getTopologyOptional();
 
4384
        if (topology != null) {
 
4385
            topology.unfreshRTree();
 
4386
        }
 
4387
    }
4307
4388
 
4308
4389
    /**
4309
4390
     * Method to load isExpanded status of subcell instances from Preferences.
4313
4394
        String cellKey = "E" + cellName;
4314
4395
        boolean useWantExpanded = false, mostExpanded = false;
4315
4396
        Preferences libPrefs = Pref.getLibraryPreferences(getId().libId);
4316
 
        if (libPrefs.get(cellKey, null) == null)
 
4397
        if (libPrefs.get(cellKey, null) == null) {
4317
4398
            useWantExpanded = true;
4318
 
        else
 
4399
        } else {
4319
4400
            mostExpanded = libPrefs.getBoolean(cellKey, false);
 
4401
        }
4320
4402
        Preferences cellPrefs = null;
4321
4403
        try {
4322
 
            if (libPrefs.nodeExists(cellName))
 
4404
            if (libPrefs.nodeExists(cellName)) {
4323
4405
                cellPrefs = libPrefs.node(cellName);
 
4406
            }
4324
4407
        } catch (BackingStoreException e) {
4325
4408
            ActivityLogger.logException(e);
4326
4409
        }
4327
 
        for (Iterator<NodeInst> it = getNodes(); it.hasNext(); ) {
 
4410
        for (Iterator<NodeInst> it = getNodes(); it.hasNext();) {
4328
4411
            NodeInst ni = it.next();
4329
 
            if (!ni.isCellInstance()) continue;
4330
 
            boolean expanded = useWantExpanded ? ((Cell)ni.getProto()).isWantExpanded() : mostExpanded;
 
4412
            if (!ni.isCellInstance()) {
 
4413
                continue;
 
4414
            }
 
4415
            boolean expanded = useWantExpanded ? ((Cell) ni.getProto()).isWantExpanded() : mostExpanded;
4331
4416
            if (cellPrefs != null) {
4332
4417
                String nodeName = "E" + ni.getName();
4333
4418
                expanded = cellPrefs.getBoolean(nodeName, expanded);
4341
4426
     * Method to save isExpanded status of subcell instances to Preferences.
4342
4427
     */
4343
4428
    void saveExpandStatus() throws BackingStoreException {
4344
 
        if (!expandStatusModified) return;
4345
 
        if (Job.getDebug()) System.err.println("Save expanded status of " + this);
 
4429
        if (!expandStatusModified) {
 
4430
            return;
 
4431
        }
 
4432
        if (Job.getDebug()) {
 
4433
            System.err.println("Save expanded status of " + this);
 
4434
        }
4346
4435
        int num = 0, expanded = 0, diff = 0;
4347
 
        for (Iterator<NodeInst> it = getNodes(); it.hasNext(); ) {
 
4436
        for (Iterator<NodeInst> it = getNodes(); it.hasNext();) {
4348
4437
            NodeInst ni = it.next();
4349
 
            if (!ni.isCellInstance()) continue;
 
4438
            if (!ni.isCellInstance()) {
 
4439
                continue;
 
4440
            }
4350
4441
            num++;
4351
4442
            boolean isExpanded = isExpanded(ni.getD().nodeId);
4352
 
            if (isExpanded) expanded++;
4353
 
            if (isExpanded != ((Cell)ni.getProto()).isWantExpanded())
 
4443
            if (isExpanded) {
 
4444
                expanded++;
 
4445
            }
 
4446
            if (isExpanded != ((Cell) ni.getProto()).isWantExpanded()) {
4354
4447
                diff++;
 
4448
            }
4355
4449
        }
4356
4450
        String cellName = noLibDescribe().replace('/', ':');
4357
4451
        String cellKey = "E" + cellName;
4377
4471
            Preferences cellPrefs = libPrefs.node(cellName);
4378
4472
            cellPrefs.clear();
4379
4473
            cellPrefs.put("CELL", cellName);
4380
 
            for (Iterator<NodeInst> it = getNodes(); it.hasNext(); ) {
 
4474
            for (Iterator<NodeInst> it = getNodes(); it.hasNext();) {
4381
4475
                NodeInst ni = it.next();
4382
 
                if (!ni.isCellInstance()) continue;
4383
 
                boolean defaultExpanded = useWantExpanded ? ((Cell)ni.getProto()).isWantExpanded() : mostExpanded;
 
4476
                if (!ni.isCellInstance()) {
 
4477
                    continue;
 
4478
                }
 
4479
                boolean defaultExpanded = useWantExpanded ? ((Cell) ni.getProto()).isWantExpanded() : mostExpanded;
4384
4480
                boolean isExpanded = isExpanded(ni.getD().nodeId);
4385
4481
                if (isExpanded != defaultExpanded) {
4386
4482
                    String nodeName = "E" + ni.getName();
4392
4488
    }
4393
4489
 
4394
4490
    /**
4395
 
         * Method to set the multi-page capability of this Cell.
4396
 
         * Multipage cells (usually schematics) must have cell frames to isolate the different
4397
 
         * areas of the cell that are different pages.
4398
 
         * @param multi true to make this cell multi-page.
4399
 
         */
4400
 
        public void setMultiPage(boolean multi) { setFlag(MULTIPAGE, multi); }
 
4491
     * Method to set the multi-page capability of this Cell.
 
4492
     * Multipage cells (usually schematics) must have cell frames to isolate the different
 
4493
     * areas of the cell that are different pages.
 
4494
     * @param multi true to make this cell multi-page.
 
4495
     */
 
4496
    public void setMultiPage(boolean multi) {
 
4497
        setFlag(MULTIPAGE, multi);
 
4498
    }
4401
4499
 
4402
 
        /**
4403
 
         * Method to tell if this Cell is a multi-page drawing.
4404
 
         * Multipage cells (usually schematics) must have cell frames to isolate the different
4405
 
         * areas of the cell that are different pages.
4406
 
         * @return true if this Cell is a multi-page drawing.
4407
 
         */
4408
 
        public boolean isMultiPage() { return isFlag(MULTIPAGE); }
 
4500
    /**
 
4501
     * Method to tell if this Cell is a multi-page drawing.
 
4502
     * Multipage cells (usually schematics) must have cell frames to isolate the different
 
4503
     * areas of the cell that are different pages.
 
4504
     * @return true if this Cell is a multi-page drawing.
 
4505
     */
 
4506
    public boolean isMultiPage() {
 
4507
        return isFlag(MULTIPAGE);
 
4508
    }
4409
4509
 
4410
4510
    /**
4411
4511
     * Returns true if this Cell is linked into database.
4412
4512
     * @return true if this Cell is linked into database.
4413
4513
     */
4414
 
        public boolean isLinked()
4415
 
        {
 
4514
    public boolean isLinked() {
 
4515
        database.checkExamine();
4416
4516
        return inCurrentThread(getId()) == this;
4417
 
        }
 
4517
    }
4418
4518
 
4419
 
        /**
4420
 
         * Returns database to which this Cell belongs.
 
4519
    /**
 
4520
     * Returns database to which this Cell belongs.
4421
4521
     * @return database to which this ElectricObject belongs.
4422
 
         */
4423
 
        public EDatabase getDatabase() { return database; }
 
4522
     */
 
4523
    public EDatabase getDatabase() {
 
4524
        return database;
 
4525
    }
4424
4526
 
4425
 
        /**
4426
 
         * Method to check and repair data structure errors in this Cell.
4427
 
         */
4428
 
        public int checkAndRepair(boolean repair, ErrorLogger errorLogger)
4429
 
        {
4430
 
                int errorCount = 0;
 
4527
    /**
 
4528
     * Method to check and repair data structure errors in this Cell.
 
4529
     */
 
4530
    public int checkAndRepair(boolean repair, ErrorLogger errorLogger) {
 
4531
        int errorCount = 0;
4431
4532
        List<Geometric> list = new ArrayList<Geometric>();
4432
4533
 
4433
 
                for(Iterator<ArcInst> it = getArcs(); it.hasNext(); )
4434
 
                {
4435
 
                        ArcInst ai = it.next();
 
4534
        for (Iterator<ArcInst> it = getArcs(); it.hasNext();) {
 
4535
            ArcInst ai = it.next();
4436
4536
            errorCount += ai.checkAndRepair(repair, list, errorLogger);
4437
 
                }
4438
 
                for(Iterator<NodeInst> it = getNodes(); it.hasNext(); )
4439
 
                {
4440
 
                        NodeInst ni = it.next();
4441
 
                        errorCount += ni.checkAndRepair(repair, list, errorLogger);
4442
 
                }
4443
 
        if (repair && list.size() > 0)
4444
 
        {
4445
 
                CircuitChangeJobs.eraseObjectsInList(this, list, false, null);
 
4537
        }
 
4538
        for (Iterator<NodeInst> it = getNodes(); it.hasNext();) {
 
4539
            NodeInst ni = it.next();
 
4540
            errorCount += ni.checkAndRepair(repair, list, errorLogger);
 
4541
        }
 
4542
        if (repair && list.size() > 0) {
 
4543
            CircuitChangeJobs.eraseObjectsInList(this, list, false, null);
4446
4544
        }
4447
4545
 
4448
4546
        if (isSchematic() && getNewestVersion() == this && getCellGroup().getMainSchematics() != this) {
4449
4547
            String mainSchemMsg = "Extraneous schematic cell " + describe(false) + " in cell group " + lib.getName() + ":" + getCellGroup().getName();
4450
4548
            System.out.println(mainSchemMsg);
4451
 
            if (errorLogger != null)
 
4549
            if (errorLogger != null) {
4452
4550
                errorLogger.logWarning(mainSchemMsg, this, 1);
 
4551
            }
4453
4552
        }
4454
4553
 
4455
 
        for (Cell cell: cellGroup.cells) {
 
4554
        for (Cell cell : cellGroup.cells) {
4456
4555
            Variable var = cell.getParameterOrVariable(NccCellAnnotations.NCC_ANNOTATION_KEY);
4457
4556
            if (var != null && var.isInherit()) {
4458
4557
                // cleanup NCC cell annotations which were inheritable
4459
4558
                String nccMsg = "Cleaned up NCC annotations in cell " + cell.describe(false);
4460
4559
                if (repair) {
4461
 
                    if (isParam(var.getKey()))
4462
 
                        getCellGroup().delParam((Variable.AttrKey)var.getKey());
 
4560
                    if (isParam(var.getKey())) {
 
4561
                        getCellGroup().delParam((Variable.AttrKey) var.getKey());
 
4562
                    }
4463
4563
                    cell.addVar(var.withInherit(false).withParam(false).withInterior(true));
4464
4564
                    nccMsg += " (REPAIRED)";
4465
4565
                }
4466
4566
                System.out.println(nccMsg);
4467
 
                if (errorLogger != null)
 
4567
                if (errorLogger != null) {
4468
4568
                    errorLogger.logWarning(nccMsg, cell, 1);
 
4569
                }
4469
4570
            }
4470
4571
        }
4471
4572
 
4472
 
                return errorCount;
4473
 
        }
 
4573
        return errorCount;
 
4574
    }
4474
4575
 
4475
4576
    /**
4476
4577
     * Method to check invariants in this Cell.
4477
4578
     * @exception AssertionError if invariants are not valid
4478
4579
     */
 
4580
    @Override
4479
4581
    protected void check() {
4480
4582
        CellId cellId = getD().cellId;
4481
4583
        super.check();
4482
4584
        assert database.getCell(cellId) == this;
4483
4585
        assert database.getLib(getD().getLibId()) == lib;
4484
 
        if (getD().techId != null)
 
4586
        if (getD().techId != null) {
4485
4587
            assert tech == database.getTech(getD().techId);
4486
 
        else
 
4588
        } else {
4487
4589
            assert tech == null;
 
4590
        }
4488
4591
        assert getCellName() != null;
4489
4592
        assert getVersion() > 0;
4490
4593
 
 
4594
        if (cellTreeFresh) {
 
4595
            assert cellBackupFresh;
 
4596
            assert backup == tree.top;
 
4597
            for (CellTree subCellTree : tree.getSubTrees()) {
 
4598
                if (subCellTree == null) {
 
4599
                    continue;
 
4600
                }
 
4601
                Cell subCell = database.getCell(subCellTree.top.cellRevision.d.cellId);
 
4602
                assert subCell.cellTreeFresh;
 
4603
                assert subCell.tree == subCellTree;
 
4604
            }
 
4605
        }
4491
4606
        CellRevision cellRevision = backup != null ? backup.cellRevision : null;
4492
4607
        if (cellBackupFresh) {
4493
4608
            assert cellRevision.d == getD();
4494
4609
            assert cellContentsFresh;
4495
4610
        }
4496
4611
        if (cellContentsFresh) {
4497
 
            assert cellRevision.nodes.size() == nodes.size();
4498
 
            assert cellRevision.arcs.size() == topology.getNumArcs();
4499
4612
            assert cellRevision.exports.size() == exports.length;
 
4613
            if (LAZY_TOPOLOGY && Job.isThreadSafe()) {
 
4614
                assert strongTopology == null;
 
4615
            }
4500
4616
        }
4501
4617
 
4502
4618
        // check exports
4505
4621
            assert e.getParent() == this;
4506
4622
            assert e.getPortIndex() == portIndex;
4507
4623
            assert chronExports[e.getId().getChronIndex()] == e;
4508
 
            if (cellContentsFresh) assert cellRevision.exports.get(portIndex) == e.getD();
4509
 
            if (portIndex > 0)
4510
 
                assert(TextUtils.STRING_NUMBER_ORDER.compare(exports[portIndex - 1].getName(), e.getName()) < 0);
 
4624
            if (cellContentsFresh) {
 
4625
                assert cellRevision.exports.get(portIndex) == e.getD();
 
4626
            }
 
4627
            if (portIndex > 0) {
 
4628
                assert (TextUtils.STRING_NUMBER_ORDER.compare(exports[portIndex - 1].getName(), e.getName()) < 0);
 
4629
            }
4511
4630
            assert e.getOriginalPort() == getPortInst(e.getD().originalNodeId, e.getD().originalPortId);
4512
4631
        }
4513
4632
        for (int chronIndex = 0; chronIndex < chronExports.length; chronIndex++) {
4514
4633
            Export e = chronExports[chronIndex];
4515
 
            if (e == null) continue;
 
4634
            if (e == null) {
 
4635
                continue;
 
4636
            }
4516
4637
            assert e.getId() == cellId.getPortId(chronIndex);
4517
4638
            assert e == exports[e.getPortIndex()];
4518
4639
        }
4519
4640
 
4520
 
        // check arcs
 
4641
        // check topology
 
4642
        Topology topology = getTopologyOptional();
4521
4643
        if (topology != null) {
4522
 
            topology.check();
 
4644
            topology.check(cellUsages);
4523
4645
            if (cellContentsFresh) {
4524
 
                for(int arcIndex = 0; arcIndex < topology.getNumArcs(); arcIndex++) {
 
4646
                assert cellRevision.arcs.size() == topology.getNumArcs();
 
4647
                for (int arcIndex = 0; arcIndex < topology.getNumArcs(); arcIndex++) {
4525
4648
                    ArcInst ai = topology.getArc(arcIndex);
4526
4649
                    ImmutableArcInst a = ai.getD();
4527
4650
                    assert cellRevision.arcs.get(arcIndex) == a;
4528
4651
                }
4529
 
            }
4530
 
        }
4531
 
 
4532
 
        // check nodes
4533
 
        NodeInst prevNi = null;
4534
 
        int[] usages = new int[cellId.numUsagesIn()];
4535
 
        for(int nodeIndex = 0; nodeIndex < nodes.size(); nodeIndex++) {
4536
 
            NodeInst ni = nodes.get(nodeIndex);
4537
 
            ImmutableNodeInst n = ni.getD();
4538
 
            assert ni.getParent() == this;
4539
 
            assert ni.getNodeIndex() == nodeIndex;
4540
 
            assert chronNodes.get(n.nodeId) == ni;
4541
 
            if (cellContentsFresh) assert cellRevision.nodes.get(nodeIndex) == n;
4542
 
            if (prevNi != null) {
4543
 
                assert TextUtils.STRING_NUMBER_ORDER.compare(prevNi.getName(), ni.getName()) < 0;
4544
 
            }
4545
 
            if (ni.isCellInstance()) {
4546
 
                Cell subCell = (Cell)ni.getProto();
4547
 
                assert subCell.isLinked();
4548
 
                assert subCell.database == database;
4549
 
                CellUsage u = cellId.getUsageIn(subCell.getId());
4550
 
                usages[u.indexInParent]++;
4551
 
            }
4552
 
            ni.check();
4553
 
            prevNi = ni;
4554
 
        }
4555
 
        for (int nodeId = 0; nodeId < chronNodes.size(); nodeId++) {
4556
 
            NodeInst ni = chronNodes.get(nodeId);
4557
 
            if (ni == null) continue;
4558
 
            assert ni.getD().nodeId == nodeId;
4559
 
            assert ni == nodes.get(ni.getNodeIndex());
4560
 
        }
4561
 
 
4562
 
        // check node usages
4563
 
        for (int i = 0; i < cellUsages.length; i++)
4564
 
            assert cellUsages[i] == usages[i];
4565
 
        for (int i = cellUsages.length; i < usages.length; i++)
4566
 
            assert usages[i] == 0;
 
4652
                assert cellRevision.nodes.size() == topology.getNumNodes();
 
4653
                for (int nodeIndex = 0; nodeIndex < topology.getNumNodes(); nodeIndex++) {
 
4654
                    NodeInst ni = topology.getNode(nodeIndex);
 
4655
                    ImmutableNodeInst n = ni.getD();
 
4656
                    assert cellRevision.nodes.get(nodeIndex) == n;
 
4657
                }
 
4658
            }
 
4659
        }
4567
4660
 
4568
4661
        // check group pointers
4569
4662
        assert cellGroup.containsCell(this);
4570
 
 
4571
 
        // check bounds and RTree
4572
 
        if (boundsDirty == BOUNDS_CORRECT) {
4573
 
            assert computeBounds() == cellBounds;
4574
 
            assert boundsDirty == BOUNDS_CORRECT;
4575
 
        }
4576
4663
    }
4577
4664
 
4578
4665
    /**
4579
4666
     * Method to tell whether an ElectricObject exists in this Cell.
4580
 
         * Used when saving and restoring highlighting to ensure that the object still
4581
 
         * exists.
4582
 
         * @param eObj the ElectricObject in question
4583
 
         * @return true if that ElectricObject is in this Cell.
4584
 
         */
4585
 
        public boolean objInCell(ElectricObject eObj)
4586
 
        {
4587
 
                if (eObj instanceof NodeInst)
4588
 
                {
4589
 
                        for(Iterator<NodeInst> it = getNodes(); it.hasNext(); )
4590
 
                                if (it.next() == eObj) return true;
4591
 
                } else if (eObj instanceof ArcInst)
4592
 
                {
4593
 
                        for(Iterator<ArcInst> it = getArcs(); it.hasNext(); )
4594
 
                                if (it.next() == eObj) return true;
4595
 
                } else if (eObj instanceof PortInst)
4596
 
                {
4597
 
                        NodeInst ni = ((PortInst)eObj).getNodeInst();
4598
 
                        for(Iterator<NodeInst> it = getNodes(); it.hasNext(); )
4599
 
                                if (it.next() == ni) return true;
4600
 
                }
4601
 
                return false;
4602
 
        }
4603
 
 
4604
 
        /**
4605
 
         * Method to get the 0-based index of this Cell.
4606
 
         * @return the index of this Cell.
4607
 
         */
4608
 
        public final int getCellIndex() { return getId().cellIndex; }
4609
 
 
4610
 
        /**
4611
 
         * Method to set an arbitrary integer in a temporary location on this Cell.
4612
 
         * @param tempInt the integer to be set on this Cell.
4613
 
         */
4614
 
        public void setTempInt(int tempInt) { checkChanging(); this.tempInt = tempInt; }
4615
 
 
4616
 
        /**
4617
 
         * Method to get the temporary integer on this Cell.
4618
 
         * @return the temporary integer on this Cell.
4619
 
         */
4620
 
        public int getTempInt() { return tempInt; }
4621
 
 
4622
 
        /**
4623
 
         * Method to determine the appropriate Cell associated with this ElectricObject.
4624
 
         * @return the appropriate Cell associated with this ElectricObject..
4625
 
         * Returns null if no Cell can be found.
4626
 
         */
4627
 
        public Cell whichCell() { return this; }
4628
 
 
4629
 
        /**
4630
 
         * Method to get the library to which this Cell belongs.
4631
 
         * @return to get the library to which this Cell belongs.
4632
 
         */
4633
 
        public Library getLibrary() { return lib; }
4634
 
 
4635
 
        /**
4636
 
         * Method to return the Technology of this Cell.
4637
 
         * It can be quite complex to determine which Technology a Cell belongs to.
4638
 
         * The system examines all of the nodes and arcs in it, and also considers
4639
 
         * the Cell's view.
4640
 
         * @return return the Technology of this Cell.
4641
 
         */
4642
 
        public Technology getTechnology() {
4643
 
        if (tech == null)
4644
 
            setTechnology(Technology.whatTechnology(this, null, 0, 0, null));
4645
 
                return tech;
4646
 
        }
4647
 
 
4648
 
        /**
4649
 
         * Method to set the Technology to which this NodeProto belongs
4650
 
         * It can only be called for Cells because PrimitiveNodes have fixed Technology membership.
4651
 
         * @param tech the new technology for this NodeProto (Cell).
4652
 
         */
4653
 
        public void setTechnology(Technology tech) {
 
4667
     * Used when saving and restoring highlighting to ensure that the object still
 
4668
     * exists.
 
4669
     * @param eObj the ElectricObject in question
 
4670
     * @return true if that ElectricObject is in this Cell.
 
4671
     */
 
4672
    public boolean objInCell(ElectricObject eObj) {
 
4673
        if (eObj instanceof NodeInst) {
 
4674
            for (Iterator<NodeInst> it = getNodes(); it.hasNext();) {
 
4675
                if (it.next() == eObj) {
 
4676
                    return true;
 
4677
                }
 
4678
            }
 
4679
        } else if (eObj instanceof ArcInst) {
 
4680
            for (Iterator<ArcInst> it = getArcs(); it.hasNext();) {
 
4681
                if (it.next() == eObj) {
 
4682
                    return true;
 
4683
                }
 
4684
            }
 
4685
        } else if (eObj instanceof PortInst) {
 
4686
            NodeInst ni = ((PortInst) eObj).getNodeInst();
 
4687
            for (Iterator<NodeInst> it = getNodes(); it.hasNext();) {
 
4688
                if (it.next() == ni) {
 
4689
                    return true;
 
4690
                }
 
4691
            }
 
4692
        }
 
4693
        return false;
 
4694
    }
 
4695
 
 
4696
    /**
 
4697
     * Method to get the 0-based index of this Cell.
 
4698
     * @return the index of this Cell.
 
4699
     */
 
4700
    public final int getCellIndex() {
 
4701
        return getId().cellIndex;
 
4702
    }
 
4703
 
 
4704
    /**
 
4705
     * Method to set an arbitrary integer in a temporary location on this Cell.
 
4706
     * @param tempInt the integer to be set on this Cell.
 
4707
     */
 
4708
    public void setTempInt(int tempInt) {
 
4709
        checkChanging();
 
4710
        this.tempInt = tempInt;
 
4711
    }
 
4712
 
 
4713
    /**
 
4714
     * Method to get the temporary integer on this Cell.
 
4715
     * @return the temporary integer on this Cell.
 
4716
     */
 
4717
    public int getTempInt() {
 
4718
        return tempInt;
 
4719
    }
 
4720
 
 
4721
    /**
 
4722
     * Method to determine the appropriate Cell associated with this ElectricObject.
 
4723
     * @return the appropriate Cell associated with this ElectricObject..
 
4724
     * Returns null if no Cell can be found.
 
4725
     */
 
4726
    public Cell whichCell() {
 
4727
        return this;
 
4728
    }
 
4729
 
 
4730
    /**
 
4731
     * Method to get the library to which this Cell belongs.
 
4732
     * @return to get the library to which this Cell belongs.
 
4733
     */
 
4734
    public Library getLibrary() {
 
4735
        return lib;
 
4736
    }
 
4737
 
 
4738
    /**
 
4739
     * Method to return the Technology of this Cell.
 
4740
     * It can be quite complex to determine which Technology a Cell belongs to.
 
4741
     * The system examines all of the nodes and arcs in it, and also considers
 
4742
     * the Cell's view.
 
4743
     * @return return the Technology of this Cell.
 
4744
     */
 
4745
    public Technology getTechnology() {
 
4746
        if (tech == null) {
 
4747
            NodeProto[] nodeProtos = null;
 
4748
            ArcProto[] arcProtos = null;
 
4749
            if (backup == null && getTopologyOptional() == null) {
 
4750
                nodeProtos = new NodeProto[0];
 
4751
                arcProtos = new ArcProto[0];
 
4752
            }
 
4753
            setTechnology(Technology.whatTechnology(this, nodeProtos, 0, 0, arcProtos));
 
4754
        }
 
4755
        return tech;
 
4756
    }
 
4757
 
 
4758
    /**
 
4759
     * Method to set the Technology to which this NodeProto belongs
 
4760
     * It can only be called for Cells because PrimitiveNodes have fixed Technology membership.
 
4761
     * @param tech the new technology for this NodeProto (Cell).
 
4762
     */
 
4763
    public void setTechnology(Technology tech) {
4654
4764
        TechId techId = null;
4655
4765
        if (tech != null) {
4656
4766
            techId = tech.getId();
4657
 
            if (database.getTech(techId) != tech)
 
4767
            if (database.getTech(techId) != tech) {
4658
4768
                throw new IllegalArgumentException("tech");
 
4769
            }
4659
4770
        }
4660
4771
        setD(getD().withTechId(techId));
4661
4772
        this.tech = tech;
4662
4773
    }
4663
4774
 
4664
 
        /**
4665
 
         * Finds the Schematic Cell associated with this Icon Cell.
4666
 
         * If this Cell is an Icon View then find the schematic Cell in its
4667
 
         * CellGroup.
4668
 
         * @return the Schematic Cell.  Returns null if there is no equivalent.
4669
 
         * If there are multiple versions of the Schematic View then
4670
 
         * return the latest version.
4671
 
         */
4672
 
        public Cell getEquivalent()
4673
 
        {
4674
 
                return isIcon() ? getCellGroup().getMainSchematics() : this;
4675
 
        }
4676
 
 
4677
 
        /**
4678
 
         * Use to compare cells in Cross Library Check
4679
 
         * @param obj Object to compare to
4680
 
         * @param buffer To store comparison messages in case of failure
4681
 
         * @return True if objects represent same NodeInst
4682
 
         */
4683
 
        public boolean compare(Object obj, StringBuffer buffer)
4684
 
        {
4685
 
                if (this == obj) return (true);
4686
 
 
4687
 
                // Consider already obj==null
4688
 
        if (obj == null || getClass() != obj.getClass())
 
4775
    /**
 
4776
     * Finds the Schematic Cell associated with this Icon Cell.
 
4777
     * If this Cell is an Icon View then find the schematic Cell in its
 
4778
     * CellGroup.
 
4779
     * @return the Schematic Cell.  Returns null if there is no equivalent.
 
4780
     * If there are multiple versions of the Schematic View then
 
4781
     * return the latest version.
 
4782
     */
 
4783
    public Cell getEquivalent() {
 
4784
        return isIcon() ? getCellGroup().getMainSchematics() : this;
 
4785
    }
 
4786
 
 
4787
    /**
 
4788
     * Use to compare cells in Cross Library Check
 
4789
     * @param obj Object to compare to
 
4790
     * @param buffer To store comparison messages in case of failure
 
4791
     * @return True if objects represent same NodeInst
 
4792
     */
 
4793
    public boolean compare(Object obj, StringBuffer buffer) {
 
4794
        if (this == obj) {
 
4795
            return (true);
 
4796
        }
 
4797
 
 
4798
        // Consider already obj==null
 
4799
        if (obj == null || getClass() != obj.getClass()) {
4689
4800
            return (false);
 
4801
        }
4690
4802
 
4691
 
                Cell toCompare = (Cell)obj;
 
4803
        Cell toCompare = (Cell) obj;
4692
4804
 
4693
4805
        // Traversing nodes
4694
4806
        // @TODO GVG This should be removed if equals is implemented
4695
4807
        Set<Object> noCheckAgain = new HashSet<Object>();
4696
 
        for (Iterator<NodeInst> it = getNodes(); it.hasNext(); )
4697
 
        {
 
4808
        for (Iterator<NodeInst> it = getNodes(); it.hasNext();) {
4698
4809
            boolean found = false;
4699
4810
            NodeInst node = it.next();
4700
4811
 
4701
 
            for (Iterator<NodeInst> i = toCompare.getNodes(); i.hasNext();)
4702
 
            {
 
4812
            for (Iterator<NodeInst> i = toCompare.getNodes(); i.hasNext();) {
4703
4813
                NodeInst n = i.next();
4704
4814
 
4705
 
                if (noCheckAgain.contains(n)) continue;
 
4815
                if (noCheckAgain.contains(n)) {
 
4816
                    continue;
 
4817
                }
4706
4818
 
4707
 
                if (node.compare(n, buffer))
4708
 
                {
 
4819
                if (node.compare(n, buffer)) {
4709
4820
                    found = true;
4710
4821
                    // if node is found, remove elem from iterator
4711
4822
                    // because it was found
4716
4827
                }
4717
4828
            }
4718
4829
            // No correspoding NodeInst found
4719
 
            if (!found)
4720
 
            {
4721
 
                    if (buffer != null)
4722
 
                        buffer.append("No corresponding node '" + node + "' found in '" + toCompare + "'\n");
4723
 
                    return (false);
 
4830
            if (!found) {
 
4831
                if (buffer != null) {
 
4832
                    buffer.append("No corresponding node '" + node + "' found in '" + toCompare + "'\n");
 
4833
                }
 
4834
                return (false);
4724
4835
            }
4725
4836
        }
4726
4837
        // other node has more instances
4727
 
        if (getNumNodes() != toCompare.getNumNodes())
4728
 
        {
4729
 
            if (buffer != null)
 
4838
        if (getNumNodes() != toCompare.getNumNodes()) {
 
4839
            if (buffer != null) {
4730
4840
                buffer.append("Cell '" + toCompare.libDescribe() + "' has more nodes than '" + this + "'\n");
 
4841
            }
4731
4842
            return (false);
4732
4843
        }
4733
4844
 
4734
4845
        // Traversing Arcs
4735
 
        for (Iterator<ArcInst> it = getArcs(); it.hasNext(); )
4736
 
        {
 
4846
        for (Iterator<ArcInst> it = getArcs(); it.hasNext();) {
4737
4847
            boolean found = false;
4738
4848
            ArcInst arc = it.next();
4739
4849
 
4740
 
            for (Iterator<ArcInst> i = toCompare.getArcs(); i.hasNext();)
4741
 
            {
 
4850
            for (Iterator<ArcInst> i = toCompare.getArcs(); i.hasNext();) {
4742
4851
                ArcInst a = i.next();
4743
4852
 
4744
 
                if (noCheckAgain.contains(a)) continue;
 
4853
                if (noCheckAgain.contains(a)) {
 
4854
                    continue;
 
4855
                }
4745
4856
 
4746
 
                if (arc.compare(a, buffer))
4747
 
                {
 
4857
                if (arc.compare(a, buffer)) {
4748
4858
                    found = true;
4749
4859
                    noCheckAgain.add(a);
4750
4860
                    break;
4751
4861
                }
4752
4862
            }
4753
4863
            // No correspoding ArcInst found
4754
 
            if (!found)
4755
 
            {
4756
 
                    if (buffer != null)
4757
 
                        buffer.append("No corresponding arc '" + arc + "' found in other cell" + "\n");
4758
 
                    return (false);
 
4864
            if (!found) {
 
4865
                if (buffer != null) {
 
4866
                    buffer.append("No corresponding arc '" + arc + "' found in other cell" + "\n");
 
4867
                }
 
4868
                return (false);
4759
4869
            }
4760
4870
        }
4761
4871
        // other node has more instances
4762
 
        if (getNumArcs() != toCompare.getNumArcs())
4763
 
        {
4764
 
            if (buffer != null)
 
4872
        if (getNumArcs() != toCompare.getNumArcs()) {
 
4873
            if (buffer != null) {
4765
4874
                buffer.append("Cell '" + toCompare.libDescribe() + "' has more arcs than '" + this + "'\n");
 
4875
            }
4766
4876
            return (false);
4767
4877
        }
4768
4878
 
4769
4879
        // Traversing ports. This includes Exports
4770
4880
        noCheckAgain.clear();
4771
 
        for (Iterator<Export> it = getExports(); it.hasNext(); )
4772
 
        {
 
4881
        for (Iterator<Export> it = getExports(); it.hasNext();) {
4773
4882
            boolean found = false;
4774
4883
            Export port = it.next();
4775
4884
 
4776
 
            for (Iterator<Export> i = toCompare.getExports(); i.hasNext();)
4777
 
            {
 
4885
            for (Iterator<Export> i = toCompare.getExports(); i.hasNext();) {
4778
4886
                Export p = i.next();
4779
4887
 
4780
 
                if (noCheckAgain.contains(p)) continue;
 
4888
                if (noCheckAgain.contains(p)) {
 
4889
                    continue;
 
4890
                }
4781
4891
 
4782
 
                if (port.compare(p, buffer))
4783
 
                {
 
4892
                if (port.compare(p, buffer)) {
4784
4893
                    found = true;
4785
4894
                    noCheckAgain.add(p);
4786
4895
                    break;
4787
4896
                }
4788
4897
            }
4789
4898
            // No correspoding PortProto found
4790
 
            if (!found)
4791
 
            {
 
4899
            if (!found) {
4792
4900
                // Message is already added in port.compare()
4793
4901
//                if (buffer != null)
4794
4902
//                    buffer.append("No corresponding port '" + port.getName() + "' found in other cell" + "\n");
4796
4904
            }
4797
4905
        }
4798
4906
        // other node has more instances
4799
 
        if (getNumPorts() != toCompare.getNumPorts())
4800
 
        {
4801
 
            if (buffer != null)
 
4907
        if (getNumPorts() != toCompare.getNumPorts()) {
 
4908
            if (buffer != null) {
4802
4909
                buffer.append("Cell '" + toCompare.libDescribe() + "' has more pors than '" + this + "'\n");
 
4910
            }
4803
4911
            return (false);
4804
4912
        }
4805
4913
 
4806
4914
        // Checking parameters
4807
 
        if (getNumParameters() != toCompare.getNumParameters())
4808
 
        {
4809
 
            if (buffer != null)
 
4915
        if (getNumParameters() != toCompare.getNumParameters()) {
 
4916
            if (buffer != null) {
4810
4917
                buffer.append("Cell '" + toCompare + "' has more parameters than '" + this + "'\n");
 
4918
            }
4811
4919
            return (false);
4812
4920
 
4813
4921
        }
4814
 
        for (Iterator<Variable> it1 = getParameters(), it2 = toCompare.getParameters(); it1.hasNext(); ) {
 
4922
        for (Iterator<Variable> it1 = getParameters(), it2 = toCompare.getParameters(); it1.hasNext();) {
4815
4923
            Variable param1 = it1.next();
4816
4924
            Variable param2 = it2.next();
4817
4925
            if (!param1.compare(param2, buffer)) {
4818
 
                if (buffer != null)
 
4926
                if (buffer != null) {
4819
4927
                    buffer.append("No corresponding parameter '" + param1 + "' found in other cell" + "\n");
 
4928
                }
4820
4929
                return (false);
4821
4930
            }
4822
4931
        }
4823
4932
 
4824
4933
        // Checking attributes
4825
4934
        noCheckAgain.clear();
4826
 
        for (Iterator<Variable> it = getVariables(); it.hasNext(); )
4827
 
        {
 
4935
        for (Iterator<Variable> it = getVariables(); it.hasNext();) {
4828
4936
            Variable var = it.next();
4829
4937
            boolean found = false;
4830
4938
 
4831
 
            for (Iterator<Variable> i = toCompare.getVariables(); i.hasNext();)
4832
 
            {
 
4939
            for (Iterator<Variable> i = toCompare.getVariables(); i.hasNext();) {
4833
4940
                Variable v = i.next();
4834
4941
 
4835
 
                if (noCheckAgain.contains(v)) continue;
 
4942
                if (noCheckAgain.contains(v)) {
 
4943
                    continue;
 
4944
                }
4836
4945
 
4837
 
                if (var.compare(v, buffer))
4838
 
                {
 
4946
                if (var.compare(v, buffer)) {
4839
4947
                    found = true;
4840
4948
                    noCheckAgain.add(v);
4841
4949
                    break;
4842
4950
                }
4843
4951
            }
4844
4952
            // No correspoding Variable found
4845
 
            if (!found)
4846
 
            {
4847
 
                if (buffer != null)
 
4953
            if (!found) {
 
4954
                if (buffer != null) {
4848
4955
                    buffer.append("No corresponding variable '" + var + "' found in other cell" + "\n");
 
4956
                }
4849
4957
                return (false);
4850
4958
            }
4851
4959
        }
4852
4960
        // other node has more instances
4853
 
        if (getNumVariables() != toCompare.getNumVariables())
4854
 
        {
4855
 
            if (buffer != null)
 
4961
        if (getNumVariables() != toCompare.getNumVariables()) {
 
4962
            if (buffer != null) {
4856
4963
                buffer.append("Cell '" + toCompare + "' has more variables than '" + this + "'\n");
 
4964
            }
4857
4965
            return (false);
4858
4966
        }
4859
4967
        return (true);
4860
 
        }
 
4968
    }
4861
4969
 
4862
4970
    /**
4863
4971
     * Compares Cells by their Libraries and CellNames.
4864
4972
     * @param that the other Cell.
4865
4973
     * @return a comparison between the Cells.
4866
4974
     */
4867
 
        public int compareTo(Cell that)
4868
 
        {
4869
 
                if (this.lib != that.lib)
4870
 
                {
4871
 
                        int cmp = this.lib.compareTo(that.lib);
4872
 
                        if (cmp != 0) return cmp;
4873
 
                }
4874
 
                return this.getCellName().compareTo(that.getCellName());
4875
 
        }
 
4975
    public int compareTo(Cell that) {
 
4976
        if (this.lib != that.lib) {
 
4977
            int cmp = this.lib.compareTo(that.lib);
 
4978
            if (cmp != 0) {
 
4979
                return cmp;
 
4980
            }
 
4981
        }
 
4982
        return this.getCellName().compareTo(that.getCellName());
 
4983
    }
4876
4984
 
4877
 
        /**
4878
 
         * Method to get MinZ and MaxZ of the cell calculated based on nodes.
4879
 
         * You must guarantee minZ = Double.MaxValue() and maxZ = Double.MinValue()
4880
 
         * for initial call.
4881
 
         * @param array array[0] is minZ and array[1] is max
4882
 
         */
4883
 
        public void getZValues(double [] array)
4884
 
        {
4885
 
                for (Iterator<NodeInst> it = getNodes(); it.hasNext(); )
4886
 
                {
4887
 
                        NodeInst ni = it.next();
4888
 
                        if (ni.isCellInstance())
4889
 
                        {
4890
 
                                Cell nCell = (Cell)ni.getProto();
4891
 
                                nCell.getZValues(array);
4892
 
                        }
4893
 
                        else
4894
 
                        {
4895
 
                                PrimitiveNode np = (PrimitiveNode)ni.getProto();
4896
 
                                np.getZValues(array);
4897
 
                        }
4898
 
                }
4899
 
        for (Iterator<ArcInst> it = getArcs(); it.hasNext(); )
4900
 
        {
 
4985
    /**
 
4986
     * Method to get MinZ and MaxZ of the cell calculated based on nodes.
 
4987
     * You must guarantee minZ = Double.MaxValue() and maxZ = Double.MinValue()
 
4988
     * for initial call.
 
4989
     * @param array array[0] is minZ and array[1] is max
 
4990
     */
 
4991
    public void getZValues(double[] array) {
 
4992
        for (Iterator<NodeInst> it = getNodes(); it.hasNext();) {
 
4993
            NodeInst ni = it.next();
 
4994
            if (ni.isCellInstance()) {
 
4995
                Cell nCell = (Cell) ni.getProto();
 
4996
                nCell.getZValues(array);
 
4997
            } else {
 
4998
                PrimitiveNode np = (PrimitiveNode) ni.getProto();
 
4999
                np.getZValues(array);
 
5000
            }
 
5001
        }
 
5002
        for (Iterator<ArcInst> it = getArcs(); it.hasNext();) {
4901
5003
            ArcInst ai = it.next();
4902
5004
            ArcProto ap = ai.getProto();
4903
5005
            ap.getZValues(array);
4904
5006
        }
4905
 
        }
4906
 
 
4907
 
        /**
4908
 
         * Method to fill a set with any nodes in this Cell that refer to an external library.
4909
 
         * @param elib the external library being considered.
4910
 
         * @param set the set being filled.
4911
 
         * @return true if anything was added to the set.
4912
 
         */
4913
 
        public boolean findReferenceInCell(Library elib, Set<Cell> set)
4914
 
        {
4915
 
                // Stop recursive search here
4916
 
 
4917
 
                if (lib == elib)
4918
 
                {
4919
 
                        //set.add(this);
4920
 
                        return (true);
4921
 
                }
4922
 
                int initial = set.size();
4923
 
 
4924
 
                for (int i = 0; i < nodes.size(); i++)
4925
 
                {
4926
 
                        NodeInst ni = nodes.get(i);
4927
 
                        if (ni.isCellInstance())
4928
 
                        {
4929
 
                                Cell nCell = (Cell)ni.getProto();
4930
 
                                if (nCell.getLibrary() == elib)
4931
 
                                        set.add(this);
4932
 
                                else
4933
 
                                        nCell.findReferenceInCell(elib, set);
4934
 
                        }
4935
 
                }
4936
 
                return (set.size() != initial);
4937
 
        }
 
5007
    }
 
5008
 
 
5009
    /**
 
5010
     * Method to fill a set with any nodes in this Cell that refer to an external library.
 
5011
     * @param elib the external library being considered.
 
5012
     * @param set the set being filled.
 
5013
     * @return true if anything was added to the set.
 
5014
     */
 
5015
    public boolean findReferenceInCell(Library elib, Set<Cell> set) {
 
5016
        // Stop recursive search here
 
5017
 
 
5018
        if (lib == elib) {
 
5019
            //set.add(this);
 
5020
            return (true);
 
5021
        }
 
5022
        int initial = set.size();
 
5023
 
 
5024
        for (Iterator<CellUsage> it = getUsagesIn(); it.hasNext();) {
 
5025
            CellUsage cu = it.next();
 
5026
            Cell nCell = cu.getProto(database);
 
5027
            if (nCell.getLibrary() == elib) {
 
5028
                set.add(this);
 
5029
            } else {
 
5030
                nCell.findReferenceInCell(elib, set);
 
5031
            }
 
5032
        }
 
5033
        return (set.size() != initial);
 
5034
    }
4938
5035
}