/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.plugin.ij.refactor.signature;
import com.intellij.codeInsight.completion.JavaCompletionUtil;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFileFactory;
import com.intellij.psi.PsiType;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.refactoring.changeSignature.ParameterInfoImpl;
import com.intellij.refactoring.ui.StringTableCellEditor;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.ui.ColoredTableCellRenderer;
import com.intellij.ui.EditorTextField;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.ui.ColumnInfo;
import gw.plugin.ij.completion.handlers.SymbolCompletionHandler;
import gw.plugin.ij.editors.LightweightGosuEditor;
import gw.plugin.ij.lang.GosuLanguage;
import gw.plugin.ij.lang.psi.impl.GosuFragmentFileImpl;
import gw.plugin.ij.lang.psi.impl.types.CompletionVoter;
import gw.plugin.ij.refactor.GosuRefactoringUtil;
import gw.plugin.ij.util.LightVirtualFileWithModule;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.LineBorder;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.LinkedHashSet;
import java.util.Set;
import static gw.plugin.ij.refactor.GosuRefactoringUtil.findFragmentType;
public class GosuParameterTableModel extends ParameterTableModelBase {
private final Project myProject;
private GosuChangeSignatureDialog dialog;
public GosuParameterTableModel(final PsiElement typeContext,
PsiElement defaultValueContext,
final GosuChangeSignatureDialog dialog) {
this(typeContext, defaultValueContext,
new JavaTypeColumn(typeContext.getProject()),
new JavaNameColumn(typeContext.getProject()),
new DefaultValueColumn(typeContext.getProject(), GosuLanguage.instance().getAssociatedFileType()),
new AnyVarColumn() {
@Override
public boolean isCellEditable(ParameterTableModelItem item) {
return dialog.isGenerateDelegate() && super.isCellEditable(item);
}
});
this.dialog = dialog;
}
protected GosuParameterTableModel(PsiElement typeContext, PsiElement defaultValueContext, ColumnInfo... columns) {
super(typeContext, defaultValueContext, columns);
myProject = typeContext.getProject();
}
private static int id;
private static synchronized String genName() {
return GosuParameterTableModel.class.getName() + "_" + id++;
}
public LightweightGosuEditor createDefaultValueEditor(String content) {
final VirtualFile virtualFile = PsiFileFactory.getInstance(myProject).
createFileFromText(genName(), GosuLanguage.instance(), content, true, false).
getVirtualFile();
return makeGosuEditor(virtualFile);
}
private LightweightGosuEditor makeGosuEditor(VirtualFile virtualFile) {
LightVirtualFileWithModule.attachModule((LightVirtualFile) virtualFile, dialog.getModule());
LightweightGosuEditor editor = new LightweightGosuEditor(myProject, virtualFile, dialog.getDisposable());
editor.setOneLineMode(true);
return editor;
}
@Override
protected ParameterTableModelItem createRowItem(@Nullable ParameterInfoImpl parameterInfo) {
if (parameterInfo == null) {
parameterInfo = new ParameterInfoImpl(-1);
}
LightweightGosuEditor defaultValueCode = createDefaultValueEditor(parameterInfo.getDefaultValue());
LightweightGosuEditor paramTypeCode = createTypeEditor(parameterInfo.getTypeText());
return new ParameterTableModelItem(parameterInfo, paramTypeCode, defaultValueCode);
}
private LightweightGosuEditor createTypeEditor(String typeText) {
GosuFragmentFileImpl fragmentFile = new GosuFragmentFileImpl(myProject, typeText, genName(), myTypeContext);
fragmentFile.setAllowedCompletionHandlers(SymbolCompletionHandler.class);
fragmentFile.setAllowedCompletionTypes(CompletionVoter.Type.TYPE);
return makeGosuEditor(fragmentFile.getVirtualFile());
}
@Nullable
private static PsiType getRowType(JTable table, int row) {
return findFragmentType(((GosuParameterTableModel)table.getModel()).getItems().get(row).typeCodeFragment.getPsiFile());
}
private static class VariableCompletionTableCellEditor extends StringTableCellEditor {
public VariableCompletionTableCellEditor(Project project) {
super(project);
}
public Component getTableCellEditorComponent(final JTable table,
Object value,
boolean isSelected,
final int row,
int column) {
final EditorTextField textField = (EditorTextField)super.getTableCellEditorComponent(table, value, isSelected, row, column);
textField.registerKeyboardAction(new ActionListener() {
public void actionPerformed(ActionEvent e) {
PsiType type = getRowType(table, row);
if (type != null) {
completeVariable(textField, type);
}
}
}, KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, InputEvent.CTRL_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW);
textField.setBorder(new LineBorder(table.getSelectionBackground()));
return textField;
}
private static void completeVariable(EditorTextField editorTextField, PsiType type) {
Editor editor = editorTextField.getEditor();
String prefix = editorTextField.getText();
if (prefix == null) prefix = "";
Set<LookupElement> set = new LinkedHashSet<LookupElement>();
JavaCompletionUtil.completeVariableNameForRefactoring(editorTextField.getProject(), set, prefix, type, VariableKind.PARAMETER);
LookupElement[] lookupItems = set.toArray(new LookupElement[set.size()]);
editor.getCaretModel().moveToOffset(prefix.length());
editor.getSelectionModel().removeSelection();
LookupManager.getInstance(editorTextField.getProject()).showLookup(editor, lookupItems, prefix);
}
}
public static class JavaTypeColumn extends TypeColumn {
public JavaTypeColumn(Project project) {
super(project, GosuLanguage.instance().getAssociatedFileType());
}
@Override
public TableCellEditor doCreateEditor(ParameterTableModelItem o) {
return new LightEditorCellEditor(myProject, GosuLanguage.instance().getAssociatedFileType());
}
}
public static class JavaNameColumn extends NameColumn {
private final Project myProject;
public JavaNameColumn(Project project) {
super(project);
myProject = project;
}
@Override
public TableCellEditor doCreateEditor(ParameterTableModelItem o) {
return new VariableCompletionTableCellEditor(myProject);
}
@Override
public TableCellRenderer doCreateRenderer(ParameterTableModelItem item) {
return new ColoredTableCellRenderer() {
public void customizeCellRenderer(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
if (value == null) return;
if (isSelected || hasFocus) {
acquireState(table, true, false, row, column);
getCellState().updateRenderer(this);
setPaintFocusBorder(false);
}
append((String)value, new SimpleTextAttributes(Font.PLAIN, null));
}
};
}
}
}