/******************************************************************************* * Copyright (c) 2000, 2009 IBM Corporation and others. * 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.ui.views.markers.internal; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import org.eclipse.help.HelpSystem; import org.eclipse.help.IContext; import org.eclipse.help.IContextProvider; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.dnd.Clipboard; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DragSourceAdapter; import org.eclipse.swt.dnd.DragSourceEvent; import org.eclipse.swt.dnd.DragSourceListener; import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.HelpEvent; import org.eclipse.swt.events.HelpListener; import org.eclipse.swt.events.TreeAdapter; import org.eclipse.swt.events.TreeEvent; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Tree; import org.eclipse.core.commands.operations.IUndoContext; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.IJobChangeListener; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.resources.mapping.ResourceMapping; import org.eclipse.core.resources.mapping.ResourceMappingContext; import org.eclipse.core.resources.mapping.ResourceTraversal; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.AbstractTreeViewer; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.OpenEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.window.Window; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IMemento; import org.eclipse.ui.ISelectionListener; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.IWorkbenchCommandConstants; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.WorkbenchException; import org.eclipse.ui.XMLMemento; import org.eclipse.ui.actions.ActionFactory; import org.eclipse.ui.actions.ContributionItemFactory; import org.eclipse.ui.actions.SelectionProviderAction; import org.eclipse.ui.ide.IDE; import org.eclipse.ui.ide.ResourceUtil; import org.eclipse.ui.internal.ide.IDEWorkbenchMessages; import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin; import org.eclipse.ui.internal.ide.Policy; import org.eclipse.ui.keys.IBindingService; import org.eclipse.ui.operations.RedoActionHandler; import org.eclipse.ui.operations.UndoActionHandler; import org.eclipse.ui.part.IShowInSource; import org.eclipse.ui.part.MarkerTransfer; import org.eclipse.ui.part.ShowInContext; import org.eclipse.ui.preferences.ViewPreferencesAction; import org.eclipse.ui.progress.IWorkbenchSiteProgressService; import org.eclipse.ui.progress.WorkbenchJob; import org.eclipse.ui.views.markers.internal.MarkerAdapter.MarkerCategory; import org.eclipse.ui.views.tasklist.ITaskListResourceAdapter; /** * MarkerView is the abstract super class of the marker based views. * */ public abstract class MarkerView extends TableView { private static final String TAG_SELECTION = "selection"; //$NON-NLS-1$ private static final String TAG_MARKER = "marker"; //$NON-NLS-1$ private static final String TAG_RESOURCE = "resource"; //$NON-NLS-1$ private static final String TAG_ID = "id"; //$NON-NLS-1$ private static final String TAG_FILTERS_SECTION = "filters"; //$NON-NLS-1$ private static final String TAG_FILTER_ENTRY = "filter"; //$NON-NLS-1$ private static final String MENU_FILTERS_GROUP = "group.filter";//$NON-NLS-1$ private static final String MENU_SHOW_IN_GROUP = "group.showIn";//$NON-NLS-1$ // Section from a 3.1 or earlier workbench private static final String OLD_FILTER_SECTION = "filter"; //$NON-NLS-1$ static final Object MARKER_UPDATE_FAMILY = new Object(); class MarkerProcessJob extends Job { /** * Create a new instance of the receiver. */ MarkerProcessJob() { super(MarkerMessages.MarkerView_processUpdates); setSystem(true); } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) */ protected IStatus run(IProgressMonitor monitor) { updateForContentsRefresh(monitor); return Status.OK_STATUS; } /* * (non-Javadoc) * * @see org.eclipse.ui.progress.WorkbenchJob#shouldRun() */ public boolean shouldRun() { // Do not run if the change came in before there is a viewer return PlatformUI.isWorkbenchRunning(); } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.jobs.Job#belongsTo(java.lang.Object) */ public boolean belongsTo(Object family) { return MARKER_UPDATE_FAMILY == family; } } MarkerProcessJob markerProcessJob = new MarkerProcessJob(); private class UpdateJob extends WorkbenchJob { private class MarkerDescriptor { String description; String folder; String resource; int line; MarkerDescriptor(ConcreteMarker marker) { description = marker.getDescription(); folder = marker.getFolder(); resource = marker.getResourceName(); line = marker.getLine(); } boolean isEquivalentTo(ConcreteMarker marker) { return marker.getDescription().equals(description) && marker.getFolder().equals(folder) && marker.getResourceName().equals(resource) && marker.getLine() == line; } } private Collection categoriesToExpand = new HashSet(); private Collection preservedSelection = new ArrayList(); UpdateJob() { super(MarkerMessages.MarkerView_queueing_updates); setSystem(true); } /* * (non-Javadoc) * * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor) */ public IStatus runInUIThread(IProgressMonitor monitor) { if (getViewer().getControl().isDisposed()) { return Status.CANCEL_STATUS; } if (monitor.isCanceled()) return Status.CANCEL_STATUS; getViewer().refresh(true); Tree tree = getTree(); if (tree != null && !tree.isDisposed()) { updateStatusMessage(); updateTitle(); // Expand all if the list is small if (getCurrentMarkers().getSize() < 20) { getViewer().expandAll(); } else {// Reexpand the old categories MarkerCategory[] categories = getMarkerAdapter() .getCategories(); if (categories == null) categoriesToExpand.clear(); else { if (categories.length == 1) {// Expand if there is // only // one getViewer().expandAll(); categoriesToExpand.clear(); if (monitor.isCanceled()) return Status.CANCEL_STATUS; categoriesToExpand.add(categories[0].getName()); } else { Collection newCategories = new HashSet(); for (int i = 0; i < categories.length; i++) { if (monitor.isCanceled()) return Status.CANCEL_STATUS; MarkerCategory category = categories[i]; if (categoriesToExpand.contains(category .getName())) { getViewer().expandToLevel(category, AbstractTreeViewer.ALL_LEVELS); newCategories.add(category.getName()); } } categoriesToExpand = newCategories; } } } } if (preservedSelection.size() > 0) { Collection newSelection = new ArrayList(); ConcreteMarker[] markers = getCurrentMarkers().toArray(); for (int i = 0; i < markers.length; i++) { Iterator preserved = preservedSelection.iterator(); while (preserved.hasNext()) { MarkerDescriptor next = (MarkerDescriptor) preserved .next(); if (next.isEquivalentTo(markers[i])) { newSelection.add(markers[i]); continue; } } } getViewer().setSelection( new StructuredSelection(newSelection.toArray()), true); preservedSelection.clear(); } if (getViewer().getTree().getItemCount() > 0) getViewer().getTree().setTopItem( getViewer().getTree().getItem(0)); return Status.OK_STATUS; } /** * Add the category to the list of expanded categories. * * @param category */ public void addExpandedCategory(MarkerCategory category) { categoriesToExpand.add(category.getName()); } /** * Remove the category from the list of expanded ones. * * @param category */ public void removeExpandedCategory(MarkerCategory category) { categoriesToExpand.remove(category.getName()); } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.jobs.Job#belongsTo(java.lang.Object) */ public boolean belongsTo(Object family) { return family == MARKER_UPDATE_FAMILY; } /** * Preserve the selection for reselection after the next update. * * @param selection */ public void saveSelection(ISelection selection) { preservedSelection.clear(); if (selection instanceof IStructuredSelection) { IStructuredSelection structured = (IStructuredSelection) selection; Iterator iterator = structured.iterator(); while (iterator.hasNext()) { MarkerNode next = (MarkerNode) iterator.next(); if (next.isConcrete()) { preservedSelection.add(new MarkerDescriptor(next .getConcreteRepresentative())); } } } } /* * (non-Javadoc) * * @see org.eclipse.ui.progress.WorkbenchJob#shouldRun() */ public boolean shouldRun() { return !getMarkerAdapter().isBuilding(); } } private UpdateJob updateJob = new UpdateJob(); // A private field for keeping track of the number of markers // before the busy testing started private int preBusyMarkers = 0; protected Object[] focusElements; private Clipboard clipboard; IResourceChangeListener markerUpdateListener = new IResourceChangeListener() { /* * (non-Javadoc) * * @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent) */ public void resourceChanged(IResourceChangeEvent event) { if (!hasMarkerDelta(event)) return; if (event.getType() == IResourceChangeEvent.POST_BUILD) { scheduleMarkerUpdate(Util.SHORT_DELAY); return; } // After 30 seconds do updates anyways IWorkbenchSiteProgressService progressService = getProgressService(); if (progressService == null) markerProcessJob.schedule(Util.LONG_DELAY); else getProgressService() .schedule(markerProcessJob, Util.LONG_DELAY); } /** * Returns whether or not the given even contains marker deltas for this * view. * * @param event * the resource change event * @return <code>true</code> if the event contains at least one * relevant marker delta * @since 3.3 */ private boolean hasMarkerDelta(IResourceChangeEvent event) { String[] markerTypes = getMarkerTypes(); for (int i = 0; i < markerTypes.length; i++) { if (event.findMarkerDeltas(markerTypes[i], true).length > 0) { return true; } } return false; } }; private class ContextProvider implements IContextProvider { public int getContextChangeMask() { return SELECTION; } public IContext getContext(Object target) { String contextId = null; // See if there is a context registered for the current selection ConcreteMarker marker = getSelectedConcreteMarker(); if (marker != null) { contextId = IDE.getMarkerHelpRegistry().getHelp( marker.getMarker()); } if (contextId == null) { contextId = getStaticContextId(); } return HelpSystem.getContext(contextId); } /** * Return the currently selected concrete marker or <code>null</code> * if there isn't one. * * @return ConcreteMarker */ private ConcreteMarker getSelectedConcreteMarker() { IStructuredSelection selection = (IStructuredSelection) getViewer() .getSelection(); if (selection.isEmpty()) return null; if (selection.getFirstElement() instanceof ConcreteMarker) return (ConcreteMarker) selection.getFirstElement(); return null; } /* * (non-Javadoc) * * @see org.eclipse.help.IContextProvider#getSearchExpression(java.lang.Object) */ public String getSearchExpression(Object target) { return null; } } private ContextProvider contextProvider = new ContextProvider(); protected ActionCopyMarker copyAction; protected ActionPasteMarker pasteAction; protected SelectionProviderAction revealAction; protected SelectionProviderAction openAction; protected SelectionProviderAction deleteAction; protected SelectionProviderAction selectAllAction; protected SelectionProviderAction propertiesAction; protected UndoActionHandler undoAction; protected RedoActionHandler redoAction; private ISelectionListener focusListener = new ISelectionListener() { public void selectionChanged(IWorkbenchPart part, ISelection selection) { MarkerView.this.focusSelectionChanged(part, selection); } }; private int totalMarkers = 0; private MarkerFilter[] markerFilters = new MarkerFilter[0]; // A cache of the enabled filters private MarkerFilter[] enabledFilters = null; private MenuManager filtersMenu; private MenuManager showInMenu; private IPropertyChangeListener workingSetListener; private MarkerAdapter adapter; private IPropertyChangeListener preferenceListener; /** * Create a new instance of the receiver, */ public MarkerView() { super(); preferenceListener = new IPropertyChangeListener() { /* * (non-Javadoc) * * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent) */ public void propertyChange(PropertyChangeEvent event) { if (event.getProperty().equals(getFiltersPreferenceName())) { loadFiltersPreferences(); clearEnabledFilters(); refreshForFocusUpdate(); } } }; IDEWorkbenchPlugin.getDefault().getPreferenceStore() .addPropertyChangeListener(preferenceListener); } /** * Get the current markers for the receiver. * * @return MarkerList */ public MarkerList getCurrentMarkers() { return getMarkerAdapter().getCurrentMarkers(); } /** * Get the marker adapter for the receiver. * * @return MarkerAdapter */ protected MarkerAdapter getMarkerAdapter() { return adapter; } /** * Update for the change in the contents. * * @param monitor */ public void updateForContentsRefresh(IProgressMonitor monitor) { updateJob.cancel(); getMarkerAdapter().buildAllMarkers(monitor); getProgressService().schedule(updateJob); } /* * (non-Javadoc) * * @see org.eclipse.ui.IViewPart#init(org.eclipse.ui.IViewSite, * org.eclipse.ui.IMemento) */ public void init(IViewSite site, IMemento memento) throws PartInitException { super.init(site, memento); IWorkbenchSiteProgressService progressService = getProgressService(); if (progressService != null) { getProgressService().showBusyForFamily( ResourcesPlugin.FAMILY_MANUAL_BUILD); getProgressService().showBusyForFamily( ResourcesPlugin.FAMILY_AUTO_BUILD); getProgressService().showBusyForFamily(MARKER_UPDATE_FAMILY); } loadFiltersPreferences(); } /** * Load the filters preference. */ private void loadFiltersPreferences() { String preference = IDEWorkbenchPlugin.getDefault() .getPreferenceStore().getString(getFiltersPreferenceName()); if (preference.equals(IPreferenceStore.STRING_DEFAULT_DEFAULT)) { createDefaultFilter(); return; } StringReader reader = new StringReader(preference); try { restoreFilters(XMLMemento.createReadRoot(reader)); } catch (WorkbenchException e) { IDEWorkbenchPlugin.log(e.getLocalizedMessage(), e); } } /** * Update for filter changes. Save the preference and clear the enabled * cache. */ void updateForFilterChanges() { XMLMemento memento = XMLMemento.createWriteRoot(TAG_FILTERS_SECTION); writeFiltersSettings(memento); StringWriter writer = new StringWriter(); try { memento.save(writer); } catch (IOException e) { IDEWorkbenchPlugin.getDefault().getLog().log(Util.errorStatus(e)); } IDEWorkbenchPlugin.getDefault().getPreferenceStore().putValue( getFiltersPreferenceName(), writer.toString()); IDEWorkbenchPlugin.getDefault().savePluginPreferences(); clearEnabledFilters(); refreshFilterMenu(); refreshViewer(); } /** * Write the filter settings to the memento. * * @param memento */ protected void writeFiltersSettings(XMLMemento memento) { MarkerFilter[] filters = getUserFilters(); for (int i = 0; i < filters.length; i++) { IMemento child = memento.createChild(TAG_FILTER_ENTRY, filters[i] .getName()); filters[i].saveFilterSettings(child); } } /** * Get the name of the filters preference for instances of the receiver. * * @return String */ abstract String getFiltersPreferenceName(); /** * Restore the filters from the mimento. * * @param memento */ void restoreFilters(IMemento memento) { IMemento[] sections = null; if (memento != null) { sections = memento.getChildren(TAG_FILTER_ENTRY); } if (sections == null) { // Check if we have an old filter setting around IDialogSettings mainSettings = getDialogSettings(); IDialogSettings filtersSection = mainSettings .getSection(OLD_FILTER_SECTION); if (filtersSection != null) { MarkerFilter markerFilter = createFilter(MarkerMessages.MarkerFilter_defaultFilterName); markerFilter.restoreFilterSettings(filtersSection); setFilters(new MarkerFilter[] { markerFilter }); } } else { MarkerFilter[] newFilters = new MarkerFilter[sections.length]; for (int i = 0; i < sections.length; i++) { newFilters[i] = createFilter(sections[i].getID()); newFilters[i].restoreState(sections[i]); } setFilters(newFilters); } if (markerFilters.length == 0) {// Make sure there is at least a default createDefaultFilter(); } } /** * Create a default filter for the receiver. * */ private void createDefaultFilter() { MarkerFilter filter = createFilter(MarkerMessages.MarkerFilter_defaultFilterName); setFilters(new MarkerFilter[] { filter }); } /** * Create a filter called name. * * @param name * @return MarkerFilter */ protected abstract MarkerFilter createFilter(String name); /** * Return the memento tag for the receiver. * * @return String */ protected abstract String getSectionTag(); /* * (non-Javadoc) * * @see org.eclipse.ui.views.internal.tableview.TableView#createPartControl(org.eclipse.swt.widgets.Composite) */ public void createPartControl(Composite parent) { clipboard = new Clipboard(parent.getDisplay()); super.createPartControl(parent); initDragAndDrop(); getSite().getPage().addSelectionListener(focusListener); focusSelectionChanged(getSite().getPage().getActivePart(), getSite() .getPage().getSelection()); PlatformUI.getWorkbench().getWorkingSetManager() .addPropertyChangeListener(getWorkingSetListener()); // Set help on the view itself getViewer().getControl().addHelpListener(new HelpListener() { /* * (non-Javadoc) * * @see org.eclipse.swt.events.HelpListener#helpRequested(org.eclipse.swt.events.HelpEvent) */ public void helpRequested(HelpEvent e) { IContext context = contextProvider.getContext(getViewer() .getControl()); PlatformUI.getWorkbench().getHelpSystem().displayHelp(context); } }); // Hook up to the resource changes after all widget have been created ResourcesPlugin.getWorkspace().addResourceChangeListener( markerUpdateListener, IResourceChangeEvent.POST_CHANGE | IResourceChangeEvent.PRE_BUILD | IResourceChangeEvent.POST_BUILD); } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) */ public Object getAdapter(Class adaptable) { if (adaptable.equals(IContextProvider.class)) { return contextProvider; } if (adaptable.equals(IShowInSource.class)) { return new IShowInSource() { public ShowInContext getShowInContext() { ISelection selection = getViewer().getSelection(); if (!(selection instanceof IStructuredSelection)) { return null; } IStructuredSelection structured = (IStructuredSelection) selection; Iterator markerIterator = structured.iterator(); List newSelection = new ArrayList(); while (markerIterator.hasNext()) { ConcreteMarker element = (ConcreteMarker) markerIterator .next(); newSelection.add(element.getResource()); } return new ShowInContext(getViewer().getInput(), new StructuredSelection(newSelection)); } }; } return super.getAdapter(adaptable); } /* * (non-Javadoc) * * @see org.eclipse.ui.views.markers.internal.TableView#viewerSelectionChanged(org.eclipse.jface.viewers.IStructuredSelection) */ protected void viewerSelectionChanged(IStructuredSelection selection) { Object[] rawSelection = selection.toArray(); List markers = new ArrayList(); for (int idx = 0; idx < rawSelection.length; idx++) { if (rawSelection[idx] instanceof ConcreteMarker) markers.add(((ConcreteMarker) rawSelection[idx]).getMarker()); } setSelection(new StructuredSelection(markers)); updateStatusMessage(selection); } /* * (non-Javadoc) * * @see org.eclipse.ui.views.internal.tableview.TableView#dispose() */ public void dispose() { super.dispose(); cancelJobs(); ResourcesPlugin.getWorkspace().removeResourceChangeListener( markerUpdateListener); PlatformUI.getWorkbench().getWorkingSetManager() .removePropertyChangeListener(workingSetListener); IDEWorkbenchPlugin.getDefault().getPreferenceStore() .removePropertyChangeListener(preferenceListener); getSite().getPage().removeSelectionListener(focusListener); // dispose of selection provider actions (may not have been created yet // if createPartControls was never called) if (openAction != null) { openAction.dispose(); copyAction.dispose(); selectAllAction.dispose(); deleteAction.dispose(); revealAction.dispose(); propertiesAction.dispose(); undoAction.dispose(); redoAction.dispose(); clipboard.dispose(); } if (showInMenu != null) { showInMenu.dispose(); } } /* * (non-Javadoc) * * @see org.eclipse.ui.views.internal.tableview.TableView#createActions() */ protected void createActions() { revealAction = new ActionRevealMarker(this, getViewer()); openAction = new ActionOpenMarker(this, getViewer()); copyAction = new ActionCopyMarker(this, getViewer()); copyAction.setClipboard(clipboard); copyAction.setProperties(getSortingFields()); pasteAction = new ActionPasteMarker(this, getViewer(), getMarkerName()); pasteAction.setClipboard(clipboard); pasteAction.setPastableTypes(getMarkerTypes()); deleteAction = new ActionRemoveMarker(this, getViewer(), getMarkerName()); selectAllAction = new ActionSelectAll(this); propertiesAction = new ActionMarkerProperties(this, getViewer(), getMarkerName()); IUndoContext undoContext = getUndoContext(); undoAction = new UndoActionHandler(getSite(), undoContext); redoAction = new RedoActionHandler(getSite(), undoContext); super.createActions(); setFilterAction(new FiltersAction(this)); setPreferencesAction(new ViewPreferencesAction() { /* * (non-Javadoc) * * @see org.eclipse.ui.preferences.ViewPreferencesAction#openViewPreferencesDialog() */ public void openViewPreferencesDialog() { openPreferencesDialog(getMarkerEnablementPreferenceName(), getMarkerLimitPreferenceName()); } }); } /** * Open a dialog to set the preferences. * * @param markerEnablementPreferenceName * @param markerLimitPreferenceName */ private void openPreferencesDialog(String markerEnablementPreferenceName, String markerLimitPreferenceName) { Dialog dialog = new MarkerViewPreferenceDialog(getSite() .getWorkbenchWindow().getShell(), markerEnablementPreferenceName, markerLimitPreferenceName, MarkerMessages.MarkerPreferences_DialogTitle); if (dialog.open() == Window.OK) { refreshViewer(); } } /** * Get the name of the marker enablement preference. * * @return String */ abstract String getMarkerLimitPreferenceName(); abstract String[] getMarkerTypes(); /* * (non-Javadoc) * * @see org.eclipse.ui.views.internal.tableview.TableView#initToolBar(org.eclipse.jface.action.IToolBarManager) */ protected void initToolBar(IToolBarManager tbm) { tbm.add(deleteAction); tbm.add(getFilterAction()); tbm.update(false); } /* * (non-Javadoc) * * @see org.eclipse.ui.views.internal.tableview.TableView#registerGlobalActions(org.eclipse.ui.IActionBars) */ protected void registerGlobalActions(IActionBars actionBars) { copyAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_COPY); pasteAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_PASTE); deleteAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_DELETE); selectAllAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_SELECT_ALL); propertiesAction.setActionDefinitionId(IWorkbenchCommandConstants.FILE_PROPERTIES); undoAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_UNDO); redoAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_REDO); actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(), copyAction); actionBars.setGlobalActionHandler(ActionFactory.PASTE.getId(), pasteAction); actionBars.setGlobalActionHandler(ActionFactory.DELETE.getId(), deleteAction); actionBars.setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(), selectAllAction); actionBars.setGlobalActionHandler(ActionFactory.PROPERTIES.getId(), propertiesAction); actionBars.setGlobalActionHandler(ActionFactory.UNDO.getId(), undoAction); actionBars.setGlobalActionHandler(ActionFactory.REDO.getId(), redoAction); } protected void initDragAndDrop() { int operations = DND.DROP_COPY; Transfer[] transferTypes = new Transfer[] { MarkerTransfer.getInstance(), TextTransfer.getInstance() }; DragSourceListener listener = new DragSourceAdapter() { public void dragSetData(DragSourceEvent event) { performDragSetData(event); } public void dragFinished(DragSourceEvent event) { } }; getViewer().addDragSupport(operations, transferTypes, listener); } /** * The user is attempting to drag marker data. Add the appropriate data to * the event depending on the transfer type. */ private void performDragSetData(DragSourceEvent event) { if (MarkerTransfer.getInstance().isSupportedType(event.dataType)) { event.data = getSelectedMarkers(); return; } if (TextTransfer.getInstance().isSupportedType(event.dataType)) { List selection = ((IStructuredSelection) getViewer().getSelection()) .toList(); try { IMarker[] markers = new IMarker[selection.size()]; selection.toArray(markers); if (markers != null) { event.data = copyAction.createMarkerReport(markers); } } catch (ArrayStoreException e) { } } } /** * Get the array of selected markers. * * @return IMarker[] */ private IMarker[] getSelectedMarkers() { Object[] selection = ((IStructuredSelection) getViewer().getSelection()) .toArray(); ArrayList markers = new ArrayList(); for (int i = 0; i < selection.length; i++) { if (selection[i] instanceof ConcreteMarker) { markers.add(((ConcreteMarker) selection[i]).getMarker()); } } return (IMarker[]) markers.toArray(new IMarker[markers.size()]); } /* * (non-Javadoc) * * @see org.eclipse.ui.views.internal.tableview.TableView#fillContextMenu(org.eclipse.jface.action.IMenuManager) */ protected void fillContextMenu(IMenuManager manager) { if (manager == null) { return; } manager.add(openAction); createShowInMenu(manager); manager.add(new Separator()); manager.add(copyAction); pasteAction.updateEnablement(); manager.add(pasteAction); if (canBeEditable()) { manager.add(deleteAction); } manager.add(selectAllAction); fillContextMenuAdditions(manager); manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); manager.add(new Separator()); manager.add(propertiesAction); } /** * Return whether or not any of the types in the receiver can be editable. * * @return <code>true</code> if it is possible to have an editable marker * in this view. */ boolean canBeEditable() { return true; } /** * Fill the context menu for the receiver. * * @param manager */ abstract void fillContextMenuAdditions(IMenuManager manager); /** * Get the filters for the receiver. * * @return MarkerFilter[] */ protected final MarkerFilter[] getUserFilters() { return markerFilters; } /* * (non-Javadoc) * * @see org.eclipse.ui.views.internal.tableview.TableView#handleOpenEvent(org.eclipse.jface.viewers.OpenEvent) */ protected void handleOpenEvent(OpenEvent event) { if (openAction.isEnabled()) { openAction.run(); } } /* * (non-Javadoc) * * @see org.eclipse.ui.views.internal.tableview.TableView#saveSelection(org.eclipse.ui.IMemento) */ protected void saveSelection(IMemento memento) { IStructuredSelection selection = (IStructuredSelection) getViewer() .getSelection(); IMemento selectionMem = memento.createChild(TAG_SELECTION); for (Iterator iterator = selection.iterator(); iterator.hasNext();) { Object next = iterator.next(); if (!(next instanceof ConcreteMarker)) { continue; } ConcreteMarker marker = (ConcreteMarker) next; IMemento elementMem = selectionMem.createChild(TAG_MARKER); elementMem.putString(TAG_RESOURCE, marker.getMarker().getResource() .getFullPath().toString()); elementMem.putString(TAG_ID, String.valueOf(marker.getMarker() .getId())); } } protected abstract String[] getRootTypes(); /** * @param part * @param selection */ protected void focusSelectionChanged(IWorkbenchPart part, ISelection selection) { List selectedElements = new ArrayList(); if (part instanceof IEditorPart) { IEditorPart editor = (IEditorPart) part; IFile file = ResourceUtil.getFile(editor.getEditorInput()); if (file == null) { IEditorInput editorInput = editor.getEditorInput(); if (editorInput != null) { Object mapping = editorInput .getAdapter(ResourceMapping.class); if (mapping != null) { selectedElements.add(mapping); } } } else { selectedElements.add(file); } } else { if (selection instanceof IStructuredSelection) { for (Iterator iterator = ((IStructuredSelection) selection) .iterator(); iterator.hasNext();) { Object object = iterator.next(); if (object instanceof IAdaptable) { ITaskListResourceAdapter taskListResourceAdapter; Object adapter = ((IAdaptable) object) .getAdapter(ITaskListResourceAdapter.class); if (adapter != null && adapter instanceof ITaskListResourceAdapter) { taskListResourceAdapter = (ITaskListResourceAdapter) adapter; } else { taskListResourceAdapter = DefaultMarkerResourceAdapter .getDefault(); } IResource resource = taskListResourceAdapter .getAffectedResource((IAdaptable) object); if (resource == null) { Object mapping = ((IAdaptable) object) .getAdapter(ResourceMapping.class); if (mapping != null) { selectedElements.add(mapping); } } else { selectedElements.add(resource); } } } } } updateFocusMarkers(selectedElements.toArray()); } /** * Update the focus resources of the filters. * * @param elements */ protected final void updateFilterSelection(Object[] elements) { Collection resourceCollection = new ArrayList(); for (int i = 0; i < elements.length; i++) { if (elements[i] instanceof IResource) { resourceCollection.add(elements[i]); } else { addResources(resourceCollection, ((ResourceMapping) elements[i])); } } IResource[] resources = new IResource[resourceCollection.size()]; resourceCollection.toArray(resources); for (int i = 0; i < markerFilters.length; i++) { markerFilters[i].setFocusResource(resources); } Iterator systemFilters = MarkerSupportRegistry.getInstance() .getRegisteredFilters().iterator(); while (systemFilters.hasNext()) { MarkerFilter filter = (MarkerFilter) systemFilters.next(); filter.setFocusResource(resources); } } /** * Add the resources for the mapping to resources. * * @param resources * @param mapping */ private void addResources(Collection resources, ResourceMapping mapping) { try { ResourceTraversal[] traversals = mapping.getTraversals( ResourceMappingContext.LOCAL_CONTEXT, new NullProgressMonitor()); for (int i = 0; i < traversals.length; i++) { ResourceTraversal traversal = traversals[i]; IResource[] result = traversal.getResources(); for (int j = 0; j < result.length; j++) { resources.add(result[j]); } } } catch (CoreException e) { Policy.handle(e); return; } } protected abstract String getStaticContextId(); /** * Update the focus markers for the supplied elements. * * @param elements */ void updateFocusMarkers(Object[] elements) { boolean updateNeeded = updateNeeded(focusElements, elements); if (updateNeeded) { focusElements = elements; refreshForFocusUpdate(); } } private boolean updateNeeded(Object[] oldElements, Object[] newElements) { // determine if an update if refiltering is required MarkerFilter[] filters = getEnabledFilters(); boolean updateNeeded = false; for (int i = 0; i < filters.length; i++) { MarkerFilter filter = filters[i]; if (!filter.isEnabled()) { continue; } int onResource = filter.getOnResource(); if (onResource == MarkerFilter.ON_ANY || onResource == MarkerFilter.ON_WORKING_SET) { continue; } if (newElements == null || newElements.length < 1) { continue; } if (oldElements == null || oldElements.length < 1) { return true; } if (Arrays.equals(oldElements, newElements)) { continue; } if (onResource == MarkerFilter.ON_ANY_IN_SAME_CONTAINER) { Collection oldProjects = MarkerFilter .getProjectsAsCollection(oldElements); Collection newProjects = MarkerFilter .getProjectsAsCollection(newElements); if (oldProjects.size() == newProjects.size()) { if (newProjects.containsAll(oldProjects)) { continue; } } return true; } updateNeeded = true;// We are updating as there is nothing to stop // us } return updateNeeded; } void updateTitle() { String status = Util.EMPTY_STRING; int filteredCount = getCurrentMarkers().getItemCount(); int totalCount = getTotalMarkers(); if (filteredCount == totalCount) { status = NLS.bind(MarkerMessages.filter_itemsMessage, new Integer( totalCount)); } else { status = NLS.bind(MarkerMessages.filter_matchedMessage, new Integer(filteredCount), new Integer(totalCount)); } setContentDescription(status); } /** * Updates the message displayed in the status line. This method is invoked * in the following cases: * <ul> * <li>when this view is first created</li> * <li>when new elements are added</li> * <li>when something is deleted</li> * <li>when the filters change</li> * </ul> * <p> * By default, this method calls * <code>updateStatusMessage(IStructuredSelection)</code> with the current * selection or <code>null</code>. Classes wishing to override this * functionality, should just override the method * <code>updateStatusMessage(IStructuredSelection)</code>. * </p> */ protected void updateStatusMessage() { ISelection selection = getViewer().getSelection(); if (selection instanceof IStructuredSelection) { updateStatusMessage((IStructuredSelection) selection); } else { updateStatusMessage(null); } } /** * Updates that message displayed in the status line. If the selection * parameter is <code>null</code> or its size is 0, the status area is * blanked out. If only 1 marker is selected, the status area is updated * with the contents of the message attribute of this marker. In other cases * (more than one marker is selected) the status area indicates how many * items have been selected. * <p> * This method may be overwritten. * </p> * <p> * This method is called whenever a selection changes in this view. * </p> * * @param selection * a valid selection or <code>null</code> */ protected void updateStatusMessage(IStructuredSelection selection) { String message = ""; //$NON-NLS-1$ if (selection == null || selection.size() == 0) { // Show stats on all items in the view message = updateSummaryVisible(); } else if (selection.size() == 1) { // Use the Message attribute of the marker Object first = selection.getFirstElement(); if (first instanceof ConcreteMarker) { message = ((ConcreteMarker) first).getDescription(); } } else if (selection.size() > 1) { // Show stats on only those items in the selection message = updateSummarySelected(selection); } getViewSite().getActionBars().getStatusLineManager() .setMessage(message); } /** * @param selection * @return the summary status message */ protected String updateSummarySelected(IStructuredSelection selection) { // Show how many items selected return MessageFormat.format( MarkerMessages.marker_statusSummarySelected, new Object[] { new Integer(selection.size()) }); } /** * @return the update summary */ protected String updateSummaryVisible() { return ""; //$NON-NLS-1$ } /** * Open a dialog on the filters * */ public final void openFiltersDialog() { DialogMarkerFilter dialog = createFiltersDialog(); if (dialog.open() == Window.OK) { MarkerFilter[] result = dialog.getFilters(); if (result == null) { return; } if (result.length == 0) { setFilters(new MarkerFilter[] { createFilter(MarkerMessages.MarkerFilter_defaultFilterName) }); } else { setFilters(result); } updateForFilterChanges(); } } /** * Refresh the contents of the viewer. */ public void refreshViewer() { scheduleMarkerUpdate(Util.SHORT_DELAY); } /** * Set the filters to newFilters. * * @param newFilters */ void setFilters(MarkerFilter[] newFilters) { markerFilters = newFilters; } /** * Clear the cache of enabled filters. * */ void clearEnabledFilters() { enabledFilters = null; } /** * Refresh the contents of the filter sub menu. */ private void refreshFilterMenu() { if (filtersMenu == null) { return; } filtersMenu.removeAll(); MarkerFilter[] filters = getAllFilters(); for (int i = 0; i < filters.length; i++) { filtersMenu.add(new FilterEnablementAction(filters[i], this)); } } /** * Open a filter dialog on the receiver. */ protected abstract DialogMarkerFilter createFiltersDialog(); /** * Given a selection of IMarker, reveals the corresponding elements in the * viewer * * @param structuredSelection * @param reveal */ public void setSelection(IStructuredSelection structuredSelection, boolean reveal) { TreeViewer viewer = getViewer(); List newSelection = new ArrayList(structuredSelection.size()); for (Iterator i = structuredSelection.iterator(); i.hasNext();) { Object next = i.next(); if (next instanceof IMarker) { ConcreteMarker marker = getCurrentMarkers().getMarker( (IMarker) next); if (marker != null) { newSelection.add(marker); } } } if (viewer != null) { viewer.setSelection(new StructuredSelection(newSelection), reveal); } } protected MarkerList getVisibleMarkers() { return getCurrentMarkers(); } /** * Returns the total number of markers. Should not be called while the * marker list is still updating. * * @return the total number of markers in the workspace (including * everything that doesn't pass the filters) */ int getTotalMarkers() { // The number of visible markers should never exceed the total number of // markers in // the workspace. If this assertation fails, it probably indicates some // sort of concurrency problem // (most likely, getTotalMarkers was called while we were still // computing the marker lists) // Assert.isTrue(totalMarkers >= currentMarkers.getItemCount()); return totalMarkers; } /* * (non-Javadoc) * * @see org.eclipse.ui.part.WorkbenchPart#showBusy(boolean) */ public void showBusy(boolean busy) { super.showBusy(busy); if (busy) { preBusyMarkers = totalMarkers; } else {// Only bold if there has been a change in count if (totalMarkers != preBusyMarkers) { getProgressService().warnOfContentChange(); } } } /** * Get the filters that are currently enabled. * * @return MarkerFilter[] */ MarkerFilter[] getEnabledFilters() { if (enabledFilters == null) { Collection filters = findEnabledFilters(); enabledFilters = new MarkerFilter[filters.size()]; filters.toArray(enabledFilters); } return enabledFilters; } /** * Find the filters enabled in the view. * * @return Collection of MarkerFilter */ protected Collection findEnabledFilters() { MarkerFilter[] allFilters = getAllFilters(); ArrayList filters = new ArrayList(0); for (int i = 0; i < allFilters.length; i++) { if (allFilters[i].isEnabled()) { filters.add(allFilters[i]); } } return filters; } /** * Get all of the filters applied to the receiver. * * @return MarkerFilter[] */ MarkerFilter[] getAllFilters() { return getUserFilters(); } /* * (non-Javadoc) * * @see org.eclipse.ui.views.markers.internal.TableView#addDropDownContributions(org.eclipse.jface.action.IMenuManager) */ void addDropDownContributions(IMenuManager menu) { super.addDropDownContributions(menu); menu.add(new Separator(MENU_FILTERS_GROUP)); // Don't add in the filters until they are set filtersMenu = new MenuManager(MarkerMessages.filtersSubMenu_title); refreshFilterMenu(); menu.appendToGroup(MENU_FILTERS_GROUP, filtersMenu); } /** * Create the show in menu if there is a single selection. * * @param menu */ void createShowInMenu(IMenuManager menu) { ISelection selection = getViewer().getSelection(); if (!(selection instanceof IStructuredSelection)) { return; } IStructuredSelection structured = (IStructuredSelection) selection; if (!Util.isSingleConcreteSelection(structured)) { return; } menu.add(new Separator(MENU_SHOW_IN_GROUP)); // Don't add in the filters until they are set String showInLabel = IDEWorkbenchMessages.Workbench_showIn; IBindingService bindingService = (IBindingService) PlatformUI .getWorkbench().getAdapter(IBindingService.class); if (bindingService != null) { String keyBinding = bindingService .getBestActiveBindingFormattedFor(IWorkbenchCommandConstants.NAVIGATE_SHOW_IN_QUICK_MENU); if (keyBinding != null) { showInLabel += '\t' + keyBinding; } } showInMenu = new MenuManager(showInLabel); showInMenu.add(ContributionItemFactory.VIEWS_SHOW_IN .create(getViewSite().getWorkbenchWindow())); menu.appendToGroup(MENU_SHOW_IN_GROUP, showInMenu); } /** * Refresh the marker counts * * @param monitor */ void refreshMarkerCounts(IProgressMonitor monitor) { monitor.subTask(MarkerMessages.MarkerView_refreshing_counts); try { totalMarkers = MarkerList.compute(getMarkerTypes()).length; } catch (CoreException e) { Policy.handle(e); return; } } /** * Returns the marker limit or -1 if unlimited * * @return int */ int getMarkerLimit() { // If limits are enabled return it. Otherwise return -1 if (IDEWorkbenchPlugin.getDefault().getPreferenceStore().getBoolean( getMarkerEnablementPreferenceName())) { return IDEWorkbenchPlugin.getDefault().getPreferenceStore().getInt( getMarkerLimitPreferenceName()); } return -1; } /** * Get the name of the marker limit preference. * * @return String */ abstract String getMarkerEnablementPreferenceName(); /* * (non-Javadoc) * * @see org.eclipse.ui.views.markers.internal.TableView#createViewerInput() */ Object createViewerInput() { adapter = new MarkerAdapter(this); return adapter; } /** * Add a listener for the end of the update. * * @param listener */ public void addUpdateFinishListener(IJobChangeListener listener) { updateJob.addJobChangeListener(listener); } /** * Remove a listener for the end of the update. * * @param listener */ public void removeUpdateFinishListener(IJobChangeListener listener) { updateJob.removeJobChangeListener(listener); } /** * Create a listener for working set changes. * * @return IPropertyChangeListener */ private IPropertyChangeListener getWorkingSetListener() { workingSetListener = new IPropertyChangeListener() { /* * (non-Javadoc) * * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent) */ public void propertyChange(PropertyChangeEvent event) { clearEnabledFilters(); refreshViewer(); } }; return workingSetListener; } /** * Schedule an update of the markers with a delay of time * * @param time */ void scheduleMarkerUpdate(int time) { cancelJobs(); getProgressService().schedule(markerProcessJob, time); } /** * Cancel the pending jobs in the receiver. */ private void cancelJobs() { markerProcessJob.cancel(); updateJob.cancel(); } /* * (non-Javadoc) * * @see org.eclipse.ui.views.markers.internal.TableView#createTree(org.eclipse.swt.widgets.Composite) */ protected Tree createTree(Composite parent) { Tree tree = super.createTree(parent); tree.addTreeListener(new TreeAdapter() { /* * (non-Javadoc) * * @see org.eclipse.swt.events.TreeAdapter#treeCollapsed(org.eclipse.swt.events.TreeEvent) */ public void treeCollapsed(TreeEvent e) { updateJob.removeExpandedCategory((MarkerCategory) e.item .getData()); } /* * (non-Javadoc) * * @see org.eclipse.swt.events.TreeAdapter#treeExpanded(org.eclipse.swt.events.TreeEvent) */ public void treeExpanded(TreeEvent e) { updateJob .addExpandedCategory((MarkerCategory) e.item.getData()); } }); return tree; } /** * The focus elements have changed. Update accordingly. */ private void refreshForFocusUpdate() { if (focusElements != null) { updateFilterSelection(focusElements); refreshViewer(); } } /** * Save the current selection in the update for reselection after update. */ protected void preserveSelection() { updateJob.saveSelection(getViewer().getSelection()); } /** * Return the string name of the specific type of marker shown in this view. */ protected abstract String getMarkerName(); /** * Return the undo context associated with operations performed in this * view. By default, return the workspace undo context. Subclasses should * override if a more specific undo context should be used. */ protected IUndoContext getUndoContext() { return (IUndoContext) ResourcesPlugin.getWorkspace().getAdapter( IUndoContext.class); } }