blob: 61fe5b0cc3920a3e3b26c2a20169904d0d3c14c8 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2017 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.pde.internal.ua.ui.editor.cheatsheet.simple.details;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.core.commands.ParameterizedCommand;
import org.eclipse.core.commands.SerializationException;
import org.eclipse.core.commands.common.NotDefinedException;
import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.jface.window.Window;
import org.eclipse.pde.internal.core.util.PDETextHelper;
import org.eclipse.pde.internal.ua.core.cheatsheet.simple.*;
import org.eclipse.pde.internal.ua.ui.PDEUserAssistanceUIPlugin;
import org.eclipse.pde.internal.ua.ui.editor.cheatsheet.CSAbstractSubDetails;
import org.eclipse.pde.internal.ua.ui.editor.cheatsheet.ICSMaster;
import org.eclipse.pde.internal.ua.ui.editor.cheatsheet.simple.SimpleCSInputContext;
import org.eclipse.pde.internal.ui.commands.CommandComposerDialog;
import org.eclipse.pde.internal.ui.commands.CommandComposerPart;
import org.eclipse.pde.internal.ui.editor.FormLayoutFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.forms.IFormColors;
import org.eclipse.ui.forms.widgets.ExpandableComposite;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.handlers.IHandlerService;
public class SimpleCSCommandDetails extends CSAbstractSubDetails {
private ISimpleCSRun fRun;
private Table fCommandTable;
private SimpleCSCommandComboPart fCommandCombo;
private ControlDecoration fCommandInfoDecoration;
private Button fCommandBrowse;
private Button fCommandOptional;
private static final String F_NO_COMMAND = SimpleDetailsMessages.SimpleCSCommandDetails_none;
private static final int F_COMMAND_INSERTION_INDEX = 1;
public SimpleCSCommandDetails(ICSMaster section) {
super(section, SimpleCSInputContext.CONTEXT_ID);
fRun = null;
fCommandTable = null;
fCommandCombo = null;
fCommandInfoDecoration = null;
fCommandBrowse = null;
fCommandOptional = null;
}
public void setData(ISimpleCSRun object) {
// Set data
fRun = object;
}
@Override
public void createDetails(Composite parent) {
int columnSpan = 3;
Section commandSection = null;
FormToolkit toolkit = getToolkit();
Color foreground = toolkit.getColors().getColor(IFormColors.TITLE);
GridData data = null;
Label label = null;
// Create command section
commandSection = toolkit.createSection(parent, Section.DESCRIPTION | ExpandableComposite.TITLE_BAR);
commandSection.clientVerticalSpacing = FormLayoutFactory.SECTION_HEADER_VERTICAL_SPACING;
commandSection.setText(SimpleDetailsMessages.SimpleCSCommandDetails_commandSectionText);
commandSection.setDescription(SimpleDetailsMessages.SimpleCSCommandDetails_commandSectionDesc);
commandSection.setLayout(FormLayoutFactory.createClearGridLayout(false, 1));
data = new GridData(GridData.FILL_HORIZONTAL);
commandSection.setLayoutData(data);
// Create container for command section
Composite commandSectionClient = toolkit.createComposite(commandSection);
commandSectionClient.setLayout(FormLayoutFactory.createSectionClientGridLayout(false, columnSpan));
// Element: command
// Label
label = toolkit.createLabel(commandSectionClient, SimpleDetailsMessages.SimpleCSCommandDetails_attrCommand, SWT.WRAP);
label.setForeground(foreground);
// Combo box
fCommandCombo = new SimpleCSCommandComboPart();
fCommandCombo.createControl(commandSectionClient, toolkit, SWT.READ_ONLY);
data = new GridData(GridData.FILL_HORIZONTAL);
data.horizontalIndent = FormLayoutFactory.CONTROL_HORIZONTAL_INDENT;
fCommandCombo.getControl().setLayoutData(data);
// Insertion index is 0 for no command combo box entry
// Always keep this entry as the first entry
fCommandCombo.add(F_NO_COMMAND);
fCommandCombo.setText(F_NO_COMMAND);
fCommandCombo.populate();
// Always insert new command keys obtained from other combo boxes in
// the position after the no command entry
fCommandCombo.setNewCommandKeyIndex(F_COMMAND_INSERTION_INDEX);
// Limit the combo box to the 11 most recent entries (includes no
// command entry)
fCommandCombo.setComboEntryLimit(11);
createCommandInfoDecoration();
// Button
fCommandBrowse = toolkit.createButton(commandSectionClient, SimpleDetailsMessages.SimpleCSCommandDetails_browse, SWT.PUSH);
// Element: command
// Label for parameters
label = toolkit.createLabel(commandSectionClient, SimpleDetailsMessages.SimpleCSCommandDetails_attrParameters, SWT.WRAP);
label.setForeground(foreground);
data = new GridData(GridData.FILL_HORIZONTAL);
data.horizontalSpan = columnSpan;
label.setLayoutData(data);
fCommandTable = toolkit.createTable(commandSectionClient, SWT.SINGLE | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
data = new GridData(GridData.FILL_HORIZONTAL);
data.heightHint = 25;
data.horizontalSpan = columnSpan;
fCommandTable.setLayoutData(data);
//fCommandTable.setHeaderVisible(true);
fCommandTable.setLinesVisible(true);
//fCommandTable.setForeground(foreground);
TableColumn tableColumn1 = new TableColumn(fCommandTable, SWT.LEFT);
tableColumn1.setText(SimpleDetailsMessages.SimpleCSCommandDetails_name);
TableColumn tableColumn2 = new TableColumn(fCommandTable, SWT.LEFT);
tableColumn2.setText(SimpleDetailsMessages.SimpleCSCommandDetails_value);
// Attribute: required
fCommandOptional = getToolkit().createButton(commandSectionClient, SimpleDetailsMessages.SimpleCSCommandDetails_attrOptional, SWT.CHECK);
data = new GridData(GridData.FILL_HORIZONTAL);
data.horizontalSpan = columnSpan;
fCommandOptional.setLayoutData(data);
fCommandOptional.setForeground(foreground);
// Bind widgets
toolkit.paintBordersFor(commandSectionClient);
commandSection.setClient(commandSectionClient);
// Mark as a details part to enable cut, copy, paste, etc.
markDetailsPart(commandSection);
}
private void createCommandInfoDecoration() {
// Command info decoration
int bits = SWT.TOP | SWT.LEFT;
fCommandInfoDecoration = new ControlDecoration(fCommandCombo.getControl(), bits);
fCommandInfoDecoration.setMarginWidth(1);
fCommandInfoDecoration.setDescriptionText(SimpleDetailsMessages.SimpleCSCommandDetails_disabled);
updateCommandInfoDecoration(false);
fCommandInfoDecoration.setImage(FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_INFORMATION).getImage());
}
@Override
public void hookListeners() {
// Element: command
fCommandCombo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
// Ensure data object is defined
if (fRun == null) {
return;
}
String selection = fCommandCombo.getSelection();
if (selection.equals(F_NO_COMMAND) == false) {
// Get the associated serialization stored as data against the
// command name
String serialization = fCommandCombo.getValue(selection);
if (PDETextHelper.isDefined(serialization)) {
// Create the new command in the model
createCommandInModel(serialization);
ParameterizedCommand result = getParameterizedCommand(serialization);
if (result != null) {
updateCommandTable(result.getParameterMap());
}
}
} else {
// The empty entry was selected
// Delete the existing command
fRun.setExecutable(null);
fCommandTable.clearAll();
}
// Update the master section buttons
getMasterSection().updateButtons();
// Update the optional command checkbox
updateUICommandOptional();
}
});
fCommandBrowse.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
// Ensure data object is defined
if (fRun == null) {
return;
}
// Open the command composer dialog using the input from the
// currently selected command
CommandComposerDialog dialog = new CommandComposerDialog(fCommandBrowse.getShell(), CommandComposerPart.F_CHEATSHEET_FILTER, getParameterizedCommand(fRun), getSnapshotContext());
// Check result of dialog
if (dialog.open() == Window.OK) {
// Command composer exited successfully
// Update accordingly
updateCommandCombo(dialog.getCommand(), true);
// Update the master section buttons
getMasterSection().updateButtons();
// Update the optional command checkbox
updateUICommandOptional();
}
}
});
// Attribute: required
fCommandOptional.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
// Ensure data object is defined
if (fRun == null) {
return;
}
// Get the command
ISimpleCSCommand commandObject = getCommandObject(fRun);
// Ensure the command is defined
if (commandObject == null) {
return;
}
// Set required value in model
boolean isRequired = (fCommandOptional.getSelection() == false);
commandObject.setRequired(isRequired);
}
});
}
@Override
public void updateFields() {
// Ensure data object is defined
if (fRun == null) {
return;
}
// i.e. Action: class
ParameterizedCommand command = getParameterizedCommand(fRun);
if (command == null) {
// Since, this page is static the command combo and command table
// must be reset
clearCommandUI();
} else {
updateCommandCombo(command, false);
}
// Update the optional command checkbox
updateUICommandOptional();
// Update command UI enablement
updateCommandEnablement();
}
private void updateUICommandOptional() {
// Attribute: required
ISimpleCSCommand commandObject = getCommandObject(fRun);
if (commandObject == null) {
fCommandOptional.setSelection(false);
fCommandOptional.setEnabled(false);
} else {
boolean isOptional = (commandObject.getRequired() == false);
fCommandOptional.setSelection(isOptional);
fCommandOptional.setEnabled(isEditableElement());
}
}
private ISimpleCSCommand getCommandObject(ISimpleCSRun runObject) {
// Ensure the run object is defined
if (runObject == null) {
return null;
}
// Get the executable
ISimpleCSRunContainerObject executable = runObject.getExecutable();
// Ensure executable is defined
if (executable == null) {
return null;
} else if (executable.getType() != ISimpleCSConstants.TYPE_COMMAND) {
// Not a command
return null;
}
return (ISimpleCSCommand) executable;
}
private void clearCommandUI() {
// Clear the command combo
fCommandCombo.setText(F_NO_COMMAND);
// Clear the command table
fCommandTable.clearAll();
}
private void updateCommandEnablement() {
// Ensure data object is defined
if (fRun == null) {
return;
}
boolean editable = isEditableElement();
if (fRun.getType() == ISimpleCSConstants.TYPE_ITEM) {
ISimpleCSItem item = (ISimpleCSItem) fRun;
// Preserve cheat sheet validity
// Semantic Rule: Cannot have a subitem and any of the following
// together: perform-when, command, action
if (item.hasSubItems()) {
editable = false;
updateCommandInfoDecoration(true);
} else {
updateCommandInfoDecoration(false);
}
}
fCommandCombo.setEnabled(editable);
fCommandTable.setEnabled(true);
fCommandBrowse.setEnabled(editable);
}
private void createCommandInModel(String serialization) {
// Ensure data object is defined
if (fRun == null) {
return;
}
ISimpleCSCommand command = fRun.getModel().getFactory().createSimpleCSCommand(fRun);
command.setSerialization(serialization);
command.setRequired(false);
fRun.setExecutable(command);
}
private void updateCommandCombo(ParameterizedCommand result, boolean createInModel) {
if (result == null) {
return;
}
// Get serialization
String serialization = result.serialize();
// Get presentable command name
String commandName = null;
try {
commandName = result.getCommand().getName();
} catch (NotDefinedException e) {
// Ignore, name will be undefined
}
// Get command ID
String commandId = result.getId();
if (PDETextHelper.isDefined(serialization) && PDETextHelper.isDefined(commandId)) {
if (createInModel) {
// Create the new command in the model
createCommandInModel(serialization);
}
// Determine the presentable name to use in the combo box and the
// key to store the serialization data against in the widget
String nameToUse = null;
if (PDETextHelper.isDefined(commandName)) {
nameToUse = commandName;
} else {
nameToUse = commandId;
}
// Add new selection to the combo box if it is not already there
// Associate the serialization with the command name
// in the widget to retrieve for later use
fCommandCombo.putValue(nameToUse, serialization, F_COMMAND_INSERTION_INDEX);
// Select it
fCommandCombo.setText(nameToUse);
// Update the command table parameters
updateCommandTable(result.getParameterMap());
} else {
// No serialization, something bad happened
fCommandCombo.setText(F_NO_COMMAND);
}
}
private ParameterizedCommand getParameterizedCommand(String serialization) {
if (PDETextHelper.isDefined(serialization)) {
ICommandService service = getCommandService();
if (service != null) {
try {
return service.deserialize(serialization);
} catch (NotDefinedException | SerializationException e) {
PDEUserAssistanceUIPlugin.logException(e, SimpleDetailsMessages.SimpleCSCommandDetails_errTitle, SimpleDetailsMessages.SimpleCSCommandDetails_errMsg + serialization);
}
}
}
return null;
}
private ParameterizedCommand getParameterizedCommand(ISimpleCSRun run) {
if (run == null) {
return null;
}
ISimpleCSRunContainerObject object = run.getExecutable();
if ((object != null) && (object.getType() == ISimpleCSConstants.TYPE_COMMAND)) {
ISimpleCSCommand command = (ISimpleCSCommand) object;
return getParameterizedCommand(command.getSerialization());
}
return null;
}
private void updateCommandTable(Map<Object, Object> parameters) {
// Clear the table contents
fCommandTable.clearAll();
if (parameters != null && !parameters.isEmpty()) {
int rowCount = 0;
for (Entry<Object, Object> entry : parameters.entrySet()) {
// Track number of keys / rows processed
TableItem item = null;
// Determine if there is an existing row already at that index
if (rowCount < fCommandTable.getItemCount()) {
// There is, reuse it
item = fCommandTable.getItem(rowCount);
} else {
// There isn't, create a new one
item = new TableItem(fCommandTable, SWT.NONE);
}
if (entry.getKey() instanceof String) {
String keyString = (String) entry.getKey();
// If present, remove the fully qualified ID from the
// paramater key
// i.e. "org.eclipse.ui.perspective" becomes just
// "perspective"
int dotIndex = keyString.lastIndexOf('.');
if ((dotIndex != -1) && (dotIndex != (keyString.length() - 1))) {
keyString = keyString.substring(dotIndex + 1);
}
// Set parameter key in first column
item.setText(0, keyString);
}
Object value = entry.getValue();
if (value instanceof String) {
// Set parameter value in second column
item.setText(1, (String) value);
}
rowCount++;
}
// Pack the columns with the new data
for (int i = 0; i < fCommandTable.getColumnCount(); i++) {
TableColumn tableColumn = fCommandTable.getColumn(i);
tableColumn.pack();
}
}
}
private static ICommandService getCommandService() {
IWorkbench workbench = PlatformUI.getWorkbench();
return workbench.getAdapter(ICommandService.class);
}
private static IHandlerService getGlobalHandlerService() {
return PlatformUI.getWorkbench().getService(IHandlerService.class);
}
private static IEvaluationContext getSnapshotContext() {
IHandlerService service = getGlobalHandlerService();
return service.createContextSnapshot(false);
}
private void updateCommandInfoDecoration(boolean showDecoration) {
if (showDecoration) {
fCommandInfoDecoration.show();
} else {
fCommandInfoDecoration.hide();
}
fCommandInfoDecoration.setShowHover(showDecoration);
}
@Override
public void commit(boolean onSave) {
super.commit(onSave);
// NO-OP
// No form entries
}
}