/******************************************************************************* * Copyright (c) 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.swt.tools.internal; import java.util.ArrayList; import java.util.Collections; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.eclipse.swt.*; import org.eclipse.swt.custom.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.layout.*; import org.eclipse.swt.widgets.*; public class MacGeneratorUI { MacGenerator gen; boolean actions = true; public static boolean SHOW_SWT_PREFIX = true; Tree nodesTree; Table attribTable; public MacGeneratorUI(MacGenerator gen) { this.gen = gen; } TreeItem lastParent; TreeItem addChild (Node node, TreeItem superItem) { if (node.getNodeType() == Node.TEXT_NODE) return null; String name = node.getNodeName(); TreeItem parentItem = null; if (lastParent != null && !lastParent.isDisposed() && lastParent.getParentItem() == superItem && name.equals(lastParent.getData())) { parentItem = lastParent; } else { TreeItem[] items = superItem.getItems(); for (int i = 0; i < items.length; i++) { if (name.equals(items[i].getData())) { parentItem = items[i]; break; } } if (parentItem == null) { parentItem = new TreeItem(superItem, SWT.NONE); parentItem.setData(name); parentItem.setText(getPrettyText(name)); } lastParent = parentItem; } TreeItem item = new TreeItem(parentItem, SWT.NONE); Node idAttrib = gen.getIDAttribute(node); item.setText(idAttrib != null ? idAttrib.getNodeValue() : name); item.setData(node); checkItem(node, item); NodeList childNodes = node.getChildNodes(); if (childNodes.getLength() > 0) new TreeItem(item, SWT.NONE); return item; } void checkPath(TreeItem item, boolean checked, boolean grayed) { if (item == null) return; if (grayed) { checked = true; } else { int index = 0; TreeItem[] items = item.getItems(); while (index < items.length) { TreeItem child = items[index]; if (child.getGrayed() || checked != child.getChecked()) { checked = grayed = true; break; } index++; } } item.setChecked(checked); item.setGrayed(grayed); updateGenAttribute(item); checkPath(item.getParentItem(), checked, grayed); } void checkItem(Node node, TreeItem item) { NamedNodeMap attributes = node.getAttributes(); Node gen = attributes.getNamedItem("swt_gen"); if (gen != null) { String value = gen.getNodeValue(); boolean grayed = value.equals("mixed"); boolean checked = grayed || value.equals("true"); item.setChecked(checked); item.setGrayed(grayed); } } boolean getEditable(TableItem item, int column) { if (!(item.getData() instanceof Node)) return false; if (column == 0) return false; String attribName = item.getText(); return attribName.startsWith("swt_") || item.getData("swt_") != null; } String getPrettyText(String text) { if (text.equals("class")) return "Classes"; if (text.equals("depends_on")) return "Depends_on"; return text.substring(0, 1).toUpperCase() + text.substring(1) + "s"; } void checkChildren(TreeItem item) { TreeItem dummy; if (item.getItemCount() == 1 && (dummy = item.getItem(0)).getData() == null) { dummy.dispose(); Node node = (Node)item.getData(); NodeList childNodes = node.getChildNodes(); for (int i = 0, length = childNodes.getLength(); i < length; i++) { addChild(childNodes.item(i), item); } /* Figure out categories state */ TreeItem[] items = item.getItems(); for (int i = 0; i < items.length; i++) { TreeItem[] children = items[i].getItems(); int checkedCount = 0; for (int j = 0; j < children.length; j++) { if (children[j].getChecked()) checkedCount++; if (children[j].getGrayed()) break; } items[i].setChecked(checkedCount != 0); items[i].setGrayed(checkedCount != children.length); } } } void checkItems(TreeItem item, boolean checked) { item.setGrayed(false); item.setChecked(checked); updateGenAttribute(item); TreeItem[] items = item.getItems(); if (items.length == 1 && items[0].getData() == null) { /* Update model only if view is not created */ Node node = (Node)item.getData(); NodeList childNodes = node.getChildNodes(); for (int i = 0, length = childNodes.getLength(); i < length; i++) { checkNodes(childNodes.item(i), checked); } } else { for (int i = 0; i < items.length; i++) { checkItems(items[i], checked); } } } void checkNodes(Node node, boolean checked) { if (node instanceof Element) { if (checked) { ((Element)node).setAttribute("swt_gen", "true"); } else { ((Element)node).removeAttribute("swt_gen"); } } NodeList childNodes = node.getChildNodes(); for (int i = 0, length = childNodes.getLength(); i < length; i++) { checkNodes(childNodes.item(i), checked); } } void cleanup() { } Composite createSignaturesPanel(Composite parent) { Composite comp = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(2, false); layout.marginLeft = 5; layout.marginWidth = 0; comp.setLayout(layout); Label label = new Label(comp, SWT.NONE); label.setText("Signatures:"); final Text search = new Text(comp, SWT.BORDER | SWT.SINGLE | SWT.SEARCH); GridData data = new GridData(GridData.FILL_HORIZONTAL); search.setLayoutData(data); search.setText(".*"); search.addListener(SWT.DefaultSelection, new Listener() { public void handleEvent(Event arg0) { searchFor(search.getText()); } }); search.addListener(SWT.KeyDown, new Listener() { public void handleEvent(Event event) { if (event.keyCode == SWT.F6) { searchFor(search.getText()); } } }); nodesTree = new Tree(comp, SWT.SINGLE | SWT.CHECK | SWT.BORDER | SWT.FULL_SELECTION); data = new GridData(GridData.FILL_BOTH); data.horizontalSpan = 2; nodesTree.setLayoutData(data); nodesTree.addListener(SWT.Selection, new Listener() { public void handleEvent(Event event) { TreeItem item = (TreeItem)event.item; if (item == null) return; if (event.detail != SWT.CHECK) { selectChild(item); return; } boolean checked = item.getChecked(); item.getParent().setRedraw(false); checkItems(item, checked); checkPath(item.getParentItem(), checked, false); item.getParent().setRedraw(true); } }); nodesTree.addListener(SWT.Expand, new Listener() { public void handleEvent(Event event) { checkChildren((TreeItem)event.item); } }); return comp; } Composite createPropertiesPanel(Composite parent) { Composite comp = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(1, false); layout.marginWidth = 0; if (!actions) layout.marginRight = 5; comp.setLayout(layout); Label label = new Label(comp, SWT.NONE); label.setText("Properties:"); attribTable = new Table(comp, SWT.BORDER | SWT.FULL_SELECTION); GridData data = new GridData(GridData.FILL_BOTH); attribTable.setLayoutData(data); attribTable.setLinesVisible(true); attribTable.setHeaderVisible(true); TableColumn nameColumn = new TableColumn(attribTable, SWT.NONE); nameColumn.setText("Name"); nameColumn.pack(); TableColumn valueColumn = new TableColumn(attribTable, SWT.NONE); valueColumn.setText("Value"); valueColumn.pack(); final Text editorTx = new Text(attribTable, SWT.SINGLE); final TableEditor editor = new TableEditor(attribTable); editor.grabHorizontal = true; editor.setEditor(editorTx); Listener textListener = new Listener() { public void handleEvent(Event e) { if (e.type == SWT.KeyDown) { if (e.keyCode != SWT.F6) return; } if (e.type == SWT.Traverse) { switch (e.detail) { case SWT.TRAVERSE_ESCAPE: editor.setItem(null); break; default: return; } } editorTx.setVisible(false); TableItem item = editor.getItem(); if (item == null) return; int column = editor.getColumn(); String value = editorTx.getText(); item.setText(column, value); Element node = (Element)item.getData(); String name = item.getText(); if (!name.startsWith("swt_")) { name = "swt_" + name; } if (value.length() != 0) { node.setAttribute(name, value); } else { node.removeAttribute(name); } } }; editorTx.addListener(SWT.DefaultSelection, textListener); // editorTx.addListener(SWT.FocusOut, textListener); editorTx.addListener(SWT.KeyDown, textListener); editorTx.addListener(SWT.Traverse, textListener); attribTable.addListener(SWT.MouseDown, new Listener() { public void handleEvent(final Event e) { e.display.asyncExec (new Runnable () { public void run () { if (attribTable.isDisposed ()) return; if (e.button != 1) return; Point pt = new Point(e.x, e.y); TableItem item = attribTable.getItem(pt); if (item == null) return; int column = -1; for (int i = 0; i < attribTable.getColumnCount(); i++) { if (item.getBounds(i).contains(pt)) { column = i; break; } } if (column == -1) return; if (!getEditable(item, column)) return; editor.setColumn(column); editor.setItem(item); editorTx.setText(item.getText(column)); editorTx.selectAll(); editorTx.setVisible(true); editorTx.setFocus(); } }); } }); return comp; } Composite createActionsPanel(Composite parent) { Composite panel = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(1, true); layout.marginWidth = 10; panel.setLayout(layout); Button generate = new Button(panel, SWT.PUSH); generate.setText("Generate"); generate.addListener(SWT.Selection, new Listener() { public void handleEvent(Event event) { generate(null); } }); return panel; } public void generate(ProgressMonitor progress) { gen.generate(progress); } public boolean getActionsVisible() { return actions; } public void open(Composite parent) { FormLayout layout = new FormLayout(); parent.setLayout(layout); Composite signaturePanel = createSignaturesPanel(parent); final Sash sash = new Sash(parent, SWT.SMOOTH | SWT.VERTICAL); Composite propertiesPanel = createPropertiesPanel(parent); Composite actionsPanel = null; if (actions) { actionsPanel = createActionsPanel(parent); } FormData data; data = new FormData(); data.left = new FormAttachment(0, 0); data.top = new FormAttachment(0, 0); data.right = new FormAttachment(sash, 0); data.bottom = new FormAttachment(100, 0); signaturePanel.setLayoutData(data); data = new FormData(); data.left = new FormAttachment(null, Math.max(200, parent.getSize().x / 2)); data.top = new FormAttachment(0, 0); data.bottom = new FormAttachment(100, 0); sash.setLayoutData(data); data = new FormData(); data.left = new FormAttachment(sash, sash.computeSize(SWT.DEFAULT, SWT.DEFAULT).x); data.top = new FormAttachment(0, 0); data.right = actionsPanel != null ? new FormAttachment(actionsPanel, 0) : new FormAttachment(100, 0); data.bottom = new FormAttachment(100, 0); propertiesPanel.setLayoutData(data); if (actionsPanel != null) { data = new FormData(); data.top = new FormAttachment(0, 0); data.right = new FormAttachment(100, 0); data.bottom = new FormAttachment(100, 0); actionsPanel.setLayoutData(data); } sash.addListener(SWT.Selection, new Listener() { public void handleEvent(Event event) { Composite parent = sash.getParent(); Rectangle rect = parent.getClientArea(); event.x = Math.min (Math.max (event.x, 60), rect.width - 60); if (event.detail != SWT.DRAG) { FormData data = (FormData)sash.getLayoutData(); data.left.offset = event.x; parent.layout(true); } } }); updateNodes(); } public void dispose() { cleanup(); } ArrayList<Node> flatNodes; void searchFor(String name) { TreeItem[] selection = nodesTree.getSelection(); Node node = null; if (selection.length != 0) { if (selection[0].getData() instanceof Node) { node = (Node)selection[0].getData(); } else { if (selection[0].getItemCount() > 0 && selection[0].getItem(0).getData() instanceof Node) { node = (Node)selection[0].getItem(0).getData(); } } } Document[] documents = gen.getDocuments(); if (node == null && documents.length > 0) { int index = 0; while (index < documents.length && (node = documents[index]) == null) index++; } if (flatNodes == null) { flatNodes = new ArrayList<Node>(); for (int i = 0; i < documents.length; i++) { if (documents[i] != null) addNodes(documents[i], flatNodes); } } int index = 0; while (flatNodes.get(index++) != node){} int start = index; while (index < flatNodes.size()) { Node child = flatNodes.get(index); Node attribName = gen.getIDAttribute(child); if (attribName != null && attribName.getNodeValue().matches(name)) { selectNode(child); return; } index++; } index = 0; while (index < start) { Node child = flatNodes.get(index); Node attribName = gen.getIDAttribute(child); if (attribName != null && attribName.getNodeValue().matches(name)) { selectNode(child); return; } index++; } nodesTree.getDisplay().beep(); } void selectNode(Node node) { ArrayList<Node> path = new ArrayList<Node>(); do { path.add(node); node = node.getParentNode(); } while (node != null); TreeItem[] items = nodesTree.getItems(); Collections.reverse(path); path.remove(0); while (true) { TreeItem item = findItem(items, path.remove(0)); if (item == null) return; if (path.isEmpty()) { nodesTree.setSelection(item); selectChild(item); return; } items = item.getItems(); } } TreeItem findItem(TreeItem[] items, Node node) { for (int i = 0; i < items.length; i++) { TreeItem item = items[i]; checkChildren(item); if (item.getData() == node) return item; } for (int i = 0; i < items.length; i++) { TreeItem child = findItem(items[i].getItems(), node); if (child != null) return child; } return null; } void addNodes(Node node, ArrayList<Node> list) { if (node.getNodeType() == Node.TEXT_NODE) return; list.add(node); NodeList children = node.getChildNodes(); for (int i = 0, length = children.getLength(); i < length; i++) { Node child = children.item(i); addNodes(child, list); } } void selectChild(TreeItem item) { attribTable.removeAll(); if (!(item.getData() instanceof Node)) return; Node node = (Node)item.getData(); NamedNodeMap attributes = node.getAttributes(); String[] extraAttribs = gen.getExtraAttributeNames(node); for (int i = 0; i < extraAttribs.length; i++) { TableItem attribItem = new TableItem(attribTable, SWT.NONE); String attribName = extraAttribs[i]; if (!SHOW_SWT_PREFIX && attribName.startsWith("swt_")) { attribName = attribName.substring("swt_".length(), attribName.length()); attribItem.setData("swt_", "swt_"); } attribItem.setText(attribName); attribItem.setData(node); attribItem.setForeground(item.getDisplay().getSystemColor(SWT.COLOR_BLUE)); Node attrib = attributes.getNamedItem(extraAttribs[i]); if (attrib != null) { attribItem.setText(1, attrib.getNodeValue()); } } checkItem(node, item); for (int i = 0, length = attributes.getLength(); i < length; i++) { Node attrib = attributes.item(i); String attribName = attrib.getNodeName(); if (attribName.startsWith("swt_")) continue; TableItem attribItem = new TableItem(attribTable, SWT.NONE); attribItem.setText(attribName); attribItem.setText(1, attrib.getNodeValue()); } attribTable.getColumn(0).pack(); attribTable.getColumn(1).setWidth(500); } void updateGenAttribute (TreeItem item) { if (item.getData() instanceof Element) { Element node = (Element)item.getData(); if (item.getChecked()) { if (item.getGrayed()) { node.setAttribute("swt_gen", "mixed"); } else { node.setAttribute("swt_gen", "true"); } } else { node.removeAttribute("swt_gen"); } } } void updateNodes() { String[] xmls = gen.getXmls(); if (xmls == null) return; Document[] documents = gen.getDocuments(); for (int x = 0; x < xmls.length; x++) { String xmlPath = xmls[x]; Document document = documents[x]; if (document == null) { System.out.println("Could not find: " + xmlPath); continue; } TreeItem item = new TreeItem(nodesTree, SWT.NONE); String fileName = gen.getFileName(xmlPath); if (fileName.endsWith("Full.bridgesupport")) { fileName = fileName.substring(0, fileName.length() - "Full.bridgesupport".length()); } item.setText(fileName); Node node = document.getDocumentElement(); item.setData(node); checkItem(node, item); new TreeItem(item, SWT.NONE); } TreeColumn[] columns = nodesTree.getColumns(); for (int i = 0; i < columns.length; i++) { columns[i].pack(); } } public void refresh () { if (nodesTree == null) return; gen.setXmls(null); flatNodes = null; nodesTree.getDisplay().asyncExec(new Runnable() { public void run() { if (nodesTree == null || nodesTree.isDisposed()) return; nodesTree.removeAll(); attribTable.removeAll(); updateNodes(); } }); } public void setActionsVisible(boolean visible) { this.actions = visible; } public void setFocus() { nodesTree.setFocus(); } public static void main(String[] args) { String mainClass = args.length > 0 ? args[0] : "org.eclipse.swt.internal.cocoa.OS"; String outputDir = args.length > 1 ? args[1] : "../org.eclipse.swt/Eclipse SWT PI/cocoa/"; String[] xmls = {}; if (args.length > 2) { xmls = new String[args.length - 2]; System.arraycopy(args, 2, xmls, 0, xmls.length); } try { Display display = new Display(); Shell shell = new Shell(display); MacGenerator gen = new MacGenerator(); gen.setXmls(xmls); gen.setOutputDir(outputDir); gen.setMainClass(mainClass); MacGeneratorUI ui = new MacGeneratorUI(gen); ui.open(shell); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } ui.dispose(); display.dispose(); } catch (Throwable e) { e.printStackTrace(); } } }