blob: 02141b36bb2c2ed67bbe24b497d169c0665c8e85 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.tools;
import com.intellij.execution.ExecutionBundle;
import com.intellij.ide.DataManager;
import com.intellij.ide.macro.MacroManager;
import com.intellij.ide.macro.MacrosDialog;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.fileChooser.FileChooserFactory;
import com.intellij.openapi.fileChooser.PathChooserDialog;
import com.intellij.openapi.help.HelpManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.FixedSizeButton;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.util.Consumer;
import net.miginfocom.swing.MigLayout;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.text.BadLocationException;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.List;
public class ToolEditorDialog extends DialogWrapper {
private final JTextField myNameField = new JTextField();
private final JTextField myDescriptionField = new JTextField();
private final ComboBox myGroupCombo = new ComboBox(-1);
private final JCheckBox myShowInMainMenuCheckbox = new JCheckBox(ToolsBundle.message("tools.menu.main.checkbox"));
private final JCheckBox myShowInEditorCheckbox = new JCheckBox(ToolsBundle.message("tools.menu.editor.checkbox"));
private final JCheckBox myShowInProjectTreeCheckbox = new JCheckBox(ToolsBundle.message("tools.menu.project.checkbox"));
private final JCheckBox myShowInSearchResultsPopupCheckbox = new JCheckBox(ToolsBundle.message("tools.menu.search.checkbox"));
private final JCheckBox myUseConsoleCheckbox = new JCheckBox(ToolsBundle.message("tools.open.console.checkbox"));
private final JCheckBox myShowConsoleOnStdOutCheckbox = new JCheckBox(ExecutionBundle.message("logs.show.console.on.stdout"));
private final JCheckBox myShowConsoleOnStdErrCheckbox = new JCheckBox(ExecutionBundle.message("logs.show.console.on.stderr"));
private final JCheckBox mySynchronizedAfterRunCheckbox = new JCheckBox(ToolsBundle.message("tools.synchronize.files.checkbox"));
private boolean myEnabled;
// command fields
private final JTextField myTfCommandWorkingDirectory = new JTextField();
private final JTextField myTfCommand = new JTextField();
private final JTextField myParametersField = new JTextField();
private JButton myInsertWorkingDirectoryMacroButton;
private JButton myInsertCommandMacroButton;
private JButton myInsertParametersMacroButton;
private final JButton myOutputFiltersButton;
// panels
private final JPanel mySimpleProgramPanel = createCommandPane();
private FilterInfo[] myOutputFilters;
private final Project myProject;
@Override
@NotNull
protected JPanel createCenterPanel() {
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints constr;
// name and group
constr = new GridBagConstraints();
constr.gridx = 0;
constr.gridy = 0;
constr.anchor = GridBagConstraints.WEST;
constr.insets = new Insets(5, 0, 0, 0);
panel.add(new JLabel(ToolsBundle.message("tools.name.label")), constr);
constr = new GridBagConstraints();
constr.gridx = 1;
constr.gridy = 0;
constr.weightx = 1;
constr.insets = new Insets(5, 10, 0, 10);
constr.fill = GridBagConstraints.HORIZONTAL;
constr.anchor = GridBagConstraints.WEST;
panel.add(myNameField, constr);
constr = new GridBagConstraints();
constr.gridx = 2;
constr.gridy = 0;
constr.anchor = GridBagConstraints.WEST;
constr.insets = new Insets(5, 10, 0, 0);
panel.add(new JLabel(ToolsBundle.message("tools.group.label")), constr);
constr = new GridBagConstraints();
constr.gridx = 3;
constr.gridy = 0;
constr.weightx = 0.7;
constr.insets = new Insets(5, 10, 0, 0);
constr.fill = GridBagConstraints.HORIZONTAL;
constr.anchor = GridBagConstraints.WEST;
panel.add(myGroupCombo, constr);
myGroupCombo.setEditable(true);
myGroupCombo.setFont(myNameField.getFont());
Dimension comboSize = myNameField.getPreferredSize();
myGroupCombo.setMinimumSize(comboSize);
myGroupCombo.setPreferredSize(comboSize);
// description
constr = new GridBagConstraints();
constr.gridx = 0;
constr.gridy = 1;
constr.anchor = GridBagConstraints.WEST;
constr.insets = new Insets(5, 0, 0, 0);
panel.add(new JLabel(ToolsBundle.message("tools.description.label")), constr);
constr = new GridBagConstraints();
constr.gridx = 1;
constr.gridy = 1;
constr.weightx = 1;
constr.gridwidth = 3;
constr.insets = new Insets(5, 10, 0, 0);
constr.fill = GridBagConstraints.HORIZONTAL;
constr.anchor = GridBagConstraints.WEST;
panel.add(myDescriptionField, constr);
// check boxes
JPanel panel0 = new JPanel(new BorderLayout());
panel0.add(getOptionsPanel(), BorderLayout.NORTH);
panel0.add(getShowInPanel(), BorderLayout.SOUTH);
constr = new GridBagConstraints();
constr.gridy = 4;
constr.gridwidth = 4;
constr.fill = GridBagConstraints.HORIZONTAL;
constr.weightx = 1.0;
constr.insets = new Insets(5, 0, 0, 0);
panel.add(panel0, constr);
// custom panels (put into same place)
constr = new GridBagConstraints();
constr.gridx = 0;
constr.gridy = 7/*8*/;
constr.gridwidth = 4;
constr.fill = GridBagConstraints.BOTH;
constr.weightx = 1.0;
constr.weighty = 1.0;
constr.anchor = GridBagConstraints.NORTH;
panel.add(mySimpleProgramPanel, constr);
return panel;
}
@Override
@NotNull
protected Action[] createActions() {
return new Action[]{getOKAction(), getCancelAction(), getHelpAction()};
}
@Override
protected void doHelpAction() {
HelpManager.getInstance().invokeHelp(getIdForHelpAction());
}
protected String getIdForHelpAction() {
return "preferences.externalToolsEdit";
}
protected ToolEditorDialog(JComponent parent, String title) {
super(parent, true);
myOutputFiltersButton = new JButton(ToolsBundle.message("tools.filters.button"));
DataContext dataContext = DataManager.getInstance().getDataContext(parent);
myProject = CommonDataKeys.PROJECT.getData(dataContext);
MacroManager.getInstance().cacheMacrosPreview(dataContext);
setTitle(title);
init();
addListeners();
myShowConsoleOnStdOutCheckbox.setVisible(false);
myShowConsoleOnStdErrCheckbox.setVisible(false);
}
private JPanel createCommandPane() {
final JPanel pane = new JPanel(new GridBagLayout());
pane.setBorder(IdeBorderFactory.createTitledBorder(ToolsBundle.message("tools.tool.group"), true));
GridBagConstraints constr;
// program
constr = new GridBagConstraints();
constr.gridx = 0;
constr.gridy = 0;
constr.insets = new Insets(0, 0, 0, 10);
constr.anchor = GridBagConstraints.BASELINE_LEADING;
pane.add(new JLabel(ToolsBundle.message("tools.program.label")), constr);
FixedSizeButton browseCommandButton = new FixedSizeButton(myTfCommand);
addCommandBrowseAction(pane, browseCommandButton, myTfCommand);
JPanel _pane0 = new JPanel(new BorderLayout());
_pane0.add(myTfCommand, BorderLayout.CENTER);
_pane0.add(browseCommandButton, BorderLayout.EAST);
TextFieldWithBrowseButton.MyDoClickAction.addTo(browseCommandButton, myTfCommand);
constr = new GridBagConstraints();
constr.gridx = 1;
constr.gridy = 0;
constr.insets = new Insets(0, 0, 0, 10);
constr.fill = GridBagConstraints.HORIZONTAL;
constr.anchor = GridBagConstraints.BASELINE_LEADING;
constr.weightx = 1.0;
pane.add(_pane0, constr);
constr = new GridBagConstraints();
constr.gridx = 2;
constr.gridy = 0;
constr.insets = new Insets(0, 0, 0, 0);
constr.fill = GridBagConstraints.HORIZONTAL;
constr.anchor = GridBagConstraints.BASELINE_LEADING;
myInsertCommandMacroButton = new JButton(ToolsBundle.message("tools.insert.macro.button"));
pane.add(myInsertCommandMacroButton, constr);
// parameters
constr = new GridBagConstraints();
constr.gridx = 0;
constr.gridy = 1;
constr.insets = new Insets(5, 0, 0, 10);
constr.anchor = GridBagConstraints.BASELINE_LEADING;
pane.add(new JLabel(ToolsBundle.message("tools.parameters.label")), constr);
constr = new GridBagConstraints();
constr.gridx = 1;
constr.gridy = 1;
constr.insets = new Insets(5, 0, 0, 10);
constr.fill = GridBagConstraints.HORIZONTAL;
constr.anchor = GridBagConstraints.BASELINE_LEADING;
constr.weightx = 1.0;
pane.add(myParametersField, constr);
constr = new GridBagConstraints();
constr.gridx = 2;
constr.gridy = 1;
constr.insets = new Insets(5, 0, 0, 0);
constr.fill = GridBagConstraints.HORIZONTAL;
constr.anchor = GridBagConstraints.BASELINE_LEADING;
myInsertParametersMacroButton = new JButton(ToolsBundle.message("tools.insert.macro.button.a"));
pane.add(myInsertParametersMacroButton, constr);
// working directory
constr = new GridBagConstraints();
constr.gridx = 0;
constr.gridy = 2;
constr.insets = new Insets(5, 0, 0, 10);
constr.anchor = GridBagConstraints.BASELINE_LEADING;
pane.add(new JLabel(ToolsBundle.message("tools.working.directory.label")), constr);
FixedSizeButton browseDirectoryButton = new FixedSizeButton(myTfCommandWorkingDirectory);
TextFieldWithBrowseButton.MyDoClickAction.addTo(browseDirectoryButton, myTfCommandWorkingDirectory);
addWorkingDirectoryBrowseAction(pane, browseDirectoryButton, myTfCommandWorkingDirectory);
JPanel _pane1 = new JPanel(new BorderLayout());
_pane1.add(myTfCommandWorkingDirectory, BorderLayout.CENTER);
_pane1.add(browseDirectoryButton, BorderLayout.EAST);
constr = new GridBagConstraints();
constr.gridx = 1;
constr.gridy = 2;
constr.gridwidth = 1;
constr.insets = new Insets(5, 0, 0, 10);
constr.fill = GridBagConstraints.HORIZONTAL;
constr.anchor = GridBagConstraints.WEST;
constr.weightx = 1.0;
pane.add(_pane1, constr);
constr = new GridBagConstraints();
constr.gridx = 2;
constr.gridy = 2;
constr.insets = new Insets(5, 0, 0, 0);
constr.fill = GridBagConstraints.HORIZONTAL;
constr.anchor = GridBagConstraints.BASELINE_LEADING;
myInsertWorkingDirectoryMacroButton = new JButton(ToolsBundle.message("tools.insert.macro.button.c"));
pane.add(myInsertWorkingDirectoryMacroButton, constr);
// for normal resizing
constr = new GridBagConstraints();
constr.gridy = 3;
constr.fill = GridBagConstraints.BASELINE_LEADING;
constr.weighty = 1.0;
pane.add(new JLabel(), constr);
return pane;
}
protected void addWorkingDirectoryBrowseAction(final JPanel pane,
FixedSizeButton browseDirectoryButton,
JTextField tfCommandWorkingDirectory) {
browseDirectoryButton.addActionListener(
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
PathChooserDialog chooser = FileChooserFactory.getInstance().createPathChooser(descriptor, myProject, pane);
chooser.choose(null, new Consumer<List<VirtualFile>>() {
@Override
public void consume(List<VirtualFile> files) {
VirtualFile file = !files.isEmpty() ? files.get(0) : null;
if (file != null) {
myTfCommandWorkingDirectory.setText(file.getPresentableUrl());
}
}
});
}
}
);
}
protected void addCommandBrowseAction(final JPanel pane, FixedSizeButton browseCommandButton, JTextField tfCommand) {
browseCommandButton.addActionListener(
new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFileOrExecutableAppDescriptor();
PathChooserDialog chooser = FileChooserFactory.getInstance().createPathChooser(descriptor, myProject, pane);
chooser.choose(null, new Consumer<List<VirtualFile>>() {
@Override
public void consume(List<VirtualFile> files) {
VirtualFile file = !files.isEmpty() ? files.get(0) : null;
if (file != null) {
myTfCommand.setText(file.getPresentableUrl());
String workingDirectory = myTfCommandWorkingDirectory.getText();
if (workingDirectory == null || workingDirectory.isEmpty()) {
VirtualFile parent = file.getParent();
if (parent != null && parent.isDirectory()) {
myTfCommandWorkingDirectory.setText(parent.getPresentableUrl());
}
}
}
}
});
}
}
);
}
private class InsertMacroActionListener implements ActionListener {
private final JTextField myTextField;
public InsertMacroActionListener(JTextField textField) {
myTextField = textField;
}
@Override
public void actionPerformed(ActionEvent e) {
MacrosDialog dialog = new MacrosDialog(myProject);
dialog.show();
if (dialog.isOK() && dialog.getSelectedMacro() != null) {
String macro = dialog.getSelectedMacro().getName();
int position = myTextField.getCaretPosition();
try {
myTextField.getDocument().insertString(position, "$" + macro + "$", null);
myTextField.setCaretPosition(position + macro.length() + 2);
}
catch (BadLocationException ignored) {
}
}
IdeFocusManager.findInstance().requestFocus(myTextField, true);
}
}
private void addListeners() {
myOutputFiltersButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
OutputFiltersDialog dialog = new OutputFiltersDialog(myOutputFiltersButton, getData().getOutputFilters());
dialog.show();
if (dialog.isOK()) {
myOutputFilters = dialog.getData();
}
}
});
myInsertCommandMacroButton.addActionListener(new InsertMacroActionListener(myTfCommand));
myInsertParametersMacroButton.addActionListener(new InsertMacroActionListener(myParametersField));
myInsertWorkingDirectoryMacroButton.addActionListener(new InsertMacroActionListener(myTfCommandWorkingDirectory));
myNameField.getDocument().addDocumentListener(new DocumentAdapter() {
@Override
public void textChanged(DocumentEvent event) {
handleOKButton();
}
});
myUseConsoleCheckbox.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
myShowConsoleOnStdOutCheckbox.setVisible(myUseConsoleCheckbox.isSelected());
myShowConsoleOnStdErrCheckbox.setVisible(myUseConsoleCheckbox.isSelected());
}
});
}
private void handleOKButton() {
setOKActionEnabled(!myNameField.getText().trim().isEmpty());
}
public Tool getData() {
Tool tool = createTool();
tool.setName(convertString(myNameField.getText()));
tool.setDescription(convertString(myDescriptionField.getText()));
Object selectedItem = myGroupCombo.getSelectedItem();
tool.setGroup(StringUtil.notNullize(selectedItem != null ? convertString(selectedItem.toString()) : ""));
tool.setShownInMainMenu(myShowInMainMenuCheckbox.isSelected());
tool.setShownInEditor(myShowInEditorCheckbox.isSelected());
tool.setShownInProjectViews(myShowInProjectTreeCheckbox.isSelected());
tool.setShownInSearchResultsPopup(myShowInSearchResultsPopupCheckbox.isSelected());
tool.setUseConsole(myUseConsoleCheckbox.isSelected());
tool.setShowConsoleOnStdOut(myShowConsoleOnStdOutCheckbox.isSelected());
tool.setShowConsoleOnStdErr(myShowConsoleOnStdErrCheckbox.isSelected());
tool.setFilesSynchronizedAfterRun(mySynchronizedAfterRunCheckbox.isSelected());
tool.setEnabled(myEnabled);
tool.setWorkingDirectory(toSystemIndependentFormat(myTfCommandWorkingDirectory.getText()));
tool.setProgram(convertString(myTfCommand.getText()));
tool.setParameters(convertString(myParametersField.getText()));
tool.setOutputFilters(myOutputFilters);
return tool;
}
protected Tool createTool() {
return new Tool();
}
@Override
protected String getDimensionServiceKey() {
return "#com.intellij.tools.ToolEditorDialog";
}
/**
* Initialize controls
*/
protected void setData(Tool tool, String[] existingGroups) {
myNameField.setText(tool.getName());
myDescriptionField.setText(tool.getDescription());
if (myGroupCombo.getItemCount() > 0) {
myGroupCombo.removeAllItems();
}
for (int i = 0; i < existingGroups.length; i++) {
if (existingGroups[i] != null) {
myGroupCombo.addItem(existingGroups[i]);
}
}
myGroupCombo.setSelectedItem(tool.getGroup());
myShowInMainMenuCheckbox.setSelected(tool.isShownInMainMenu());
myShowInEditorCheckbox.setSelected(tool.isShownInEditor());
myShowInProjectTreeCheckbox.setSelected(tool.isShownInProjectViews());
myShowInSearchResultsPopupCheckbox.setSelected(tool.isShownInSearchResultsPopup());
myUseConsoleCheckbox.setSelected(tool.isUseConsole());
myShowConsoleOnStdOutCheckbox.setSelected(tool.isShowConsoleOnStdOut());
myShowConsoleOnStdErrCheckbox.setSelected(tool.isShowConsoleOnStdErr());
mySynchronizedAfterRunCheckbox.setSelected(tool.synchronizeAfterExecution());
myEnabled = tool.isEnabled();
myTfCommandWorkingDirectory.setText(toCurrentSystemFormat(tool.getWorkingDirectory()));
myTfCommand.setText(tool.getProgram());
myParametersField.setText(tool.getParameters());
myOutputFilters = tool.getOutputFilters();
mySimpleProgramPanel.setVisible(true);
handleOKButton();
}
@Override
public JComponent getPreferredFocusedComponent() {
return myNameField;
}
private JPanel getShowInPanel() {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 0));
panel.setBorder(IdeBorderFactory.createTitledBorder(ToolsBundle.message("tools.menu.group"), true));
panel.add(myShowInMainMenuCheckbox);
panel.add(myShowInEditorCheckbox);
panel.add(myShowInProjectTreeCheckbox);
panel.add(myShowInSearchResultsPopupCheckbox);
return panel;
}
private JPanel getOptionsPanel() {
JPanel panel = new JPanel(new MigLayout("fill, gap 10"));
panel.setBorder(IdeBorderFactory.createTitledBorder(ToolsBundle.message("tools.options.group"), true));
panel.add(mySynchronizedAfterRunCheckbox);
panel.add(myUseConsoleCheckbox);
panel.add(myOutputFiltersButton, "ax right, wrap");
panel.add(myShowConsoleOnStdOutCheckbox);
panel.add(myShowConsoleOnStdErrCheckbox, "spanx 2");
return panel;
}
private String convertString(String s) {
if (s != null && s.trim().isEmpty()) return null;
return s;
}
private String toSystemIndependentFormat(String s) {
if (s == null) return null;
s = s.trim();
if (s.isEmpty()) return null;
return s.replace(File.separatorChar, '/');
}
private String toCurrentSystemFormat(String s) {
if (s == null) return null;
s = s.trim();
if (s.isEmpty()) return null;
return s.replace('/', File.separatorChar);
}
public Project getProject() {
return myProject;
}
}