package com.redhat.ceylon.eclipse.code.refactor; import java.util.ArrayList; import java.util.List; import org.antlr.runtime.CommonToken; import org.eclipse.jface.dialogs.PopupDialog; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.StyledCellLabelProvider; import org.eclipse.jface.viewers.StyledString; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableItem; import com.redhat.ceylon.compiler.typechecker.tree.Node; import com.redhat.ceylon.compiler.typechecker.tree.Tree; import com.redhat.ceylon.compiler.typechecker.tree.Visitor; import com.redhat.ceylon.eclipse.code.editor.CeylonEditor; import com.redhat.ceylon.eclipse.ui.CeylonPlugin; import com.redhat.ceylon.eclipse.util.Highlights; import com.redhat.ceylon.eclipse.util.Nodes; abstract class SelectExpressionPopup extends PopupDialog { private CeylonEditor editor; private TableViewer table; private List<Tree.Term> containingExpressions; abstract void finish(); SelectExpressionPopup(Shell parent, int shellStyle, CeylonEditor editor, String title) { super(parent, shellStyle, true, true, false, false, false, null, null); this.editor = editor; setTitleText(title); containingExpressions = containingExpressions(); } private Point getLocation() { StyledText text = editor.getCeylonSourceViewer() .getTextWidget(); Point selection = text.getSelection(); Point p = text.getLocationAtOffset(selection.x); p.x -= getShell().getBorderWidth(); if (p.x < 0) p.x= 0; if (p.y < 0) p.y= 0; p = new Point(p.x, p.y + text.getLineHeight(selection.x)); p = text.toDisplay(p); return p; } @Override public int open() { if (containingExpressions.size()>1) { int result = super.open(); getShell().setLocation(getLocation()); setFocus(); return result; } else { finish(); return OK; } } private List<Tree.Term> containingExpressions() { final List<Tree.Term> expressions = new ArrayList<Tree.Term>(); Tree.CompilationUnit rootNode = editor.getParseController() .getLastCompilationUnit(); if (rootNode!=null) { new Visitor() { IRegion selection = editor.getSelection(); private void option(Tree.Term that) { if (that.getStartIndex() <= selection.getOffset() && that.getEndIndex() >= selection.getOffset() + selection.getLength()) { expressions.add(that); } } @Override public void visit(Tree.Expression that) { //don't propose parenthesized expressions if (that.getTerm()!=null) { that.getTerm().visit(this); } } @Override public void visit(Tree.AssignmentOp that) { //don't visit LHS if (that.getRightTerm()!=null) { that.getRightTerm().visit(this); } } @Override public void visit(Tree.SpecifierStatement that) { //don't visit LHS if (that.getSpecifierExpression()!=null) { that.getSpecifierExpression().visit(this); } } @Override public void visit(Tree.Term that) { super.visit(that); option(that); } @Override public void visit(Tree.StringTemplate that) { //don't visit the string fragments for (Tree.Expression e: that.getExpressions()) { e.visit(this); } option(that); } }.visit(rootNode); } return expressions; } @Override protected Control createDialogArea(Composite parent) { GridLayout layout = new GridLayout(); layout.marginTop = 0; layout.marginLeft = 2; layout.marginRight = 2; layout.marginBottom = 2; parent.setLayout(layout); table = new TableViewer(parent, SWT.NO_TRIM|SWT.SINGLE|SWT.FULL_SELECTION); final Table tab = table.getTable(); tab.setFont(CeylonPlugin.getCompletionFont()); Display display = getShell().getDisplay(); tab.setCursor(new Cursor(display, SWT.CURSOR_HAND)); tab.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); table.setLabelProvider(new StyledCellLabelProvider() { @Override public void update(ViewerCell cell) { Tree.Term e = (Tree.Term) cell.getElement(); StyledString result = new StyledString(); List<CommonToken> tokens = editor.getParseController() .getTokens(); String text = Nodes.text(e, tokens) .replaceAll("\\s\\s+|\n|\r|\f", " "); Highlights.styleFragment(result, text, false, null, CeylonPlugin.getCompletionFont()); cell.setText(result.toString()); cell.setStyleRanges(result.getStyleRanges()); super.update(cell); } }); table.setContentProvider(ArrayContentProvider.getInstance()); table.setInput(containingExpressions); tab.setSelection(0); tab.addKeyListener(new KeyListener() { @Override public void keyReleased(KeyEvent e) {} @Override public void keyPressed(KeyEvent e) { if (e.keyCode == 0x0D || e.keyCode == SWT.KEYPAD_CR) { // Enter key select(); } if (e.character == 0x1B) { // ESC close(); } } }); tab.addListener(SWT.MouseMove, new Listener() { @Override public void handleEvent(Event event) { Rectangle bounds = event.getBounds(); Point point = new Point(bounds.x, bounds.y); TableItem item = tab.getItem(point); if (item!=null) { StructuredSelection selection = new StructuredSelection( item.getData()); table.setSelection(selection); } } }); tab.addMouseListener(new MouseListener() { @Override public void mouseUp(MouseEvent e) { select(); } @Override public void mouseDown(MouseEvent e) {} @Override public void mouseDoubleClick(MouseEvent e) { select(); } }); return parent; } public void setFocus() { getShell().forceFocus(); table.getControl().setFocus(); } private void select() { IStructuredSelection selection = (IStructuredSelection) table.getSelection(); Node e = (Node) selection.getFirstElement(); if (e!=null) { editor.getSelectionProvider() .setSelection(new TextSelection( e.getStartIndex(), e.getDistance())); } close(); finish(); } }