/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: CellMenu.java * * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. * * Electric(tm) is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Electric(tm) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Electric(tm); see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, Mass 02111-1307, USA. */ package com.sun.electric.tool.user.menus; import static com.sun.electric.tool.user.menus.EMenuItem.SEPARATOR; import com.sun.electric.Main; import com.sun.electric.database.geometry.EPoint; import com.sun.electric.database.hierarchy.Cell; import com.sun.electric.database.hierarchy.Library; import com.sun.electric.database.hierarchy.Nodable; import com.sun.electric.database.hierarchy.View; import com.sun.electric.database.topology.ArcInst; import com.sun.electric.database.topology.Geometric; import com.sun.electric.database.topology.NodeInst; import com.sun.electric.database.variable.VarContext; import com.sun.electric.tool.Job; import com.sun.electric.tool.JobException; import com.sun.electric.tool.extract.GeometrySearch; import com.sun.electric.tool.user.CellChangeJobs; import com.sun.electric.tool.user.CircuitChangeJobs; import com.sun.electric.tool.user.CircuitChanges; import com.sun.electric.tool.user.ExportChanges; import com.sun.electric.tool.user.Highlighter; import com.sun.electric.tool.user.User; import com.sun.electric.tool.user.ViewChanges; import com.sun.electric.tool.user.dialogs.CellBrowser; import com.sun.electric.tool.user.dialogs.CellLists; import com.sun.electric.tool.user.dialogs.CellProperties; import com.sun.electric.tool.user.dialogs.CrossLibCopy; import com.sun.electric.tool.user.dialogs.EDialog; import com.sun.electric.tool.user.dialogs.NewCell; import com.sun.electric.tool.user.ui.ClickZoomWireListener; import com.sun.electric.tool.user.ui.EditWindow; import com.sun.electric.tool.user.ui.ToolBar; import com.sun.electric.tool.user.ui.WindowFrame; import java.awt.Dimension; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPopupMenu; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.SwingConstants; /** * Class to handle the commands in the "Cell" pulldown menu. */ public class CellMenu { static EMenu makeMenu() { /****************************** THE CELL MENU ******************************/ // mnemonic keys available: H J Q Z return new EMenu("_Cell", new EMenuItem("Ne_w Cell...", 'N') { public void run() { newCellCommand(); }}, new EMenuItem("_Edit Cell...") { public void run() { cellBrowserCommand(CellBrowser.DoAction.editCell); }}, new EMenuItem("_Place Cell Instance...", KeyStroke.getKeyStroke('N', 0)) { public void run() { cellBrowserCommand(CellBrowser.DoAction.newInstance); }}, new EMenuItem("_Rename Cell...") { public void run() { cellBrowserCommand(CellBrowser.DoAction.renameCell); }}, new EMenuItem("Duplic_ate Cell...") { public void run() { cellBrowserCommand(CellBrowser.DoAction.duplicateCell); }}, new EMenuItem("De_lete Cell...") { public void run() { cellBrowserCommand(CellBrowser.DoAction.deleteCell); }}, // mnemonic keys available: AB FGHIJKL NOPQRSTU WXYZ new EMenu("_Multi-Page Cells", new EMenuItem("_Make Cell Multi-Page") { public void run() { makeMultiPageCell(); }}, new EMenuItem("_Create New Page") { public void run() { createNewMultiPage(); }}, new EMenuItem("_Delete This Page") { public void run() { deleteThisMultiPage(); }}, new EMenuItem("_Edit Next Page") { public void run() { editNextMultiPage(); }}, new EMenuItem("Con_vert old-style Multi-Page Schematics") { public void run() { ViewChanges.convertMultiPageViews(); }}), SEPARATOR, new EMenuItem("_Cross-Library Copy...") { public void run() { crossLibraryCopyCommand(); }}, // mnemonic keys available: BCDEFGHIJKLMNOPQ STUVWXYZ new EMenu("Merge Li_braries", new EMenuItem("_Add Exports from Library...") { public void run() { ExportChanges.synchronizeLibrary(); }}, new EMenuItem("_Replace Cells from Library...") { public void run() { ExportChanges.replaceFromOtherLibrary(); }}), SEPARATOR, // mnemonic keys available: ABC E GHIJ LMNO QRSTUV XYZ new EMenu("_Down Hierarchy", new EMenuItem("_Down Hierarchy", 'D') { public void run() { downHierCommand(false, false); }}, new EMenuItem("Down Hierarchy, Keep _Focus") { public void run() { downHierCommand(true, false); }}, new EMenuItem("Down Hierarchy, New _Window") { public void run() { downHierCommand(false, true); }}, new EMenuItem("Down Hierarchy, _Keep Focus, New Window") { public void run() { downHierCommand(true, true); }}, SEPARATOR, new EMenuItem("Down Hierarchy In _Place", KeyStroke.getKeyStroke('D', 0)) { public void run() { downHierInPlaceCommand(); }}, new EMenuItem("Down Hierarchy In Place To Object", KeyStroke.getKeyStroke('D', KeyEvent.SHIFT_MASK)) { public void run() { downHierInPlaceToObject(); }}), new EMenu("_Up Hierarchy", new EMenuItem("_Up Hierarchy", 'U') { public void run() { upHierCommand(false); }}, new EMenuItem("Up Hierarchy, Keep _Focus") { public void run() { upHierCommand(true); }}), // mnemonic keys available: A CDE GHIJKLMNOPQRSTUVWXYZ new EMenu("Cell Viewing Histor_y", new EMenuItem("Go _Back a Cell") { public void run() { changeCellHistory(true); }}, new EMenuItem("Go _Forward a Cell") { public void run() { changeCellHistory(false); }}), SEPARATOR, new EMenuItem("New _Version of Current Cell") { public void run() { newCellVersionCommand(); }}, new EMenuItem("Duplicate Curre_nt Cell") { public void run() { duplicateCellCommand(); }}, new EMenuItem("Delete Unused _Old Versions") { public void run() { deleteOldCellVersionsCommand(); }}, SEPARATOR, // mnemonic keys available: BC JK M OPQR WXYZ new EMenu("Cell In_fo", new EMenuItem("_Describe this Cell") { public void run() { CellLists.describeThisCellCommand(); }}, new EMenuItem("_General Cell Lists...") { public void run() { CellLists.generalCellListsCommand(); }}, SEPARATOR, new EMenuItem("_Summarize Cell Contents") { public void run() { CellLists.designSummaryCommand(); }}, new EMenuItem("List _Nodes/Arcs in this Cell") { public void run() { CellLists.listNodesAndArcsInCellCommand(); }}, new EMenuItem("List Cell _Instances") { public void run() { CellLists.listCellInstancesCommand(); }}, new EMenuItem("List Cell _Usage") { public void run() { CellLists.listCellUsageCommand(false); }}, new EMenuItem("List Cell Usage, _Hierarchically") { public void run() { CellLists.listCellUsageCommand(true); }}, new EMenuItem("Number of _Transistors") { public void run() { CellLists.numberOfTransistorsCommand(); }}, SEPARATOR, new EMenuItem("Cell Graph, _Entire Library") { public void run() { CircuitChanges.graphCellsInLibrary(); }}, new EMenuItem("Cell Graph, _From Current Cell") { public void run() { CircuitChanges.graphCellsFromCell(); }}, new EMenuItem("_Library Graph") { public void run() { CircuitChanges.graphLibraries(); }}), new EMenuItem("Cell Propertie_s...") { public void run() { cellControlCommand(); }}, SEPARATOR, // mnemonic keys available: BCDEFGHIJKLMN PQR TUVWXYZ new EMenu("E_xpand Cell Instances", ToolBar.expandOneLevelCommand, // O new EMenuItem("_All the Way") { public void run() { CircuitChanges.DoExpandCommands(false, Integer.MAX_VALUE); }}, new EMenuItem("_Specified Amount...") { public void run() { CircuitChanges.DoExpandCommands(false, -1); }}), // mnemonic keys available: BCDEFGHIJKLMN PQR TUVWXYZ new EMenu("Unexpand Cell Ins_tances", ToolBar.unexpandOneLevelCommand, // O new EMenuItem("_All the Way") { public void run() { CircuitChanges.DoExpandCommands(true, Integer.MAX_VALUE); }}, new EMenuItem("_Specified Amount...") { public void run() { CircuitChanges.DoExpandCommands(true, -1); }}), new EMenuItem("Loo_k Inside Highlighted", 'P') { public void run() { peekCommand(); }}, SEPARATOR, new EMenuItem("Packa_ge Into Cell...") { public void run() { CircuitChanges.packageIntoCell(); }}, // mnemonic keys available: BCDEFGHIJKLMN PQR TUVWXYZ new EMenu("Extract Cell _Instance", new EMenuItem("_One Level Down") { public void run() { CircuitChanges.extractCells(1); }}, new EMenuItem("_All the Way") { public void run() { CircuitChanges.extractCells(Integer.MAX_VALUE); }}, new EMenuItem("_Specified Amount...") { public void run() { CircuitChanges.extractCells(-1); }})); } /** * This method implements the command to do cell options. */ private static void cellControlCommand() { CellProperties dialog = new CellProperties((Frame) Main.getCurrentJFrame()); dialog.setVisible(true); } /** * This command opens a dialog box to edit a Cell. */ private static void newCellCommand() { NewCell dialog = new NewCell((Frame) Main.getCurrentJFrame(), null); dialog.setVisible(true); } public static void cellBrowserCommand(CellBrowser.DoAction action) { CellBrowser dialog = new CellBrowser((Frame) Main.getCurrentJFrame(), false, action); dialog.setVisible(true); } /** * This method implements the command to make the current cell a multi-page schematic. */ private static void makeMultiPageCell() { Cell cell = WindowFrame.needCurCell(); if (cell == null) return; if (!cell.isSchematic()) { JOptionPane.showMessageDialog(Main.getCurrentJFrame(), "Only Schematic cells can be made multi-page", "Cannot make multipage design", JOptionPane.ERROR_MESSAGE); return; } new SetMultiPageJob(cell, 1); } /** * Class to set a cell to be multi-page with a given page count. */ public static class SetMultiPageJob extends Job { private static final long serialVersionUID = 1L; private Cell cell; private int numPages; public SetMultiPageJob(Cell cell, int numPages) { super("Make Cell be Multi-Page", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER); this.cell = cell; this.numPages = numPages; startJob(); } public boolean doIt() throws JobException { Dimension d = new Dimension(0,0); if (Cell.FrameDescription.getCellFrameInfo(cell, d) != 0) { cell.newVar(User.FRAME_SIZE, "a"); System.out.println("Multi-page schematics must have cell frames turned on. Setting this to A-size."); } boolean wasMulti = cell.isMultiPage(); cell.setMultiPage(true); cell.newVar(Cell.MULTIPAGE_COUNT_KEY, new Integer(numPages)); // autoboxing if (!wasMulti) System.out.println("Cell " + cell.describe(true) + " is now a multi-page schematic"); return true; } } /** * Class to delete a page from a multi-page schematic. */ public static class DeleteMultiPageJob extends Job { private static final long serialVersionUID = 1L; private Cell cell; private int page, numPages; public DeleteMultiPageJob(Cell cell, int page) { super("Delete Page from Multi-Page Schematic", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER); this.cell = cell; this.page = page; startJob(); } public boolean doIt() throws JobException { // first delete all circuitry on the page double lY = page * Cell.FrameDescription.MULTIPAGESEPARATION - Cell.FrameDescription.MULTIPAGESEPARATION/2; double hY = lY + Cell.FrameDescription.MULTIPAGESEPARATION; List<Geometric> deleteList = new ArrayList<Geometric>(); for(Iterator<NodeInst> it = cell.getNodes(); it.hasNext(); ) { NodeInst ni = it.next(); if (ni.getAnchorCenterY() > lY && ni.getAnchorCenterY() < hY) deleteList.add(ni); } for(Iterator<ArcInst> it = cell.getArcs(); it.hasNext(); ) { ArcInst ai = it.next(); double ctrY = ai.getBounds().getCenterY(); if (ctrY > lY && ctrY < hY) deleteList.add(ai); } CircuitChangeJobs.eraseObjectsInList(cell, deleteList, false, null); // now slide circuitry down if this isn't the last page numPages = cell.getNumMultiPages(); if (page+1 < numPages) { CircuitChangeJobs.spreadCircuitry(cell, null, 'u', -Cell.FrameDescription.MULTIPAGESEPARATION, 0, 0, lY, hY); } cell.newVar(Cell.MULTIPAGE_COUNT_KEY, new Integer((numPages-1))); // autoboxing fieldVariableChanged("numPages"); return true; } public void terminateOK() { for(Iterator<WindowFrame> it = WindowFrame.getWindows(); it.hasNext(); ) { WindowFrame wf = it.next(); if (wf.getContent() instanceof EditWindow) { EditWindow wnd = (EditWindow)wf.getContent(); if (wnd.getCell() == cell) { int wndPage = wnd.getMultiPageNumber(); if (wndPage+1 >= numPages) wnd.setMultiPageNumber(wndPage-1); } } } } } /** * This method implements the command to create a new page in a multi-page schematic. */ private static void createNewMultiPage() { EditWindow wnd = EditWindow.needCurrent(); if (wnd == null) return; Cell cell = WindowFrame.needCurCell(); if (cell == null) return; if (!cell.isMultiPage()) { System.out.println("First turn this cell into a multi-page schematic"); return; } int numPages = cell.getNumMultiPages(); new SetMultiPageJob(cell, numPages+1); wnd.setMultiPageNumber(numPages); } /** * This method implements the command to delete the current page in a multi-page schematic. */ private static void deleteThisMultiPage() { EditWindow wnd = EditWindow.needCurrent(); if (wnd == null) return; Cell cell = WindowFrame.needCurCell(); if (cell == null) return; if (!cell.isMultiPage()) { System.out.println("This is not a multi-page schematic. To delete this cell, use 'Cell / Delete Cell'"); return; } int curPage = wnd.getMultiPageNumber(); new DeleteMultiPageJob(cell, curPage); int numPages = cell.getNumMultiPages(); if (curPage >= numPages) wnd.setMultiPageNumber(numPages-1); } /** * This method implements the command to edit the next page in a multi-page schematic. */ private static void editNextMultiPage() { EditWindow wnd = EditWindow.needCurrent(); if (wnd == null) return; Cell cell = WindowFrame.needCurCell(); if (cell == null) return; if (!cell.isMultiPage()) { System.out.println("First turn this cell into a multi-page schematic"); return; } int curPage = wnd.getMultiPageNumber(); int numPages = cell.getNumMultiPages(); wnd.setMultiPageNumber((curPage+1) % numPages); } /** * This method implements the command to do cross-library copies. */ private static void crossLibraryCopyCommand() { CrossLibCopy dialog = new CrossLibCopy((Frame) Main.getCurrentJFrame()); dialog.setVisible(true); } /** * This command pushes down the hierarchy * @param keepFocus true to keep the zoom and scale in the new window. * @param newWindow true to create a new window for the cell. */ private static void downHierCommand(boolean keepFocus, boolean newWindow) { EditWindow curEdit = EditWindow.needCurrent(); if (curEdit == null) return; curEdit.downHierarchy(keepFocus, newWindow, false); } /** * This command pushes down the hierarchy "in place". */ private static void downHierInPlaceCommand() { EditWindow curEdit = EditWindow.needCurrent(); if (curEdit == null) return; curEdit.downHierarchy(false, false, true); } private static class DownHierToObjectActionListener implements ActionListener { GeometrySearch.GeometrySearchResult result; DownHierToObjectActionListener(GeometrySearch.GeometrySearchResult r) { result = r; } public void actionPerformed(ActionEvent e) { descendToObject(result); } } private static void downHierInPlaceToObject() { EditWindow curEdit = EditWindow.needCurrent(); if (curEdit == null) return; Cell cell = curEdit.getCell(); if (cell == null) return; if (cell.getView() != View.LAYOUT) { System.out.println("Current cell should be a layout cell for 'Down Hierarchy In Place To Object'"); return; } // find all objects under the mouse Point2D mouse = ClickZoomWireListener.theOne.getLastMouse(); Point2D mouseDB = curEdit.screenToDatabase((int)mouse.getX(), (int)mouse.getY()); EPoint point = new EPoint(mouseDB.getX(), mouseDB.getY()); GeometrySearch.GeometrySearchResult foundAtTopLevel = null; GeometrySearch search = new GeometrySearch(curEdit.getLayerVisibility(), curEdit.getGraphicsPreferences()); List<GeometrySearch.GeometrySearchResult> possibleTargets = search.searchGeometries(cell, point, true); // eliminate results at the top level and duplicate results at any lower level for(int i=0; i<possibleTargets.size(); i++) { GeometrySearch.GeometrySearchResult res = possibleTargets.get(i); if (res.getContext() == VarContext.globalContext) { possibleTargets.remove(i); i--; foundAtTopLevel = res; continue; } // also remove duplicate contexts at lower levels for(int j=0; j<i; j++) { GeometrySearch.GeometrySearchResult oRes = possibleTargets.get(j); if (sameContext(oRes.getContext(), res.getContext())) { possibleTargets.remove(i); i--; } } } // give error if nothing was found if (possibleTargets.size() == 0) { // nothing found, if top-level stuff found, say so if (foundAtTopLevel != null) System.out.println(foundAtTopLevel.describe() + " is at the top level, not down the hierarchy"); else System.out.println("No primitive node or arc found under the mouse at lower levels of hierarchy"); return; } // get the selected object to edit if (possibleTargets.size() == 1) { descendToObject(possibleTargets.get(0)); } else { // let the user choose JPopupMenu menu = new JPopupMenu(); JMenuItem menuItem = new JMenuItem("Multiple objects under the cursor...choose one"); menu.add(menuItem); menu.addSeparator(); for(GeometrySearch.GeometrySearchResult res : possibleTargets) { menuItem = new JMenuItem(res.describe()); menuItem.addActionListener(new DownHierToObjectActionListener(res)); menu.add(menuItem); } menu.show(curEdit, 100, 100); } } private static boolean sameContext(VarContext vc1, VarContext vc2) { if (vc1.getNumLevels() != vc2.getNumLevels()) return false; while (vc1.getNodable() != null && vc2.getNodable() != null) { if (vc1.getNodable() != vc2.getNodable()) return false; vc1 = vc1.pop(); vc2 = vc2.pop(); } return true; } private static void descendToObject(GeometrySearch.GeometrySearchResult res) { // descend to that object EditWindow curEdit = EditWindow.needCurrent(); System.out.println("Descending to cell " + res.getGeometric().getParent().getName()); for (Iterator<Nodable> it = res.getContext().getPathIterator(); it.hasNext(); ) { Nodable no = it.next(); Cell curCell = no.getParent(); curEdit.getHighlighter().clear(); curEdit.getHighlighter().addElectricObject(no.getNodeInst(), curCell); curEdit.getHighlighter().finished(); System.out.println(" Descended into "+no.getName()+"["+no.getProto().getName()+"] in cell "+curCell.getName()); curEdit.downHierarchy(false, false, true); } curEdit.getHighlighter().clear(); curEdit.getHighlighter().addElectricObject(res.getGeometric(), res.getGeometric().getParent()); curEdit.getHighlighter().finished(); } /** * This command goes up the hierarchy */ private static void upHierCommand(boolean keepFocus) { EditWindow curEdit = EditWindow.needCurrent(); if (curEdit == null) return; curEdit.upHierarchy(keepFocus); } private static void changeCellHistory(boolean back) { WindowFrame wf = WindowFrame.getCurrentWindowFrame(); if (wf == null) return; if (back) wf.cellHistoryGoBack(); else wf.cellHistoryGoForward(); } /** * This method implements the command to make a new version of the current Cell. */ private static void newCellVersionCommand() { Cell curCell = WindowFrame.needCurCell(); if (curCell == null) return; CircuitChanges.newVersionOfCell(curCell); } /** * This method implements the command to make a copy of the current Cell. */ private static void duplicateCellCommand() { Cell curCell = WindowFrame.needCurCell(); if (curCell == null) return; new CellMenu.NewCellName(false, curCell); } public static class NewCellName extends EDialog { private static final long serialVersionUID = 1L; private JTextField cellName; private Cell cell; private boolean allInGroup; /** Creates new form New Cell Name */ public NewCellName(boolean allInGroup, Cell cell) { super((Frame) Main.getCurrentJFrame(), true); this.allInGroup = allInGroup; this.cell = cell; setTitle(allInGroup ? "New Group Name" : "New Cell Name"); setName(""); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent evt) { closeDialog(); } }); getContentPane().setLayout(new GridBagLayout()); String prompt = "Name of duplicated cell"; if (allInGroup) prompt += " group"; JLabel lab = new JLabel(prompt + ":"); lab.setHorizontalAlignment(SwingConstants.LEFT); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; gbc.gridwidth = 2; gbc.anchor = GridBagConstraints.WEST; gbc.insets = new Insets(4, 4, 4, 4); getContentPane().add(lab, gbc); String oldCellName = cell.getName(); String newName = oldCellName + "NEW"; cellName = new JTextField(newName); cellName.setSelectionStart(oldCellName.length()); cellName.setSelectionEnd(newName.length()); cellName.setColumns(Math.max(20, newName.length())); cellName.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { ok(); } }); gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 1; gbc.gridwidth = 2; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.WEST; gbc.weightx = 1.0; gbc.insets = new Insets(4, 4, 4, 4); getContentPane().add(cellName, gbc); JButton cancel = new JButton("Cancel"); cancel.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { closeDialog(); } }); gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 2; gbc.insets = new Insets(4, 4, 4, 4); getContentPane().add(cancel, gbc); JButton ok = new JButton("OK"); ok.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { ok(); } }); gbc = new GridBagConstraints(); gbc.gridx = 1; gbc.gridy = 2; gbc.insets = new Insets(4, 4, 4, 4); getContentPane().add(ok, gbc); getRootPane().setDefaultButton(ok); pack(); finishInitialization(); setVisible(true); } protected void escapePressed() { closeDialog(); } private void ok() { String newName = cellName.getText(); closeDialog(); Cell already = cell.getLibrary().findNodeProto(newName); if (already != null && already.getView() == cell.getView()) { int response = JOptionPane.showOptionDialog(Main.getCurrentJFrame(), "Cell " + newName + " already exists. Make this a new version?", "Confirm duplication", JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, new String[] {"Yes", "Cancel"}, "Yes"); if (response != 0) return; } new CellChangeJobs.DuplicateCell(cell, newName, cell.getLibrary(), allInGroup, false); } } /** * Method to delete old, unused versions of cells. */ private static void deleteOldCellVersionsCommand() { // count the number of old unused cells to delete in the current and in other libraries int oldUnusedCurrent = 0, oldUnusedElsewhere = 0; for(Library lib : Library.getVisibleLibraries()) { for(Iterator<Cell> it = lib.getCells(); it.hasNext(); ) { Cell cell = it.next(); if (cell.getNewestVersion() == cell) continue; if (cell.getInstancesOf().hasNext()) continue; if (lib == Library.getCurrent()) oldUnusedCurrent++; else oldUnusedElsewhere++; } } // if complex, prompt for what to do if (oldUnusedCurrent+oldUnusedElsewhere != 0 && oldUnusedElsewhere != 0) { // old unused cells are not just in the current library: ask what to do String [] options = {"Current library", "Other libraries", "All libraries", "Cancel"}; int ret = Job.getUserInterface().askForChoice("There are " + oldUnusedCurrent + " old unused cells in the current library and " + oldUnusedElsewhere + " in other libraries. Which libraries should have their old unused cells deleted?", "Which Old Unused Cells to Delete", options, "No"); if (ret == 0) oldUnusedElsewhere = 0; if (ret == 1) oldUnusedCurrent = 0; if (ret == 3) return; } // stop now if nothing to delete if (oldUnusedCurrent == 0 && oldUnusedElsewhere == 0) { System.out.println("There are no old unused cells to delete"); return; } // pre-clean the cell references List<Cell> cellsToDelete = new ArrayList<Cell>(); for(Library lib : Library.getVisibleLibraries()) { if (lib == Library.getCurrent()) { if (oldUnusedCurrent == 0) continue; } else { if (oldUnusedElsewhere == 0) continue; } for(Iterator<Cell> it = lib.getCells(); it.hasNext(); ) { Cell cell = it.next(); if (cell.getNewestVersion() == cell) continue; if (cell.getInstancesOf().hasNext()) continue; CircuitChanges.cleanCellRef(cell); cellsToDelete.add(cell); } } // do the deletion new CellChangeJobs.DeleteManyCells(cellsToDelete); } /** * Method to temporarily expand the current selected area to the bottom. */ private static void peekCommand() { EditWindow wnd = EditWindow.needCurrent(); if (wnd == null) return; Highlighter highlighter = wnd.getHighlighter(); if (highlighter == null) return; Rectangle2D bounds = highlighter.getHighlightedArea(wnd); if (bounds == null) { System.out.println("Must define an area in which to display"); return; } wnd.repaintContents(bounds, true); } }