/*
*
* * Copyright (C) 2015 CS SI
* *
* * This program is free software; you can redistribute it and/or modify it
* * under the terms of the GNU General Public License as published by the Free
* * Software Foundation; either version 3 of the License, or (at your option)
* * any later version.
* * This program is distributed in the hope that it will be useful, but WITHOUT
* * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* * more details.
* *
* * You should have received a copy of the GNU General Public License along
* * with this program; if not, see http://www.gnu.org/licenses/
*
*/
package org.esa.snap.ui.tooladapter.dialogs;
import com.bc.ceres.binding.PropertyDescriptor;
import com.bc.ceres.binding.ValidationException;
import com.bc.ceres.binding.validators.NotEmptyValidator;
import com.bc.ceres.swing.binding.PropertyEditor;
import com.bc.ceres.swing.binding.PropertyEditorRegistry;
import com.bc.ceres.swing.binding.internal.TextFieldEditor;
import org.esa.snap.core.gpf.descriptor.SystemDependentVariable;
import org.esa.snap.core.gpf.descriptor.SystemVariable;
import org.esa.snap.core.gpf.descriptor.ToolAdapterOperatorDescriptor;
import org.esa.snap.core.gpf.operators.tooladapter.ToolAdapterConstants;
import org.esa.snap.ui.AppContext;
import org.esa.snap.ui.UIUtils;
import org.esa.snap.ui.tool.ToolButtonFactory;
import org.esa.snap.ui.tooladapter.model.OperationType;
import org.esa.snap.ui.tooladapter.validators.RegexFieldValidator;
import org.esa.snap.utils.SpringUtilities;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.text.MessageFormat;
import java.util.HashSet;
import static org.esa.snap.utils.SpringUtilities.DEFAULT_PADDING;
/**
* A tabbed dialog window used to edit an operator, or to create a new operator.
* It shows details of an operator such as: descriptor details (name, alias, label, version, copyright,
* authors, description), system variables, preprocessing tool, product writer, tool location,
* operator working directory, command line template content, tool output patterns and parameters.
*
* @author Ramona Manda
* @author Cosmin Cara
*/
public class ToolAdapterTabbedEditorDialog extends AbstractAdapterEditor {
private JTabbedPane tabbedPane;
public ToolAdapterTabbedEditorDialog(AppContext appContext, JDialog parent, ToolAdapterOperatorDescriptor operatorDescriptor, OperationType operation) {
super(appContext, parent, operatorDescriptor, operation);
}
public ToolAdapterTabbedEditorDialog(AppContext appContext, JDialog parent, ToolAdapterOperatorDescriptor operatorDescriptor, int newNameIndex, OperationType operation) {
super(appContext, parent, operatorDescriptor, newNameIndex, operation);
}
@Override
protected JTabbedPane createMainPanel() {
this.tabbedPane = new JTabbedPane(JTabbedPane.LEFT);
this.tabbedPane.setBorder(BorderFactory.createEmptyBorder());
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
double widthRatio = 0.5;
formWidth = Math.max((int) (screenSize.width * widthRatio), MIN_TABBED_WIDTH);
double heightRatio = 0.5;
int formHeight = Math.max((int) (screenSize.height * heightRatio), MIN_TABBED_HEIGHT);
tabbedPane.setPreferredSize(new Dimension(formWidth, formHeight));
getJDialog().setMinimumSize(new Dimension(formWidth + 16, formHeight + 72));
addTab(tabbedPane, Bundle.CTL_Panel_OperatorDescriptor_Text(), createDescriptorTab());
addTab(tabbedPane, Bundle.CTL_Panel_ConfigParams_Text(), createToolInfoPanel());
addTab(tabbedPane, Bundle.CTL_Panel_PreProcessing_Border_TitleText(), createPreProcessingTab());
addTab(tabbedPane, Bundle.CTL_Panel_OpParams_Border_TitleText(), createParametersTab(formWidth));
addTab(tabbedPane, Bundle.CTL_Panel_SysVar_Border_TitleText(), createVariablesPanel());
formWidth = tabbedPane.getTabComponentAt(0).getWidth();
return tabbedPane;
}
@Override
protected JPanel createDescriptorPanel() {
JPanel descriptorPanel = new JPanel(new SpringLayout());
TextFieldEditor textEditor = new TextFieldEditor();
addValidatedTextField(descriptorPanel, textEditor, Bundle.CTL_Label_Alias_Text(), ToolAdapterConstants.ALIAS, "[^\\\\\\?%\\*:\\|\"<>\\./]*");
addTextField(descriptorPanel, textEditor, Bundle.CTL_Label_UniqueName_Text(), ToolAdapterConstants.NAME, true);
addTextField(descriptorPanel, textEditor, Bundle.CTL_Label_Label_Text(), ToolAdapterConstants.LABEL, true);
addTextField(descriptorPanel, textEditor, Bundle.CTL_Label_Version_Text(), ToolAdapterConstants.VERSION, true);
addTextField(descriptorPanel, textEditor, Bundle.CTL_Label_Copyright_Text(), ToolAdapterConstants.COPYRIGHT, false);
addTextField(descriptorPanel, textEditor, Bundle.CTL_Label_Authors_Text(), ToolAdapterConstants.AUTHORS, false);
addTextField(descriptorPanel, textEditor, Bundle.CTL_Label_Description_Text(), ToolAdapterConstants.DESCRIPTION, false);
propertyContainer.addPropertyChangeListener(ToolAdapterConstants.ALIAS, evt -> propertyContainer.setValue(ToolAdapterConstants.NAME, ToolAdapterConstants.OPERATOR_NAMESPACE + evt.getNewValue().toString()));
java.util.List<String> menus = getAvailableMenuOptions(null);
addComboField(descriptorPanel, Bundle.CTL_Label_MenuLocation_Text(), ToolAdapterConstants.MENU_LOCATION, menus, true, true);
addComboField(descriptorPanel, Bundle.CTL_Label_TemplateType_Text(), ToolAdapterConstants.TEMPLATE_TYPE, true, false);
SpringUtilities.makeCompactGrid(descriptorPanel, 9, 2, DEFAULT_PADDING, DEFAULT_PADDING, DEFAULT_PADDING, DEFAULT_PADDING);
return descriptorPanel;
}
@Override
protected JPanel createVariablesPanel() {
JPanel variablesBorderPanel = new JPanel();
BoxLayout layout = new BoxLayout(variablesBorderPanel, BoxLayout.PAGE_AXIS);
variablesBorderPanel.setLayout(layout);
AbstractButton addVariableButton = ToolButtonFactory.createButton(UIUtils.loadImageIcon(Bundle.Icon_Add()), false);
addVariableButton.setText(Bundle.CTL_Button_Add_Variable_Text());
addVariableButton.setMaximumSize(new Dimension(150, controlHeight));
addVariableButton.setAlignmentX(Component.LEFT_ALIGNMENT);
AbstractButton addDependentVariableButton = ToolButtonFactory.createButton(UIUtils.loadImageIcon(Bundle.Icon_Add()), false);
addDependentVariableButton.setText(Bundle.CTL_Button_Add_PDVariable_Text());
addDependentVariableButton.setMaximumSize(new Dimension(250, controlHeight));
addDependentVariableButton.setAlignmentX(Component.LEFT_ALIGNMENT);
JPanel buttonsPannel = new JPanel(new SpringLayout());
buttonsPannel.add(addVariableButton);
buttonsPannel.add(addDependentVariableButton);
SpringUtilities.makeCompactGrid(buttonsPannel, 1, 2, 0, 0, 0, 0);
buttonsPannel.setAlignmentX(Component.LEFT_ALIGNMENT);
variablesBorderPanel.add(buttonsPannel);
varTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
varTable.setRowHeight(controlHeight);
int widths[] = {controlHeight, (int) (formWidth * 0.3), (int) (formWidth * 0.7) - controlHeight};
for (int i = 0; i < widths.length; i++) {
varTable.getColumnModel().getColumn(i).setPreferredWidth(widths[i]);
}
JScrollPane scrollPane = new JScrollPane(varTable);
scrollPane.setAlignmentX(Component.LEFT_ALIGNMENT);
variablesBorderPanel.add(scrollPane);
variablesBorderPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
Dimension variablesPanelDimension = new Dimension((formWidth - 3 * DEFAULT_PADDING) / 2 - 2 * DEFAULT_PADDING, 130);
variablesBorderPanel.setMinimumSize(variablesPanelDimension);
variablesBorderPanel.setMaximumSize(variablesPanelDimension);
variablesBorderPanel.setPreferredSize(variablesPanelDimension);
addVariableButton.addActionListener(e -> {
newOperatorDescriptor.getVariables().add(new SystemVariable("key", ""));
varTable.revalidate();
});
addDependentVariableButton.addActionListener(e -> {
newOperatorDescriptor.getVariables().add(new SystemDependentVariable("key", ""));
varTable.revalidate();
});
return variablesBorderPanel;
}
@Override
protected JPanel createPreProcessingPanel() {
PropertyDescriptor propertyDescriptor = propertyContainer.getDescriptor("preprocessorExternalTool");
PropertyEditor editor = PropertyEditorRegistry.getInstance().findPropertyEditor(propertyDescriptor);
JComponent firstEditorComponent = editor.createEditorComponent(propertyDescriptor, bindingContext);
firstEditorComponent.setMaximumSize(new Dimension(firstEditorComponent.getMaximumSize().width, controlHeight));
firstEditorComponent.setPreferredSize(new Dimension(firstEditorComponent.getPreferredSize().width, controlHeight));
propertyDescriptor = propertyContainer.getDescriptor("processingWriter");
editor = PropertyEditorRegistry.getInstance().findPropertyEditor(propertyDescriptor);
JComponent secondEditorComponent = editor.createEditorComponent(propertyDescriptor, bindingContext);
secondEditorComponent.setMaximumSize(new Dimension(secondEditorComponent.getMaximumSize().width, controlHeight));
secondEditorComponent.setPreferredSize(new Dimension(secondEditorComponent.getPreferredSize().width, controlHeight));
JCheckBox checkBoxComponent = (JCheckBox)createCheckboxComponent("preprocessTool", firstEditorComponent, newOperatorDescriptor.getPreprocessTool());
checkBoxComponent.setText(Bundle.CTL_Label_PreprocessingTool_Text());
JCheckBox writeComponent = (JCheckBox)createCheckboxComponent("writeForProcessing", secondEditorComponent, newOperatorDescriptor.shouldWriteBeforeProcessing());
writeComponent.setText(Bundle.CTL_Label_WriteBefore_Text());
JPanel preProcessingPanel = new JPanel(new SpringLayout());
preProcessingPanel.add(checkBoxComponent);
preProcessingPanel.add(firstEditorComponent);
preProcessingPanel.add(writeComponent);
preProcessingPanel.add(secondEditorComponent);
SpringUtilities.makeCompactGrid(preProcessingPanel, 2, 2, DEFAULT_PADDING, DEFAULT_PADDING, DEFAULT_PADDING, DEFAULT_PADDING);
forwardFocusWhenTabKeyReleased(checkBoxComponent, firstEditorComponent);
forwardFocusWhenTabKeyReleased(firstEditorComponent, writeComponent);
forwardFocusWhenTabKeyReleased(writeComponent, secondEditorComponent);
forwardFocusWhenTabKeyReleased(secondEditorComponent, this.tabbedPane);
return preProcessingPanel;
}
@Override
protected JPanel createToolInfoPanel() {
final JPanel configPanel = new JPanel(new SpringLayout());
JPanel panelToolFiles = new JPanel(new SpringLayout());
PropertyEditorRegistry editorRegistry = PropertyEditorRegistry.getInstance();
PropertyDescriptor propertyDescriptor = propertyContainer.getDescriptor(ToolAdapterConstants.MAIN_TOOL_FILE_LOCATION);
propertyDescriptor.setValidator(new NotEmptyValidator());
PropertyEditor editor = editorRegistry.findPropertyEditor(propertyDescriptor);
JComponent editorComponent = editor.createEditorComponent(propertyDescriptor, bindingContext);
editorComponent.setMaximumSize(new Dimension(editorComponent.getMaximumSize().width, controlHeight));
editorComponent.setPreferredSize(new Dimension(editorComponent.getPreferredSize().width, controlHeight));
panelToolFiles.add(new JLabel(Bundle.CTL_Label_ToolLocation_Text()));
panelToolFiles.add(editorComponent);
propertyDescriptor = propertyContainer.getDescriptor(ToolAdapterConstants.WORKING_DIR);
propertyDescriptor.setAttribute("directory", true);
propertyDescriptor.setValidator((property, value) -> {
if (value == null || value.toString().trim().isEmpty()) {
throw new ValidationException(MessageFormat.format("Value for ''{0}'' must not be empty.",
property.getDescriptor().getDisplayName()));
}
});
editor = editorRegistry.findPropertyEditor(propertyDescriptor);
editorComponent = editor.createEditorComponent(propertyDescriptor, bindingContext);
editorComponent.setMaximumSize(new Dimension(editorComponent.getMaximumSize().width, controlHeight));
editorComponent.setPreferredSize(new Dimension(editorComponent.getPreferredSize().width, controlHeight));
panelToolFiles.add(new JLabel(Bundle.CTL_Label_WorkDir_Text()));
panelToolFiles.add(editorComponent);
SpringUtilities.makeCompactGrid(panelToolFiles, 2, 2, DEFAULT_PADDING, DEFAULT_PADDING, DEFAULT_PADDING, DEFAULT_PADDING);
configPanel.add(panelToolFiles);
JPanel checkPanel = new JPanel(new SpringLayout());
propertyDescriptor = propertyContainer.getDescriptor(ToolAdapterConstants.HANDLE_OUTPUT);
editor = editorRegistry.findPropertyEditor(propertyDescriptor);
editorComponent = editor.createEditorComponent(propertyDescriptor, bindingContext);
editorComponent.setMaximumSize(new Dimension(editorComponent.getMaximumSize().width, controlHeight));
editorComponent.setPreferredSize(new Dimension(editorComponent.getPreferredSize().width, controlHeight));
checkPanel.add(editorComponent);
checkPanel.add(new JLabel("Tool produces the name of the output product"));
SpringUtilities.makeCompactGrid(checkPanel, 1, 2, DEFAULT_PADDING, DEFAULT_PADDING, DEFAULT_PADDING, DEFAULT_PADDING);
configPanel.add(checkPanel);
JLabel label = new JLabel(Bundle.CTL_Label_CmdLineTemplate_Text());
configPanel.add(label);
JScrollPane scrollPane = new JScrollPane(createTemplateEditorField());
configPanel.add(scrollPane);
configPanel.add(createPatternsPanel());
SpringUtilities.makeCompactGrid(configPanel, 5, 1, DEFAULT_PADDING, DEFAULT_PADDING, DEFAULT_PADDING, DEFAULT_PADDING);
return configPanel;
}
@Override
protected JPanel createPatternsPanel() {
JPanel patternsPanel = new JPanel(new SpringLayout());
TitledBorder titledBorder = BorderFactory.createTitledBorder(Bundle.CTL_Panel_OutputPattern_Border_TitleText());
titledBorder.setTitleJustification(TitledBorder.CENTER);
patternsPanel.setBorder(titledBorder);
TextFieldEditor textEditor = new TextFieldEditor();
addTextField(patternsPanel, textEditor, Bundle.CTL_Label_ProgressPattern(), ToolAdapterConstants.PROGRESS_PATTERN, false);
propertyContainer.getDescriptor(ToolAdapterConstants.PROGRESS_PATTERN).setValidator(new RegexFieldValidator());
addTextField(patternsPanel, textEditor, Bundle.CTL_Label_StepPattern(), ToolAdapterConstants.STEP_PATTERN, false);
propertyContainer.getDescriptor(ToolAdapterConstants.STEP_PATTERN).setValidator(new RegexFieldValidator());
addTextField(patternsPanel, textEditor, Bundle.CTL_Label_ErrorPattern(), ToolAdapterConstants.ERROR_PATTERN, false);
propertyContainer.getDescriptor(ToolAdapterConstants.ERROR_PATTERN).setValidator(new RegexFieldValidator());
SpringUtilities.makeCompactGrid(patternsPanel, 3, 2, DEFAULT_PADDING, DEFAULT_PADDING, DEFAULT_PADDING, DEFAULT_PADDING);
return patternsPanel;
}
@Override
protected JPanel createParametersPanel() {
JPanel paramsPanel = new JPanel();
BoxLayout layout = new BoxLayout(paramsPanel, BoxLayout.PAGE_AXIS);
paramsPanel.setLayout(layout);
AbstractButton addParamBut = ToolButtonFactory.createButton(UIUtils.loadImageIcon(Bundle.Icon_Add()), false);
addParamBut.setText("New Parameter");
addParamBut.setMaximumSize(new Dimension(150, controlHeight));
addParamBut.setAlignmentX(Component.LEFT_ALIGNMENT);
addParamBut.setAlignmentY(Component.TOP_ALIGNMENT);
paramsPanel.add(addParamBut);
JScrollPane tableScrollPane = new JScrollPane(paramsTable);
tableScrollPane.setAlignmentX(Component.LEFT_ALIGNMENT);
paramsPanel.add(tableScrollPane);
addParamBut.addActionListener(e -> {
paramsTable.addParameterToTable();
});
return paramsPanel;
}
private JPanel createPreProcessingTab() {
JPanel preprocessAndPatternsPanel = new JPanel(new SpringLayout());
preprocessAndPatternsPanel.add(createPreProcessingPanel());
SpringUtilities.makeCompactGrid(preprocessAndPatternsPanel, 1, 1, DEFAULT_PADDING, DEFAULT_PADDING, DEFAULT_PADDING, DEFAULT_PADDING);
preprocessAndPatternsPanel.setMaximumSize(preprocessAndPatternsPanel.getSize());
return preprocessAndPatternsPanel;
}
private JPanel createDescriptorTab() {
JPanel jPanel = new JPanel(new SpringLayout());
jPanel.add(createDescriptorPanel());
SpringUtilities.makeCompactGrid(jPanel, 1, 1, DEFAULT_PADDING, DEFAULT_PADDING, DEFAULT_PADDING, DEFAULT_PADDING);
jPanel.setMaximumSize(jPanel.getSize());
return jPanel;
}
private JPanel createParametersTab(int width) {
JPanel paramsPanel = createParametersPanel();
int tableWidth = width - 2 * DEFAULT_PADDING;
int widths[] = {controlHeight, 5 * controlHeight, 5 * controlHeight, 3 * controlHeight, 3 * controlHeight, (int)(tableWidth * 0.3), 30};
for(int i=0; i < widths.length; i++) {
paramsTable.getColumnModel().getColumn(i).setPreferredWidth(widths[i]);
}
paramsTable.setRowHeight(controlHeight);
return paramsPanel;
}
private void addTab(JTabbedPane tabControl, String title, JPanel content) {
JLabel tabText = new JLabel(title, JLabel.LEFT);
tabText.setPreferredSize(new Dimension(6 * controlHeight, controlHeight));
TitledBorder titledBorder = BorderFactory.createTitledBorder(title);
titledBorder.setTitleJustification(TitledBorder.CENTER);
content.setBorder(titledBorder);
tabControl.addTab(null, content);
tabControl.setTabComponentAt(tabControl.getTabCount() - 1, tabText);
}
private static void forwardFocusWhenTabKeyReleased(JComponent aSenderComponent, JComponent aReceiverComponent) {
ForwardFocusAction forwardFocusAction = new ForwardFocusAction("TabKeyAction", aReceiverComponent);
aSenderComponent.setFocusTraversalKeys(0, new HashSet());
int modifiers = 0; // '0' => no modifiers
int keyCode = KeyEvent.VK_TAB;
boolean onKeyRelease = true;
KeyStroke tabKeyReleased = KeyStroke.getKeyStroke(keyCode, modifiers, onKeyRelease);
aSenderComponent.getInputMap(1).put(tabKeyReleased, forwardFocusAction.getName());
aSenderComponent.getActionMap().put(forwardFocusAction.getName(), forwardFocusAction);
}
}