blob: e29b797d581145b559c9538a35cab33e2c51f330 [file] [log] [blame]
/*
* Copyright 2000-2012 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.ide.todo.configurable;
import com.intellij.icons.AllIcons;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.todo.TodoConfiguration;
import com.intellij.ide.todo.TodoFilter;
import com.intellij.openapi.options.BaseConfigurable;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.psi.search.TodoAttributesUtil;
import com.intellij.psi.search.TodoPattern;
import com.intellij.ui.*;
import com.intellij.ui.table.JBTable;
import com.intellij.util.ui.Table;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableColumn;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
/**
* @author Vladimir Kondratyev
*/
public class TodoConfigurable extends BaseConfigurable implements SearchableConfigurable, Configurable.NoScroll {
/*
* UI resources
*/
private JPanel myPanel;
private JBTable myPatternsTable;
private JBTable myFiltersTable;
private final List<TodoPattern> myPatterns;
private final PatternsTableModel myPatternsModel;
private final List<TodoFilter> myFilters;
private final FiltersTableModel myFiltersModel;
/**
* Invoked by reflection
*/
public TodoConfigurable() {
myPatterns = new ArrayList<TodoPattern>();
myFilters = new ArrayList<TodoFilter>();
myFiltersModel = new FiltersTableModel(myFilters);
myPatternsModel = new PatternsTableModel(myPatterns);
}
private boolean arePatternsModified() {
TodoConfiguration todoConfiguration = TodoConfiguration.getInstance();
TodoPattern[] initialPatterns = todoConfiguration.getTodoPatterns();
if (initialPatterns.length != myPatterns.size()) {
return true;
}
for (TodoPattern initialPattern : initialPatterns) {
if (!myPatterns.contains(initialPattern)) {
return true;
}
}
return false;
}
private boolean areFiltersModified() {
TodoConfiguration todoConfiguration = TodoConfiguration.getInstance();
TodoFilter[] initialFilters = todoConfiguration.getTodoFilters();
if (initialFilters.length != myFilters.size()) {
return true;
}
for (TodoFilter initialFilter : initialFilters) {
if (!myFilters.contains(initialFilter)) {
return true;
}
}
return false;
}
@Override
public boolean isModified() {
// This method is always invoked before close configuration dialog or leave "ToDo" page.
// So it's a good place to commit all changes.
stopEditing();
return arePatternsModified() || areFiltersModified();
}
@Override
public void apply() throws ConfigurationException {
stopEditing();
if (arePatternsModified()) {
TodoPattern[] patterns = myPatterns.toArray(new TodoPattern[myPatterns.size()]);
TodoConfiguration.getInstance().setTodoPatterns(patterns);
}
if (areFiltersModified()) {
TodoFilter[] filters = myFilters.toArray(new TodoFilter[myFilters.size()]);
TodoConfiguration.getInstance().setTodoFilters(filters);
}
}
@Override
public void disposeUIResources() {
myPanel = null;
myPatternsModel.removeTableModelListener(myPatternsTable);
myPatternsTable = null;
myFiltersModel.removeTableModelListener(myFiltersTable);
myFiltersTable = null;
}
@Override
public JComponent createComponent() {
// Panel with patterns
PanelWithButtons patternsPanel = new PanelWithButtons() {
{
initPanel();
}
@Override
protected String getLabelText() {
return IdeBundle.message("label.todo.patterns");
}
@Override
protected JComponent createMainComponent() {
// JTable with TodoPaterns
myPatternsTable = new Table(myPatternsModel);
myPatternsTable.getEmptyText().setText(IdeBundle.message("text.todo.no.patterns"));
myPatternsTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
// Column "Icon"
JComboBox todoTypeCombo =
new JComboBox(new Icon[]{AllIcons.General.TodoDefault, AllIcons.General.TodoQuestion, AllIcons.General.TodoImportant});
todoTypeCombo.setRenderer(new TodoTypeListCellRenderer());
TableColumn typeColumn = myPatternsTable.getColumnModel().getColumn(0);
DefaultCellEditor todoTypeEditor = new DefaultCellEditor(todoTypeCombo);
todoTypeEditor.setClickCountToStart(1);
typeColumn.setCellEditor(todoTypeEditor);
TodoTypeTableCellRenderer todoTypeRenderer = new TodoTypeTableCellRenderer();
typeColumn.setCellRenderer(todoTypeRenderer);
int width = myPatternsTable.getFontMetrics(myPatternsTable.getFont()).stringWidth(myPatternsTable.getColumnName(0)) + 10;
typeColumn.setPreferredWidth(width);
typeColumn.setMaxWidth(width);
typeColumn.setMinWidth(width);
// Column "Case Sensitive"
TableColumn todoCaseSensitiveColumn = myPatternsTable.getColumnModel().getColumn(1);
width = myPatternsTable.getFontMetrics(myPatternsTable.getFont()).stringWidth(myPatternsTable.getColumnName(1)) + 10;
todoCaseSensitiveColumn.setPreferredWidth(width);
todoCaseSensitiveColumn.setMaxWidth(width);
todoCaseSensitiveColumn.setMinWidth(width);
// Column "Pattern"
TodoPatternTableCellRenderer todoPatternRenderer = new TodoPatternTableCellRenderer(myPatterns);
TableColumn patternColumn = myPatternsTable.getColumnModel().getColumn(2);
patternColumn.setCellRenderer(todoPatternRenderer);
((DefaultCellEditor)myPatternsTable.getDefaultEditor(String.class)).setClickCountToStart(2);
JPanel panel = ToolbarDecorator.createDecorator(myPatternsTable)
.setAddAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
stopEditing();
TodoPattern pattern = new TodoPattern(TodoAttributesUtil.createDefault());
PatternDialog dialog = new PatternDialog(myPanel, pattern);
dialog.setTitle(IdeBundle.message("title.add.todo.pattern"));
dialog.show();
if (!dialog.isOK()) {
return;
}
myPatterns.add(pattern);
int index = myPatterns.size() - 1;
myPatternsModel.fireTableRowsInserted(index, index);
myPatternsTable.getSelectionModel().setSelectionInterval(index, index);
myPatternsTable.scrollRectToVisible(myPatternsTable.getCellRect(index, 0, true));
}
}).setEditAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
editSelectedPattern();
}
}).setRemoveAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
stopEditing();
int selectedIndex = myPatternsTable.getSelectedRow();
if (selectedIndex < 0 || selectedIndex >= myPatternsModel.getRowCount()) {
return;
}
TodoPattern patternToBeRemoved = myPatterns.get(selectedIndex);
TableUtil.removeSelectedItems(myPatternsTable);
for (int i = 0; i < myFilters.size(); i++) {
TodoFilter filter = myFilters.get(i);
if (filter.contains(patternToBeRemoved)) {
filter.removeTodoPattern(patternToBeRemoved);
myFiltersModel.fireTableRowsUpdated(i, i);
}
}
}
}).disableUpDownActions().createPanel();
return panel;
}
@Override
protected JButton[] createButtons() {
return new JButton[]{};
}
};
// double click in "Patterns" table should also start editing of selected pattern
new DoubleClickListener() {
@Override
protected boolean onDoubleClick(MouseEvent e) {
editSelectedPattern();
return true;
}
}.installOn(myPatternsTable);
// Panel with filters
PanelWithButtons filtersPanel = new PanelWithButtons() {
{
initPanel();
}
@Override
protected String getLabelText() {
return IdeBundle.message("label.todo.filters");
}
@Override
protected JComponent createMainComponent() {
myFiltersTable = new Table(myFiltersModel);
myFiltersTable.getEmptyText().setText(IdeBundle.message("text.todo.no.filters"));
myFiltersTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
// Column "Name"
TableColumn nameColumn = myFiltersTable.getColumnModel().getColumn(0);
int width = myPatternsTable.getColumnModel().getColumn(0).getPreferredWidth()/*typeColumn*/ +
myPatternsTable.getColumnModel().getColumn(1).getPreferredWidth()/*todoCaseSensitiveColumn*/;
nameColumn.setPreferredWidth(width);
nameColumn.setMaxWidth(width);
nameColumn.setMinWidth(width);
nameColumn.setCellRenderer(new MyFilterNameTableCellRenderer());
JPanel panel = ToolbarDecorator.createDecorator(myFiltersTable)
.setAddAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
stopEditing();
TodoFilter filter = new TodoFilter();
FilterDialog dialog = new FilterDialog(myPanel, filter, -1, myFilters, myPatterns);
dialog.setTitle(IdeBundle.message("title.add.todo.filter"));
dialog.show();
int exitCode = dialog.getExitCode();
if (DialogWrapper.OK_EXIT_CODE == exitCode) {
myFilters.add(filter);
int index = myFilters.size() - 1;
myFiltersModel.fireTableRowsInserted(index, index);
myFiltersTable.getSelectionModel().setSelectionInterval(index, index);
myFiltersTable.scrollRectToVisible(myFiltersTable.getCellRect(index, 0, true));
}
}
}).setEditAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
editSelectedFilter();
}
}).setRemoveAction(new AnActionButtonRunnable() {
@Override
public void run(AnActionButton button) {
stopEditing();
TableUtil.removeSelectedItems(myFiltersTable);
}
}).disableUpDownActions().createPanel();
return panel;
}
@Override
protected JButton[] createButtons() {
return new JButton[]{};
}
};
// double click in "Filters" table should also start editing of selected filter
new DoubleClickListener() {
@Override
protected boolean onDoubleClick(MouseEvent e) {
editSelectedFilter();
return true;
}
}.installOn(myFiltersTable);
myPanel = new JPanel(new GridBagLayout());
myPanel.add(patternsPanel, new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.NORTH, GridBagConstraints.BOTH,
new Insets(0,0,0,0), 0, 0));
myPanel.add(filtersPanel, new GridBagConstraints(0, 1, 1, 1, 1, 1, GridBagConstraints.NORTH, GridBagConstraints.BOTH,
new Insets(0,0,0,0), 0, 0));
return myPanel;
}
private void editSelectedPattern() {
stopEditing();
int selectedIndex = myPatternsTable.getSelectedRow();
if (selectedIndex < 0 || selectedIndex >= myPatternsModel.getRowCount()) {
return;
}
TodoPattern sourcePattern = myPatterns.get(selectedIndex);
TodoPattern pattern = sourcePattern.clone();
PatternDialog dialog = new PatternDialog(myPanel, pattern);
dialog.setTitle(IdeBundle.message("title.edit.todo.pattern"));
dialog.show();
if (!dialog.isOK()) {
return;
}
myPatterns.set(selectedIndex, pattern);
myPatternsModel.fireTableRowsUpdated(selectedIndex, selectedIndex);
myPatternsTable.getSelectionModel().setSelectionInterval(selectedIndex, selectedIndex);
// Update model with patterns
for (int i = 0; i < myFilters.size(); i++) {
TodoFilter filter = myFilters.get(i);
if (filter.contains(sourcePattern)) {
filter.removeTodoPattern(sourcePattern);
filter.addTodoPattern(pattern);
myFiltersModel.fireTableRowsUpdated(i, i);
}
}
}
private void editSelectedFilter() {
stopEditing();
int selectedIndex = myFiltersTable.getSelectedRow();
if (selectedIndex < 0 || selectedIndex >= myFiltersModel.getRowCount()) {
return;
}
TodoFilter sourceFilter = myFilters.get(selectedIndex);
TodoFilter filter = sourceFilter.clone();
FilterDialog dialog = new FilterDialog(myPanel, filter, selectedIndex, myFilters, myPatterns);
dialog.setTitle(IdeBundle.message("title.edit.todo.filter"));
dialog.show();
int exitCode = dialog.getExitCode();
if (DialogWrapper.OK_EXIT_CODE == exitCode) {
myFilters.set(selectedIndex, filter);
myFiltersModel.fireTableRowsUpdated(selectedIndex, selectedIndex);
myFiltersTable.getSelectionModel().setSelectionInterval(selectedIndex, selectedIndex);
}
}
private void stopEditing() {
if (myPatternsTable.isEditing()) {
TableCellEditor editor = myPatternsTable.getCellEditor();
if (editor != null) {
editor.stopCellEditing();
}
}
if (myFiltersTable.isEditing()) {
TableCellEditor editor = myFiltersTable.getCellEditor();
if (editor != null) {
editor.stopCellEditing();
}
}
}
@Override
public String getDisplayName() {
return IdeBundle.message("title.todo");
}
@Override
@NotNull
public String getHelpTopic() {
return "preferences.toDoOptions";
}
@Override
public void reset() {
// Patterns
myPatterns.clear();
TodoConfiguration todoConfiguration = TodoConfiguration.getInstance();
TodoPattern[] patterns = todoConfiguration.getTodoPatterns();
for (TodoPattern pattern : patterns) {
myPatterns.add(pattern.clone());
}
myPatternsModel.fireTableDataChanged();
// Filters
myFilters.clear();
TodoFilter[] filters = todoConfiguration.getTodoFilters();
for (TodoFilter filter : filters) {
myFilters.add(filter.clone());
}
myFiltersModel.fireTableDataChanged();
}
private final class MyFilterNameTableCellRenderer extends DefaultTableCellRenderer {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
TodoFilter filter = myFilters.get(row);
if (isSelected) {
setForeground(UIUtil.getTableSelectionForeground());
}
else {
if (filter.isEmpty()) {
setForeground(JBColor.RED);
}
else {
setForeground(UIUtil.getTableForeground());
}
}
return this;
}
}
@Override
@NotNull
public String getId() {
return getHelpTopic();
}
@Override
@Nullable
public Runnable enableSearch(String option) {
return null;
}
}