/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.ui.search; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.search.ui.text.AbstractTextSearchViewPage; import org.eclipse.search.ui.text.Match; import org.eclipse.swt.widgets.Table; import org.eclipse.ui.part.IShowInTargetList; import org.teiid.designer.ui.UiConstants; import org.teiid.designer.ui.UiPlugin; import org.teiid.designer.ui.actions.IModelerActionConstants; import org.teiid.designer.ui.common.actions.ActionService; import org.teiid.designer.ui.common.util.UiUtil; import org.teiid.designer.ui.editors.ModelEditorManager; /** * * * @since 8.0 */ public class MetadataSearchResultPage extends AbstractTextSearchViewPage implements IAdaptable, UiConstants { // =========================================================================================================================== // Constants // =========================================================================================================================== /** * The limit of results displayed. * * @since 6.0.0 */ private static final int DEFAULT_RESULT_LIMIT = 1000; /** * The settings key of the result limit. * * @since 6.0.0 */ private static final String RESULT_LIMIT_KEY = "org.teiid.designer.search.resultpage.limit"; //$NON-NLS-1$ static final String[] SHOW_IN_TARGETS = new String[] {Extensions.Explorer.VIEW}; private static final IShowInTargetList SHOW_IN_TARGET_LIST = new IShowInTargetList() { @Override public String[] getShowInTargetIds() { return SHOW_IN_TARGETS; } }; // =========================================================================================================================== // Fields // =========================================================================================================================== private ResultsContentProvider contentProvider; private ILabelProvider labelProvider; // =========================================================================================================================== // Constructors // =========================================================================================================================== public MetadataSearchResultPage() { this.contentProvider = new ResultsContentProvider(); this.labelProvider = new MetadataSearchLabelProvider(); setElementLimit(new Integer(DEFAULT_RESULT_LIMIT)); } // =========================================================================================================================== // Methods // =========================================================================================================================== StructuredViewer accessViewer() { return getViewer(); } /** * {@inheritDoc} * * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#clear() */ @Override protected void clear() { if (this.contentProvider != null) { this.contentProvider.clear(); getViewer().refresh(); } } /** * {@inheritDoc} * * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#configureTableViewer(org.eclipse.jface.viewers.TableViewer) */ @Override protected void configureTableViewer( TableViewer viewer ) { viewer.setUseHashlookup(true); viewer.setContentProvider(this.contentProvider); viewer.setLabelProvider(this.labelProvider); viewer.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged( SelectionChangedEvent event ) { focusPage(); } }); } /** * {@inheritDoc} * * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#configureTreeViewer(org.eclipse.jface.viewers.TreeViewer) */ @Override protected void configureTreeViewer( TreeViewer viewer ) { viewer.setUseHashlookup(true); viewer.setContentProvider(this.contentProvider); viewer.setLabelProvider(this.labelProvider); viewer.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged( SelectionChangedEvent event ) { focusPage(); } }); } /** * {@inheritDoc} * * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#elementsChanged(java.lang.Object[]) */ @Override protected void elementsChanged( Object[] objects ) { // this method is called when search again is run if (this.contentProvider != null) { this.contentProvider.elementsChanged(objects); getViewer().refresh(); } } /** * {@inheritDoc} * * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#fillContextMenu(org.eclipse.jface.action.IMenuManager) */ @Override protected void fillContextMenu( IMenuManager mgr ) { try { ActionService actionService = UiPlugin.getDefault().getActionService(this.getSite().getWorkbenchWindow().getActivePage()); IAction action = actionService.getAction(IModelerActionConstants.ModelerGlobalActions.EDIT); mgr.add(action); } catch (CoreException err) { Util.log(err); } super.fillContextMenu(mgr); } /** * There is a problem when a new viewer selection occurs the search view does not get activated. This is a workaround. * * @since 6.0.6 */ void focusPage() { if (!getViewer().getControl().isDisposed()) { UiUtil.getWorkbenchPage().activate(getViewPart()); } } /** * {@inheritDoc} * * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) */ @Override public Object getAdapter( Class adapter ) { if (IShowInTargetList.class.equals(adapter)) { return SHOW_IN_TARGET_LIST; } return null; } /** * {@inheritDoc} * * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#getCurrentMatch() */ @Override public Match getCurrentMatch() { IStructuredSelection selection = (IStructuredSelection)getViewer().getSelection(); if (!selection.isEmpty()) { Object element = selection.getFirstElement(); if (element instanceof Match) { return (Match)element; } return super.getCurrentMatch(); } return null; } /** * {@inheritDoc} * * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#getDisplayedMatchCount(java.lang.Object) */ @Override public int getDisplayedMatchCount( Object element ) { if (element instanceof Match) { return super.getDisplayedMatchCount(((Match)element).getElement()); } return super.getDisplayedMatchCount(element); } /** * {@inheritDoc} * * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#gotoNextMatch() */ @Override public void gotoNextMatch() { Match currMatch = getCurrentMatch(); Match[] matches = getInput().getMatches(currMatch.getElement()); boolean foundNextMatch = false; for (int i = 0; i < matches.length; ++i) { if (matches[i].equals(currMatch) && (i < (matches.length - 1))) { foundNextMatch = true; showMatch(matches[i + 1], 0, 0, true); break; } } if (!foundNextMatch) { navigate(true); showMatch(getCurrentMatch(), 0, 0, true); } } /** * {@inheritDoc} * * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#gotoPreviousMatch() */ @Override public void gotoPreviousMatch() { Match currMatch = getCurrentMatch(); Match[] matches = getInput().getMatches(currMatch.getElement()); boolean foundPrevMatch = false; for (int i = 0; i < matches.length; ++i) { if (matches[i].equals(currMatch) && (i > 0)) { foundPrevMatch = true; showMatch(matches[i - 1], 0, 0, true); break; } } if (!foundPrevMatch) { navigate(false); showMatch(getCurrentMatch(), 0, 0, true); } } /** * {@inheritDoc} * * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#internalRemoveSelected() */ @Override public void internalRemoveSelected() { StructuredViewer viewer = getViewer(); IStructuredSelection selection = (IStructuredSelection)viewer.getSelection(); this.contentProvider.remove(selection.toArray()); viewer.refresh(); } private void navigate( boolean forward ) { if (getLayout() == FLAG_LAYOUT_FLAT) { Table table = (Table)getViewer().getControl(); int itemCount = table.getItemCount(); if (itemCount == 0) { return; } int[] selection = table.getSelectionIndices(); int nextIndex = 0; if (selection.length > 0) { if (forward) { nextIndex = selection[selection.length - 1] + 1; if (nextIndex >= itemCount) { nextIndex = 0; } } else { nextIndex = selection[0] - 1; if (nextIndex < 0) { nextIndex = itemCount - 1; } } } table.setSelection(nextIndex); table.showSelection(); } else { // TreeItem currentItem = getCurrentItem(forward); // if (currentItem == null) return; // TreeItem nextItem = null; // if (forward) { // nextItem = getNextItemForward(currentItem); // if (nextItem == null) nextItem = getFirstItem(); // } else { // nextItem = getNextItemBackward(currentItem); // if (nextItem == null) nextItem = getLastItem(); // } // if (nextItem != null) { // internalSetSelection(nextItem); // } } } /** * {@inheritDoc} * * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#setElementLimit(java.lang.Integer) */ @Override public void setElementLimit( Integer limit ) { super.setElementLimit(limit); // save new limit getSettings().put(RESULT_LIMIT_KEY, limit); } /** * {@inheritDoc} * * @see org.eclipse.search.ui.text.AbstractTextSearchViewPage#showMatch(org.eclipse.search.ui.text.Match, int, int, boolean) */ @Override protected void showMatch( Match match, int currentOffset, int currentLength, boolean activate ) { IModelObjectMatch modelObjMatch = (IModelObjectMatch)match; ModelEditorManager.open(modelObjMatch.getEObject(), true); getViewer().setSelection(new StructuredSelection(match), true); } // =========================================================================================================================== // Inner Class // =========================================================================================================================== class ResultsContentProvider implements ITreeContentProvider { // ======================================================================================================================= // Fields // ======================================================================================================================= private MetadataSearchResult result; private Map<MetadataMatchInfo, Match[]> model = new HashMap<MetadataMatchInfo, Match[]>(); // ======================================================================================================================= // Methods // ======================================================================================================================= public void clear() { this.model.clear(); } /** * {@inheritDoc} * * @see org.eclipse.jface.viewers.IContentProvider#dispose() */ @Override public void dispose() { // nothing to do } public void elementsChanged( Object[] updatedElements ) { ensureModelLoaded(); } private void ensureModelLoaded() { if (this.result == null) { this.model.clear(); } else { for (Object matchInfo : this.result.getElements()) { this.model.put((MetadataMatchInfo)matchInfo, this.result.getMatches(matchInfo)); } } } /** * {@inheritDoc} * * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object) */ @Override public Object[] getChildren( Object parentElement ) { return this.result.getMatches(parentElement); } /** * {@inheritDoc} * * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object) */ @Override public Object getParent( Object element ) { if (element instanceof Match) { return ((Match)element).getElement(); } return null; } /** * {@inheritDoc} * * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object) */ @Override public Object[] getElements( Object inputElement ) { // if the input element is a result the layout could be changing so make sure the model has been loaded ensureModelLoaded(); if (getLayout() == FLAG_LAYOUT_FLAT) { // return matches List<Match> allMatches = new ArrayList<Match>(); for (Match[] matches : this.model.values()) { for (Match match : matches) { allMatches.add(match); } } return allMatches.toArray(); } return this.model.keySet().toArray(); } /** * {@inheritDoc} * * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object) */ @Override public boolean hasChildren( Object element ) { return (element instanceof MetadataMatchInfo ? true : false); } /** * {@inheritDoc} * * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, * java.lang.Object) */ @Override public void inputChanged( Viewer viewer, Object oldInput, Object newInput ) { this.model.clear(); this.result = null; if (newInput instanceof MetadataSearchResult) { this.result = (MetadataSearchResult)newInput; } } public void remove(Object[] removedObjects) { for (Object obj : removedObjects) { if (obj instanceof MetadataMatch) { MetadataMatch match = (MetadataMatch)obj; this.result.removeMatch(match); if (this.result.getMatches(match.getElement()).length == 0) { this.model.remove(match.getElement()); } } else if (obj instanceof MetadataMatchInfo) { this.result.removeMatches(this.result.getMatches(obj)); this.model.remove(obj); } } } } }