/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: TechEditWizard.java * * Copyright (c) 2008, 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.tecEditWizard2; import com.sun.electric.Main; import com.sun.electric.tool.user.dialogs.EDialog; 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.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.Arrays; import java.util.List; import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTree; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeExpansionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; /** * Class to handle the "Technology Creation Wizard" dialog. */ public class TechEditWizard extends EDialog { private JSplitPane splitPane; private JTree optionTree; private TechEditWizardPanel currentOptionPanel; private DefaultMutableTreeNode currentDMTN; private static TechEditWizardData data = new TechEditWizardData(); /** The name of the current tab in this dialog. */ private static String currentTabName = "General"; /** * This method implements the command to show the Technology Creation Wizard dialog. */ public static void techEditWizardCommand() { TechEditWizard dialog = new TechEditWizard((Frame) Main.getCurrentJFrame()); dialog.setVisible(true); } /** Creates new form TechEditWizard */ public TechEditWizard(Frame parent) { super(parent, true); getContentPane().setLayout(new GridBagLayout()); setTitle("Technology Creation Wizard"); setName(""); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent evt) { closeDialog(evt); } }); DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("Technology Parameters"); DefaultTreeModel treeModel = new DefaultTreeModel(rootNode); optionTree = new JTree(treeModel); TreeHandler handler = new TreeHandler(this); optionTree.addMouseListener(handler); optionTree.addTreeExpansionListener(handler); addTreeNode(rootNode, "General"); addTreeNode(rootNode, "Active"); addTreeNode(rootNode, "Poly"); addTreeNode(rootNode, "Gate"); addTreeNode(rootNode, "Contact"); addTreeNode(rootNode, "Well/Implant"); addTreeNode(rootNode, "Metal"); for (int i = 1; i <= 3; i++) { addTreeNode(rootNode, "Metal" + i); } addTreeNode(rootNode, "Via"); addTreeNode(rootNode, "Antenna"); addTreeNode(rootNode, "GDS"); // pre-expand the tree TreePath topPath = optionTree.getPathForRow(0); optionTree.expandPath(topPath); topPath = optionTree.getPathForRow(1); optionTree.expandPath(topPath); // searching for selected node openSelectedPath(rootNode); // the left side of the Technology Editor dialog: a tree JPanel leftPanel = new JPanel(); leftPanel.setLayout(new GridBagLayout()); JScrollPane scrolledTree = new JScrollPane(optionTree); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; gbc.gridwidth = 2; gbc.fill = GridBagConstraints.BOTH; gbc.weightx = 1.0; gbc.weighty = 1.0; leftPanel.add(scrolledTree, gbc); JButton importBut = new JButton("Load Parameters"); importBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { importActionPerformed(); } }); gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 1; gbc.insets = new Insets(4, 4, 4, 4); leftPanel.add(importBut, gbc); JButton exportBut = new JButton("Save Parameters"); exportBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { exportActionPerformed(); } }); gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 2; gbc.insets = new Insets(4, 4, 4, 4); leftPanel.add(exportBut, gbc); JButton makeTech = new JButton("Write XML"); makeTech.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { makeTechnologyActionPerformed(); } }); gbc = new GridBagConstraints(); gbc.gridx = 1; gbc.gridy = 1; gbc.insets = new Insets(4, 4, 4, 4); leftPanel.add(makeTech, gbc); JButton okBut = new JButton("Done"); okBut.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { okActionPerformed(); } }); gbc = new GridBagConstraints(); gbc.gridx = 1; gbc.gridy = 2; gbc.insets = new Insets(4, 4, 4, 4); leftPanel.add(okBut, gbc); getRootPane().setDefaultButton(okBut); // build Technology Editor framework splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); loadOptionPanel(); recursivelyHighlight(optionTree, rootNode, currentDMTN, optionTree.getPathForRow(0)); splitPane.setLeftComponent(leftPanel); gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; gbc.gridwidth = 1; gbc.fill = GridBagConstraints.BOTH; gbc.weightx = 1.0; gbc.weighty = 1.0; getContentPane().add(splitPane, gbc); pack(); finishInitialization(); } private void addTreeNode(DefaultMutableTreeNode rootNode, String name) { DefaultMutableTreeNode dmtn = new DefaultMutableTreeNode(name); rootNode.add(dmtn); if (name.equals(currentTabName)) currentDMTN = dmtn; } public TechEditWizardData getTechEditData() { return data; } private boolean openSelectedPath(DefaultMutableTreeNode rootNode) { for (int i = 0; i < rootNode.getChildCount(); i++) { DefaultMutableTreeNode node = (DefaultMutableTreeNode)rootNode.getChildAt(i); Object o = node.getUserObject(); if (o.toString().equals(currentTabName)) { optionTree.scrollPathToVisible(new TreePath(node.getPath())); return true; } if (openSelectedPath(node)) return true; } return false; } private void okActionPerformed() { // gather preference changes on the client if (currentOptionPanel != null) { currentOptionPanel.term(); currentOptionPanel = null; } closeDialog(null); } private void importActionPerformed() { data.importData(); if (currentOptionPanel != null) currentOptionPanel.init(); } private void exportActionPerformed() { if (currentOptionPanel != null) currentOptionPanel.term(); data.exportData(); } private void makeTechnologyActionPerformed() { if (currentOptionPanel != null) currentOptionPanel.term(); data.writeXML(); } private void loadOptionPanel() { TechEditWizardPanel ti = createOptionPanel(isModal()); if (ti == null) return; if (currentOptionPanel != null) currentOptionPanel.term(); currentOptionPanel = ti; ti.init(); splitPane.setRightComponent(ti.getComponent()); } private TechEditWizardPanel createOptionPanel(boolean modal) { if (currentTabName.equals("Active")) { List<String> labels = Arrays.asList( "Width (A):", "Poly overhang (B):", "Contact overhang (C):", "Spacing (D):"); data = getTechEditData(); List<WizardField> fields = Arrays.asList( data.getDiffWidth(), data.getDiffPolyOverhang(), data.getDiffContactOverhang(), data.getDiffSpacing() ); return new GenericPanel(this, "Active", "Active Parameters", labels, fields); } if (currentTabName.equals("General")) return new General(this, modal); if (currentTabName.equals("Gate")) { List<String> labels = Arrays.asList( "Length (A):", "Width (B):", "Contact spacing (C):", "Spacing (D):"); data = getTechEditData(); List<WizardField> fields = Arrays.asList( data.getGateLength(), data.getGateWidth(), data.getGateContactSpacing(), data.getGateSpacing() ); return new GenericPanel(this, "Gate", "Gate Parameters", labels, fields); } if (currentTabName.equals("Poly")) { List<String> labels = Arrays.asList( "Width (A):", "Endcap (B):", "Active spacing (C):", "Spacing (D):"); data = getTechEditData(); List<WizardField> fields = Arrays.asList( data.getPolyWidth(), data.getPolyEndcap(), data.getPolyDiffSpacing(), data.getPolySpacing() ); return new GenericPanel(this, "Poly", "Polysilicon Parameters", labels, fields); } if (currentTabName.equals("Contact")) { List<String> labels = Arrays.asList( "Cut size (A):", "Cut inline spacing (B):", "Cut array spacing (C):", "Metal overhang, inline (D):", "Metal overhang, all (E):", "Poly overhang (F):", "Active spacing (G):"); data = getTechEditData(); List<WizardField> fields = Arrays.asList( data.getContactSize(), data.getContactSpacing(), data.getContactArraySpacing(), data.getContactMetalOverhangInlineOnly(), data.getContactMetalOverhangAllSides(), data.getContactPolyOverhang(), data.getContactArraySpacing() ); return new GenericPanel(this, "Contact", "Contact Parameters", labels, fields); } if (currentTabName.equals("Well/Implant")) { List<String> labels = Arrays.asList( "NPlus width (A):", "NPlus active overhang (B):", "NPlus STRAP overhang (B'):", "NPlus poly overhang (C):", "NPlus spacing (D):", "PPlus width (E):", "PPlus active overhang (F):", "PPlus STRAP overhang (F'):", "PPlus poly overhang (G):", "PPlus spacing (H):", "NWell width (I):", "NWell P active overhang (J):", "NWell N active overhang (K):", "NWell spacing (L):"); data = getTechEditData(); List<WizardField> fields = Arrays.asList( data.getNPlusWidth(), data.getNPlusOverhangDiff(), data.getNPlusOverhangStrap(), data.getNPlusOverhangPoly(), data.getNPlusSpacing(), data.getPPlusWidth(), data.getPPlusOverhangDiff(), data.getPPlusOverhangStrap(), data.getPPlusOverhangPoly(), data.getPPlusSpacing(), data.getNWellWidth(), data.getNWellOverhangDiffP(), data.getNWellOverhangDiffN(), data.getNWellWidth() ); return new GenericPanel(this, "WellImplant", "Well / Implant Parameters", labels, fields); } if (currentTabName.equals("Metal")) return new Metal(this, modal); if (currentTabName.startsWith("Metal")) { int metalIndex = Integer.valueOf(currentTabName.substring(5)); List<String> labels = Arrays.asList( "Metal-" + metalIndex + " width (A):", "Metal-" + metalIndex + " spacing (B):"); List<WizardField> fields = Arrays.asList( data.getMetalWidth()[metalIndex - 1], data.getMetalSpacing()[metalIndex - 1] ); return new GenericPanel(this, "Metal", "Metal-" + metalIndex + " Parameters", labels, fields); } if (currentTabName.equals("Via")) return new Via(this, modal); if (currentTabName.equals("Antenna")) return new Antenna(this, modal); if (currentTabName.equals("GDS")) return new GDS(this, modal); return null; } protected void escapePressed() { okActionPerformed(); } private static class TreeHandler implements MouseListener, TreeExpansionListener { private TechEditWizard dialog; TreeHandler(TechEditWizard dialog) { this.dialog = dialog; } public void mouseClicked(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} public void mousePressed(MouseEvent e) { TreePath currentPath = dialog.optionTree.getPathForLocation(e.getX(), e.getY()); if (currentPath == null) return; dialog.optionTree.setSelectionPath(currentPath); DefaultMutableTreeNode node = (DefaultMutableTreeNode)currentPath.getLastPathComponent(); currentTabName = (String)node.getUserObject(); dialog.optionTree.expandPath(currentPath); if (!currentTabName.endsWith(" ")) { dialog.loadOptionPanel(); } dialog.pack(); } public void treeCollapsed(TreeExpansionEvent e) { dialog.pack(); } public void treeExpanded(TreeExpansionEvent e) { TreePath tp = e.getPath(); if (tp.getPathCount() == 2) { // opened a path down to the bottom: close all others TreePath topPath = dialog.optionTree.getPathForRow(0); DefaultMutableTreeNode node = (DefaultMutableTreeNode)topPath.getLastPathComponent(); int numChildren = node.getChildCount(); for(int i=0; i<numChildren; i++) { DefaultMutableTreeNode child = (DefaultMutableTreeNode)node.getChildAt(i); TreePath descentPath = topPath.pathByAddingChild(child); if (!descentPath.getLastPathComponent().equals(tp.getLastPathComponent())) { dialog.optionTree.collapsePath(descentPath); } } } dialog.pack(); } } /** Closes the dialog */ private void closeDialog(WindowEvent evt) { setVisible(false); dispose(); } }