### Eclipse Workspace Patch 1.0 #P org.eclipse.mylyn.tasks.ui Index: META-INF/MANIFEST.MF =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/META-INF/MANIFEST.MF,v retrieving revision 1.415 diff -u -r1.415 MANIFEST.MF --- META-INF/MANIFEST.MF 7 Apr 2010 20:54:55 -0000 1.415 +++ META-INF/MANIFEST.MF 3 May 2010 19:35:47 -0000 @@ -17,6 +17,7 @@ org.eclipse.ui.ide, org.eclipse.ui.views, org.eclipse.ui.workbench.texteditor, + org.eclipse.ui.navigator, org.eclipse.mylyn.context.core;bundle-version="[3.0.0,4.0.0)", org.eclipse.mylyn.commons.core;bundle-version="[3.0.0,4.0.0)", org.eclipse.mylyn.monitor.ui;bundle-version="[3.0.0,4.0.0)", Index: plugin.xml =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/plugin.xml,v retrieving revision 1.377 diff -u -r1.377 plugin.xml --- plugin.xml 3 Apr 2010 01:33:20 -0000 1.377 +++ plugin.xml 3 May 2010 19:35:47 -0000 @@ -631,7 +631,12 @@ value="org.eclipse.mylyn.tasks.ui.views.tasks"> - + + + @@ -828,6 +833,13 @@ style="push" toolbarPath="org.eclipse.search.searchActionSet/Search" tooltip="%OpenTaskAction.tooltip"/> + + @@ -835,6 +847,12 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: src/org/eclipse/mylyn/internal/tasks/ui/CommonViewerTaskDataContentProvider.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/CommonViewerTaskDataContentProvider.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/CommonViewerTaskDataContentProvider.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/tasks/ui/CommonViewerTaskDataContentProvider.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2010 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.tasks.ui; + +import org.eclipse.jface.viewers.ITreeContentProvider; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.mylyn.tasks.core.data.TaskData; + +public class CommonViewerTaskDataContentProvider implements ITreeContentProvider { + + public Object[] getChildren(Object parentElement) { + Object[] result = {}; + if (parentElement instanceof TaskData) { + TaskData node = (TaskData) parentElement; + result = node.getRoot().getAttributes().values().toArray(); +// } else if (parentElement instanceof TaskAttribute) { +// TaskAttribute node = (TaskAttribute) parentElement; +// result = node.getAttributes().values().toArray(); + } + return result; + } + + public Object[] getElements(Object inputElement) { + return getChildren(inputElement); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object) + */ + public Object getParent(Object element) { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object) + */ + public boolean hasChildren(Object element) { + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.IContentProvider#dispose() + */ + public void dispose() { + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object) + */ + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + +} Index: src/org/eclipse/mylyn/internal/tasks/ui/CommonViewerTaskDataFilter.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/CommonViewerTaskDataFilter.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/CommonViewerTaskDataFilter.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/tasks/ui/CommonViewerTaskDataFilter.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2010 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.tasks.ui; + +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.mylyn.tasks.core.data.TaskAttribute; +import org.eclipse.ui.internal.misc.StringMatcher; + +public class CommonViewerTaskDataFilter extends ViewerFilter { + + private StringMatcher stringMatcher; + + @Override + public boolean select(Viewer viewer, Object parentElement, Object element) { + if (element instanceof TaskAttribute) { + TaskAttribute attribute = (TaskAttribute) element; + String metaType = attribute.getMetaData().getType(); + if (TaskAttribute.TYPE_OPERATION.equals(metaType)) { + return false; + } + } + if ((stringMatcher == null) || ((viewer instanceof TreeViewer) == false)) { + return true; + } + TreeViewer treeViewer = (TreeViewer) viewer; + // Match the pattern against the label of the given element + String matchName = ((ILabelProvider) treeViewer.getLabelProvider()).getText(element); + // Element passes the filter if it matches the pattern + if ((matchName != null) && stringMatcher.match(matchName)) { + return true; + } + return false; + } + + public void setStringMatcher(StringMatcher stringMatcher) { + this.stringMatcher = stringMatcher; + } + +} Index: src/org/eclipse/mylyn/internal/tasks/ui/CommonViewerTaskDataLabelProvider.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/CommonViewerTaskDataLabelProvider.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/CommonViewerTaskDataLabelProvider.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/tasks/ui/CommonViewerTaskDataLabelProvider.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2010 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.tasks.ui; + +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.mylyn.tasks.core.data.TaskAttribute; +import org.eclipse.mylyn.tasks.core.data.TaskAttributeMetaData; +import org.eclipse.mylyn.tasks.core.data.TaskData; +import org.eclipse.swt.graphics.Image; + +public class CommonViewerTaskDataLabelProvider implements ILabelProvider { + public String getText(Object element) { + String result = ""; //$NON-NLS-1$ + if (element instanceof TaskData) { + TaskData node = (TaskData) element; + result = node.getTaskId(); + } else if (element instanceof TaskAttribute) { + TaskAttribute node = (TaskAttribute) element; + TaskAttributeMetaData meta = node.getMetaData(); + if (meta != null) { + String lable = meta.getLabel(); + if (lable != null) { + result = lable + " (" + node.getId() + ")"; + } else { + if (TaskAttribute.TYPE_ATTACHMENT.equals(meta.getType())) { + result = "Attachment: " + node.getValue(); //$NON-NLS-1$ + } else if (TaskAttribute.TYPE_COMMENT.equals(meta.getType())) { + result = "Comment: " + node.getValue(); //$NON-NLS-1$ + } else { + result = "<" + node.getId() + ">"; //$NON-NLS-1$//$NON-NLS-2$ + } + } + } + } else if (element instanceof String) { + result = (String) element; + } + return result; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.ILabelProvider#getImage(java.lang.Object) + */ + public Image getImage(Object element) { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener) + */ + public void addListener(ILabelProviderListener listener) { + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose() + */ + public void dispose() { + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, java.lang.String) + */ + public boolean isLabelProperty(Object element, String property) { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener) + */ + public void removeListener(ILabelProviderListener listener) { + } + +} Index: src/org/eclipse/mylyn/internal/tasks/ui/CommonViewerTaskDataOpenListener.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/CommonViewerTaskDataOpenListener.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/CommonViewerTaskDataOpenListener.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/tasks/ui/CommonViewerTaskDataOpenListener.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,160 @@ +/******************************************************************************* + * Copyright (c) 2010 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.tasks.ui; + +import org.eclipse.jface.viewers.DoubleClickEvent; +import org.eclipse.jface.viewers.IDoubleClickListener; +import org.eclipse.jface.viewers.IOpenListener; +import org.eclipse.jface.viewers.OpenEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.mylyn.internal.provisional.commons.ui.CommonFormUtil; +import org.eclipse.mylyn.internal.tasks.core.TaskAttachment; +import org.eclipse.mylyn.internal.tasks.ui.editors.TaskEditorAttributePart; +import org.eclipse.mylyn.tasks.core.data.TaskAttribute; +import org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPage; +import org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPart; +import org.eclipse.mylyn.tasks.ui.editors.TaskEditor; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.TableItem; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.forms.IManagedForm; +import org.eclipse.ui.forms.editor.IFormPage; +import org.eclipse.ui.forms.widgets.ExpandableComposite; +import org.eclipse.ui.forms.widgets.ScrolledForm; +import org.eclipse.ui.forms.widgets.Section; + +public class CommonViewerTaskDataOpenListener implements IOpenListener, IDoubleClickListener, MouseListener { + + private final Viewer viewer; + + public CommonViewerTaskDataOpenListener(Viewer viewer) { + this.viewer = viewer; + } + + public void mouseDoubleClick(MouseEvent e) { + setSelection(e); + } + + public void mouseDown(MouseEvent e) { + setSelection(e); + } + + public void mouseUp(MouseEvent e) { + // ignore + + } + + public void doubleClick(DoubleClickEvent event) { + open(null); + } + + public void open(OpenEvent event) { + StructuredSelection selection = (StructuredSelection) viewer.getSelection(); + Object object = selection.getFirstElement(); + if (object instanceof TaskAttribute) { + TaskAttribute attribute = (TaskAttribute) object; + IEditorPart editorPart = PlatformUI.getWorkbench() + .getActiveWorkbenchWindow() + .getActivePage() + .getActiveEditor(); + AbstractTaskEditorPage taskEditorPage = null; + if (editorPart instanceof TaskEditor) { + TaskEditor taskEditor = (TaskEditor) editorPart; + IFormPage formPage = taskEditor.getActivePageInstance(); + if (formPage instanceof AbstractTaskEditorPage) { + taskEditorPage = (AbstractTaskEditorPage) formPage; + } + } + if (TaskAttribute.TYPE_ATTACHMENT.equals(attribute.getMetaData().getType())) { + AbstractTaskEditorPart actionPart = taskEditorPage.getPart(AbstractTaskEditorPage.ID_PART_ATTACHMENTS); + if (actionPart != null && actionPart.getControl() instanceof ExpandableComposite) { + CommonFormUtil.setExpanded((ExpandableComposite) actionPart.getControl(), true); + if (actionPart.getControl() instanceof Section) { + Control client = actionPart.getControl(); + if (client instanceof Composite) { + for (Control control : ((Composite) client).getChildren()) { + if (control instanceof Composite) { + for (Control control1 : ((Composite) control).getChildren()) { + if (control1 instanceof org.eclipse.swt.widgets.Table) { + org.eclipse.swt.widgets.Table attachmentTable = ((org.eclipse.swt.widgets.Table) control1); + TableItem[] attachments = attachmentTable.getItems(); + int index = 0; + for (TableItem attachment : attachments) { + TaskAttachment attachmentData = ((TaskAttachment) attachment.getData()); + if (attachmentData.getTaskAttribute() == attribute) { + attachmentTable.deselectAll(); + attachmentTable.select(index); + IManagedForm mform = actionPart.getManagedForm(); + ScrolledForm form = mform.getForm(); +// EditorUtil.focusOn(form, attachmentTable, 30); + taskEditorPage.focusOn(attachmentTable); + break; + } + index++; + } + } + } + } + } + } + } + } + } else { + if (TaskAttribute.TYPE_COMMENT.equals(attribute.getMetaData().getType())) { + AbstractTaskEditorPart actionPart = taskEditorPage.getPart(AbstractTaskEditorPage.ID_PART_COMMENTS); + if (actionPart != null && actionPart.getControl() instanceof ExpandableComposite) { + CommonFormUtil.setExpanded((ExpandableComposite) actionPart.getControl(), true); + if (actionPart.getControl() instanceof Section) { + Control client = ((Section) actionPart.getControl()).getClient(); + if (client instanceof Composite) { + for (Control control : ((Composite) client).getChildren()) { + // toggle subsections + if (control instanceof Section) { + CommonFormUtil.setExpanded((Section) control, true); + } + } + } + } + } + } else { + TaskEditorAttributePart actionPart = (TaskEditorAttributePart) taskEditorPage.getPart(AbstractTaskEditorPage.ID_PART_ATTRIBUTES); + Section section = actionPart.getSection(); + boolean expanded = section.isExpanded(); + if (!expanded && actionPart != null && actionPart.getControl() instanceof ExpandableComposite) { + CommonFormUtil.setExpanded((ExpandableComposite) actionPart.getControl(), true); + if (!expanded) { + CommonFormUtil.setExpanded((ExpandableComposite) actionPart.getControl(), false); + } + } + } + taskEditorPage.reveal(attribute.getId()); + } + } + } + + private void setSelection(MouseEvent event) { + try { + Object selection = ((Tree) event.getSource()).getSelection()[0].getData(); + viewer.setSelection(new StructuredSelection(selection)); + open(null); + } catch (Exception e) { + // ignore + } + } + +} Index: src/org/eclipse/mylyn/internal/tasks/ui/actions/QuickOutlineTaskDataAction.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/actions/QuickOutlineTaskDataAction.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/actions/QuickOutlineTaskDataAction.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/tasks/ui/actions/QuickOutlineTaskDataAction.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2010 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.tasks.ui.actions; + +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.mylyn.internal.tasks.core.TaskTask; +import org.eclipse.mylyn.internal.tasks.ui.views.QuickOutlineTaskDataDialog; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.IWorkbenchWindowActionDelegate; +import org.eclipse.ui.PlatformUI; + +public class QuickOutlineTaskDataAction implements IWorkbenchWindowActionDelegate { + + private QuickOutlineTaskDataDialog inplaceDialog; + + private TaskTask sel; + + public void run(IAction action) { + Shell parent = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); + inplaceDialog = new QuickOutlineTaskDataDialog(parent); + inplaceDialog.open(); + inplaceDialog.setFocus(); + } + + public void selectionChanged(IAction action, ISelection selection) { + // ignore + if (selection instanceof StructuredSelection) { + StructuredSelection a = (StructuredSelection) selection; + if (a.size() > 0) { + if (a.getFirstElement() instanceof TaskTask) { + sel = (TaskTask) a.getFirstElement(); + } + } + } + } + + public void dispose() { + inplaceDialog = null; + } + + public void init(IWorkbenchWindow window) { + // ignore + } + +} Index: src/org/eclipse/mylyn/internal/tasks/ui/editors/EditorUtil.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/EditorUtil.java,v retrieving revision 1.40 diff -u -r1.40 EditorUtil.java --- src/org/eclipse/mylyn/internal/tasks/ui/editors/EditorUtil.java 15 Oct 2009 02:27:13 -0000 1.40 +++ src/org/eclipse/mylyn/internal/tasks/ui/editors/EditorUtil.java 3 May 2010 19:35:49 -0000 @@ -153,7 +153,7 @@ * @param control * The StyledText to scroll to */ - private static void focusOn(ScrolledForm form, Control control) { + public static void focusOn(ScrolledForm form, Control control) { int pos = 0; control.setEnabled(true); control.setFocus(); @@ -405,8 +405,11 @@ } else { roundedBorder.setLayout(GridLayoutFactory.fillDefaults().margins(0, 6).create()); } - GridDataFactory.fillDefaults().align(SWT.FILL, SWT.BEGINNING).hint(EditorUtil.MAXIMUM_WIDTH, SWT.DEFAULT).grab( - true, false).applyTo(roundedBorder); + GridDataFactory.fillDefaults() + .align(SWT.FILL, SWT.BEGINNING) + .hint(EditorUtil.MAXIMUM_WIDTH, SWT.DEFAULT) + .grab(true, false) + .applyTo(roundedBorder); return roundedBorder; } @@ -432,8 +435,11 @@ textFont.dispose(); } }); - Color color = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry().get( - CommonThemes.COLOR_COMPLETED); + Color color = PlatformUI.getWorkbench() + .getThemeManager() + .getCurrentTheme() + .getColorRegistry() + .get(CommonThemes.COLOR_COMPLETED); text.setForeground(color); return textFont; } Index: src/org/eclipse/mylyn/internal/tasks/ui/views/Messages.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/views/Messages.java,v retrieving revision 1.11 diff -u -r1.11 Messages.java --- src/org/eclipse/mylyn/internal/tasks/ui/views/Messages.java 5 Nov 2009 12:16:24 -0000 1.11 +++ src/org/eclipse/mylyn/internal/tasks/ui/views/Messages.java 3 May 2010 19:35:49 -0000 @@ -29,6 +29,8 @@ public static String PriorityDropDownAction_Filter_Priority_Lower_Than; + public static String QuickOutlineTaskDataDialog_InfoText; + public static String RepositoryElementActionGroup_Copy_Detail_Menu_Label; public static String RepositoryElementActionGroup_New; Index: src/org/eclipse/mylyn/internal/tasks/ui/views/QuickOutlineTaskDataDialog.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/views/QuickOutlineTaskDataDialog.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/views/QuickOutlineTaskDataDialog.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/tasks/ui/views/QuickOutlineTaskDataDialog.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,462 @@ +/******************************************************************************* + * Copyright (c) 2010 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.tasks.ui.views; + +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.PopupDialog; +import org.eclipse.jface.text.IInformationControl; +import org.eclipse.jface.text.IInformationControlExtension; +import org.eclipse.jface.text.IInformationControlExtension2; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.mylyn.internal.tasks.ui.CommonViewerTaskDataFilter; +import org.eclipse.mylyn.internal.tasks.ui.CommonViewerTaskDataOpenListener; +import org.eclipse.mylyn.tasks.core.data.TaskData; +import org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPage; +import org.eclipse.mylyn.tasks.ui.editors.TaskEditor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.FocusListener; +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.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.FontMetrics; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.Tree; +import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.forms.editor.IFormPage; +import org.eclipse.ui.internal.misc.StringMatcher; +import org.eclipse.ui.navigator.CommonViewer; + +public class QuickOutlineTaskDataDialog extends PopupDialog implements IInformationControl, + IInformationControlExtension, IInformationControlExtension2, DisposeListener { + + public static final String ID_VIEWER = "org.eclipse.mylyn.internal.tasks.ui.taskdata.quick"; //$NON-NLS-1$ + + private CommonViewer commonViewer; + + private Text fFilterText; + + private StringMatcher fStringMatcher; + + private CommonViewerTaskDataFilter namePatternFilter; + + private CommonViewerTaskDataOpenListener openListener; + + public QuickOutlineTaskDataDialog(Shell parent) { + super(parent, SWT.RESIZE, true, true, true, true, true, null, Messages.QuickOutlineTaskDataDialog_InfoText); + create(); + } + + @Override + public boolean close() { + // nothing additional to dispose + return super.close(); + } + + @Override + protected Control createDialogArea(Composite parent) { + createViewer(parent); + createUIListenersTreeViewer(); + addDisposeListener(this); + + return commonViewer.getControl(); + } + + private void createViewer(Composite parent) { + Control composite = super.createDialogArea(parent); + commonViewer = createCommonViewer((Composite) composite); + + openListener = new CommonViewerTaskDataOpenListener(commonViewer); + + commonViewer.addOpenListener(openListener); + commonViewer.getTree().addMouseListener(openListener); + + namePatternFilter = new CommonViewerTaskDataFilter(); + commonViewer.addFilter(namePatternFilter); + + try { + commonViewer.getControl().setRedraw(false); + IEditorPart activeEditor = PlatformUI.getWorkbench() + .getActiveWorkbenchWindow() + .getActivePage() + .getActiveEditor(); + if (activeEditor instanceof TaskEditor) { + TaskEditor taskEditor = (TaskEditor) activeEditor; + IFormPage pageInstance = taskEditor.getActivePageInstance(); + if (pageInstance instanceof AbstractTaskEditorPage) { + AbstractTaskEditorPage taskEditorPage = (AbstractTaskEditorPage) pageInstance; + TaskData taskData = taskEditorPage.getModel().getTaskData(); + commonViewer.setInput(taskData); + } + } + commonViewer.expandAll(); + } finally { + commonViewer.getControl().setRedraw(true); + } + } + + protected CommonViewer createCommonViewer(Composite parent) { + CommonViewer viewer = new CommonViewer(ID_VIEWER, parent, SWT.H_SCROLL | SWT.V_SCROLL); + viewer.setUseHashlookup(true); + viewer.getControl().setLayoutData(new GridData(500, 400)); + return viewer; + } + + @Override + protected void fillDialogMenu(IMenuManager dialogMenu) { + dialogMenu.add(new Separator()); + super.fillDialogMenu(dialogMenu); + } + + private void createUIListenersTreeViewer() { + final Tree tree = commonViewer.getTree(); + tree.addKeyListener(new KeyListener() { + public void keyPressed(KeyEvent e) { + if (e.character == 0x1B) { + // Dispose on ESC key press + dispose(); + } + } + + public void keyReleased(KeyEvent e) { + // ignore + } + }); + + tree.addMouseListener(new MouseAdapter() { + @Override + public void mouseUp(MouseEvent e) { + handleTreeViewerMouseUp(tree, e); + } + }); + + tree.addSelectionListener(new SelectionListener() { + public void widgetSelected(SelectionEvent e) { + // ignore + } + + public void widgetDefaultSelected(SelectionEvent e) { + gotoSelectedElement(); + } + }); + } + + private void handleTreeViewerMouseUp(final Tree tree, MouseEvent e) { + if ((tree.getSelectionCount() < 1) || (e.button != 1) || (tree.equals(e.getSource()) == false)) { + return; + } + // Selection is made in the selection changed listener + Object object = tree.getItem(new Point(e.x, e.y)); + TreeItem selection = tree.getSelection()[0]; + if (selection.equals(object)) { + gotoSelectedElement(); + } + } + + private Object getSelectedElement() { + if (commonViewer == null) { + return null; + } + return ((IStructuredSelection) commonViewer.getSelection()).getFirstElement(); + } + + public void addDisposeListener(DisposeListener listener) { + getShell().addDisposeListener(listener); + } + + public void addFocusListener(FocusListener listener) { + getShell().addFocusListener(listener); + } + + public Point computeSizeHint() { + // Note that it already has the persisted size if persisting is enabled. + return getShell().getSize(); + } + + public void dispose() { + close(); + } + + public boolean isFocusControl() { + if (commonViewer.getControl().isFocusControl() || fFilterText.isFocusControl()) { + return true; + } + return false; + } + + public void removeDisposeListener(DisposeListener listener) { + getShell().removeDisposeListener(listener); + } + + public void removeFocusListener(FocusListener listener) { + getShell().removeFocusListener(listener); + } + + public void setBackgroundColor(Color background) { + applyBackgroundColor(background, getContents()); + } + + public void setFocus() { + getShell().forceFocus(); + fFilterText.setFocus(); + } + + public void setForegroundColor(Color foreground) { + applyForegroundColor(foreground, getContents()); + } + + public void setInformation(String information) { + // See IInformationControlExtension2 + } + + public void setLocation(Point location) { + /* + * If the location is persisted, it gets managed by PopupDialog - fine. Otherwise, the location is + * computed in Window#getInitialLocation, which will center it in the parent shell / main + * monitor, which is wrong for two reasons: + * - we want to center over the editor / subject control, not the parent shell + * - the center is computed via the initalSize, which may be also wrong since the size may + * have been updated since via min/max sizing of AbstractInformationControlManager. + * In that case, override the location with the one computed by the manager. Note that + * the call to constrainShellSize in PopupDialog.open will still ensure that the shell is + * entirely visible. + */ + if (getPersistLocation() == false || getDialogSettings() == null) { + getShell().setLocation(location); + } + } + + public void setSize(int width, int height) { + getShell().setSize(width, height); + } + + public void setSizeConstraints(int maxWidth, int maxHeight) { + // Ignore + } + + public void setVisible(boolean visible) { + if (visible) { + open(); + } else { + saveDialogBounds(getShell()); + getShell().setVisible(false); + } + } + + public boolean hasContents() { + if ((commonViewer == null) || (commonViewer.getInput() == null)) { + return false; + } + return true; + } + + public void setInput(Object input) { + // Input comes from PDESourceInfoProvider.getInformation2() + // The input should be a model object of some sort + // Turn it into a structured selection and set the selection in the tree + if (input != null) { + commonViewer.setSelection(new StructuredSelection(input)); + } + } + + public void widgetDisposed(DisposeEvent e) { + // Note: We do not reuse the dialog + commonViewer = null; + fFilterText = null; + } + + @Override + protected Control createTitleControl(Composite parent) { + // Applies only to dialog title - not body. See createDialogArea + // Create the text widget + createUIWidgetFilterText(parent); + // Add listeners to the text widget + createUIListenersFilterText(); + // Return the text widget + return fFilterText; + } + + private void createUIWidgetFilterText(Composite parent) { + // Create the widget + fFilterText = new Text(parent, SWT.NONE); + // Set the font + GC gc = new GC(parent); + gc.setFont(parent.getFont()); + FontMetrics fontMetrics = gc.getFontMetrics(); + gc.dispose(); + // Create the layout + GridData data = new GridData(GridData.FILL_HORIZONTAL); + data.heightHint = Dialog.convertHeightInCharsToPixels(fontMetrics, 1); + data.horizontalAlignment = GridData.FILL; + data.verticalAlignment = GridData.CENTER; + fFilterText.setLayoutData(data); + } + + /** + * + */ + private void gotoSelectedElement() { + Object selectedElement = getSelectedElement(); + if (selectedElement == null) { + return; + } + dispose(); + } + + private void createUIListenersFilterText() { + fFilterText.addKeyListener(new KeyListener() { + public void keyPressed(KeyEvent e) { + if (e.keyCode == 0x0D) { + // Return key was pressed + gotoSelectedElement(); + } else if (e.keyCode == SWT.ARROW_DOWN) { + // Down key was pressed + commonViewer.getTree().setFocus(); + } else if (e.keyCode == SWT.ARROW_UP) { + // Up key was pressed + commonViewer.getTree().setFocus(); + } else if (e.character == 0x1B) { + // Escape key was pressed + dispose(); + } + } + + public void keyReleased(KeyEvent e) { + // NO-OP + } + }); + // Handle text modify events + fFilterText.addModifyListener(new ModifyListener() { + public void modifyText(ModifyEvent e) { + String text = ((Text) e.widget).getText(); + int length = text.length(); + if (length > 0) { + // Append a '*' pattern to the end of the text value if it + // does not have one already + if (text.charAt(length - 1) != '*') { + text = text + '*'; + } + // Prepend a '*' pattern to the beginning of the text value + // if it does not have one already + if (text.charAt(0) != '*') { + text = '*' + text; + } + } + // Set and update the pattern + setMatcherString(text, true); + } + }); + } + + /** + * Sets the patterns to filter out for the receiver. + *

