blob: 8b0688f3d9a37ce1afe3761e5208b9cca842d6ea [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2016 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.tools.internal;
import java.util.*;
import org.eclipse.swt.*;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.widgets.Text;
import org.w3c.dom.*;
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 {
for (TreeItem item : superItem.getItems()) {
if (name.equals(item.getData())) {
parentItem = item;
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 */
for (TreeItem child : item.getItems()) {
TreeItem[] children = child.getItems();
int checkedCount = 0;
for (TreeItem element : children) {
if (element.getChecked()) checkedCount++;
if (element.getGrayed()) break;
}
child.setChecked(checkedCount != 0);
child.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 (TreeItem item2 : items) {
checkItems(item2, 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, arg0 -> searchFor(search.getText()));
search.addListener(SWT.KeyDown, 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, 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, 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 = 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, e -> e.display.asyncExec (new Runnable () {
@Override
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, 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, event -> {
Composite parent1 = sash.getParent();
Rectangle rect = parent1.getClientArea();
event.x = Math.min (Math.max (event.x, 60), rect.width - 60);
if (event.detail != SWT.DRAG) {
FormData data1 = (FormData)sash.getLayoutData();
data1.left.offset = event.x;
parent1.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<>();
for (Document document : documents) {
if (document != null) addNodes(document, 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<>();
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 (TreeItem item : items) {
checkChildren(item);
if (item.getData() == node) return item;
}
for (TreeItem item : items) {
TreeItem child = findItem(item.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();
for (String extraAttrib : gen.getExtraAttributeNames(node)) {
TableItem attribItem = new TableItem(attribTable, SWT.NONE);
String attribName = extraAttrib;
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(extraAttrib);
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);
}
for (TreeColumn column : nodesTree.getColumns()) {
column.pack();
}
}
public void refresh () {
if (nodesTree == null) return;
gen.setXmls(null);
flatNodes = null;
nodesTree.getDisplay().asyncExec(() -> {
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 selectorEnumClass = args.length > 2 ? args[2] : "org.eclipse.swt.internal.cocoa.Selector";
String[] xmls = {};
if (args.length > 3) {
xmls = new String[args.length - 3];
System.arraycopy(args, 3, 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);
gen.setSelectorEnum(selectorEnumClass);
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();
}
}
}