/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.components.outputwriter.gui;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.annotate.JsonMethod;
import org.codehaus.jackson.map.ObjectMapper;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;
import de.rcenvironment.components.outputwriter.common.OutputLocation;
import de.rcenvironment.components.outputwriter.common.OutputLocationList;
import de.rcenvironment.components.outputwriter.common.OutputWriterComponentConstants;
import de.rcenvironment.core.component.model.endpoint.api.EndpointDescription;
import de.rcenvironment.core.component.workflow.model.spi.ComponentInstanceProperties;
import de.rcenvironment.core.datamodel.api.DataType;
import de.rcenvironment.core.gui.workflow.editor.properties.Refreshable;
import de.rcenvironment.core.gui.workflow.editor.properties.WorkflowNodeCommand;
import de.rcenvironment.core.gui.workflow.editor.properties.WorkflowNodeCommand.Executor;
import de.rcenvironment.core.utils.common.JsonUtils;
/**
* UI part to add and edit OutputLocations in the OutputWriter Component.
*
* @author Brigitte Boden
*/
public class OutputLocationPane implements Refreshable {
protected Section section;
protected Composite client;
protected ComponentInstanceProperties configuration;
protected Table table;
protected Button buttonAdd;
protected Button buttonEdit;
protected Button buttonRemove;
protected ButtonSelectionAdapter buttonListener;
protected MenuItem itemAdd;
protected MenuItem itemEdit;
protected MenuItem itemRemove;
protected Image icon;
protected TableColumnLayout tableLayout;
protected Executor executor;
protected ObjectMapper jsonMapper;
public OutputLocationPane(Executor executor) {
super();
this.executor = executor;
jsonMapper = JsonUtils.getDefaultObjectMapper();
jsonMapper.setVisibility(JsonMethod.ALL, Visibility.ANY);
}
/**
* {@inheritDoc}
*
* @see de.rcenvironment.core.gui.workflow.editor.properties.Refreshable#refresh()
*/
@Override
public void refresh() {
updateTable();
}
/**
* @return the main Control
*/
public Control getControl() {
return section;
}
/**
* Set the component instance configuration for configuration handling & storage; must not be null.
*
* @param configuration Component configuration
*/
public void setConfiguration(final ComponentInstanceProperties configuration) {
this.configuration = configuration;
updateTable();
}
/**
* Creating gui.
*
* @param parent parent Composite
* @param title Title of selection pane
* @param toolkit Formtoolkit to use
* @return control
*/
public Control createControl(final Composite parent, String title, FormToolkit toolkit) {
section = toolkit.createSection(parent, Section.TITLE_BAR | Section.EXPANDED);
section.setText(title);
client = toolkit.createComposite(section);
client.setLayout(new GridLayout(2, false));
final Composite tableComposite = toolkit.createComposite(client);
tableLayout = new TableColumnLayout();
tableComposite.setLayout(tableLayout);
table = toolkit.createTable(tableComposite, SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI | SWT.FULL_SELECTION | SWT.BORDER);
table.setHeaderVisible(true);
GridData tableLayoutData = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 3);
final int minHeight = 100;
tableLayoutData.heightHint = minHeight; // effectively min height
tableComposite.setLayoutData(tableLayoutData);
Listener tableListener = getTableListener(parent);
table.addListener(SWT.Dispose, tableListener);
table.addListener(SWT.KeyDown, tableListener);
table.addListener(SWT.MouseMove, tableListener);
table.addListener(SWT.MouseHover, tableListener);
table.addListener(SWT.MouseDoubleClick, tableListener);
final int columnWeight = 20;
// column - Target Name
TableColumn colName = new TableColumn(table, SWT.NONE);
colName.setText(de.rcenvironment.components.outputwriter.gui.Messages.outputLocFilename);
// column - Target Folder
TableColumn colFolder = new TableColumn(table, SWT.NONE);
colFolder.setText(de.rcenvironment.components.outputwriter.gui.Messages.targetFolder);
// column - Inputs
TableColumn colInputs = new TableColumn(table, SWT.NONE);
colInputs.setText(de.rcenvironment.components.outputwriter.gui.Messages.inputsForOutputLocation);
tableLayout.setColumnData(colInputs, new ColumnWeightData(columnWeight, true));
tableLayout.setColumnData(colName, new ColumnWeightData(columnWeight, true));
tableLayout.setColumnData(colFolder, new ColumnWeightData(columnWeight, true));
buttonAdd = toolkit.createButton(client, Messages.add, SWT.FLAT);
buttonAdd.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
buttonEdit = toolkit.createButton(client, Messages.edit, SWT.FLAT);
buttonEdit.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
buttonEdit.setEnabled(false);
buttonRemove = toolkit.createButton(client, Messages.remove, SWT.FLAT);
buttonRemove.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
buttonRemove.setEnabled(false);
table.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateButtonActivation();
}
});
buttonListener = new ButtonSelectionAdapter();
buttonAdd.addSelectionListener(buttonListener);
buttonEdit.addSelectionListener(buttonListener);
buttonRemove.addSelectionListener(buttonListener);
fillContextMenu(table);
table.addKeyListener(new DeleteKeyListener());
section.setClient(client);
toolkit.paintBordersFor(client);
section.setExpanded(true);
return section;
}
private void fillContextMenu(Table tab) {
Menu menu = new Menu(tab);
itemAdd = new MenuItem(menu, SWT.PUSH);
itemAdd.setText(Messages.add);
itemAdd.addSelectionListener(buttonListener);
itemEdit = new MenuItem(menu, SWT.PUSH);
itemEdit.setText(Messages.edit);
itemEdit.addSelectionListener(buttonListener);
itemRemove = new MenuItem(menu, SWT.PUSH);
itemRemove.setText(Messages.remove);
itemRemove.addSelectionListener(buttonListener);
tab.setMenu(menu);
}
private Listener getTableListener(final Composite parent) {
Listener tableListener = new Listener() {
private Shell tip = null;
@Override
public void handleEvent(Event event) {
switch (event.type) {
case SWT.Dispose:
case SWT.KeyDown:
case SWT.MouseMove:
if (tip == null) {
break;
}
tip.dispose();
tip = null;
break;
case SWT.MouseHover:
break;
case SWT.MouseDoubleClick:
if (buttonEdit != null && buttonEdit.isEnabled() && event.button == 1) {
onEditClicked();
}
break;
default:
break;
}
}
};
return tableListener;
}
/**
*
* Delete by keyboard.
*
*/
private class DeleteKeyListener implements KeyListener {
@Override
public void keyPressed(KeyEvent event) {
if (event.keyCode == SWT.DEL) {
if (buttonRemove.isEnabled()) {
onRemovedClicked();
}
}
}
@Override
public void keyReleased(KeyEvent event) {}
}
protected void onRemovedClicked() {
TableItem[] selection = table.getSelection();
List<String> names = new LinkedList<String>();
for (int i = 0; i < selection.length; i++) {
names.add((String) selection[i].getData());
}
executeRemoveCommand(names);
}
protected void executeRemoveCommand(String name) {
List<String> nameList = new ArrayList<String>();
nameList.add(name);
executeRemoveCommand(nameList);
}
protected void executeRemoveCommand(List<String> names) {
final WorkflowNodeCommand command = new RemoveOutputLocationsCommand(names, this);
execute(command);
}
protected void updateTable() {
if (!getControl().isDisposed()) {
fillTable();
updateButtonActivation();
}
}
/**
* Loads the current output locations into the UI table.
*/
protected void fillTable() {
if (client.getSize().x != 0) {
table.removeAll();
String jsonString = configuration.getConfigurationDescription()
.getConfigurationValue(OutputWriterComponentConstants.CONFIG_KEY_OUTPUTLOCATIONS);
if (jsonString == null) {
jsonString = "";
}
try {
OutputLocationList list =
jsonMapper.readValue(jsonString, OutputLocationList.class);
for (OutputLocation ol : list.getOutputLocations()) {
TableItem item = new TableItem(table, SWT.None);
item.setData(ol.getGroupId());
item.setText(0, ol.getFilename());
item.setText(1, ol.getFolderForSaving());
item.setText(2, ol.getInputs().toString());
}
} catch (IOException e) {
LogFactory.getLog(getClass()).debug("Error when reading targets from JSON: " + e.getMessage());
}
}
}
/**
* SelectionAdapter for the Add, Edit and Remove Buttons.
*
*/
private class ButtonSelectionAdapter extends SelectionAdapter {
@Override
public void widgetSelected(SelectionEvent e) {
if (e.widget == buttonAdd || e.widget == itemAdd) {
onAddClicked();
} else if (e.widget == buttonEdit || e.widget == itemEdit) {
onEditClicked();
} else if (e.widget == buttonRemove || e.widget == itemRemove) {
onRemovedClicked();
}
}
}
protected void onEditClicked() {
final String id = (String) table.getSelection()[0].getData();
OutputLocation selectedLocation = new OutputLocation();
Set<String> paths = new TreeSet<String>();
List<String> possibleInputs = getPossibleInputs();
List<String> selectedInputs = new ArrayList<String>();
List<String> otherOutputLocationNamesWithPahts = new ArrayList<String>();
// Parse outputLocation Configuration for initializing the dialog values
String jsonString = configuration.getConfigurationDescription()
.getConfigurationValue(OutputWriterComponentConstants.CONFIG_KEY_OUTPUTLOCATIONS);
if (jsonString == null) {
jsonString = "{}";
}
try {
OutputLocationList list = jsonMapper.readValue(jsonString, OutputLocationList.class);
selectedLocation = list.getOutputLocationById(id);
// Parse folders for paths and parse selected inputs
for (OutputLocation ol : list.getOutputLocations()) {
paths.add(ol.getFolderForSaving());
if (!ol.getGroupId().equals(id)) {
selectedInputs.addAll(ol.getInputs());
otherOutputLocationNamesWithPahts.add(ol.getFolderForSaving() + File.separator + ol.getFilename());
}
}
} catch (IOException e) {
LogFactory.getLog(getClass()).debug("Error when parsing JSON file " + e.getMessage());
}
OutputLocationEditDialog dialog =
new OutputLocationEditDialog(Display.getDefault().getActiveShell(), Messages.outputLocationEditDialogTitle, paths,
possibleInputs, selectedInputs, otherOutputLocationNamesWithPahts);
dialog.initializeValues(selectedLocation);
if (dialog.open() == Dialog.OK) {
// If some values have changed, execute an edit command
if (!dialog.getChosenFilename().equals(selectedLocation.getFilename())
|| !dialog.getChosenFolderForSaving().equals(
selectedLocation.getFolderForSaving())
|| !dialog.getChosenHeader().equals(
selectedLocation.getHeader())
|| !dialog.getChosenFormatString().equals(
selectedLocation.getFormatString())
|| !dialog.getChosenHandle().equals(
selectedLocation.getHandleExistingFile())
|| !dialog.getChosenInputSet().equals(selectedLocation.getInputs())) {
OutputLocation out =
new OutputLocation(id, dialog.getChosenFilename(), dialog.getChosenFolderForSaving(), dialog.getChosenHeader(),
dialog.getChosenFormatString(), dialog.getChosenHandle(), dialog.getChosenInputSet());
WorkflowNodeCommand command = new EditOutputLocationsCommand(out, this);
execute(command);
}
}
refresh();
}
protected void onAddClicked() {
Set<String> paths = new TreeSet<String>();
List<String> possibleInputs = getPossibleInputs();
List<String> selectedInputs = new ArrayList<String>();
List<String> otherOutputLocationNameswithPaths = new ArrayList<String>();
// Parse outputLocation Configuration for initializing names, paths and possible inputs
String jsonString = configuration.getConfigurationDescription()
.getConfigurationValue(OutputWriterComponentConstants.CONFIG_KEY_OUTPUTLOCATIONS);
if (jsonString == null) {
jsonString = "{}";
}
try {
OutputLocationList list = jsonMapper.readValue(jsonString, OutputLocationList.class);
// Parse folders for paths and parse selected inputs
for (OutputLocation ol : list.getOutputLocations()) {
paths.add(ol.getFolderForSaving());
selectedInputs.addAll(ol.getInputs());
otherOutputLocationNameswithPaths.add(ol.getFolderForSaving() + File.separator + ol.getFilename());
}
} catch (IOException e) {
LogFactory.getLog(getClass()).debug("Error when parsing JSON file " + e.getMessage());
}
OutputLocationEditDialog dialog =
new OutputLocationEditDialog(Display.getDefault().getActiveShell(),
de.rcenvironment.components.outputwriter.gui.Messages.outputLocationAddDialogTitle, paths, possibleInputs,
selectedInputs, otherOutputLocationNameswithPaths);
if (dialog.open() == Dialog.OK) {
OutputLocation out =
new OutputLocation(dialog.getChosenFilename(), dialog.getChosenFolderForSaving(), dialog.getChosenHeader(),
dialog.getChosenFormatString(), dialog.getChosenHandle(), dialog.getChosenInputSet());
WorkflowNodeCommand command = new EditOutputLocationsCommand(out, this);
execute(command);
}
refresh();
}
private List<String> getPossibleInputs() {
// Search component configuration for possible inputs (only simple data types can be written into an output location)
List<String> possibleInputs = new ArrayList<String>();
for (EndpointDescription input : configuration.getInputDescriptionsManager().getEndpointDescriptions()) {
if (!input.getDataType().equals(DataType.FileReference) && !input.getDataType().equals(DataType.DirectoryReference)) {
possibleInputs.add(input.getName());
}
}
return possibleInputs;
}
protected void execute(final WorkflowNodeCommand command) {
if (executor == null) {
throw new RuntimeException("No executor set for execution of workflow node commands");
}
if (command != null) {
executor.execute(command);
}
}
/**
* Enabled or disables the "add", "edit" and "remove" buttons.
*/
protected void updateButtonActivation() {
TableItem[] selection = table.getSelection();
boolean hasSelection = selection.length != 0;
buttonRemove.setEnabled(hasSelection);
if (selection.length == 1 && !getPossibleInputs().isEmpty()) {
buttonEdit.setEnabled(true);
} else {
buttonEdit.setEnabled(false);
}
if (getPossibleInputs().isEmpty()) {
buttonAdd.setEnabled(false);
//Only disable table if it is empty
if (table.getItemCount() == 0) {
table.setEnabled(false);
}
} else {
buttonAdd.setEnabled(true);
table.setEnabled(true);
}
itemEdit.setEnabled(buttonEdit.isEnabled());
itemRemove.setEnabled(buttonRemove.isEnabled());
itemAdd.setEnabled(buttonAdd.isEnabled());
}
/**
*
* @param inputName Name of input
* @return ID of outputLocation, if inputName is connected to one, null otherwise
*/
protected String outputIdForInputName(String inputName) {
String jsonString = configuration.getConfigurationDescription()
.getConfigurationValue(OutputWriterComponentConstants.CONFIG_KEY_OUTPUTLOCATIONS);
if (jsonString == null) {
jsonString = "";
}
try {
OutputLocationList list =
jsonMapper.readValue(jsonString, OutputLocationList.class);
for (OutputLocation ol : list.getOutputLocations()) {
if (ol.getInputs().contains(inputName)) {
return ol.getGroupId();
}
}
} catch (IOException e) {
LogFactory.getLog(getClass()).debug("Error when reading JSON: " + e.getMessage());
}
return null;
}
/**
*
* @param inputName Name of input
* @return Name of outputLocation, if inputName is connected to one, null otherwise
*/
protected String outputNameForInputName(String inputName) {
String jsonString = configuration.getConfigurationDescription()
.getConfigurationValue(OutputWriterComponentConstants.CONFIG_KEY_OUTPUTLOCATIONS);
if (jsonString == null) {
jsonString = "";
}
try {
OutputLocationList list =
jsonMapper.readValue(jsonString, OutputLocationList.class);
for (OutputLocation ol : list.getOutputLocations()) {
if (ol.getInputs().contains(inputName)) {
return ol.getFilename();
}
}
} catch (IOException e) {
LogFactory.getLog(getClass()).debug("Error when reading JSON: " + e.getMessage());
}
return null;
}
}