blob: 305af75de669259ceafaaf0fb7daebec02595de3 [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.diagnostic.logging;
import com.intellij.diagnostic.DiagnosticBundle;
import com.intellij.execution.configurations.LogFileOptions;
import com.intellij.execution.configurations.PredefinedLogFile;
import com.intellij.execution.configurations.RunConfigurationBase;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.ui.TextComponentAccessor;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.*;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.table.TableView;
import com.intellij.util.SmartList;
import com.intellij.util.ui.AbstractTableCellEditor;
import com.intellij.util.ui.CellEditorComponentWithBrowseButton;
import com.intellij.util.ui.ColumnInfo;
import com.intellij.util.ui.ListTableModel;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* User: anna
* Date: Apr 22, 2005
*/
public class LogConfigurationPanel<T extends RunConfigurationBase> extends SettingsEditor<T> {
private final TableView<LogFileOptions> myFilesTable;
private final ListTableModel<LogFileOptions> myModel;
private JPanel myWholePanel;
private JPanel myScrollPanel;
private JBCheckBox myRedirectOutputCb;
private TextFieldWithBrowseButton myOutputFile;
private JCheckBox myShowConsoleOnStdOutCb;
private JCheckBox myShowConsoleOnStdErrCb;
private final Map<LogFileOptions, PredefinedLogFile> myLog2Predefined = new THashMap<LogFileOptions, PredefinedLogFile>();
private final List<PredefinedLogFile> myUnresolvedPredefined = new SmartList<PredefinedLogFile>();
public LogConfigurationPanel() {
ColumnInfo<LogFileOptions, Boolean> IS_SHOW = new MyIsActiveColumnInfo();
ColumnInfo<LogFileOptions, LogFileOptions> FILE = new MyLogFileColumnInfo();
ColumnInfo<LogFileOptions, Boolean> IS_SKIP_CONTENT = new MyIsSkipColumnInfo();
myModel = new ListTableModel<LogFileOptions>(IS_SHOW, FILE, IS_SKIP_CONTENT);
myFilesTable = new TableView<LogFileOptions>(myModel);
myFilesTable.getEmptyText().setText(DiagnosticBundle.message("log.monitor.no.files"));
final JTableHeader tableHeader = myFilesTable.getTableHeader();
@SuppressWarnings("ConstantConditions")
final FontMetrics fontMetrics = tableHeader.getFontMetrics(tableHeader.getFont());
int preferredWidth = fontMetrics.stringWidth(IS_SHOW.getName()) + 20;
setUpColumnWidth(tableHeader, preferredWidth, 0);
preferredWidth = fontMetrics.stringWidth(IS_SKIP_CONTENT.getName()) + 20;
setUpColumnWidth(tableHeader, preferredWidth, 2);
myFilesTable.setColumnSelectionAllowed(false);
myFilesTable.setShowGrid(false);
myFilesTable.setDragEnabled(false);
myFilesTable.setShowHorizontalLines(false);
myFilesTable.setShowVerticalLines(false);
myFilesTable.setIntercellSpacing(new Dimension(0, 0));
myScrollPanel.add(
ToolbarDecorator.createDecorator(myFilesTable)
.setAddAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
ArrayList<LogFileOptions> newList = new ArrayList<LogFileOptions>(myModel.getItems());
LogFileOptions newOptions = new LogFileOptions("", "", true, true, false);
if (showEditorDialog(newOptions)) {
newList.add(newOptions);
myModel.setItems(newList);
int index = myModel.getRowCount() - 1;
myModel.fireTableRowsInserted(index, index);
myFilesTable.setRowSelectionInterval(index, index);
}
}
}).setRemoveAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
TableUtil.stopEditing(myFilesTable);
final int[] selected = myFilesTable.getSelectedRows();
if (selected.length == 0) return;
for (int i = selected.length - 1; i >= 0; i--) {
myModel.removeRow(selected[i]);
}
for (int i = selected.length - 1; i >= 0; i--) {
int idx = selected[i];
myModel.fireTableRowsDeleted(idx, idx);
}
int selection = selected[0];
if (selection >= myModel.getRowCount()) {
selection = myModel.getRowCount() - 1;
}
if (selection >= 0) {
myFilesTable.setRowSelectionInterval(selection, selection);
}
myFilesTable.requestFocus();
}
}).setEditAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
final int selectedRow = myFilesTable.getSelectedRow();
//noinspection ConstantConditions
showEditorDialog(myFilesTable.getSelectedObject());
myModel.fireTableDataChanged();
myFilesTable.setRowSelectionInterval(selectedRow, selectedRow);
}
}).setRemoveActionUpdater(new AnActionButtonUpdater() {
@Override
public boolean isEnabled(AnActionEvent e) {
return myFilesTable.getSelectedRowCount() >= 1 &&
!myLog2Predefined.containsKey(myFilesTable.getSelectedObject());
}
}).setEditActionUpdater(new AnActionButtonUpdater() {
@Override
public boolean isEnabled(AnActionEvent e) {
return myFilesTable.getSelectedRowCount() >= 1 &&
!myLog2Predefined.containsKey(myFilesTable.getSelectedObject()) &&
myFilesTable.getSelectedObject() != null;
}
}).disableUpDownActions().createPanel(), BorderLayout.CENTER);
myWholePanel.setPreferredSize(new Dimension(-1, 150));
myOutputFile.addBrowseFolderListener("Choose File to Save Console Output", "Console output would be saved to the specified file", null,
FileChooserDescriptorFactory.createSingleFileOrFolderDescriptor(),
TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT);
myRedirectOutputCb.addActionListener(new ActionListener() {
@Override
public void actionPerformed(@NotNull ActionEvent e) {
myOutputFile.setEnabled(myRedirectOutputCb.isSelected());
}
});
}
private void setUpColumnWidth(final JTableHeader tableHeader, final int preferredWidth, int columnIdx) {
myFilesTable.getColumnModel().getColumn(columnIdx).setCellRenderer(new BooleanTableCellRenderer());
final TableColumn tableColumn = tableHeader.getColumnModel().getColumn(columnIdx);
tableColumn.setWidth(preferredWidth);
tableColumn.setPreferredWidth(preferredWidth);
tableColumn.setMinWidth(preferredWidth);
tableColumn.setMaxWidth(preferredWidth);
}
public void refreshPredefinedLogFiles(RunConfigurationBase configurationBase) {
List<LogFileOptions> items = myModel.getItems();
List<LogFileOptions> newItems = new ArrayList<LogFileOptions>();
boolean changed = false;
for (LogFileOptions item : items) {
final PredefinedLogFile predefined = myLog2Predefined.get(item);
if (predefined != null) {
final LogFileOptions options = configurationBase.getOptionsForPredefinedLogFile(predefined);
if (LogFileOptions.areEqual(item, options)) {
newItems.add(item);
}
else {
changed = true;
myLog2Predefined.remove(item);
if (options == null) {
myUnresolvedPredefined.add(predefined);
}
else {
newItems.add(options);
myLog2Predefined.put(options, predefined);
}
}
}
else {
newItems.add(item);
}
}
final PredefinedLogFile[] unresolved = myUnresolvedPredefined.toArray(new PredefinedLogFile[myUnresolvedPredefined.size()]);
for (PredefinedLogFile logFile : unresolved) {
final LogFileOptions options = configurationBase.getOptionsForPredefinedLogFile(logFile);
if (options != null) {
changed = true;
myUnresolvedPredefined.remove(logFile);
myLog2Predefined.put(options, logFile);
newItems.add(options);
}
}
if (changed) {
myModel.setItems(newItems);
}
}
@Override
protected void resetEditorFrom(final RunConfigurationBase configuration) {
ArrayList<LogFileOptions> list = new ArrayList<LogFileOptions>();
final List<LogFileOptions> logFiles = configuration.getLogFiles();
for (LogFileOptions setting : logFiles) {
list.add(
new LogFileOptions(setting.getName(), setting.getPathPattern(), setting.isEnabled(), setting.isSkipContent(), setting.isShowAll()));
}
myLog2Predefined.clear();
myUnresolvedPredefined.clear();
final List<PredefinedLogFile> predefinedLogFiles = configuration.getPredefinedLogFiles();
for (PredefinedLogFile predefinedLogFile : predefinedLogFiles) {
PredefinedLogFile logFile = new PredefinedLogFile(predefinedLogFile);
final LogFileOptions options = configuration.getOptionsForPredefinedLogFile(logFile);
if (options != null) {
myLog2Predefined.put(options, logFile);
list.add(options);
}
else {
myUnresolvedPredefined.add(logFile);
}
}
myModel.setItems(list);
final boolean redirectOutputToFile = configuration.isSaveOutputToFile();
myRedirectOutputCb.setSelected(redirectOutputToFile);
final String fileOutputPath = configuration.getOutputFilePath();
myOutputFile.setText(fileOutputPath != null ? FileUtil.toSystemDependentName(fileOutputPath) : "");
myOutputFile.setEnabled(redirectOutputToFile);
myShowConsoleOnStdOutCb.setSelected(configuration.isShowConsoleOnStdOut());
myShowConsoleOnStdErrCb.setSelected(configuration.isShowConsoleOnStdErr());
}
@Override
protected void applyEditorTo(final RunConfigurationBase configuration) throws ConfigurationException {
myFilesTable.stopEditing();
configuration.removeAllLogFiles();
configuration.removeAllPredefinedLogFiles();
for (int i = 0; i < myModel.getRowCount(); i++) {
LogFileOptions options = (LogFileOptions)myModel.getValueAt(i, 1);
if (Comparing.equal(options.getPathPattern(), "")) {
continue;
}
final Boolean checked = (Boolean)myModel.getValueAt(i, 0);
final Boolean skipped = (Boolean)myModel.getValueAt(i, 2);
final PredefinedLogFile predefined = myLog2Predefined.get(options);
if (predefined != null) {
configuration.addPredefinedLogFile(new PredefinedLogFile(predefined.getId(), options.isEnabled()));
}
else {
configuration
.addLogFile(options.getPathPattern(), options.getName(), checked.booleanValue(), skipped.booleanValue(), options.isShowAll());
}
}
for (PredefinedLogFile logFile : myUnresolvedPredefined) {
configuration.addPredefinedLogFile(logFile);
}
final String text = myOutputFile.getText();
configuration.setFileOutputPath(StringUtil.isEmpty(text) ? null : FileUtil.toSystemIndependentName(text));
configuration.setSaveOutputToFile(myRedirectOutputCb.isSelected());
configuration.setShowConsoleOnStdOut(myShowConsoleOnStdOutCb.isSelected());
configuration.setShowConsoleOnStdErr(myShowConsoleOnStdErrCb.isSelected());
}
@Override
@NotNull
protected JComponent createEditor() {
return myWholePanel;
}
private static boolean showEditorDialog(@NotNull LogFileOptions options) {
EditLogPatternDialog dialog = new EditLogPatternDialog();
dialog.init(options.getName(), options.getPathPattern(), options.isShowAll());
dialog.show();
if (dialog.isOK()) {
options.setName(dialog.getName());
options.setPathPattern(dialog.getLogPattern());
options.setShowAll(dialog.isShowAllFiles());
return true;
}
return false;
}
private class MyLogFileColumnInfo extends ColumnInfo<LogFileOptions, LogFileOptions> {
public MyLogFileColumnInfo() {
super(DiagnosticBundle.message("log.monitor.log.file.column"));
}
@Override
public TableCellRenderer getRenderer(final LogFileOptions p0) {
return new DefaultTableCellRenderer() {
@NotNull
@Override
public Component getTableCellRendererComponent(@NotNull JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
final Component renderer = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
setText(((LogFileOptions)value).getName());
//noinspection ConstantConditions
setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
setBorder(null);
return renderer;
}
};
}
@Override
public LogFileOptions valueOf(final LogFileOptions object) {
return object;
}
@Override
public TableCellEditor getEditor(final LogFileOptions item) {
return new LogFileCellEditor(item);
}
@Override
public void setValue(final LogFileOptions o, final LogFileOptions aValue) {
if (aValue != null) {
if (!o.getName().equals(aValue.getName()) || !o.getPathPattern().equals(aValue.getPathPattern())
|| o.isShowAll() != aValue.isShowAll()) {
myLog2Predefined.remove(o);
}
o.setName(aValue.getName());
o.setShowAll(aValue.isShowAll());
o.setPathPattern(aValue.getPathPattern());
}
}
@Override
public boolean isCellEditable(final LogFileOptions o) {
return !myLog2Predefined.containsKey(o);
}
}
private class MyIsActiveColumnInfo extends ColumnInfo<LogFileOptions, Boolean> {
protected MyIsActiveColumnInfo() {
super(DiagnosticBundle.message("log.monitor.is.active.column"));
}
@Override
public Class getColumnClass() {
return Boolean.class;
}
@Override
public Boolean valueOf(final LogFileOptions object) {
return object.isEnabled();
}
@Override
public boolean isCellEditable(LogFileOptions element) {
return true;
}
@Override
public void setValue(LogFileOptions element, Boolean checked) {
final PredefinedLogFile predefinedLogFile = myLog2Predefined.get(element);
if (predefinedLogFile != null) {
predefinedLogFile.setEnabled(checked.booleanValue());
}
element.setEnable(checked.booleanValue());
}
}
private class MyIsSkipColumnInfo extends ColumnInfo<LogFileOptions, Boolean> {
protected MyIsSkipColumnInfo() {
super(DiagnosticBundle.message("log.monitor.is.skipped.column"));
}
@Override
public Class getColumnClass() {
return Boolean.class;
}
@Override
public Boolean valueOf(final LogFileOptions element) {
return element.isSkipContent();
}
@Override
public boolean isCellEditable(LogFileOptions element) {
return !myLog2Predefined.containsKey(element);
}
@Override
public void setValue(LogFileOptions element, Boolean skipped) {
element.setSkipContent(skipped.booleanValue());
}
}
private class LogFileCellEditor extends AbstractTableCellEditor {
private final CellEditorComponentWithBrowseButton<JTextField> myComponent;
private final LogFileOptions myLogFileOptions;
public LogFileCellEditor(LogFileOptions options) {
myLogFileOptions = options;
myComponent = new CellEditorComponentWithBrowseButton<JTextField>(new TextFieldWithBrowseButton(), this);
getChildComponent().setEditable(false);
getChildComponent().setBorder(null);
myComponent.getComponentWithButton().getButton().addActionListener(new ActionListener() {
@Override
public void actionPerformed(@NotNull ActionEvent e) {
showEditorDialog(myLogFileOptions);
JTextField textField = getChildComponent();
textField.setText(myLogFileOptions.getName());
textField.requestFocus();
myModel.fireTableDataChanged();
}
});
}
@Override
public Object getCellEditorValue() {
return myLogFileOptions;
}
private JTextField getChildComponent() {
return myComponent.getChildComponent();
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
getChildComponent().setText(((LogFileOptions)value).getName());
return myComponent;
}
}
}