package org.csstudio.sds.ui.internal.editor.newproperties;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.csstudio.sds.internal.model.StringMapProperty;
import org.csstudio.sds.model.AbstractWidgetModel;
import org.csstudio.sds.model.WidgetProperty;
import org.csstudio.sds.ui.SdsUiPlugin;
import org.csstudio.sds.ui.internal.editor.newproperties.table.ColumnConfig;
import org.csstudio.sds.ui.internal.editor.newproperties.table.ConvenienceTableWrapper;
import org.csstudio.sds.ui.internal.editor.newproperties.table.ITableRow;
import org.csstudio.ui.util.CustomMediaFactory;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.bindings.keys.ParseException;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
import org.eclipse.jface.fieldassist.IContentProposal;
import org.eclipse.jface.fieldassist.IContentProposalProvider;
import org.eclipse.jface.fieldassist.TextContentAdapter;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.widgets.Hyperlink;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
/**
* Section implementation for {@link StringMapProperty}.
*
* @author Sven Wende
*
*/
public class StringMapSection extends AbstractBaseSection<StringMapProperty> {
private TableViewer tableViewer;
private List<TableEditor> tableEditors = new ArrayList<TableEditor>();
public StringMapSection(String propertyId) {
super(propertyId);
}
/**
*{@inheritDoc}
*/
@Override
public int getMinimumHeight() {
return 150;
}
/**
*{@inheritDoc}
*/
@Override
protected void doCreateControls(final Composite parent, TabbedPropertySheetPage tabbedPropertySheetPage) {
parent.setLayout(new FormLayout());
FormData fd;
// .. table for viewing and editing the entries
Composite tableComposite = new Composite(parent, SWT.NONE);
fd = new FormData();
fd.left = new FormAttachment(0,0);
fd.right = new FormAttachment(100,-10);
fd.top = new FormAttachment(0,0);
fd.bottom = new FormAttachment(100,-50);
tableComposite.setLayoutData(fd);
tableComposite.setLayout(new TableColumnLayout());
tableComposite.setLayoutData(fd);
Table table = getWidgetFactory().createTable(tableComposite, SWT.FULL_SELECTION | SWT.DOUBLE_BUFFERED | SWT.SCROLL_PAGE | SWT.V_SCROLL);
table.setLinesVisible(true);
table.setHeaderVisible(false);
tableViewer = ConvenienceTableWrapper.equip(table, new ColumnConfig[] { new ColumnConfig("key", "Alias Name", 100, 10, true),
new ColumnConfig("value", "Value", 150, 30, false), new ColumnConfig("remove", "Alias Name", 30, -1, true) });
// .. button to add new entries to the table
Hyperlink addHyperLink = getWidgetFactory().createHyperlink(parent, "Add Entry", SWT.NONE);
addHyperLink.setUnderlined(false);
addHyperLink.addHyperlinkListener(new HyperlinkAdapter() {
@Override
public void linkActivated(HyperlinkEvent e) {
WidgetProperty property = getMainWidgetProperty();
if (property != null) {
Map<String, String> map = property.getPropertyValue();
if (map != null) {
int i = 0;
while (map.containsKey("new" + i)) {
i++;
}
Map<String, String> newMap = new LinkedHashMap<String, String>(map);
newMap.put("new" + i, "value");
applyPropertyChange(newMap);
}
}
}
});
fd = new FormData();
fd.left = new FormAttachment(0,0);
fd.right = new FormAttachment(100,0);
fd.top = new FormAttachment(tableComposite, 5);
fd.bottom = new FormAttachment(100,0);
addHyperLink.setLayoutData(fd);
}
/**
*{@inheritDoc}
*/
@Override
protected void doRefreshControls(StringMapProperty widgetProperty) {
// .. (re)create the table editors used for removing single lines of the
// table
if (tableEditors != null) {
// .. dispose existing editors
for (TableEditor editor : tableEditors) {
if (editor.getEditor() != null) {
editor.getEditor().dispose();
}
editor.dispose();
}
tableEditors.clear();
}
// .. create new editors
if (widgetProperty != null) {
Map<String, String> map = widgetProperty.getPropertyValue();
List<ITableRow> rows = new ArrayList<ITableRow>();
AbstractWidgetModel widgetModel = widgetProperty.getWidgetModel();
Map<String, String> allAliases = widgetModel.getAllInheritedAliases();
Map<String, String> inheritedAliases = new LinkedHashMap<String, String>(allAliases);
for (String key : map.keySet()) {
inheritedAliases.remove(key);
}
for (String key : map.keySet()) {
rows.add(new MapEntryTableRowAdapter(new LinkedHashMap<String, String>(map), key, createValueProposals(inheritedAliases)));
}
tableViewer.setInput(rows);
TableItem[] items = tableViewer.getTable().getItems();
for (int i = 0; i < items.length; i++) {
final TableItem item = items[i];
TableEditor tableEditor = new TableEditor(tableViewer.getTable());
Button button = new Button(tableViewer.getTable(), SWT.FLAT);
button.setImage(CustomMediaFactory.getInstance().getImageFromPlugin(SdsUiPlugin.PLUGIN_ID, "icons/delete.gif"));
button.pack();
tableEditor.minimumWidth = button.getSize().x;
tableEditor.horizontalAlignment = SWT.LEFT;
tableEditor.setEditor(button, item, 2);
button.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
MapEntryTableRowAdapter data = (MapEntryTableRowAdapter) item.getData();
data.setValue(2, "true");
}
});
tableEditors.add(tableEditor);
}
}
}
@SuppressWarnings("unused")
private IContentProposal[] createKeyProposals(Map<String, String> inheritedAliases) {
List<IContentProposal> result = new ArrayList<IContentProposal>();
for (String alias : inheritedAliases.keySet()) {
result.add(new AliasContentProposal(alias, alias + " -> " + inheritedAliases.get(alias)));
}
return result.toArray(new IContentProposal[result.size()]);
}
private IContentProposal[] createValueProposals(Map<String, String> inheritedAliases) {
List<IContentProposal> result = new ArrayList<IContentProposal>();
for (String k : inheritedAliases.keySet()) {
result.add(new AliasContentProposal(k, inheritedAliases.get(k)));
}
return result.toArray(new IContentProposal[result.size()]);
}
/**
* Content proposal for aliases.
*
* @author Sven Wende
*
*/
private static class AliasContentProposal implements IContentProposal {
private String content;
private String label;
public AliasContentProposal(String content, String label) {
super();
this.content = content;
this.label = label;
}
@Override
public String getContent() {
return "$" + content + "$";
}
@Override
public int getCursorPosition() {
return 0;
}
@Override
public String getDescription() {
return label;
}
@Override
public String getLabel() {
return "$" + content + "$";
}
}
/**
* Row adapter for the table entries.
*
* @author Sven Wende
*
*/
private class MapEntryTableRowAdapter implements ITableRow {
private final Map<String, String> map;
private final String key;
private final IContentProposal[] valueProposals;
public MapEntryTableRowAdapter(Map<String, String> map, String key, IContentProposal[] valueProposals) {
this.map = map;
this.key = key;
this.valueProposals = valueProposals;
}
@Override
public boolean canModify(int column) {
switch (column) {
case 0:
case 1:
return true;
default:
break;
}
return true;
}
@Override
public RGB getBackgroundColor(int column) {
return null;
}
@Override
public CellEditor getCellEditor(final int column, Composite parent) {
switch (column) {
case 0:
case 1:
TextCellEditor editor = new TextCellEditor(parent);
editor.getControl().setBackground(COLOR_CONTROL_ACTIVE);
IContentProposalProvider proposalProvider = new IContentProposalProvider() {
@Override
public IContentProposal[] getProposals(String contents, int position) {
if (column == 1) {
return valueProposals;
}
return null;
}
};
ContentProposalAdapter adapter = new ContentProposalAdapter(editor.getControl(), new TextContentAdapter(), proposalProvider,
getContentProposalActivationKeystroke(), getContentProposalActivationCharacters());
adapter.setPropagateKeys(true);
adapter.setPopupSize(new Point(400, 300));
return editor;
default:
return null;
}
}
/**
* Returns the characters which activate the content proposal popup
* menu. Default is "$" Subclasses may override.
*
* @return the characters which activate the content proposal popup menu
*/
private char[] getContentProposalActivationCharacters() {
return new char[] { '$' };
}
/**
* Returns the keystroke which activates the content proposal popup
* menu. Default is CTRL+Space Subclasses may override.
*
* @return the keystroke which activates the content proposal popup menu
*/
private KeyStroke getContentProposalActivationKeystroke() {
KeyStroke keyStroke;
try {
keyStroke = KeyStroke.getInstance("Ctrl+Space");
} catch (ParseException e1) {
keyStroke = null;
}
return keyStroke;
}
@Override
public String getDisplayValue(int column) {
switch (column) {
case 0:
return key;
case 1:
return map.get(key);
default:
return null;
}
}
@Override
public String getEditingValue(int column) {
switch (column) {
case 0:
return key;
case 1:
return map.get(key);
default:
return null;
}
}
@Override
public Font getFont(int column) {
switch (column) {
case 0:
return CustomMediaFactory.getInstance().getFont("Arial", 9, SWT.BOLD);
case 1:
return CustomMediaFactory.getInstance().getFont("Arial", 9, SWT.NONE);
default:
return null;
}
}
@Override
public RGB getForegroundColor(int column) {
switch (column) {
case 0:
return CustomMediaFactory.COLOR_DARK_GRAY;
case 1:
return CustomMediaFactory.COLOR_BLUE;
default:
return null;
}
}
@Override
public Image getImage(int column) {
return null;
}
@Override
public String getTooltip() {
return null;
}
@Override
public void setValue(int column, Object value) {
switch (column) {
case 0:
String val = map.get(key);
map.remove(key);
map.put(value.toString(), val);
applyPropertyChange(map);
break;
case 1:
map.put(key, value.toString());
applyPropertyChange(map);
break;
case 2:
map.remove(key);
applyPropertyChange(map);
break;
default:
break;
}
}
@Override
public int compareTo(ITableRow o) {
return 0;
}
}
}