+ * The following characters have special meaning: ? => any character * => any string + *

+ * + * @param pattern + * the pattern + * @param update + * true if the viewer should be updated + */ + private void setMatcherString(String pattern, boolean update) { + if (pattern.length() == 0) { + fStringMatcher = null; + } else { + fStringMatcher = new StringMatcher(pattern, true, false); + } + // Update the name pattern filter on the tree viewer + namePatternFilter.setStringMatcher(fStringMatcher); + // Update the tree viewer according to the pattern + if (update) { + stringMatcherUpdated(); + } + } + + /** + * The string matcher has been modified. The default implementation refreshes the view and selects the first matched + * element + */ + private void stringMatcherUpdated() { + // Refresh the tree viewer to re-filter + commonViewer.getControl().setRedraw(false); + commonViewer.refresh(); + commonViewer.expandAll(); + selectFirstMatch(); + commonViewer.getControl().setRedraw(true); + } + + /** + * Selects the first element in the tree which matches the current filter pattern. + */ + private void selectFirstMatch() { + Tree tree = commonViewer.getTree(); + Object element = findFirstMatchToPattern(tree.getItems()); + if (element != null) { + commonViewer.setSelection(new StructuredSelection(element), true); + } else { + commonViewer.setSelection(StructuredSelection.EMPTY); + } + } + + /** + * @param items + * @return + */ + private Object findFirstMatchToPattern(TreeItem[] items) { + // Match the string pattern against labels + ILabelProvider labelProvider = (ILabelProvider) commonViewer.getLabelProvider(); + // Process each item in the tree + for (TreeItem item : items) { + Object element = item.getData(); + // Return the first element if no pattern is set + if (fStringMatcher == null) { + return element; + } + // Return the element if it matches the pattern + if (element != null) { + String label = labelProvider.getText(element); + if (fStringMatcher.match(label)) { + return element; + } + } + // Recursively check the elements children for a match + element = findFirstMatchToPattern(item.getItems()); + // Return the child element match if found + if (element != null) { + return element; + } + } + // No match found + return null; + } + +} Index: src/org/eclipse/mylyn/internal/tasks/ui/views/messages.properties =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/views/messages.properties,v retrieving revision 1.12 diff -u -r1.12 messages.properties --- src/org/eclipse/mylyn/internal/tasks/ui/views/messages.properties 5 Nov 2009 12:16:25 -0000 1.12 +++ src/org/eclipse/mylyn/internal/tasks/ui/views/messages.properties 3 May 2010 19:35:50 -0000 @@ -11,6 +11,7 @@ DisconnectRepositoryAction_Disconnected=Disconnected PriorityDropDownAction_Filter_Priority_Lower_Than=Hide Priority Lower Than +QuickOutlineTaskDataDialog_InfoText=TaskDetail RepositoryElementActionGroup_Copy_Detail_Menu_Label=Copy Details RepositoryElementActionGroup_New=New Index: src/org/eclipse/mylyn/tasks/ui/editors/AbstractTaskEditorPage.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/tasks/ui/editors/AbstractTaskEditorPage.java,v retrieving revision 1.158 diff -u -r1.158 AbstractTaskEditorPage.java --- src/org/eclipse/mylyn/tasks/ui/editors/AbstractTaskEditorPage.java 22 Apr 2010 20:33:14 -0000 1.158 +++ src/org/eclipse/mylyn/tasks/ui/editors/AbstractTaskEditorPage.java 3 May 2010 19:35:50 -0000 @@ -1239,15 +1239,21 @@ if (part.getControl() != null) { if (ID_PART_ACTIONS.equals(part.getPartId())) { // do not expand horizontally - GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(false, false).applyTo( - part.getControl()); + GridDataFactory.fillDefaults() + .align(SWT.FILL, SWT.FILL) + .grab(false, false) + .applyTo(part.getControl()); } else { if (part.getExpandVertically()) { - GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).applyTo( - part.getControl()); + GridDataFactory.fillDefaults() + .align(SWT.FILL, SWT.FILL) + .grab(true, true) + .applyTo(part.getControl()); } else { - GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP).grab(true, false).applyTo( - part.getControl()); + GridDataFactory.fillDefaults() + .align(SWT.FILL, SWT.TOP) + .grab(true, false) + .applyTo(part.getControl()); } } // for outline @@ -1669,5 +1675,11 @@ // toolBarManager.add(submitButtonContribution); // } // } + public boolean reveal(String key) { + return EditorUtil.reveal(form, key); + } + public void focusOn(Control control) { + EditorUtil.focusOn(form, control); + } }