/******************************************************************************* * Copyright (c) 2007 IBM Corporation. * All rights reserved. This program and the accompanying materials * are 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: * Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation *******************************************************************************/ package org.eclipse.imp.editor; import java.util.HashMap; import java.util.Map; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.imp.editor.OutlineLabelProvider.IElementImageProvider; import org.eclipse.imp.editor.internal.AbstractInformationControl; import org.eclipse.imp.language.Language; import org.eclipse.imp.language.ServiceFactory; import org.eclipse.imp.runtime.RuntimePlugin; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.bindings.keys.KeySequence; import org.eclipse.jface.bindings.keys.KeyStroke; import org.eclipse.jface.bindings.keys.SWTKeySupport; import org.eclipse.jface.viewers.AbstractTreeViewer; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.viewers.ViewerSorter; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.events.KeyAdapter; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Item; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.Widget; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PlatformUI; public class OutlineInformationControl extends AbstractInformationControl { private KeyAdapter fKeyAdapter; private OutlineContentProviderBase fOutlineContentProvider; private Object fInput= null; private OutlineSorter fOutlineSorter; private OutlineLabelProvider fInnerLabelProvider; protected Color fForegroundColor; // private boolean fShowOnlyMainType; // RMF what would this mean in general? private LexicalSortingAction fLexicalSortingAction; Map fTypeHierarchies= new HashMap(); private Language fLanguage; // All of the following should be provided by language-specific extensions. // private ViewerFilter fElementFilter; private ILabelProvider fLangLabelProvider; private IElementImageProvider fElemImageProvider; private final boolean fShowStorage= false; protected static final Object[] NO_CHILDREN= new Object[0]; private class OutlineTreeViewer extends TreeViewer { private boolean fIsFiltering= false; private OutlineTreeViewer(Tree tree) { super(tree); } protected Object[] getFilteredChildren(Object parent) { Object[] result= getRawChildren(parent); int unfilteredChildren= result.length; ViewerFilter[] filters= getFilters(); if (filters != null) { for(int i= 0; i < filters.length; i++) result= filters[i].filter(this, parent, result); } fIsFiltering= unfilteredChildren != result.length; return result; } protected void internalExpandToLevel(Widget node, int level) { if (!fIsFiltering && node instanceof Item) { // Item i= (Item) node; // if (i.getData() instanceof IJavaElement) { // IJavaElement je= (IJavaElement) i.getData(); // if (je.getElementType() == IJavaElement.IMPORT_CONTAINER || isInnerType(je)) { // setExpanded(i, false); // return; // } // } } super.internalExpandToLevel(node, level); } // private boolean isInnerType(IJavaElement element) { // if (element != null && element.getElementType() == IJavaElement.TYPE) { // IType type= (IType) element; // return type.isMember(); // } // return false; // } } private class OutlineSorter extends ViewerSorter { // TODO Should be extensible by lang-specific implementation. // Maybe an interface with a pair of methods: categoryOf(e) and compare(e1, e2)? private static final int OTHER= 1; // private static final int TYPE= 2; // private static final int ANONYM= 3; // private JavaElementSorter fJavaElementSorter= new JavaElementSorter(); /* * @see org.eclipse.jface.viewers.ViewerSorter#sort(org.eclipse.jface.viewers.Viewer, java.lang.Object[]) */ public void sort(Viewer viewer, Object[] elements) { if (!fLexicalSortingAction.isChecked()) return; super.sort(viewer, elements); } /* * @see org.eclipse.jface.viewers.ViewerSorter#compare(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object) */ public int compare(Viewer viewer, Object e1, Object e2) { int cat1= category(e1); int cat2= category(e2); if (cat1 != cat2) return cat1 - cat2; // if (cat1 == OTHER) { // method or field // if (fSortByDefiningTypeAction.isChecked()) { // IType def1= (e1 instanceof IMethod) ? getDefiningType((IMethod) e1) : null; // IType def2= (e2 instanceof IMethod) ? getDefiningType((IMethod) e2) : null; // if (def1 != null) { // if (def2 != null) { // if (!def2.equals(def1)) { // return compareInHierarchy(getSuperTypeHierarchy(def1), def1, def2); // } // } else { // return -1; // } // } else { // if (def2 != null) { // return 1; // } // } // } // } else if (cat1 == ANONYM) { // return 0; // } String label1= fLangLabelProvider.getText(e1); String label2= fLangLabelProvider.getText(e2); return label1.compareTo(label2); } /* * @see org.eclipse.jface.viewers.ViewerSorter#category(java.lang.Object) */ public int category(Object element) { // if (element instanceof IType) { // IType type= (IType) element; // if (type.getElementName().length() == 0) { // return ANONYM; // } // return TYPE; // } return OTHER; } } private class LexicalSortingAction extends Action { private static final String STORE_LEXICAL_SORTING_CHECKED= "LexicalSortingAction.isChecked"; //$NON-NLS-1$ private TreeViewer fOutlineViewer; private LexicalSortingAction(TreeViewer outlineViewer) { super("Sort", IAction.AS_CHECK_BOX); setToolTipText("Sort by name"); setDescription("Sort entries lexically by name"); RuntimePlugin.getImageDescriptor("alphab_sort_co.gif"); //$NON-NLS-1$ fOutlineViewer= outlineViewer; boolean checked= getDialogSettings().getBoolean(STORE_LEXICAL_SORTING_CHECKED); setChecked(checked); // PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IJavaHelpContextIds.LEXICAL_SORTING_BROWSING_ACTION); } public void run() { valueChanged(isChecked(), true); } private void valueChanged(final boolean on, boolean store) { setChecked(on); BusyIndicator.showWhile(fOutlineViewer.getControl().getDisplay(), new Runnable() { public void run() { fOutlineViewer.refresh(false); } }); if (store) getDialogSettings().put(STORE_LEXICAL_SORTING_CHECKED, on); } } public OutlineInformationControl(Shell parent, int shellStyle, int treeStyle, String commandId, Language language) { super(parent, shellStyle, treeStyle, commandId, true); fLanguage= language; } protected Text createFilterText(Composite parent) { Text text= super.createFilterText(parent); text.addKeyListener(getKeyAdapter()); return text; } protected TreeViewer createTreeViewer(Composite parent, int style) { Tree tree= new Tree(parent, SWT.SINGLE | (style & ~SWT.MULTI)); GridData gd= new GridData(GridData.FILL_BOTH); gd.heightHint= tree.getItemHeight() * 12; tree.setLayoutData(gd); final TreeViewer treeViewer= new OutlineTreeViewer(tree); // Hard-coded filters fLexicalSortingAction= new LexicalSortingAction(treeViewer); // JJV: this code is broken: // if (fElementFilter != null) // treeViewer.addFilter(fElementFilter); fForegroundColor= parent.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY); // RMF 7/7/2006 - oops, fLanguage is still null at this point, b/c createTreeViewer() gets called from super ctor and field inits haven't happened yet... fLanguage= ((UniversalEditor) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor()).fLanguage; fOutlineContentProvider= new ModelTreeContentProvider(null); fOutlineContentProvider.setInfoControl(this); fLangLabelProvider= ServiceFactory.getInstance().getLabelProvider(fLanguage); fElemImageProvider= ServiceFactory.getInstance().getElementImageProvider(fLanguage); // JJV; commented out because untested // fElementFilter= (ViewerFilter) ExtensionPointFactory.createExtensionPoint(fLanguage, ILanguageService.VIEWER_FILTER_SERVICE); fInnerLabelProvider= new OutlineLabelProvider(fLangLabelProvider, fElemImageProvider, fOutlineContentProvider.fShowInheritedMembers, fShowStorage, fForegroundColor); fInnerLabelProvider.addLabelDecorator(new ProblemsLabelDecorator(fLanguage)); // IDecoratorManager decoratorMgr= PlatformUI.getWorkbench().getDecoratorManager(); // if (decoratorMgr.getEnabled("org.eclipse.jdt.ui.override.decorator")) //$NON-NLS-1$ // fInnerLabelProvider.addLabelDecorator(new OverrideIndicatorLabelDecorator(null)); treeViewer.setLabelProvider(fInnerLabelProvider); treeViewer.addFilter(new NamePatternFilter()); // fSortByDefiningTypeAction= new SortByDefiningTypeAction(treeViewer); // fShowOnlyMainTypeAction= new ShowOnlyMainTypeAction(treeViewer); treeViewer.setContentProvider(fOutlineContentProvider); fOutlineSorter= new OutlineSorter(); treeViewer.setSorter(fOutlineSorter); treeViewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS); treeViewer.getTree().addKeyListener(getKeyAdapter()); return treeViewer; } @Override public TreeViewer getTreeViewer() { // make visible to OutlineContentProviderBase return super.getTreeViewer(); } @Override public Object getSelectedElement() { // make visible to OutlineContentProviderBase return super.getSelectedElement(); } protected String getStatusFieldText() { // KeySequence[] sequences= new KeySequence[0]; // getInvokingCommandKeySequences(); // Disabled for now, since impl in jdt relied on deprecated API // if (sequences == null || sequences.length == 0) // return ""; //$NON-NLS-1$ // String keySequence= sequences[0].format(); if (fOutlineContentProvider.isShowingInheritedMembers()) return "Press Ctrl+O to hide inherited members"; else return "Press Ctrl+O to show inherited members"; } /* * @see org.eclipse.jdt.internal.ui.text.AbstractInformationControl#getId() * @since 3.0 */ protected String getId() { return "org.eclipse.imp.QuickOutline"; //$NON-NLS-1$ } /** * {@inheritDoc} */ public void setInput(Object information) { if (information == null || information instanceof String) { inputChanged(null, null); return; } // IJavaElement je= (IJavaElement) information; // ICompilationUnit cu= (ICompilationUnit) je.getAncestor(IJavaElement.COMPILATION_UNIT); // if (cu != null) // fInput= cu; // else // fInput= je.getAncestor(IJavaElement.CLASS_FILE); fInput= information; inputChanged(fInput, information); } private KeyAdapter getKeyAdapter() { if (fKeyAdapter == null) { fKeyAdapter= new KeyAdapter() { public void keyPressed(KeyEvent e) { int accelerator= SWTKeySupport.convertEventToUnmodifiedAccelerator(e); KeySequence keySequence= KeySequence.getInstance(SWTKeySupport.convertAcceleratorToKeyStroke(accelerator)); KeyStroke[] strokes= keySequence.getKeyStrokes(); for(int i= 0; i < strokes.length; i++) { // HACK Hard-wired code for detecting Ctrl-O... if ((strokes[i].getModifierKeys() & SWT.CTRL) != 0 && strokes[i].getNaturalKey() == 'O') { e.doit= false; toggleShowInheritedMembers(); return; } } // KeySequence[] sequences= new KeySequence[0]; // getInvokingCommandKeySequences(); // RMF 6/1/2006 - disabled since impl used deprecated API // if (sequences == null) // return; // for(int i= 0; i < sequences.length; i++) { // if (sequences[i].equals(keySequence)) { // e.doit= false; // toggleShowInheritedMembers(); // return; // } // } } }; } return fKeyAdapter; } /** * {@inheritDoc} */ protected void handleStatusFieldClicked() { toggleShowInheritedMembers(); } protected void toggleShowInheritedMembers() { // long flags= AppearanceAwareLabelProvider.DEFAULT_TEXTFLAGS | JavaElementLabels.F_APP_TYPE_SIGNATURE; // if (!fOutlineContentProvider.isShowingInheritedMembers()) // flags|= JavaElementLabels.ALL_POST_QUALIFIED; // fInnerLabelProvider.setTextFlags(flags); fOutlineContentProvider.toggleShowInheritedMembers(); updateStatusFieldText(); } /* * @see org.eclipse.jdt.internal.ui.text.AbstractInformationControl#fillViewMenu(org.eclipse.jface.action.IMenuManager) */ protected void fillViewMenu(IMenuManager viewMenu) { super.fillViewMenu(viewMenu); // viewMenu.add(fShowOnlyMainTypeAction); //$NON-NLS-1$ viewMenu.add(new Separator("Sorters")); //$NON-NLS-1$ if (fLexicalSortingAction != null) viewMenu.add(fLexicalSortingAction); // viewMenu.add(fSortByDefiningTypeAction); } private IProgressMonitor getProgressMonitor() { IWorkbenchPage wbPage= RuntimePlugin.getInstance().getWorkbench().getActiveWorkbenchWindow().getActivePage(); if (wbPage == null) return null; IEditorPart editor= wbPage.getActiveEditor(); if (editor == null) return null; return editor.getEditorSite().getActionBars().getStatusLineManager().getProgressMonitor(); } }