| /******************************************************************************* |
| * Copyright (c) 2004, 2009 Tasktop Technologies 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: |
| * Tasktop Technologies - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.mylyn.internal.context.ui.editors; |
| |
| import java.lang.reflect.Method; |
| import java.util.List; |
| |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.jface.action.IMenuListener; |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.action.MenuManager; |
| import org.eclipse.jface.action.Separator; |
| import org.eclipse.jface.layout.GridDataFactory; |
| import org.eclipse.jface.viewers.AbstractTreeViewer; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.ITreeContentProvider; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.jface.viewers.StructuredViewer; |
| import org.eclipse.mylyn.commons.core.StatusHandler; |
| import org.eclipse.mylyn.context.core.AbstractContextListener; |
| import org.eclipse.mylyn.context.core.AbstractContextStructureBridge; |
| import org.eclipse.mylyn.context.core.ContextChangeEvent; |
| import org.eclipse.mylyn.context.core.ContextCore; |
| import org.eclipse.mylyn.context.core.IInteractionElement; |
| import org.eclipse.mylyn.internal.context.core.ContextCorePlugin; |
| import org.eclipse.mylyn.internal.context.ui.ContextUiPlugin; |
| import org.eclipse.mylyn.internal.context.ui.actions.ContextAttachAction; |
| import org.eclipse.mylyn.internal.context.ui.actions.ContextClearAction; |
| import org.eclipse.mylyn.internal.context.ui.actions.ContextCopyAction; |
| import org.eclipse.mylyn.internal.context.ui.actions.ContextRetrieveAction; |
| import org.eclipse.mylyn.internal.context.ui.views.ContextNodeOpenListener; |
| import org.eclipse.mylyn.internal.provisional.commons.ui.CommonImages; |
| import org.eclipse.mylyn.internal.provisional.commons.ui.DelayedRefreshJob; |
| import org.eclipse.mylyn.tasks.core.ITask; |
| import org.eclipse.mylyn.tasks.ui.TasksUi; |
| import org.eclipse.mylyn.tasks.ui.TasksUiImages; |
| import org.eclipse.mylyn.tasks.ui.editors.TaskEditorInput; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.MouseAdapter; |
| import org.eclipse.swt.events.MouseEvent; |
| import org.eclipse.swt.events.MouseListener; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.events.SelectionListener; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.layout.FillLayout; |
| 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.Label; |
| import org.eclipse.swt.widgets.Menu; |
| import org.eclipse.swt.widgets.Scale; |
| import org.eclipse.ui.IWorkbenchActionConstants; |
| import org.eclipse.ui.forms.IManagedForm; |
| import org.eclipse.ui.forms.editor.FormEditor; |
| import org.eclipse.ui.forms.editor.FormPage; |
| import org.eclipse.ui.forms.events.HyperlinkEvent; |
| import org.eclipse.ui.forms.events.IHyperlinkListener; |
| import org.eclipse.ui.forms.widgets.ExpandableComposite; |
| import org.eclipse.ui.forms.widgets.FormToolkit; |
| import org.eclipse.ui.forms.widgets.Hyperlink; |
| import org.eclipse.ui.forms.widgets.ImageHyperlink; |
| import org.eclipse.ui.forms.widgets.ScrolledForm; |
| import org.eclipse.ui.forms.widgets.Section; |
| import org.eclipse.ui.navigator.CommonViewer; |
| import org.eclipse.ui.navigator.INavigatorContentExtension; |
| |
| /** |
| * @author Mik Kersten |
| */ |
| @SuppressWarnings("deprecation") |
| public class ContextEditorFormPage extends FormPage { |
| |
| private static final int SCALE_STEPS = 14; |
| |
| public static final String ID_VIEWER = "org.eclipse.mylyn.context.ui.navigator.context"; //$NON-NLS-1$ |
| |
| private ScrolledForm form; |
| |
| private Composite sectionClient; |
| |
| private FormToolkit toolkit; |
| |
| private CommonViewer commonViewer; |
| |
| private Hyperlink activateTaskHyperlink; |
| |
| private final ScalableInterestFilter interestFilter = new ScalableInterestFilter(); |
| |
| private Scale doiScale; |
| |
| private ITask task; |
| |
| private class ContextEditorDelayedRefreshJob extends DelayedRefreshJob { |
| |
| public ContextEditorDelayedRefreshJob(StructuredViewer treeViewer, String name) { |
| super(treeViewer, name); |
| } |
| |
| @Override |
| protected void doRefresh(Object[] items) { |
| if (commonViewer != null && !commonViewer.getTree().isDisposed()) { |
| commonViewer.refresh(); |
| if (items != null) { |
| for (Object item : items) { |
| updateExpansionState(item); |
| } |
| } else { |
| updateExpansionState(null); |
| } |
| } |
| if (invisiblePart != null) { |
| invisiblePart.updateInvisibleElementsSection(); |
| } |
| } |
| |
| protected void updateExpansionState(Object item) { |
| if (commonViewer != null && !commonViewer.getTree().isDisposed()) { |
| try { |
| commonViewer.getTree().setRedraw(false); |
| if (/*!mouseDown && */item == null) { |
| commonViewer.expandAll(); |
| } else if (item != null && item instanceof IInteractionElement) { |
| IInteractionElement node = (IInteractionElement) item; |
| AbstractContextStructureBridge structureBridge = ContextCorePlugin.getDefault() |
| .getStructureBridge(node.getContentType()); |
| Object objectToRefresh = structureBridge.getObjectForHandle(node.getHandleIdentifier()); |
| if (objectToRefresh != null) { |
| commonViewer.expandToLevel(objectToRefresh, AbstractTreeViewer.ALL_LEVELS); |
| } |
| } |
| } finally { |
| commonViewer.getTree().setRedraw(true); |
| } |
| } |
| } |
| |
| } |
| |
| private final AbstractContextListener CONTEXT_LISTENER = new AbstractContextListener() { |
| |
| @Override |
| public void contextChanged(ContextChangeEvent event) { |
| Control partControl = getPartControl(); |
| switch (event.getEventKind()) { |
| case ACTIVATED: |
| if (partControl != null && !partControl.isDisposed()) { |
| updateContentArea(); |
| refresh(); |
| } |
| break; |
| case DEACTIVATED: |
| if (partControl != null && !partControl.isDisposed()) { |
| updateContentArea(); |
| refresh(); |
| } |
| break; |
| case CLEARED: |
| if (event.isActiveContext()) { |
| refresh(); |
| } |
| break; |
| case ELEMENTS_DELETED: |
| case INTEREST_CHANGED: |
| case LANDMARKS_ADDED: |
| case LANDMARKS_REMOVED: |
| refresh(event.getElements()); |
| break; |
| } |
| } |
| |
| }; |
| |
| public ContextEditorFormPage(FormEditor editor, String id, String title) { |
| super(editor, id, title); |
| } |
| |
| @Override |
| protected void createFormContent(IManagedForm managedForm) { |
| ContextCore.getContextManager().addListener(CONTEXT_LISTENER); |
| task = ((TaskEditorInput) getEditorInput()).getTask(); |
| |
| form = managedForm.getForm(); |
| |
| toolkit = managedForm.getToolkit(); |
| |
| //form.setImage(TaskListImages.getImage(TaskListImages.TASK_ACTIVE_CENTERED)); |
| //form.setText(LABEL); |
| //toolkit.decorateFormHeading(form.getForm()); |
| |
| form.getBody().setLayout(new FillLayout()); |
| Composite composite = new Composite(form.getBody(), SWT.NONE) { |
| @Override |
| public Point computeSize(int widhtHint, int heigtHint, boolean changed) { |
| Rectangle clientArea = getClientArea(); |
| return super.computeSize(widhtHint, clientArea.height, changed); |
| } |
| }; |
| toolkit.adapt(composite); |
| composite.setLayout(new GridLayout(2, false)); |
| |
| createActionsSection(composite); |
| createContentSection(composite); |
| |
| form.reflow(true); |
| } |
| |
| @Override |
| public void dispose() { |
| super.dispose(); |
| // ContextUiPlugin.getViewerManager().removeManagedViewer(commonViewer, |
| // this); |
| ContextCore.getContextManager().removeListener(CONTEXT_LISTENER); |
| } |
| |
| private void createActionsSection(Composite composite) { |
| Section section = toolkit.createSection(composite, ExpandableComposite.TITLE_BAR | ExpandableComposite.EXPANDED); |
| section.setText(Messages.ContextEditorFormPage_Actions); |
| |
| section.setLayout(new GridLayout()); |
| GridData sectionGridData = new GridData(GridData.VERTICAL_ALIGN_BEGINNING); |
| sectionGridData.widthHint = 80; |
| section.setLayoutData(sectionGridData); |
| |
| Composite sectionClient = toolkit.createComposite(section); |
| section.setClient(sectionClient); |
| sectionClient.setLayout(new GridLayout(2, false)); |
| sectionClient.setLayoutData(new GridData()); |
| |
| ImageHyperlink filterImage = toolkit.createImageHyperlink(sectionClient, SWT.NONE); |
| filterImage.setImage(CommonImages.getImage(CommonImages.FILTER)); |
| filterImage.setToolTipText(Messages.ContextEditorFormPage_Show_All_Elements); |
| filterImage.addHyperlinkListener(new IHyperlinkListener() { |
| |
| public void linkActivated(HyperlinkEvent e) { |
| doiScale.setSelection(0); |
| interestFilter.setThreshold(Integer.MIN_VALUE); |
| refresh(); |
| } |
| |
| public void linkEntered(HyperlinkEvent e) { |
| // ignore |
| } |
| |
| public void linkExited(HyperlinkEvent e) { |
| // ignore |
| } |
| }); |
| |
| doiScale = new Scale(sectionClient, SWT.FLAT); |
| GridData scaleGridData = new GridData(GridData.FILL_HORIZONTAL); |
| scaleGridData.heightHint = 36; |
| scaleGridData.widthHint = 80; |
| doiScale.setLayoutData(scaleGridData); |
| doiScale.setPageIncrement(1); |
| doiScale.setMinimum(0); |
| doiScale.setSelection(SCALE_STEPS / 2); |
| doiScale.setMaximum(SCALE_STEPS); |
| doiScale.addSelectionListener(new SelectionListener() { |
| public void widgetSelected(SelectionEvent e) { |
| updateFilterThreshold(); |
| } |
| |
| public void widgetDefaultSelected(SelectionEvent e) { |
| // don't care about default selection |
| } |
| }); |
| |
| if (!isActiveTask()) { |
| doiScale.setEnabled(false); |
| } |
| |
| Label attachImage = toolkit.createLabel(sectionClient, ""); //$NON-NLS-1$ |
| attachImage.setImage(CommonImages.getImage(TasksUiImages.CONTEXT_ATTACH)); |
| attachImage.setEnabled(task != null); |
| Hyperlink attachHyperlink = toolkit.createHyperlink(sectionClient, |
| Messages.ContextEditorFormPage_Attach_context_, SWT.NONE); |
| attachHyperlink.setEnabled(task != null); |
| attachHyperlink.addMouseListener(new MouseListener() { |
| |
| public void mouseUp(MouseEvent e) { |
| new ContextAttachAction().run(task); |
| } |
| |
| public void mouseDoubleClick(MouseEvent e) { |
| // ignore |
| } |
| |
| public void mouseDown(MouseEvent e) { |
| // ignore |
| } |
| }); |
| |
| Label retrieveImage = toolkit.createLabel(sectionClient, ""); //$NON-NLS-1$ |
| retrieveImage.setImage(CommonImages.getImage(TasksUiImages.CONTEXT_RETRIEVE)); |
| retrieveImage.setEnabled(task != null); |
| Hyperlink retrieveHyperlink = toolkit.createHyperlink(sectionClient, |
| Messages.ContextEditorFormPage_Retrieve_Context_, SWT.NONE); |
| retrieveHyperlink.setEnabled(task != null); |
| retrieveHyperlink.addMouseListener(new MouseListener() { |
| |
| public void mouseUp(MouseEvent e) { |
| new ContextRetrieveAction().run(task); |
| } |
| |
| public void mouseDoubleClick(MouseEvent e) { |
| // ignore |
| } |
| |
| public void mouseDown(MouseEvent e) { |
| // ignore |
| } |
| }); |
| |
| Label copyImage = toolkit.createLabel(sectionClient, ""); //$NON-NLS-1$ |
| copyImage.setImage(CommonImages.getImage(TasksUiImages.CONTEXT_COPY)); |
| Hyperlink copyHyperlink = toolkit.createHyperlink(sectionClient, |
| Messages.ContextEditorFormPage_Copy_Context_to_, SWT.NONE); |
| copyHyperlink.addMouseListener(new MouseListener() { |
| |
| public void mouseUp(MouseEvent e) { |
| new ContextCopyAction().run(task); |
| } |
| |
| public void mouseDoubleClick(MouseEvent e) { |
| // ignore |
| } |
| |
| public void mouseDown(MouseEvent e) { |
| // ignore |
| } |
| }); |
| |
| Label clearImage = toolkit.createLabel(sectionClient, ""); //$NON-NLS-1$ |
| clearImage.setImage(CommonImages.getImage(TasksUiImages.CONTEXT_CLEAR)); |
| Hyperlink clearHyperlink = toolkit.createHyperlink(sectionClient, Messages.ContextEditorFormPage_RemoveAll, |
| SWT.NONE); |
| clearHyperlink.addMouseListener(new MouseListener() { |
| |
| public void mouseUp(MouseEvent e) { |
| new ContextClearAction().run(task); |
| } |
| |
| public void mouseDoubleClick(MouseEvent e) { |
| // ignore |
| } |
| |
| public void mouseDown(MouseEvent e) { |
| // ignore |
| } |
| }); |
| section.setExpanded(true); |
| } |
| |
| private ContextEditorDelayedRefreshJob refreshJob; |
| |
| private InvisibleContextElementsPart invisiblePart; |
| |
| /** |
| * Scales logarithmically to a reasonable interest threshold range (e.g. -10000..10000). |
| */ |
| protected void updateFilterThreshold() { |
| if (doiScale.getSelection() == 0) { |
| interestFilter.setThreshold(Integer.MIN_VALUE); |
| } else if (doiScale.getSelection() == SCALE_STEPS) { |
| interestFilter.setThreshold(Integer.MAX_VALUE); |
| } else { |
| double setting = doiScale.getSelection() - (SCALE_STEPS / 2); |
| double threshold = Math.signum(setting) * Math.pow(Math.exp(Math.abs(setting)), 1.5); |
| interestFilter.setThreshold(threshold); |
| } |
| refresh(); |
| } |
| |
| private void refresh() { |
| createRefreshJob(); |
| if (refreshJob != null) { |
| refreshJob.refresh(); |
| } |
| } |
| |
| private synchronized void createRefreshJob() { |
| if (commonViewer == null) { |
| return; |
| } |
| if (refreshJob == null) { |
| refreshJob = new ContextEditorDelayedRefreshJob(commonViewer, "refresh viewer"); //$NON-NLS-1$ |
| } |
| } |
| |
| private void refresh(List<IInteractionElement> elements) { |
| createRefreshJob(); |
| if (refreshJob != null) { |
| refreshJob.doRefresh(elements.toArray()); |
| } |
| } |
| |
| private void createContentSection(Composite composite) { |
| Section section = toolkit.createSection(composite, ExpandableComposite.TITLE_BAR | ExpandableComposite.EXPANDED); |
| section.setText(Messages.ContextEditorFormPage_Elements); |
| section.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| |
| sectionClient = toolkit.createComposite(section); |
| sectionClient.setLayout(new FillLayout()); |
| section.setClient(sectionClient); |
| |
| updateContentArea(); |
| |
| toolkit.createLabel(composite, " "); //$NON-NLS-1$ |
| |
| invisiblePart = new InvisibleContextElementsPart(commonViewer); |
| Control invisibleControl = invisiblePart.createControl(toolkit, composite); |
| GridDataFactory.fillDefaults().applyTo(invisibleControl); |
| } |
| |
| private void createActivateTaskHyperlink(Composite parent) { |
| activateTaskHyperlink = toolkit.createHyperlink(parent, |
| Messages.ContextEditorFormPage_Activate_task_to_edit_context, SWT.NONE); |
| activateTaskHyperlink.addMouseListener(new MouseAdapter() { |
| @Override |
| public void mouseUp(MouseEvent e) { |
| TasksUi.getTaskActivityManager().activateTask(task); |
| } |
| }); |
| } |
| |
| /** |
| * Disposes the viewer when the current task is not active or creates it if task is activated. |
| */ |
| private void updateContentArea() { |
| if (isActiveTask()) { |
| doiScale.setEnabled(true); |
| doiScale.setSelection(SCALE_STEPS / 2); |
| if (activateTaskHyperlink != null) { |
| activateTaskHyperlink.dispose(); |
| activateTaskHyperlink = null; |
| } |
| if (commonViewer == null) { |
| createViewer(sectionClient); |
| } |
| |
| if (invisiblePart != null) { |
| invisiblePart.setCommonViewer(commonViewer); |
| } |
| updateFilterThreshold(); |
| } else { |
| doiScale.setEnabled(false); |
| doiScale.setSelection(SCALE_STEPS / 2); |
| if (commonViewer != null) { |
| commonViewer.getControl().dispose(); |
| commonViewer = null; |
| if (invisiblePart != null) { |
| invisiblePart.setCommonViewer(commonViewer); |
| } |
| disposeRefreshJob(); |
| } |
| if (activateTaskHyperlink == null) { |
| createActivateTaskHyperlink(sectionClient); |
| } |
| } |
| sectionClient.layout(); |
| } |
| |
| private synchronized void disposeRefreshJob() { |
| if (refreshJob != null) { |
| refreshJob.cancel(); |
| refreshJob = null; |
| } |
| } |
| |
| private boolean isActiveTask() { |
| return task.equals(TasksUi.getTaskActivityManager().getActiveTask()); |
| } |
| |
| private void createViewer(Composite parent) { |
| commonViewer = new CommonViewer(ID_VIEWER, parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); |
| commonViewer.setUseHashlookup(true); |
| commonViewer.addFilter(interestFilter); |
| commonViewer.addOpenListener(new ContextNodeOpenListener(commonViewer)); |
| try { |
| commonViewer.getControl().setRedraw(false); |
| |
| forceFlatLayoutOfJavaContent(commonViewer); |
| |
| commonViewer.setInput(getSite().getPage().getInput()); |
| getSite().setSelectionProvider(commonViewer); |
| hookContextMenu(); |
| commonViewer.expandAll(); |
| } finally { |
| commonViewer.getControl().setRedraw(true); |
| } |
| } |
| |
| public static void forceFlatLayoutOfJavaContent(CommonViewer commonViewer) { |
| INavigatorContentExtension javaContent = commonViewer.getNavigatorContentService().getContentExtensionById( |
| "org.eclipse.jdt.java.ui.javaContent"); //$NON-NLS-1$ |
| if (javaContent != null) { |
| ITreeContentProvider treeContentProvider = javaContent.getContentProvider(); |
| // TODO: find a sane way of doing this, perhaps via AbstractContextUiBridge, should be: |
| // if (javaContent.getContentProvider() != null) { |
| // JavaNavigatorContentProvider java = |
| // (JavaNavigatorContentProvider)javaContent.getContentProvider(); |
| // java.setIsFlatLayout(true); |
| // } |
| try { |
| Class<?> clazz = treeContentProvider.getClass().getSuperclass(); |
| Method method = clazz.getDeclaredMethod("setIsFlatLayout", new Class[] { boolean.class }); //$NON-NLS-1$ |
| method.invoke(treeContentProvider, new Object[] { true }); |
| } catch (Exception e) { |
| StatusHandler.log(new Status(IStatus.ERROR, ContextUiPlugin.ID_PLUGIN, |
| "Could not set flat layout on Java content provider", e)); //$NON-NLS-1$ |
| } |
| } |
| } |
| |
| private void hookContextMenu() { |
| MenuManager menuManager = new MenuManager("#PopupMenu"); //$NON-NLS-1$ |
| menuManager.setRemoveAllWhenShown(true); |
| menuManager.addMenuListener(new IMenuListener() { |
| public void menuAboutToShow(IMenuManager manager) { |
| fillContextMenu(manager); |
| } |
| }); |
| Menu menu = menuManager.createContextMenu(commonViewer.getControl()); |
| commonViewer.getControl().setMenu(menu); |
| getSite().registerContextMenu(menuManager, commonViewer); |
| } |
| |
| protected void fillContextMenu(IMenuManager manager) { |
| //manager.add(removeFromContextAction); |
| manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); |
| } |
| |
| public ISelection getSelection() { |
| if (getSite() != null && getSite().getSelectionProvider() != null) { |
| return getSite().getSelectionProvider().getSelection(); |
| } else { |
| return StructuredSelection.EMPTY; |
| } |
| } |
| } |