package rocks.inspectit.ui.rcp.storage.label.edit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import rocks.inspectit.shared.cs.storage.StorageData;
import rocks.inspectit.shared.cs.storage.label.AbstractStorageLabel;
import rocks.inspectit.shared.cs.storage.label.BooleanStorageLabel;
import rocks.inspectit.shared.cs.storage.label.type.AbstractStorageLabelType;
import rocks.inspectit.ui.rcp.formatter.TextFormatter;
import rocks.inspectit.ui.rcp.repository.CmrRepositoryDefinition;
import rocks.inspectit.ui.rcp.repository.CmrRepositoryDefinition.OnlineStatus;
import rocks.inspectit.ui.rcp.storage.label.composite.AbstractStorageLabelComposite;
import rocks.inspectit.ui.rcp.storage.label.composite.impl.BooleanStorageLabelComposite;
import rocks.inspectit.ui.rcp.storage.label.composite.impl.DateStorageLabelComposite;
import rocks.inspectit.ui.rcp.storage.label.composite.impl.NumberStorageLabelComposite;
import rocks.inspectit.ui.rcp.storage.label.composite.impl.StringStorageLabelComposite;
/**
* Editing support for the values of the table.
*
* @author Ivan Senic
*
*/
public class LabelValueEditingSupport extends EditingSupport {
/**
* {@link StorageData} needed for updating.
*/
private StorageData storageData;
/**
* {@link CmrRepositoryDefinition} needed for updating.
*/
private CmrRepositoryDefinition cmrRepositoryDefinition;
/**
* Main cell editor.
*/
private ComboBoxCellEditor generalCellEditor;
/**
* Cell editor for the boolean valued labels.
*/
private ComboBoxCellEditor booleanCellEditor;
/**
* Table that is being edited.
*/
private Table table;
/**
* Suggestion label list.
*/
private List<AbstractStorageLabel<?>> suggestionLabelList = new ArrayList<>();
/**
* Label that is being edited.
*/
private AbstractStorageLabel<?> editingLabel;
/**
* List of listeners.
*/
private List<LabelEditListener> labelEditListeners = new ArrayList<>();
/**
* Default constructor.
*
* @param viewer
* Viewer.
* @param storageData
* {@link StorageData}.
* @param cmrRepositoryDefinition
* {@link CmrRepositoryDefinition}
*/
public LabelValueEditingSupport(TableViewer viewer, StorageData storageData, CmrRepositoryDefinition cmrRepositoryDefinition) {
super(viewer);
this.storageData = storageData;
this.cmrRepositoryDefinition = cmrRepositoryDefinition;
table = viewer.getTable();
generalCellEditor = new ComboBoxCellEditor(table, new String[0], SWT.READ_ONLY);
booleanCellEditor = new ComboBoxCellEditor(table, new String[] { "Yes", "No" }, SWT.READ_ONLY);
int activationStyle = ComboBoxCellEditor.DROP_DOWN_ON_KEY_ACTIVATION | ComboBoxCellEditor.DROP_DOWN_ON_MOUSE_ACTIVATION | ComboBoxCellEditor.DROP_DOWN_ON_TRAVERSE_ACTIVATION
| ComboBoxCellEditor.DROP_DOWN_ON_PROGRAMMATIC_ACTIVATION;
generalCellEditor.setActivationStyle(activationStyle);
booleanCellEditor.setActivationStyle(activationStyle);
}
/**
* {@inheritDoc}
*/
@Override
protected CellEditor getCellEditor(Object element) {
AbstractStorageLabel<?> label = (AbstractStorageLabel<?>) element;
if (label instanceof BooleanStorageLabel) {
return booleanCellEditor;
} else {
List<String> items = new ArrayList<>();
items.add("[create new value]");
if (!Objects.equals(label, editingLabel)) {
// if we still update the same label we don't need to reload everything
if (label.getStorageLabelType().isValueReusable() && (cmrRepositoryDefinition.getOnlineStatus() != OnlineStatus.OFFLINE)) {
suggestionLabelList.clear();
suggestionLabelList.addAll(cmrRepositoryDefinition.getStorageService().getLabelSuggestions(label.getStorageLabelType()));
if (!suggestionLabelList.isEmpty() && (null != storageData)) {
suggestionLabelList.removeAll(storageData.getLabelList());
}
}
}
if (!suggestionLabelList.isEmpty()) {
Collections.sort(suggestionLabelList);
for (AbstractStorageLabel<?> existingLabel : suggestionLabelList) {
items.add(TextFormatter.getLabelValue(existingLabel, false));
}
}
generalCellEditor.setItems(items.toArray(new String[items.size()]));
return generalCellEditor;
}
}
/**
* {@inheritDoc}
*/
@Override
protected boolean canEdit(Object element) {
AbstractStorageLabel<?> label = (AbstractStorageLabel<?>) element;
return label.getStorageLabelType().isEditable();
}
/**
* {@inheritDoc}
*/
@Override
protected Object getValue(Object element) {
AbstractStorageLabel<?> label = (AbstractStorageLabel<?>) element;
editingLabel = label;
if (null != label.getValue()) {
if (label instanceof BooleanStorageLabel) {
if (((BooleanStorageLabel) label).getValue().booleanValue()) {
return 0;
} else {
return 1;
}
} else {
String value = TextFormatter.getLabelValue(label, false);
int i = 1;
for (AbstractStorageLabel<?> suggestionLabel : suggestionLabelList) {
if (Objects.equals(value, TextFormatter.getLabelValue(suggestionLabel, false))) {
return i;
}
i++;
}
}
}
return -1;
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
@Override
protected void setValue(Object element, Object value) {
int index = ((Integer) value).intValue();
if (index >= 0) {
AbstractStorageLabel<Object> label = (AbstractStorageLabel<Object>) element;
if (label.getStorageLabelType().getValueClass().equals(Boolean.class)) {
Boolean newValue = Boolean.valueOf(0 == index);
changeValue(label, newValue);
} else {
if (index == 0) {
// create new
CreateValueDialog createValueDialog = new CreateValueDialog(table.getShell(), label.getStorageLabelType());
createValueDialog.open();
if (createValueDialog.getReturnCode() == Window.OK) {
AbstractStorageLabel<?> createdLabel = createValueDialog.getCreatedLabel();
changeValue(label, createdLabel.getValue());
if (!suggestionLabelList.contains(createdLabel)) {
suggestionLabelList.add(createdLabel);
}
}
} else if (index > 0) {
AbstractStorageLabel<?> suggestionLabel = suggestionLabelList.get(index - 1);
Object labelValue = suggestionLabel.getValue();
changeValue(label, labelValue);
}
}
getViewer().refresh();
}
}
/**
* Reforms the value change and informs the listeners.
*
* @param label
* Label to have value changed.
* @param newValue
* New value to set.
*/
private void changeValue(AbstractStorageLabel<Object> label, Object newValue) {
if (!Objects.equals(label.getValue(), newValue)) {
synchronized (labelEditListeners) {
for (LabelEditListener listener : labelEditListeners) {
listener.preLabelValueChange(label);
}
}
label.setValue(newValue);
synchronized (labelEditListeners) {
for (LabelEditListener listener : labelEditListeners) {
listener.postLabelValueChange(label);
}
}
}
}
/**
* Adds a {@link LabelEditListener}.
*
* @param listener
* Listener to add.
*/
public void addLabelEditListener(LabelEditListener listener) {
synchronized (labelEditListeners) {
if (!labelEditListeners.contains(listener)) {
labelEditListeners.add(listener);
}
}
}
/**
* Removes a {@link LabelEditListener}.
*
* @param listener
* Listener to remove.
*/
public void removeLabelEditListener(LabelEditListener listener) {
synchronized (labelEditListeners) {
labelEditListeners.remove(listener);
}
}
/**
* Listener interface that will be called prior to and after label value editing.
*
* @author Ivan Senic
*
*/
public interface LabelEditListener {
/**
* Called before the label is changed.
*
* @param label
* {@link AbstractStorageLabel}.
*/
void preLabelValueChange(AbstractStorageLabel<?> label);
/**
* Called after the label is changed.
*
* @param label
* {@link AbstractStorageLabel}.
*/
void postLabelValueChange(AbstractStorageLabel<?> label);
}
/**
* Dialog for creating new values.
*
* @author Ivan Senic
*
*/
private static class CreateValueDialog extends Dialog {
/**
* Label type.
*/
private AbstractStorageLabelType<?> labelType;
/**
* Label to hold the created value.
*/
private AbstractStorageLabel<?> label;
/**
* Composite for definition.
*/
private AbstractStorageLabelComposite storageLabelComposite;
/**
* OK button.
*/
private Button okButton;
/**
* Default constructor.
*
* @param parentShell
* Shell.
* @param labelType
* Type of label.
*/
protected CreateValueDialog(Shell parentShell, AbstractStorageLabelType<?> labelType) {
super(parentShell);
this.labelType = labelType;
}
/**
* {@inheritDoc}
*/
@Override
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
newShell.setText("Create New Label Value");
}
/**
* {@inheritDoc}
*/
@Override
protected void createButtonsForButtonBar(Composite parent) {
createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, true);
okButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
okButton.setEnabled(storageLabelComposite.isInputValid());
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
@Override
protected Control createDialogArea(Composite parent) {
if (labelType.getValueClass().equals(Boolean.class)) {
storageLabelComposite = new BooleanStorageLabelComposite(parent, SWT.NONE, (AbstractStorageLabelType<Boolean>) labelType);
} else if (labelType.getValueClass().equals(Date.class)) {
storageLabelComposite = new DateStorageLabelComposite(parent, SWT.NONE, (AbstractStorageLabelType<Date>) labelType);
} else if (labelType.getValueClass().equals(Number.class)) {
storageLabelComposite = new NumberStorageLabelComposite(parent, SWT.NONE, (AbstractStorageLabelType<Number>) labelType);
} else if (labelType.getValueClass().equals(String.class)) {
storageLabelComposite = new StringStorageLabelComposite(parent, SWT.NONE, (AbstractStorageLabelType<String>) labelType);
}
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, false);
gd.minimumWidth = 300;
storageLabelComposite.setLayoutData(gd);
storageLabelComposite.addListener(new Listener() {
@Override
public void handleEvent(Event event) {
okButton.setEnabled(storageLabelComposite.isInputValid());
}
});
return storageLabelComposite;
}
/**
* {@inheritDoc}
*/
@Override
protected void buttonPressed(int buttonId) {
if (Window.OK == buttonId) {
label = storageLabelComposite.getStorageLabel();
}
super.buttonPressed(buttonId);
}
/**
* Gets {@link #label}.
*
* @return {@link #label}
*/
public AbstractStorageLabel<?> getCreatedLabel() {
return label;
}
}
}