/******************************************************************************* * Copyright (c) 2011 Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.cdi.text.ext.hyperlink; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import org.eclipse.jdt.core.IMethod; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.dialogs.PopupDialog; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.viewers.CheckStateChangedEvent; import org.eclipse.jface.viewers.CheckboxTreeViewer; import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider; import org.eclipse.jface.viewers.ICheckStateListener; import org.eclipse.jface.viewers.ICheckStateProvider; import org.eclipse.jface.viewers.IOpenListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.OpenEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.StyledCellLabelProvider; import org.eclipse.jface.viewers.StyledString; import org.eclipse.jface.viewers.StyledString.Styler; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerCell; import org.eclipse.swt.SWT; 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.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.graphics.Color; 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.Group; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Widget; import org.eclipse.ui.dialogs.SearchPattern; import org.jboss.tools.cdi.core.CDIImages; import org.jboss.tools.cdi.core.IBean; import org.jboss.tools.cdi.core.ICDIElement; import org.jboss.tools.cdi.core.IInjectionPoint; import org.jboss.tools.cdi.core.IInjectionPointParameter; import org.jboss.tools.cdi.core.IQualifierDeclaration; import org.jboss.tools.cdi.core.util.BeanPresentationUtil; import org.jboss.tools.cdi.text.ext.CDIExtensionsMessages; import org.jboss.tools.cdi.text.ext.CDIExtensionsPlugin; import org.jboss.tools.cdi.text.ext.hyperlink.AssignableBeanFilters.Checkbox; import org.jboss.tools.cdi.text.ext.hyperlink.AssignableBeanFilters.Filter; import org.jboss.tools.common.java.IParametedType; /** * * @author Viacheslav Kabanovich * */ public class AssignableBeansDialog extends PopupDialog {// TitleAreaDialog { IInjectionPoint injectionPoint; AssignableBeanFilters filters = null; Set<IBean> beans = new HashSet<IBean>(); Set<IBean> eligibleBeans = new HashSet<IBean>(); Set<IBean> resolvedBeans = new HashSet<IBean>(); Composite composite; boolean showHideOptions = true; Group filterPanel; CheckboxTreeViewer filterView; private Text fFilterText; TableViewer list; public AssignableBeansDialog(Shell parentShell) { // TitleAreaDialog // super(parentShell); //PopupDialog super(parentShell, 0, true, true, true, true, true, "title", null); setShellStyle(getShellStyle() | SWT.RESIZE); filters = new AssignableBeanFilters(); } protected void initSettings() { IDialogSettings settings = getDialogSettings(); showHideOptions = settings.getBoolean(SHOW_HIDE_PANEL); for (Checkbox c: filters.getAllOptions().values()) { String name = FILTER_OPTION + c.id; c.state = !"false".equals(settings.get(name)); } filters.getRoot().state = true; } public void setInjectionPoint(IInjectionPoint injectionPoint) { this.injectionPoint = injectionPoint; filters.init(injectionPoint); initSettings(); beans = new HashSet<IBean>(injectionPoint.getCDIProject().getBeans(false, injectionPoint)); eligibleBeans = new HashSet<IBean>(beans); for (int i = AssignableBeanFilters.OPTION_UNAVAILABLE_BEANS + 1; i < AssignableBeanFilters.OPTION_ELIMINATED_AMBIGUOUS; i++) { Filter f = filters.getFilter(i); if(f != null) { f.filter(eligibleBeans); } } resolvedBeans = new HashSet<IBean>(injectionPoint.getCDIProject().getBeans(true, injectionPoint)); } String computeTitle() { StringBuffer result = new StringBuffer(); result.append("@Inject "); if(injectionPoint instanceof IInjectionPointParameter) { IMethod m = ((IInjectionPointParameter)injectionPoint).getBeanMethod().getMethod(); result.append(m.getElementName()).append("("); } for (IQualifierDeclaration d: injectionPoint.getQualifierDeclarations()) { result.append("@").append(d.getType().getElementName()).append(" "); } IParametedType type = injectionPoint.getMemberType(); result.append(type.getType().getElementName()).append(" "); if(injectionPoint instanceof IInjectionPointParameter) { result.append(((IInjectionPointParameter)injectionPoint).getName()); result.append(")"); } else { result.append(injectionPoint.getSourceMember().getElementName()); } return result.toString(); } protected void buttonPressed(int buttonId) { if(buttonId == IDialogConstants.CLOSE_ID) { // TitleAreaDialog // cancelPressed(); } } @Override protected Control createTitleMenuArea(Composite parent) { Composite fViewMenuButtonComposite= (Composite) super.createTitleMenuArea(parent); fFilterText = createFilterText(parent); return fViewMenuButtonComposite; } @Override protected void configureShell(Shell newShell) { super.configureShell(newShell); newShell.setText(CDIExtensionsMessages.ASSIGNABLE_BEANS_DIALOG_TITLE); } @Override protected Control createDialogArea(Composite parent) { composite = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(2, false); layout.marginHeight = 0; layout.marginWidth = 0; layout.verticalSpacing = 0; layout.horizontalSpacing = 0; composite.setLayout(layout); composite.setLayoutData(new GridData(GridData.FILL_BOTH)); composite.setFont(parent.getFont()); // TitleAreaDialog // setTitle(computeTitle()); // PopupDialog setTitleText(computeTitle()); createListView(composite); if(showHideOptions) { createFilterView(composite); } installFilter(); return composite; } protected void createButtonsForButtonBar(Composite parent) { // TitleAreaDialog // createButton(parent, IDialogConstants.CLOSE_ID, IDialogConstants.CLOSE_LABEL, true); } void createListView(Composite parent) { list = new TableViewer(parent, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER/* | SWT.VIRTUAL*/); GridData g = new GridData(GridData.FILL_BOTH); list.getControl().setLayoutData(g); list.setContentProvider(new ListContent()); list.setLabelProvider(new LP()); list.setInput(injectionPoint); list.addOpenListener(new IOpenListener() { @Override public void open(OpenEvent event) { ISelection s = event.getSelection(); if(!s.isEmpty() && s instanceof IStructuredSelection) { Object o = ((IStructuredSelection)s).getFirstElement(); if(o instanceof IBean) { ((IBean)o).open(); close(); } } } }); // PopupDialog list.getTable().addMouseMoveListener(new MouseMoveListener() { @Override public void mouseMove(MouseEvent e) { ViewerCell cell = list.getCell(new Point(e.x, e.y)); if(cell != null) { Widget w = cell.getItem(); if(w != null && w.getData() != null) { list.setSelection(new StructuredSelection(w.getData())); } } list.getTable().setCursor(cell == null ? null : list.getTable().getDisplay().getSystemCursor(SWT.CURSOR_HAND)); } }); list.getTable().addMouseListener(new MouseAdapter() { @Override public void mouseUp(MouseEvent e) { gotoSelectedElement(); } }); list.refresh(); } protected void gotoSelectedElement() { ISelection s = list.getSelection(); if(!s.isEmpty() && s instanceof IStructuredSelection) { IBean b = (IBean)((IStructuredSelection)s).getFirstElement(); b.open(); close(); } } void createFilterView(Composite parent) { Group g = filterPanel = new Group(parent, 0); g.setBackground(parent.getBackground()); g.setText("Show/Hide"); g.setLayoutData(new GridData(GridData.FILL_VERTICAL | GridData.VERTICAL_ALIGN_BEGINNING)); g.setLayout(new GridLayout(1, false)); filterView = new CheckboxTreeViewer(g, 0); filterView.setAutoExpandLevel(3); filterView.setContentProvider(checkboxContentProvider); filterView.setInput(filters.getRoot()); for (Checkbox c: filters.getAllOptions().values()) { filterView.setChecked(c, true); } filterView.getControl().setBackground(g.getBackground()); g.setData(new GridData(GridData.FILL_BOTH)); filterView.addCheckStateListener(new ICheckStateListener() { @Override public void checkStateChanged(CheckStateChangedEvent event) { ((Checkbox)event.getElement()).state = event.getChecked(); filterView.refresh(); list.refresh(); } }); filterView.setCheckStateProvider(new ICheckStateProvider() { @Override public boolean isGrayed(Object element) { Checkbox c = (Checkbox)element; return c.parent != null && !c.parent.state; } @Override public boolean isChecked(Object element) { Checkbox c = (Checkbox)element; return c.state; } }); } @Override protected Control getFocusControl() { return getFilterText(); } protected Text getFilterText() { return fFilterText; } protected Text createFilterText(Composite parent) { fFilterText= new Text(parent, SWT.NONE); Dialog.applyDialogFont(fFilterText); GridData data= new GridData(GridData.FILL_HORIZONTAL); data.horizontalAlignment= GridData.FILL; data.verticalAlignment= GridData.CENTER; fFilterText.setLayoutData(data); fFilterText.addKeyListener(new KeyListener() { @Override public void keyPressed(KeyEvent e) { if (e.keyCode == 0x0D) // return gotoSelectedElement(); if (e.keyCode == SWT.ARROW_DOWN) list.getTable().setFocus(); if (e.keyCode == SWT.ARROW_UP) list.getTable().setFocus(); if (e.character == 0x1B) // ESC close(); } @Override public void keyReleased(KeyEvent e) { // do nothing } }); return fFilterText; } private void installFilter() { fFilterText.setText(""); //$NON-NLS-1$ fFilterText.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { list.refresh(); } }); } protected String getId() { return AssignableBeansDialog.class.getName(); } @Override protected Point getDefaultSize() { return new Point(700, 400); } @Override protected Point getDefaultLocation(Point size) { Display display = Display.getCurrent(); if(display == null) { display = Display.getDefault(); } if(display.getActiveShell() == null) { return super.getDefaultLocation(size); } Rectangle b = display.getActiveShell().getBounds(); int x = b.x + (b.width - size.x) / 2; int y = b.y + (b.height - size.y) / 2; return new Point(x, y); } // PopupDialog @Override protected void fillDialogMenu(IMenuManager dialogMenu) { super.fillDialogMenu(dialogMenu); dialogMenu.add(new ShowHideAction()); } @Override protected IDialogSettings getDialogSettings() { IDialogSettings settings = CDIExtensionsPlugin.getDefault().getDialogSettings().getSection(getId()); if(settings == null && filters != null && injectionPoint != null) { settings = CDIExtensionsPlugin.getDefault().getDialogSettings().addNewSection(getId()); settings.put(SHOW_HIDE_PANEL, true); for (Checkbox c: filters.getAllOptions().values()) { settings.put(FILTER_OPTION + c.id, "" + c.state); } } return settings; } @Override public boolean close() { saveFilterOptions(); return super.close(); } private static final String SHOW_HIDE_PANEL = "SHOW_HIDE_PANEL"; private static final String FILTER_OPTION = "FILTER_OPTION_"; private void saveFilterOptions() { IDialogSettings settings = getDialogSettings(); settings.put(SHOW_HIDE_PANEL, showHideOptions); for (Checkbox c: filters.getAllOptions().values()) { settings.put(FILTER_OPTION + c.id, "" + c.state); } } public List<IBean> getDisplayedBeans() { List<IBean> bs = new ArrayList<IBean>(); int index = 0; while(true) { Object o = list.getElementAt(index); if(o instanceof IBean) { bs.add((IBean)o); } else { break; } index++; } return bs; } public boolean isFilterEnabled(int index) { Checkbox c = filters.getOption(index); return c != null && c.state; } public void setFilterEnabled(int index, boolean value) { Checkbox c = filters.getOption(index); if(c == null) return; c.state = value; filterView.refresh(); // filterView.setChecked(AssignableBeanFilters.ALL_OPTIONS[index], value); list.refresh(); } public Collection<Checkbox> getOptions() { return filters.getAllOptions().values(); } class ShowHideAction extends Action { public ShowHideAction() { super("Show/Hide panel", Action.AS_CHECK_BOX); setChecked(showHideOptions); } @Override public void run() { setFiltersEnabled(isChecked()); } } protected void setFiltersEnabled(boolean enabled) { if(enabled != showHideOptions) { showHideOptions = enabled; if(!enabled && filterPanel != null) { filterPanel.dispose(); filterPanel = null; filterView = null; } else if(enabled && filterPanel == null) { createFilterView(composite); } composite.update(); composite.layout(true); } } static CheckboxContentProvider checkboxContentProvider = new CheckboxContentProvider(); static class CheckboxContentProvider implements ITreeContentProvider { @Override public void dispose() { } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } @Override public Object[] getElements(Object inputElement) { return getChildren(inputElement); } @Override public Object[] getChildren(Object parentElement) { return ((Checkbox)parentElement).children.toArray(new Checkbox[0]); } @Override public Object getParent(Object element) { return ((Checkbox)element).parent; } @Override public boolean hasChildren(Object element) { return !((Checkbox)element).children.isEmpty(); } } TextFilter textFilter = new TextFilter(); class TextFilter implements Filter { SearchPattern patternMatcher = new SearchPattern(); @Override public void filter(Set<IBean> beans) { if(fFilterText != null && !fFilterText.isDisposed()) { String text = fFilterText.getText(); if(text.length() > 0) { patternMatcher.setPattern(text); Iterator<IBean> it = beans.iterator(); while(it.hasNext()) { IBean bean = it.next(); if(!patternMatcher.matches(bean.getElementName())) { it.remove(); } } } } } } class ListContent implements IStructuredContentProvider { @Override public void dispose() { } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } @Override public Object[] getElements(Object inputElement) { Set<IBean> bs = new HashSet<IBean>(beans); Set<String> keys = new HashSet<String>(); LP p = new LP(); filters.getRoot().filter(bs); textFilter.filter(bs); Map<String, IBean> map = new TreeMap<String, IBean>(); for (IBean b: bs) { if(resolvedBeans.contains(b)) { String key = p.getText(b); if(!keys.contains(key)) { map.put(key, b); keys.add(key); } } } List<IBean> sorted = new ArrayList<IBean>(); sorted.addAll(map.values()); bs.removeAll(map.values()); map.clear(); for (IBean b: bs) { if(eligibleBeans.contains(b)) { String key = p.getText(b); if(!keys.contains(key)) { map.put(key, b); keys.add(key); } } } sorted.addAll(map.values()); bs.removeAll(map.values()); map.clear(); for (IBean b: bs) { String key = p.getText(b); if(!keys.contains(key)) { map.put(key, b); keys.add(key); } } sorted.addAll(map.values()); return sorted.toArray(new IBean[0]); } } static Color gray = new Color(null, 128, 128, 128); static Color black = Display.getDefault().getSystemColor(SWT.COLOR_INFO_FOREGROUND); static Styler RESOLVED_NAME = new DefaultStyler(black, true, false); static Styler ELIGIBLE_NAME = new DefaultStyler(black, false, false); static Styler ELIGIBLE_QUALIFIER = new DefaultStyler(gray, false, false); static Styler DISABLED = new DefaultStyler(gray, false, false); private static class DefaultStyler extends Styler { private Color foreground; private boolean bold; private boolean italic; public DefaultStyler(Color foreground, boolean bold, boolean italic) { this.foreground = foreground; this.italic = italic; this.bold = bold; } @Override public void applyStyles(TextStyle textStyle) { if (foreground != null) { textStyle.foreground = foreground; } if(italic) { textStyle.font = JFaceResources.getFontRegistry().getItalic(JFaceResources.DEFAULT_FONT); } if(bold) { textStyle.font = JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT); } } } class LP extends StyledCellLabelProvider implements DelegatingStyledCellLabelProvider.IStyledLabelProvider { @Override public void update(ViewerCell cell) { ELIGIBLE_QUALIFIER = DISABLED; Object element = cell.getElement(); StyledString styledString = getStyledText(element); cell.setText(styledString.getString()); cell.setStyleRanges(styledString.getStyleRanges()); cell.setImage(getImage(element)); super.update(cell); } public String getText(Object element) { return getStyledText(element).getString(); } @Override public StyledString getStyledText(Object element) { IBean b = (IBean)element; RESOLVED_NAME = new DefaultStyler(black, true, false); Styler nameStyler = resolvedBeans.contains(b) ? RESOLVED_NAME : eligibleBeans.contains(b) ? ELIGIBLE_NAME : DISABLED; StyledString sb = new StyledString(); //1.bean kind String kind = BeanPresentationUtil.getBeanKind(b); if(kind != null) { sb.append(kind, nameStyler).append(' '); } //2. bean element name sb.append(b.getElementName(), nameStyler); //3. bean location Styler qualifierStyler = eligibleBeans.contains(b) ? ELIGIBLE_QUALIFIER : DISABLED; sb.append(BeanPresentationUtil.getBeanLocation(b, false),qualifierStyler); return sb; } @Override public Image getImage(Object element) { return CDIImages.getImageByElement((ICDIElement)element); } } }