/*
* Copyright 2000-2009 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.refactoring.rename;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiNamedElement;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.rename.naming.AutomaticRenamer;
import com.intellij.refactoring.ui.EnableDisableAction;
import com.intellij.refactoring.ui.StringTableCellEditor;
import com.intellij.refactoring.util.RefactoringUIUtil;
import com.intellij.ui.BooleanTableCellRenderer;
import com.intellij.ui.GuiUtils;
import com.intellij.ui.TableUtil;
import com.intellij.ui.table.JBTable;
import com.intellij.usageView.UsageInfo;
import com.intellij.usages.UsageViewPresentation;
import com.intellij.usages.impl.UsagePreviewPanel;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumnModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import java.util.List;
/**
* @author dsl
*/
public class AutomaticRenamingDialog extends DialogWrapper {
private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.rename.AutomaticRenamingDialog");
private static final int CHECK_COLUMN = 0;
private static final int OLD_NAME_COLUMN = 1;
private static final int NEW_NAME_COLUMN = 2;
private final AutomaticRenamer myRenamer;
private boolean[] myShouldRename;
private String[] myNewNames;
private PsiNamedElement[] myRenames;
private MyTableModel myTableModel;
private JBTable myTable;
private JPanel myPanelForPreview;
private JButton mySelectAllButton;
private JButton myUnselectAllButton;
private JPanel myPanel;
private JSplitPane mySplitPane;
private final Project myProject;
private final UsagePreviewPanel myUsagePreviewPanel;
private final JLabel myUsageFileLabel;
private ListSelectionListener myListSelectionListener;
public AutomaticRenamingDialog(Project project, AutomaticRenamer renamer) {
super(project, true);
myProject = project;
myRenamer = renamer;
myUsagePreviewPanel = new UsagePreviewPanel(myProject, new UsageViewPresentation());
myUsageFileLabel = new JLabel();
populateData();
setTitle(myRenamer.getDialogTitle());
init();
}
private void populateData() {
final Map<PsiNamedElement, String> renames = myRenamer.getRenames();
List<PsiNamedElement> temp = new ArrayList<PsiNamedElement>();
for (final PsiNamedElement namedElement : renames.keySet()) {
final String newName = renames.get(namedElement);
if (newName != null) temp.add(namedElement);
}
myRenames = temp.toArray(new PsiNamedElement[temp.size()]);
Arrays.sort(myRenames, new Comparator<PsiNamedElement>() {
@Override
public int compare(final PsiNamedElement e1, final PsiNamedElement e2) {
return Comparing.compare(e1.getName(), e2.getName());
}
});
myNewNames = new String[myRenames.length];
for (int i = 0; i < myNewNames.length; i++) {
myNewNames[i] = renames.get(myRenames[i]);
}
myShouldRename = new boolean[myRenames.length];
if (myRenamer.isSelectedByDefault()) {
for(int i=0; i<myShouldRename.length; i++) {
myShouldRename [i] = true;
}
}
}
@Override
protected String getDimensionServiceKey() {
return "#com.intellij.refactoring.rename.AutomaticRenamingDialog";
}
@Override
protected JComponent createNorthPanel() {
final Box box = Box.createHorizontalBox();
box.add(new JLabel(myRenamer.getDialogDescription()));
box.add(Box.createHorizontalGlue());
return box;
}
@Override
public void show() {
if (ApplicationManager.getApplication().isUnitTestMode()) return;
super.show();
}
protected void handleChanges() {
final int selectedRow = myTable.getSelectedRow();
if (selectedRow > -1) {
final boolean validName = RenameUtil.isValidName(myProject, myRenames[selectedRow], myNewNames[selectedRow]);
getOKAction().setEnabled(validName);
setErrorText(validName ? null : "Identifier \'" + myNewNames[selectedRow] + "\' is invalid");
}
}
@Override
protected JComponent createCenterPanel() {
myTableModel = new MyTableModel();
myTable.setModel(myTableModel);
myTableModel.getSpaceAction().register();
myTableModel.addTableModelListener(new TableModelListener() {
@Override
public void tableChanged(TableModelEvent e) {
handleChanges();
}
});
final TableColumnModel columnModel = myTable.getColumnModel();
columnModel.getColumn(CHECK_COLUMN).setCellRenderer(new BooleanTableCellRenderer());
final int checkBoxWidth = new JCheckBox().getPreferredSize().width;
columnModel.getColumn(CHECK_COLUMN).setMaxWidth(checkBoxWidth);
columnModel.getColumn(CHECK_COLUMN).setMinWidth(checkBoxWidth);
columnModel.getColumn(NEW_NAME_COLUMN).setCellEditor(new StringTableCellEditor(myProject));
mySelectAllButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < myShouldRename.length; i++) {
myShouldRename[i] = true;
}
fireDataChanged();
}
});
myUnselectAllButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < myShouldRename.length; i++) {
myShouldRename[i] = false;
}
fireDataChanged();
}
});
myListSelectionListener = new ListSelectionListener() {
@Override
public void valueChanged(final ListSelectionEvent e) {
myUsageFileLabel.setText("");
int index = myTable.getSelectionModel().getLeadSelectionIndex();
if (index != -1) {
PsiNamedElement element = myRenames[index];
UsageInfo usageInfo = new UsageInfo(element);
myUsagePreviewPanel.updateLayout(Collections.singletonList(usageInfo));
final PsiFile containingFile = element.getContainingFile();
if (containingFile != null) {
final VirtualFile virtualFile = containingFile.getVirtualFile();
if (virtualFile != null) {
myUsageFileLabel.setText(virtualFile.getName());
}
}
}
else {
myUsagePreviewPanel.updateLayout(null);
}
}
};
myTable.getSelectionModel().addListSelectionListener(myListSelectionListener);
myPanelForPreview.add(myUsagePreviewPanel, BorderLayout.CENTER);
myUsagePreviewPanel.updateLayout(null);
myPanelForPreview.add(myUsageFileLabel, BorderLayout.NORTH);
mySplitPane.setDividerLocation(0.5);
GuiUtils.replaceJSplitPaneWithIDEASplitter(myPanel);
if (myTableModel.getRowCount() != 0) {
myTable.getSelectionModel().addSelectionInterval(0,0);
}
return myPanel;
}
private void fireDataChanged() {
int[] selectedRows = myTable.getSelectedRows();
myTable.getSelectionModel().removeListSelectionListener(myListSelectionListener);
myTableModel.fireTableDataChanged();
for (int selectedRow : selectedRows) {
myTable.addRowSelectionInterval(selectedRow, selectedRow);
}
myTable.getSelectionModel().addListSelectionListener(myListSelectionListener);
}
@Override
public JComponent getPreferredFocusedComponent() {
return myTable;
}
@Override
protected void doOKAction() {
TableUtil.stopEditing(myTable);
updateRenamer();
super.doOKAction();
}
@Override
protected void dispose() {
Disposer.dispose(myUsagePreviewPanel);
super.dispose();
}
private void updateRenamer() {
for (int i = 0; i < myRenames.length; i++) {
PsiNamedElement element = myRenames[i];
if (myShouldRename[i]) {
myRenamer.setRename(element, myNewNames[i]);
}
else {
myRenamer.doNotRename(element);
}
}
}
private void createUIComponents() {
myTable = new JBTable();
myTable.setRowHeight(myTable.getFontMetrics(UIManager.getFont("Table.font").deriveFont(Font.BOLD)).getHeight() + 4);
}
private class MyTableModel extends AbstractTableModel {
@Override
public int getColumnCount() {
return 3;
}
@Override
public int getRowCount() {
return myShouldRename.length;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
switch(columnIndex) {
case CHECK_COLUMN:
return Boolean.valueOf(myShouldRename[rowIndex]);
case OLD_NAME_COLUMN:
return "<html><nobr>" + RefactoringUIUtil.getDescription(myRenames[rowIndex], true) + "</nobr></html>";
case NEW_NAME_COLUMN:
return myNewNames[rowIndex];
default:
LOG.assertTrue(false);
return null;
}
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
switch(columnIndex) {
case CHECK_COLUMN:
myShouldRename[rowIndex] = ((Boolean)aValue).booleanValue();
break;
case NEW_NAME_COLUMN:
myNewNames[rowIndex] = (String) aValue;
break;
default:
LOG.assertTrue(false);
}
handleChanges();
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return columnIndex != OLD_NAME_COLUMN;
}
@Override
public Class getColumnClass(int columnIndex) {
switch(columnIndex) {
case CHECK_COLUMN: return Boolean.class;
case OLD_NAME_COLUMN: return String.class;
case NEW_NAME_COLUMN: return String.class;
default: return null;
}
}
@Override
public String getColumnName(int column) {
switch(column) {
case OLD_NAME_COLUMN:
return RefactoringBundle.message("automatic.renamer.enity.name.column", myRenamer.entityName());
case NEW_NAME_COLUMN:
return RefactoringBundle.message("automatic.renamer.rename.to.column");
default:
return " ";
}
}
private MyEnableDisable getSpaceAction() {
return this.new MyEnableDisable();
}
private class MyEnableDisable extends EnableDisableAction {
@Override
protected JTable getTable() {
return myTable;
}
@Override
protected boolean isRowChecked(int row) {
return myShouldRename[row];
}
@Override
protected void applyValue(int[] rows, boolean valueToBeSet) {
for (final int row : rows) {
myShouldRename[row] = valueToBeSet;
}
fireDataChanged();
}
}
}
}