/*******************************************************************************
* Copyright (c) 2011, 2012 Wind River Systems, Inc. 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:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.tcf.te.tcf.ui.controls;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.PlatformObject;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.tcf.te.runtime.interfaces.IDisposable;
import org.eclipse.tcf.te.tcf.ui.nls.Messages;
import org.eclipse.tcf.te.ui.dialogs.NameValuePairDialog;
import org.eclipse.tcf.te.ui.forms.parts.TablePart;
import org.eclipse.tcf.te.ui.swt.SWTControlUtil;
import org.eclipse.tcf.te.ui.tables.TableViewerComparator;
import org.eclipse.ui.forms.widgets.FormToolkit;
/**
* Peer attributes table part implementation.
*/
public class PeerAttributesTablePart extends TablePart implements IDisposable {
// The list of table nodes
/* default */ final List<TableNode> nodes = new ArrayList<TableNode>();
// A list of names which are banned from using
private List<String> bannedNames;
/**
* Peer attributes table table node implementation.
*/
protected static class TableNode extends PlatformObject {
/**
* The node name.
*/
public String name = ""; //$NON-NLS-1$
/**
* The node value.
*/
public String value = ""; //$NON-NLS-1$
}
/**
* Peer attributes table label provider implementation.
*/
protected static class TableLabelProvider extends LabelProvider implements ITableLabelProvider {
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int)
*/
@Override
public Image getColumnImage(Object element, int columnIndex) {
return null;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int)
*/
@Override
public String getColumnText(Object element, int columnIndex) {
String text = null;
if (element instanceof TableNode) {
switch (columnIndex) {
case 0:
text = ((TableNode)element).name;
break;
case 1:
text = ((TableNode)element).value;
break;
}
}
return text != null ? text : ""; //$NON-NLS-1$
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object)
*/
@Override
public String getText(Object element) {
return getColumnText(element, 0);
}
}
/**
* Constructor.
*/
public PeerAttributesTablePart() {
super(new String[] {
Messages.PeerAttributesTablePart_button_new,
Messages.PeerAttributesTablePart_button_edit,
Messages.PeerAttributesTablePart_button_remove
});
}
/* (non-Javadoc)
* @see org.eclipse.tcf.te.runtime.interfaces.IDisposable#dispose()
*/
@Override
public void dispose() {
}
/* (non-Javadoc)
* @see org.eclipse.tcf.te.ui.forms.parts.TablePart#configureTableViewer(org.eclipse.jface.viewers.TableViewer)
*/
@Override
protected void configureTableViewer(final TableViewer viewer) {
super.configureTableViewer(viewer);
if (viewer != null && viewer.getTable() != null && !viewer.getTable().isDisposed()) {
Table table = viewer.getTable();
// Create the table columns
new TableColumn(table, SWT.NONE).setText(Messages.PeerAttributesTablePart_column_name);
new TableColumn(table, SWT.NONE).setText(Messages.PeerAttributesTablePart_column_value);
// Create and configure the table layout
TableLayout tableLayout = new TableLayout();
tableLayout.addColumnData(new ColumnWeightData(40, true));
tableLayout.addColumnData(new ColumnWeightData(60, true));
table.setLayout(tableLayout);
table.setHeaderVisible(true);
table.setLinesVisible(true);
// Setup the cell editors
viewer.setColumnProperties(new String[] { Messages.PeerAttributesTablePart_column_name, Messages.PeerAttributesTablePart_column_value });
CellEditor[] cellEditors = new CellEditor[viewer.getColumnProperties().length];
cellEditors[0] = new TextCellEditor(table);
((Text)cellEditors[0].getControl()).setTextLimit(250);
cellEditors[1] = new TextCellEditor(table);
((Text)cellEditors[1].getControl()).setTextLimit(250);
viewer.setCellEditors(cellEditors);
viewer.setCellModifier(new ICellModifier() {
@Override
public boolean canModify(Object element, String property) {
return element instanceof TableNode && !isReadOnly();
}
@Override
public Object getValue(Object element, String property) {
String value = null;
if (element instanceof TableNode) {
if (Messages.PeerAttributesTablePart_column_name.equals(property)) {
value = ((TableNode)element).name;
}
else if (Messages.PeerAttributesTablePart_column_value.equals(property)) {
value = ((TableNode)element).value;
}
}
return value;
}
@Override
public void modify(Object element, String property, Object value) {
if (element instanceof TableItem) element = ((TableItem)element).getData();
if (element instanceof TableNode) {
if (Messages.PeerAttributesTablePart_column_name.equals(property)) {
((TableNode)element).name = value != null ? value.toString() : ""; //$NON-NLS-1$
}
else if (Messages.PeerAttributesTablePart_column_value.equals(property)) {
((TableNode)element).value = value != null ? value.toString() : ""; //$NON-NLS-1$
}
viewer.setInput(nodes);
onTableModified();
}
}
});
// Create and set content and label provider
viewer.setContentProvider(new ArrayContentProvider());
viewer.setLabelProvider(new TableLabelProvider());
// Configure the comparator
viewer.setComparator(new TableViewerComparator(viewer, (ITableLabelProvider)viewer.getLabelProvider()));
// Attach listeners
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
updateButtons();
}
});
}
}
/* (non-Javadoc)
* @see org.eclipse.tcf.te.ui.forms.parts.AbstractPartWithButtons#createControl(org.eclipse.swt.widgets.Composite, int, int, org.eclipse.ui.forms.widgets.FormToolkit)
*/
@Override
public void createControl(Composite parent, int style, int span, FormToolkit toolkit) {
super.createControl(parent, style, span, toolkit);
nodes.clear();
getTableViewer().setInput(nodes);
updateButtons();
}
/* (non-Javadoc)
* @see org.eclipse.tcf.te.ui.forms.parts.AbstractPartWithButtons#onButtonSelected(org.eclipse.swt.widgets.Button)
*/
@Override
protected void onButtonSelected(Button button) {
Assert.isNotNull(button);
if (Messages.PeerAttributesTablePart_button_new.equals(button.getText())) {
onNewPressed();
}
else if (Messages.PeerAttributesTablePart_button_edit.equals(button.getText())) {
onEditPressed();
}
else if (Messages.PeerAttributesTablePart_button_remove.equals(button.getText())) {
onRemovePressed();
}
}
/* (non-Javadoc)
* @see org.eclipse.tcf.te.ui.forms.parts.TablePart#updateButtons()
*/
@Override
public void updateButtons() {
int selectionCount = getTableViewer().getTable().getSelectionCount();
SWTControlUtil.setEnabled(getButton(Messages.PeerAttributesTablePart_button_new), !isReadOnly());
// Listed banned nodes are always read only
boolean banned = false;
if (selectionCount == 1) {
ISelection selection = getTableViewer().getSelection();
if (selection instanceof IStructuredSelection && !selection.isEmpty()) {
Object element = ((IStructuredSelection)selection).getFirstElement();
if (element instanceof TableNode && bannedNames != null) {
banned = bannedNames.contains(((TableNode)element).name);
}
}
}
SWTControlUtil.setEnabled(getButton(Messages.PeerAttributesTablePart_button_edit), selectionCount == 1 && !isReadOnly() && !banned);
SWTControlUtil.setEnabled(getButton(Messages.PeerAttributesTablePart_button_remove), selectionCount == 1 && !isReadOnly() && !banned);
}
/**
* Called from {@link #onButtonSelected(Button)} if "New..." got pressed.
*/
protected void onNewPressed() {
doEditTableNode(null);
}
/**
* Called from {@link #onButtonSelected(Button)} if "Edit..." got pressed.
*/
protected void onEditPressed() {
// Get the selection from the table
ISelection selection = getTableViewer().getSelection();
if (selection instanceof IStructuredSelection && !selection.isEmpty()) {
doEditTableNode((TableNode)((IStructuredSelection)selection).getFirstElement());
}
}
/**
* Called from {@link #onButtonSelected(Button)} if "Remove..." got pressed.
*/
protected void onRemovePressed() {
// Get the selection from the table
ISelection selection = getTableViewer().getSelection();
if (selection instanceof IStructuredSelection && !selection.isEmpty()) {
TableNode node = (TableNode)((IStructuredSelection)selection).getFirstElement();
int index = nodes.indexOf(node);
nodes.remove(node);
getTableViewer().setInput(nodes);
if (index < nodes.size()) getTableViewer().setSelection(new StructuredSelection(nodes.get(index)));
updateButtons();
onTableModified();
}
}
/**
* Opens the name/pair dialog.
*
* @param node The node to edit or <code>null</code>.
*/
protected void doEditTableNode(TableNode node) {
// If the node is null, the dialog will be opened as "Add" dialog
boolean addMode = node == null;
// Determine the initial values
String name = node != null ? node.name : ""; //$NON-NLS-1$
String value = node != null ? node.value : ""; //$NON-NLS-1$
// Determine the used names
Set<String> usedNames = new HashSet<String>(convertList2Map(nodes).keySet());
// Add banned names to the used names list
if (bannedNames != null) {
for (String bannedName : bannedNames) {
usedNames.add(bannedName);
}
}
// Remove the current name
usedNames.remove(name);
// Determine the dialog title, the title and the default message
String dialogTitle = addMode ? Messages.PeerAttributesTablePart_add_dialogTitle : Messages.PeerAttributesTablePart_edit_dialogTitle;
String title = addMode ? Messages.PeerAttributesTablePart_add_title : Messages.PeerAttributesTablePart_edit_title;
String message = addMode ? Messages.PeerAttributesTablePart_add_message : Messages.PeerAttributesTablePart_edit_message;
// Construct the name/value pair dialog
NameValuePairDialog dialog = new NameValuePairDialog(getViewer().getControl().getShell(),
dialogTitle, title, message,
new String[] { Messages.PeerAttributesTablePart_column_name, Messages.PeerAttributesTablePart_column_value },
new String[] { name, value },
usedNames
);
// Open the dialog
if (dialog.open() == Window.OK) {
// If the user pressed OK, copy the data to the given node
// or create a new node in add mode.
String[] pair = dialog.getNameValuePair();
if (addMode) {
node = new TableNode();
nodes.add(node);
}
Assert.isNotNull(node);
node.name = pair[0];
node.value = pair[1];
// Refresh the view
getTableViewer().setInput(nodes);
getTableViewer().setSelection(new StructuredSelection(node));
onTableModified();
}
}
/**
* Signals the modification of the table.
*/
protected void onTableModified() {
}
/**
* Convert the given list into a map.
*
* @param list The list of table node. Must not be <code>null</code>:
* @return The corresponding map.
*/
private static Map<String, String> convertList2Map(List<TableNode> list) {
Assert.isNotNull(list);
Map<String, String> map = new LinkedHashMap<String, String>();
for (TableNode node : list) {
map.put(node.name, node.value);
}
return map;
}
/**
* Returns the configured attributes.
*
* @return The configured attributes.
*/
public Map<String, String> getAttributes() {
return convertList2Map(nodes);
}
/**
* Set the configured attributes to what is present in the given attributes map.
* <p>
* <b>Note:</b> If the given attributes map is <code>null</code> or empty, the table
* will be effectively cleared.
*
* @param attributes The map of attributes, an empty map or <code>null</code>.
*/
public void setAttributes(Map<String, String> attributes) {
// Clear the old nodes
nodes.clear();
if (attributes != null && !attributes.isEmpty()) {
// Create the corresponding nodes for the given attributes
for (Entry<String, String> entry : attributes.entrySet()) {
TableNode node = new TableNode();
node.name = entry.getKey();
node.value = entry.getValue();
nodes.add(node);
}
}
// Refresh the view
getTableViewer().setInput(nodes);
}
/**
* Set a list of banned names.
*
* @param bannedNames The list of banned names or <code>null</code>.
*/
public final void setBannedNames(String[] bannedNames) {
this.bannedNames = bannedNames != null ? Arrays.asList(bannedNames) : null;
}
/**
* Returns the list of banned names.
*
* @return The list of banned names or <code>null</code>.
*/
public final String[] getBannedNames() {
return bannedNames != null ? bannedNames.toArray(new String[bannedNames.size()]) : new String[0];
}
}