package com.redhat.ceylon.eclipse.code.search;
import static com.redhat.ceylon.eclipse.code.editor.Navigation.gotoFile;
import static com.redhat.ceylon.eclipse.code.open.OpenDeclarationDialog.isMatchingGlob;
import static com.redhat.ceylon.eclipse.code.preferences.CeylonPreferenceInitializer.FULL_LOC_SEARCH_RESULTS;
import static com.redhat.ceylon.eclipse.ui.CeylonPlugin.PLUGIN_ID;
import static com.redhat.ceylon.eclipse.ui.CeylonPlugin.imageRegistry;
import static com.redhat.ceylon.eclipse.ui.CeylonResources.CEYLON_DECS;
import static com.redhat.ceylon.eclipse.ui.CeylonResources.CEYLON_IMPORT;
import static com.redhat.ceylon.eclipse.ui.CeylonResources.CEYLON_REFS;
import static com.redhat.ceylon.eclipse.ui.CeylonResources.FLAT_MODE;
import static com.redhat.ceylon.eclipse.ui.CeylonResources.TREE_MODE;
import static com.redhat.ceylon.eclipse.ui.CeylonResources.imageRegistry;
import static com.redhat.ceylon.eclipse.util.EditorUtil.getCommandBinding;
import static com.redhat.ceylon.eclipse.util.EditorUtil.getEnterBinding;
import static com.redhat.ceylon.eclipse.util.EditorUtil.triggersBinding;
import static com.redhat.ceylon.eclipse.util.Highlights.PACKAGE_STYLER;
import static com.redhat.ceylon.eclipse.util.Nodes.getReferencedExplicitDeclaration;
import static java.util.Collections.emptySet;
import static org.eclipse.jface.action.IAction.AS_CHECK_BOX;
import static org.eclipse.jface.viewers.StyledString.COUNTER_STYLER;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.bindings.TriggerSequence;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.PopupDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.IInformationControl;
import org.eclipse.jface.text.IInformationControlExtension2;
import org.eclipse.jface.text.IInformationControlExtension3;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StyledString;
import org.eclipse.jface.viewers.StyledString.Styler;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TreeNode;
import org.eclipse.jface.viewers.TreeNodeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.graphics.TextStyle;
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.Item;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import com.redhat.ceylon.compiler.typechecker.context.PhasedUnit;
import com.redhat.ceylon.compiler.typechecker.tree.Node;
import com.redhat.ceylon.compiler.typechecker.tree.Tree;
import com.redhat.ceylon.eclipse.code.editor.CeylonEditor;
import com.redhat.ceylon.eclipse.code.outline.TreeNodeLabelProvider;
import com.redhat.ceylon.eclipse.code.outline.TreeViewMouseListener;
import com.redhat.ceylon.eclipse.code.parse.CeylonParseController;
import com.redhat.ceylon.eclipse.ui.CeylonPlugin;
import com.redhat.ceylon.eclipse.ui.CeylonResources;
import com.redhat.ceylon.eclipse.util.Highlights;
import com.redhat.ceylon.ide.common.util.FindReferencesVisitor;
import com.redhat.ceylon.ide.common.util.FindRefinementsVisitor;
import com.redhat.ceylon.ide.common.util.FindSubtypesVisitor;
import com.redhat.ceylon.model.typechecker.model.Declaration;
import com.redhat.ceylon.model.typechecker.model.Module;
import com.redhat.ceylon.model.typechecker.model.Package;
import com.redhat.ceylon.model.typechecker.model.Referenceable;
import com.redhat.ceylon.model.typechecker.model.TypeDeclaration;
import com.redhat.ceylon.model.typechecker.model.Unit;
public final class ReferencesPopup extends PopupDialog
implements IInformationControl,
IInformationControlExtension2,
IInformationControlExtension3 {
private static final Image REFS_IMAGE =
imageRegistry().get(CEYLON_REFS);
private static final Image DECS_IMAGE =
imageRegistry().get(CEYLON_DECS);
public class ChangeLayoutListener implements SelectionListener {
@Override
public void widgetSelected(SelectionEvent e) {
switchLayout();
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {}
}
private String getPrefix() {
return filterText.getText();
}
private Font getFont() {
return viewer.getControl().getFont();
}
public final class LabelProvider extends TreeNodeLabelProvider {
public LabelProvider() {
super(new SearchResultsLabelProvider() {
@Override
public String getPrefix() {
return ReferencesPopup.this.getPrefix();
}
@Override
public Font getFont() {
return ReferencesPopup.this.getFont();
}
});
}
@Override
public StyledString getStyledText(Object element) {
Object unwrapped = unwrap(element);
if (unwrapped instanceof CeylonElement) {
CeylonElement ce = (CeylonElement) unwrapped;
StyledString label =
ce.getLabel(getPrefix(), getFont());
if (!ReferencesPopup.this.treeLayout) {
label = new StyledString().append(label);
label.append(" \u2014 ", PACKAGE_STYLER)
.append(ce.getPackageLabel(), PACKAGE_STYLER);
if (CeylonPlugin.getPreferences()
.getBoolean(FULL_LOC_SEARCH_RESULTS)) {
label.append(" \u2014 ", COUNTER_STYLER)
.append(ce.getPathString(), COUNTER_STYLER);
}
}
Integer matchCount = matchCounts.get(ce);
if (matchCount!=null && matchCount>1) {
label = new StyledString().append(label);
label.append(" (" + matchCount + " matches)",
Highlights.ARROW_STYLER);
}
return label;
}
else {
return super.getStyledText(element);
}
}
@Override
public Object unwrap(Object element) {
Object unwrapped = super.unwrap(element);
if (unwrapped instanceof CeylonSearchMatch) {
CeylonSearchMatch match =
(CeylonSearchMatch) unwrapped;
return match.getElement();
}
else {
return unwrapped;
}
}
}
public final class ClickListener implements MouseListener {
@Override
public void mouseUp(MouseEvent e) {
gotoSelectedElement();
}
@Override
public void mouseDown(MouseEvent e) {}
@Override
public void mouseDoubleClick(MouseEvent e) {
gotoSelectedElement();
}
}
public final class ShortcutKeyListener implements KeyListener {
@Override
public void keyReleased(KeyEvent e) {}
@Override
public void keyPressed(KeyEvent e) {
triggerCommand(e);
char character = e.character;
int keyCode = e.keyCode;
int stateMask = e.stateMask;
if (stateMask==SWT.NONE || stateMask==SWT.SHIFT) {
if (Character.isLetter(character)
&& keyCode==Character.toLowerCase(character)) {
String string = filterText.getText() + character;
filterText.setText(string);
filterText.setFocus();
filterText.setSelection(string.length());
}
if (character == SWT.BS && keyCode==SWT.BS) {
String string = filterText.getText();
if (string.length()>0) {
string = string.substring(0,string.length()-1);
}
filterText.setText(string);
filterText.setFocus();
filterText.setSelection(string.length());
}
}
if (keyCode == 0x0D || keyCode == SWT.KEYPAD_CR) { // Enter key
gotoSelectedElement();
}
}
}
public final class Filter extends ViewerFilter {
@Override
public boolean select(Viewer viewer,
Object parentElement, Object element) {
TreeNode treeNode = (TreeNode) element;
Object value = treeNode.getValue();
if (value instanceof CeylonSearchMatch) {
CeylonSearchMatch match =
(CeylonSearchMatch) value;
String filter = filterText.getText();
CeylonElement e = match.getElement();
String[] split =
e.getLabel()
.getString()
.split(" ");
return split.length>1 &&
isMatchingGlob(filter, split[1]) ||
isMatchingGlob(filter,
e.getPackageLabel()) ||
isMatchingGlob(filter,
e.getFile().getName());
}
else {
for (TreeNode child: treeNode.getChildren()) {
if (select(viewer, element, child)) {
return true;
}
}
return false;
}
}
}
protected Text filterText;
private ColumnViewer viewer;
private final CeylonEditor editor;
private StyledText titleLabel;
private TriggerSequence commandBinding;
private TriggerSequence findCommandBinding;
private boolean showingRefinements = false;
public ReferencesPopup(Shell parent, int shellStyle,
CeylonEditor editor) {
super(parent, shellStyle, true, true, false, true,
true, null, null);
treeLayout =
getDialogSettings()
.getBoolean("treeLayout");
includeImports =
getDialogSettings()
.getBoolean("includeImports");
setTitleText("Quick Find References");
this.editor = editor;
commandBinding =
getCommandBinding(PLUGIN_ID +
".editor.findReferences");
findCommandBinding =
getCommandBinding(PLUGIN_ID +
".action.findReferences");
setStatusText();
create();
/*Color bg = parent.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND);
getShell().setBackground(bg);
setBackgroundColor(bg);
//setBackgroundColor(getEditorWidget(editor).getBackground());
setForegroundColor(getEditorWidget(editor).getForeground());*/
}
private void setIcon() {
if (showingRefinements) {
icon.setImage(DECS_IMAGE);
}
else {
icon.setImage(REFS_IMAGE);
}
}
private void setStatusText() {
StringBuilder builder = new StringBuilder();
if (findCommandBinding!=null) {
builder.append(findCommandBinding.format())
.append(" to find all references");
}
if (commandBinding!=null) {
String message;
if (showingRefinements) {
message = " to show references";
}
else {
if (type) {
message = " to show subtypes";
}
else {
message = " to show refinements";
}
}
if (builder.length()>0) {
builder.append(" \u00b7 ");
}
builder.append(commandBinding.format())
.append(message);
}
if (builder.length()>0) {
builder.append(" \u00b7 ");
}
builder.append(getEnterBinding())
.append(" to open");
if (builder.length()>0) {
setInfoText(builder.toString());
}
}
/*private StyledText getEditorWidget(CeylonEditor editor) {
return editor.getCeylonSourceViewer().getTextWidget();
}*/
protected Control createContents(Composite parent) {
Composite composite = (Composite) super.createContents(parent);
GridLayout layout = (GridLayout) composite.getLayout();
layout.verticalSpacing=8;
layout.marginLeft=8;
layout.marginRight=8;
layout.marginTop=8;
layout.marginBottom=8;
Control[] children = composite.getChildren();
children[children.length-2].setVisible(false);
return composite;
}
@Override
protected Control createDialogArea(Composite parent) {
treeViewer = new TreeViewer(parent, SWT.SINGLE);
treeViewer.getTree().setVisible(treeLayout);
GridData gdTree = new GridData(GridData.FILL_BOTH);
gdTree.exclude = !treeLayout;
treeViewer.getTree().setLayoutData(gdTree);
treeViewer.setAutoExpandLevel(TreeViewer.ALL_LEVELS);
tableViewer = new TableViewer(parent, SWT.SINGLE);
tableViewer.getTable().setVisible(!treeLayout);
GridData gdTable = new GridData(GridData.FILL_BOTH);
gdTable.exclude = treeLayout;
tableViewer.getTable().setLayoutData(gdTable);
viewer = treeLayout ? treeViewer : tableViewer;
tableViewer.setComparator(new CeylonViewerComparator() {
@Override
public int compare(Viewer viewer, Object e1, Object e2) {
TreeNode treeNode1 = (TreeNode) e1;
TreeNode treeNode2 = (TreeNode) e2;
Object v1 = treeNode1.getValue();
Object v2 = treeNode2.getValue();
return super.compare(viewer, v1, v2);
}
});
tableViewer.setContentProvider(ArrayContentProvider.getInstance());
treeViewer.setContentProvider(new TreeNodeContentProvider());
tableViewer.setLabelProvider(new LabelProvider());
treeViewer.setLabelProvider(new LabelProvider());
installFilter();
ViewerFilter filter = new Filter();
tableViewer.addFilter(filter);
treeViewer.addFilter(filter);
// viewer.getTable().addSelectionListener(new SelectionListener() {
// public void widgetSelected(SelectionEvent e) {
// // do nothing
// }
// public void widgetDefaultSelected(SelectionEvent e) {
// gotoSelectedElement();
// }
// });
Display display = getShell().getDisplay();
Cursor cursor = new Cursor(display, SWT.CURSOR_HAND);
tableViewer.getControl().setCursor(cursor);
treeViewer.getControl().setCursor(cursor);
tableViewer.getControl()
.addMouseMoveListener(new MouseMoveListener() {
@Override
public void mouseMove(MouseEvent e) {
Item item =
tableViewer.getTable()
.getItem(new Point(e.x, e.y));
if (item!=null) {
StructuredSelection selection =
new StructuredSelection(item.getData());
tableViewer.setSelection(selection);
}
}
});
treeViewer.getControl().addMouseMoveListener(
new TreeViewMouseListener(treeViewer));
ShortcutKeyListener listener = new ShortcutKeyListener();
tableViewer.getControl().addKeyListener(listener);
treeViewer.getControl().addKeyListener(listener);
MouseListener clickListener = new ClickListener();
tableViewer.getControl().addMouseListener(clickListener);
treeViewer.getControl().addMouseListener(clickListener);
viewer.getControl().getParent().layout(/*true*/);
Font outlineFont = CeylonPlugin.getOutlineFont();
tableViewer.getControl().setFont(outlineFont);
treeViewer.getControl().setFont(outlineFont);
return viewer.getControl();
}
protected void gotoSelectedElement() {
StructuredSelection selection =
(StructuredSelection)
viewer.getSelection();
Object node = selection.getFirstElement();
if (node!=null) {
TreeNode treeNode = (TreeNode) node;
Object elem = treeNode.getValue();
if (elem instanceof CeylonSearchMatch) {
CeylonSearchMatch match =
(CeylonSearchMatch) elem;
gotoFile(match.getElement().getFile(),
match.getOffset(), match.getLength());
}
}
}
private static GridLayoutFactory popupLayoutFactory;
protected static GridLayoutFactory getPopupLayout() {
if (popupLayoutFactory == null) {
popupLayoutFactory =
GridLayoutFactory.fillDefaults()
.margins(POPUP_MARGINWIDTH, POPUP_MARGINHEIGHT)
.spacing(POPUP_HORIZONTALSPACING, POPUP_VERTICALSPACING);
}
return popupLayoutFactory;
}
protected StyledString styleTitle(final StyledText title) {
StyledString result = new StyledString();
StringTokenizer tokens =
new StringTokenizer(title.getText(),
"\u2014", false);
styleDescription(title, result, tokens.nextToken());
result.append("\u2014");
String rest = tokens.nextToken();
int loc = rest.indexOf(" to ");
if (loc<1) loc = rest.indexOf(" of ");
loc+=4;
result.append(rest.substring(0,loc));
int end = rest.indexOf(" in ", loc);
Highlights.styleFragment(result,
rest.substring(loc, end),
false, null,
CeylonPlugin.getOutlineFont());
return result;
}
protected void styleDescription(final StyledText title,
StyledString result, String desc) {
final FontData[] fontDatas =
title.getFont().getFontData();
for (int i = 0; i < fontDatas.length; i++) {
fontDatas[i].setStyle(SWT.BOLD);
}
result.append(desc, new Styler() {
@Override
public void applyStyles(TextStyle textStyle) {
textStyle.font =
new Font(title.getDisplay(),
fontDatas);
}
});
}
private boolean includeImports = false;
private boolean treeLayout = false;
@Override
protected Control createTitleControl(Composite parent) {
getPopupLayout().copy()
.numColumns(4)
.spacing(6, 6)
.applyTo(parent);
icon = new Label(parent, SWT.NONE);
icon.setImage(REFS_IMAGE);
// getShell().addKeyListener(new GotoListener());
titleLabel = new StyledText(parent, SWT.NONE);
titleLabel.addModifyListener(new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
StyleRange[] styleRanges =
styleTitle(titleLabel)
.getStyleRanges();
titleLabel.setStyleRanges(styleRanges);
}
});
titleLabel.setEditable(false);
GridDataFactory.fillDefaults()
.align(SWT.FILL, SWT.CENTER)
.grab(true,false)
.span(1, 1)
.applyTo(titleLabel);
// Button button = new Button(parent, SWT.TOGGLE);
// button.setImage(CeylonLabelProvider.IMPORT);
// button.setText("include imports");
ToolBar toolBar = new ToolBar(parent, SWT.FLAT);
createModeButtons(toolBar);
new ToolItem(toolBar, SWT.SEPARATOR);
createLayoutButtons(toolBar);
new ToolItem(toolBar, SWT.SEPARATOR);
createImportsButton(toolBar);
return null;
}
private void switchMatchesInImports() {
includeImports = !includeImports;
setInput(null);
getDialogSettings()
.put("includeImports", includeImports);
}
private void createImportsButton(ToolBar toolBar) {
importsButton = new ToolItem(toolBar, SWT.CHECK);
importsButton.setImage(CeylonResources.IMPORT);
importsButton.setToolTipText("Show Matches in Import Statements");
importsButton.setSelection(includeImports);
importsButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
switchMatchesInImports();
if (importsAction!=null) {
importsAction.setChecked(importsButton.getSelection());
}
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {}
});
}
private void createModeButtons(ToolBar toolBar) {
refsButton = new ToolItem(toolBar, SWT.CHECK);
refsButton.setImage(REFS_IMAGE);
refsButton.setToolTipText("Show References");
subsButton = new ToolItem(toolBar, SWT.CHECK);
subsButton.setImage(DECS_IMAGE);
subsButton.setToolTipText("Show Refinements/Subtypes");
updateButtonSelection();
refsButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
if (refsButton.getSelection()) {
showingRefinements = false;
setInput(null);
subsButton.setSelection(false);
}
else {
refsButton.setSelection(true);
}
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {}
});
subsButton.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
if (subsButton.getSelection()) {
showingRefinements = true;
setInput(null);
refsButton.setSelection(false);
}
else {
subsButton.setSelection(true);
}
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {}
});
}
private void updateButtonSelection() {
subsButton.setSelection(showingRefinements);
refsButton.setSelection(!showingRefinements);
}
private void createLayoutButtons(ToolBar toolBar) {
flatLayoutButton = new ToolItem(toolBar, SWT.CHECK);
flatLayoutButton.setImage(imageRegistry.get(FLAT_MODE));
flatLayoutButton.setToolTipText("Show as List");
flatLayoutButton.setSelection(!treeLayout);
treeLayoutButton = new ToolItem(toolBar, SWT.CHECK);
treeLayoutButton.setImage(imageRegistry.get(TREE_MODE));
treeLayoutButton.setToolTipText("Show as Tree");
treeLayoutButton.setSelection(treeLayout);
flatLayoutButton.addSelectionListener(
new ChangeLayoutListener() {
@Override
public void widgetSelected(SelectionEvent e) {
if (flatLayoutButton.getSelection()) {
super.widgetSelected(e);
treeLayoutButton.setSelection(false);
if (treeLayoutAction!=null) {
treeLayoutAction.setChecked(false);
}
if (flatLayoutAction!=null) {
flatLayoutAction.setChecked(true);
}
}
else {
treeLayoutButton.setSelection(true);
if (flatLayoutAction!=null) {
flatLayoutAction.setChecked(false);
}
if (treeLayoutAction!=null) {
treeLayoutAction.setChecked(true);
}
}
}
});
treeLayoutButton.addSelectionListener(new ChangeLayoutListener() {
@Override
public void widgetSelected(SelectionEvent e) {
if (treeLayoutButton.getSelection()) {
super.widgetSelected(e);
flatLayoutButton.setSelection(false);
if (flatLayoutAction!=null) {
flatLayoutAction.setChecked(false);
}
if (treeLayoutAction!=null) {
treeLayoutAction.setChecked(true);
}
}
else {
flatLayoutButton.setSelection(true);
if (treeLayoutAction!=null) {
treeLayoutAction.setChecked(false);
}
if (flatLayoutAction!=null) {
flatLayoutAction.setChecked(true);
}
}
}
});
}
protected Text createFilterText(Composite parent) {
filterText = new Text(parent,
SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL);
filterText.setMessage("type filter text");
Dialog.applyDialogFont(filterText);
GridData data = new GridData(GridData.FILL_HORIZONTAL);
data.horizontalAlignment = GridData.FILL;
data.verticalAlignment = GridData.CENTER;
filterText.setLayoutData(data);
filterText.addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
triggerCommand(e);
if (e.keyCode == 0x0D || e.keyCode == SWT.KEYPAD_CR) // Enter key
gotoSelectedElement();
if (e.keyCode == SWT.ARROW_DOWN)
viewer.getControl().setFocus();
if (e.keyCode == SWT.ARROW_UP)
viewer.getControl().setFocus();
if (e.character == 0x1B) // ESC
dispose();
}
public void keyReleased(KeyEvent e) {
// do nothing
}
});
return filterText;
}
private void triggerCommand(KeyEvent e) {
if (triggersBinding(e, commandBinding)) {
showingRefinements = !showingRefinements;
setInput(null);
e.doit=false;
}
else if (triggersBinding(e, findCommandBinding)) {
showingRefinements = !showingRefinements;
new FindReferencesAction(editor).run();
e.doit=false;
}
}
@Override
protected void setTitleText(String text) {
if (titleLabel!=null) {
titleLabel.setText(text);
}
}
private void installFilter() {
filterText.setText("");
filterText.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
Text input = (Text) e.widget;
String text = input.getText();
setMatcherString(text, true);
}
});
}
protected void setMatcherString(String pattern, boolean update) {
/*if (pattern.length() == 0) {
fPatternMatcher= null;
} else {
fPatternMatcher= new JavaElementPrefixPatternMatcher(pattern);
}*/
if (update) {
viewer.getControl()
.setRedraw(false);
viewer.refresh();
viewer.getControl()
.setRedraw(true);
selectFirst();
}
}
@Override
protected Control createTitleMenuArea(Composite parent) {
Control result = super.createTitleMenuArea(parent);
filterText = createFilterText(parent);
return result;
}
/*@Override
protected void adjustBounds() {
Rectangle bounds = getShell().getBounds();
int h = bounds.height;
if (h>400) {
bounds.height=400;
bounds.y = bounds.y + (h-400)/3;
getShell().setBounds(bounds);
}
int w = bounds.width;
if (w<600) {
bounds.width=600;
getShell().setBounds(bounds);
}
}*/
public void setInformation(String information) {
// this method is ignored, see IInformationControlExtension2
}
public void setSize(int width, int height) {
getShell().setSize(width, height);
}
public void addDisposeListener(DisposeListener listener) {
getShell().addDisposeListener(listener);
}
public void removeDisposeListener(DisposeListener listener) {
getShell().removeDisposeListener(listener);
}
public void setForegroundColor(Color foreground) {
applyForegroundColor(foreground, getContents());
}
public void setBackgroundColor(Color background) {
applyBackgroundColor(background, getContents());
}
public boolean isFocusControl() {
return getShell() ==
getShell()
.getDisplay()
.getActiveShell();
}
public void setFocus() {
getShell().forceFocus();
filterText.setFocus();
}
public void addFocusListener(FocusListener listener) {
getShell().addFocusListener(listener);
}
public void removeFocusListener(FocusListener listener) {
getShell().removeFocusListener(listener);
}
public void setSizeConstraints(int maxWidth, int maxHeight) {
// ignore
}
public void setLocation(Point location) {
/*
* If the location is persisted, it gets managed by PopupDialog - fine. Otherwise, the location is
* computed in Window#getInitialLocation, which will center it in the parent shell / main
* monitor, which is wrong for two reasons:
* - we want to center over the editor / subject control, not the parent shell
* - the center is computed via the initalSize, which may be also wrong since the size may
* have been updated since via min/max sizing of AbstractInformationControlManager.
* In that case, override the location with the one computed by the manager. Note that
* the call to constrainShellSize in PopupDialog.open will still ensure that the shell is
* entirely visible.
*/
if (!getPersistLocation() || getDialogSettings() == null)
getShell().setLocation(location);
}
public Point computeSizeHint() {
// return the shell's size - note that it already has the persisted size if persisting
// is enabled.
return getShell().getSize();
}
public void setVisible(boolean visible) {
if (visible) {
open();
}
else {
saveDialogBounds(getShell());
getShell().setVisible(false);
}
}
public final void dispose() {
close();
}
private boolean type;
private TreeViewer treeViewer;
private TableViewer tableViewer;
private Label icon;
private ToolItem refsButton;
private ToolItem subsButton;
private ToolItem flatLayoutButton;
private ToolItem treeLayoutButton;
private LayoutAction flatLayoutAction;
private LayoutAction treeLayoutAction;
private ToolItem importsButton;
private Action importsAction;
private HashMap<CeylonElement,Integer> matchCounts =
new HashMap<CeylonElement,Integer>();
public void show(boolean refinements) {
showingRefinements = refinements;
setInput(null);
open();
}
@Override
public void setInput(Object input) {
CeylonParseController pc =
editor.getParseController();
Referenceable declaration =
getReferencedExplicitDeclaration(
editor.getSelectedNode(),
pc.getLastCompilationUnit());
if (declaration==null) {
return;
}
matchCounts.clear();
type = declaration instanceof TypeDeclaration;
String message;
if (showingRefinements) {
if (type) {
message = "subtypes of";
}
else {
message = "refinements of";
}
} else {
message = "references to";
}
String name;
Unit unit = pc.getLastCompilationUnit().getUnit();
if (declaration instanceof Declaration) {
Declaration dec = (Declaration) declaration;
name = dec.getName(unit);
if (dec.isClassOrInterfaceMember()) {
Declaration container =
(Declaration)
dec.getContainer();
name = container.getName() + '.' + name;
}
}
else {
name = declaration.getNameAsString();
}
setTitleText("Quick Find References \u2014 " +
message + " " + name + " in project source");
TreeNode root = new TreeNode(new Object());
Map<Package,TreeNode> packageNodes =
new HashMap<Package,TreeNode>();
Map<Module,TreeNode> moduleNodes =
new HashMap<Module,TreeNode>();
List<TreeNode> allMatchesList =
new ArrayList<TreeNode>();
List<TreeNode> allUnitsList =
new ArrayList<TreeNode>();
List<PhasedUnit> phasedUnits =
pc.getTypeChecker()
.getPhasedUnits()
.getPhasedUnits();
for (PhasedUnit pu: phasedUnits) {
Tree.CompilationUnit cu =
pu.getCompilationUnit();
if (pu.getUnit().equals(unit) &&
editor.isDirty()) {
//search in the current dirty editor
cu = pc.getLastCompilationUnit();
}
Unit u = cu.getUnit();
TreeNode unitNode = new TreeNode(u);
List<TreeNode> unitList =
new ArrayList<TreeNode>();
Set<Node> nodes;
if (showingRefinements) {
if (declaration instanceof Declaration) {
if (type) {
TypeDeclaration td =
(TypeDeclaration)
declaration;
FindSubtypesVisitor frv =
new FindSubtypesVisitor(td);
frv.visit(cu);
@SuppressWarnings("unchecked")
Set<Node> dns = frv.getDeclarationNodeSet();
nodes = new HashSet<Node>(dns);
}
else {
Declaration d =
(Declaration)
declaration;
FindRefinementsVisitor frv =
new FindRefinementsVisitor(d);
frv.visit(cu);
Set<Tree.StatementOrArgument> dns =
frv.getDeclarationNodeSet();
nodes = new HashSet<Node>(dns);
}
}
else {
nodes = emptySet();
}
}
else {
FindReferencesVisitor frv =
new FindReferencesVisitor(declaration);
frv.visit(cu);
nodes = frv.getReferenceNodeSet();
}
for (Node node: nodes) {
CeylonSearchMatch match =
CeylonSearchMatch.create(node, cu,
pu.getUnitFile());
if (includeImports || !match.isInImport()) {
CeylonElement element = match.getElement();
Integer count = matchCounts.get(element);
if (count==null) {
count = 1;
TreeNode matchNode = new TreeNode(match);
matchNode.setParent(unitNode);
allMatchesList.add(matchNode);
unitList.add(matchNode);
}
else {
count += 1;
}
matchCounts.put(element, count);
}
}
if (!unitList.isEmpty()) {
allUnitsList.add(unitNode);
TreeNode[] array =
unitList.toArray(new TreeNode[0]);
unitNode.setChildren(array);
Package p = u.getPackage();
TreeNode packageNode = packageNodes.get(p);
if (packageNode==null) {
packageNode = new TreeNode(p);
TreeNode moduleNode =
moduleNodes.get(p.getModule());
if (moduleNode==null) {
moduleNode = new TreeNode(p.getModule());
moduleNode.setParent(root);
moduleNodes.put(p.getModule(), moduleNode);
moduleNode.setChildren(new TreeNode[] {packageNode});
}
else {
TreeNode[] oldChildren =
moduleNode.getChildren();
TreeNode[] children =
new TreeNode[oldChildren.length+1];
for (int i=0; i<oldChildren.length; i++) {
children[i] = oldChildren[i];
}
children[oldChildren.length] = packageNode;
moduleNode.setChildren(children);
}
packageNode.setParent(moduleNode);
packageNodes.put(p, packageNode);
packageNode.setChildren(new TreeNode[] {unitNode});
}
else {
TreeNode[] oldChildren =
packageNode.getChildren();
TreeNode[] children =
new TreeNode[oldChildren.length+1];
for (int i=0; i<oldChildren.length; i++) {
children[i] = oldChildren[i];
}
children[oldChildren.length] = unitNode;
packageNode.setChildren(children);
}
unitNode.setParent(packageNode);
}
}
root.setChildren(moduleNodes.values().toArray(new TreeNode[0]));
// root.setChildren(allUnitsList.toArray(new TreeNode[0]));
treeViewer.setInput(root.getChildren());
tableViewer.setInput(allMatchesList);
selectFirst();
setStatusText();
updateButtonSelection();
setIcon();
}
private void selectFirst() {
Object firstElem;
if (viewer instanceof TableViewer) {
TableViewer tv = (TableViewer) viewer;
firstElem = tv.getElementAt(0);
}
else {
TreeViewer tv = (TreeViewer) viewer;
org.eclipse.swt.widgets.Tree tree = tv.getTree();
if (tree.getItemCount()>0) {
firstElem = tree.getItem(0).getData();
}
else {
firstElem = null;
}
}
if (firstElem!=null) {
StructuredSelection selection =
new StructuredSelection(firstElem);
viewer.setSelection(selection, true);
}
}
@Override
public boolean restoresLocation() {
return getPersistLocation();
}
@Override
public boolean restoresSize() {
return getPersistSize();
}
@Override
public Rectangle getBounds() {
return getShell().getBounds();
}
@Override
public Rectangle computeTrim() {
return getShell().computeTrim(0, 0, 0, 0);
}
@Override
protected IDialogSettings getDialogSettings() {
String section =
CeylonPlugin.PLUGIN_ID
+ ".FindReferences";
IDialogSettings dialogSettings =
CeylonPlugin.getInstance()
.getDialogSettings();
IDialogSettings settings =
dialogSettings.getSection(section);
if (settings == null)
settings = dialogSettings.addNewSection(section);
return settings;
}
class LayoutAction extends Action {
LayoutAction(String name, String image) {
super(name, AS_CHECK_BOX);
setImageDescriptor(imageRegistry.getDescriptor(image));
}
@Override
public void run() {
switchLayout();
}
}
@Override
protected void fillDialogMenu(IMenuManager dialogMenu) {
flatLayoutAction =
new LayoutAction("Show as List", FLAT_MODE) {
@Override
public void run() {
super.run();
if (isChecked()) {
treeLayoutAction.setChecked(false);
treeLayoutButton.setSelection(false);
flatLayoutButton.setSelection(true);
}
else {
treeLayoutAction.setChecked(true);
treeLayoutButton.setSelection(true);
flatLayoutButton.setSelection(false);
}
}
};
flatLayoutAction.setChecked(!treeLayout);
treeLayoutAction =
new LayoutAction("Show as Tree", TREE_MODE) {
@Override
public void run() {
super.run();
if (isChecked()) {
flatLayoutAction.setChecked(false);
flatLayoutButton.setSelection(false);
treeLayoutButton.setSelection(true);
}
else {
flatLayoutAction.setChecked(true);
flatLayoutButton.setSelection(true);
treeLayoutButton.setSelection(false);
}
}
};
treeLayoutAction.setChecked(treeLayout);
dialogMenu.add(flatLayoutAction);
dialogMenu.add(treeLayoutAction);
dialogMenu.add(new Separator());
importsAction =
new Action("Show Matches in Imports",
AS_CHECK_BOX) {
{
setImageDescriptor(imageRegistry.getDescriptor(CEYLON_IMPORT));
}
@Override
public void run() {
switchMatchesInImports();
importsButton.setSelection(isChecked());
}
};
importsAction.setChecked(includeImports);
dialogMenu.add(importsAction);
dialogMenu.add(new Separator());
final IPreferenceStore prefs = CeylonPlugin.getPreferences();
Action showLocAction =
new Action("Show Full Paths", AS_CHECK_BOX) {
@Override
public void run() {
prefs.setValue(FULL_LOC_SEARCH_RESULTS,
isChecked());
tableViewer.refresh();
}
};
showLocAction.setChecked(prefs.getBoolean(
FULL_LOC_SEARCH_RESULTS));
dialogMenu.add(showLocAction);
dialogMenu.add(new Separator());
super.fillDialogMenu(dialogMenu);
}
private void switchLayout() {
treeLayout = !treeLayout;
viewer = treeLayout ? treeViewer : tableViewer;
treeViewer.getTree().setVisible(treeLayout);
tableViewer.getTable().setVisible(!treeLayout);
((GridData)treeViewer.getControl().getLayoutData()).exclude=!treeLayout;
((GridData)tableViewer.getControl().getLayoutData()).exclude=treeLayout;
viewer.getControl().getParent().layout(/*true*/);
setInput(null);
getDialogSettings().put("treeLayout", treeLayout);
}
}