### Eclipse Workspace Patch 1.0 #P org.eclipse.mylyn.tasks.ui Index: src/org/eclipse/mylyn/internal/tasks/ui/editors/PreviewAttributeEditor.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/PreviewAttributeEditor.java,v retrieving revision 1.10 diff -u -r1.10 PreviewAttributeEditor.java --- src/org/eclipse/mylyn/internal/tasks/ui/editors/PreviewAttributeEditor.java 13 Jun 2008 10:27:01 -0000 1.10 +++ src/org/eclipse/mylyn/internal/tasks/ui/editors/PreviewAttributeEditor.java 9 Jul 2008 17:19:34 -0000 @@ -98,7 +98,7 @@ Composite editorComposite = toolkit.createComposite(composite); editorComposite.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER); GridData gd = new GridData(GridData.FILL_BOTH); - gd.widthHint = EditorUtil.MAXIMUM_WIDTH; +// gd.widthHint = EditorUtil.MAXIMUM_WIDTH; gd.minimumHeight = EditorUtil.MAXIMUM_HEIGHT; gd.grabExcessHorizontalSpace = true; editorComposite.setLayoutData(gd); Index: src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskEditorRichTextPart.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskEditorRichTextPart.java,v retrieving revision 1.17 diff -u -r1.17 TaskEditorRichTextPart.java --- src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskEditorRichTextPart.java 7 Jun 2008 08:13:41 -0000 1.17 +++ src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskEditorRichTextPart.java 9 Jul 2008 17:19:34 -0000 @@ -112,8 +112,7 @@ } else { editor.createControl(composite, toolkit); if (editor.isReadOnly()) { - GridDataFactory.fillDefaults().minSize(EditorUtil.MAXIMUM_WIDTH, 0).hint(EditorUtil.MAXIMUM_WIDTH, - SWT.DEFAULT).applyTo(editor.getControl()); + composite.setLayout(new FillWidthLayout(getTaskEditorPage().getEditorLayoutAdvisor(), 0, 0, 0, 3)); } else { final GridData gd = new GridData(); // wrap text at this margin, see comment below Index: src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskEditorCommentPart.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskEditorCommentPart.java,v retrieving revision 1.34 diff -u -r1.34 TaskEditorCommentPart.java --- src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskEditorCommentPart.java 19 Jun 2008 00:27:08 -0000 1.34 +++ src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskEditorCommentPart.java 9 Jul 2008 17:19:34 -0000 @@ -80,9 +80,6 @@ }); composite.setData(KEY_EDITOR, editor); - GridDataFactory.fillDefaults().minSize(EditorUtil.MAXIMUM_WIDTH, 0).hint(EditorUtil.MAXIMUM_WIDTH, - SWT.DEFAULT).applyTo(editor.getControl()); - getTaskEditorPage().getAttributeEditorToolkit().adapt(editor); getTaskEditorPage().reflow(); } @@ -191,11 +188,8 @@ final Composite commentTextComposite = toolkit.createComposite(commentComposite); commentComposite.setClient(commentTextComposite); - GridLayout ecLayout = new GridLayout(); - ecLayout.marginHeight = 0; - ecLayout.marginBottom = 3; - ecLayout.marginLeft = 15; - commentTextComposite.setLayout(ecLayout); + commentTextComposite.setLayout(new FillWidthLayout(getTaskEditorPage().getEditorLayoutAdvisor(), 15, 0, 0, + 3)); commentTextComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); commentComposite.addExpansionListener(new ExpansionAdapter() { @Override Index: src/org/eclipse/mylyn/tasks/ui/editors/TaskEditor.java =================================================================== RCS file: /cvsroot/tools/org.eclipse.mylyn/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/tasks/ui/editors/TaskEditor.java,v retrieving revision 1.118 diff -u -r1.118 TaskEditor.java --- src/org/eclipse/mylyn/tasks/ui/editors/TaskEditor.java 30 Jun 2008 23:44:10 -0000 1.118 +++ src/org/eclipse/mylyn/tasks/ui/editors/TaskEditor.java 9 Jul 2008 17:19:35 -0000 @@ -59,6 +59,7 @@ import org.eclipse.swt.dnd.TextTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.ToolBar; @@ -106,9 +107,21 @@ private TaskDragSourceListener titleDragSourceListener; + private Composite editorParent; + public TaskEditor() { } + @Override + protected Composite createPageContainer(Composite parent) { + this.editorParent = parent; + return super.createPageContainer(parent); + } + + Composite getEditorParent() { + return editorParent; + } + @Deprecated private void addPage(AbstractTaskEditorFactory factory) { IEditorInput editorInput; 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.70 diff -u -r1.70 AbstractTaskEditorPage.java --- src/org/eclipse/mylyn/tasks/ui/editors/AbstractTaskEditorPage.java 30 Jun 2008 21:18:25 -0000 1.70 +++ src/org/eclipse/mylyn/tasks/ui/editors/AbstractTaskEditorPage.java 9 Jul 2008 17:19:34 -0000 @@ -103,6 +103,8 @@ import org.eclipse.swt.events.FocusAdapter; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.RowLayout; @@ -113,6 +115,7 @@ import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.ScrollBar; import org.eclipse.swt.widgets.Spinner; import org.eclipse.swt.widgets.TabFolder; import org.eclipse.swt.widgets.Table; @@ -388,6 +391,11 @@ this.selectionChangedListeners = new ListenerList(); } + @Override + public TaskEditor getEditor() { + return (TaskEditor) super.getEditor(); + } + private void addFocusListener(Composite composite, FocusListener listener) { Control[] children = composite.getChildren(); for (Control control : children) { @@ -448,6 +456,7 @@ @Override protected void createFormContent(final IManagedForm managedForm) { form = managedForm.getForm(); + toolkit = managedForm.getToolkit(); registerDefaultDropListener(form); EditorUtil.disableScrollingOnFocus(form); @@ -485,9 +494,39 @@ updateHeaderMessage(); } finally { setReflow(true); + + // if the editor is restored as part of workbench startup then we must reflow() asynchronously + // otherwise the editor layout is incorrect + boolean reflowRequired = calculateReflowRequired(form); + + if (reflowRequired) { + Display.getCurrent().asyncExec(new Runnable() { + public void run() { + // this fixes a problem with layout that occurs when an editor + // is restored before the workbench is fully initialized + reflow(); + } + }); + } } } + private boolean calculateReflowRequired(ScrolledForm form) { + Composite stopComposite = getEditor().getEditorParent().getParent().getParent(); + Composite composite = form.getParent(); + while (composite != null) { + Rectangle clientArea = composite.getClientArea(); + if (clientArea.width > 1) { + return false; + } + if (composite == stopComposite) { + return true; + } + composite = composite.getParent(); + } + return true; + } + private void createFormContentInternal() { // end life-cycle of previous editor controls if (attributeEditorToolkit != null) { @@ -891,6 +930,14 @@ return editorComposite; } + public Composite getEditorLayoutAdvisor() { + Composite layoutAdvisor = editorComposite; + do { + layoutAdvisor = layoutAdvisor.getParent(); + } while (!(layoutAdvisor instanceof CTabFolder)); + return layoutAdvisor.getParent(); + } + public TaskDataModel getModel() { return model; } @@ -917,7 +964,7 @@ } public TaskEditor getTaskEditor() { - return (TaskEditor) getEditor(); + return getEditor(); } public TaskRepository getTaskRepository() { @@ -1039,7 +1086,17 @@ */ public void reflow() { if (reflow) { - form.layout(true, true); + // help the layout managers: ensure that the form width always matches + // the parent client area width. + Rectangle parentClientArea = form.getParent().getClientArea(); + Point formSize = form.getSize(); + if (formSize.x != parentClientArea.width) { + ScrollBar verticalBar = form.getVerticalBar(); + int verticalBarWidth = verticalBar != null ? verticalBar.getSize().x : 15; + form.setSize(parentClientArea.width - verticalBarWidth, formSize.y); + } + + form.layout(true, false); form.reflow(true); } } Index: src/org/eclipse/mylyn/internal/tasks/ui/editors/FillWidthLayout.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/tasks/ui/editors/FillWidthLayout.java diff -N src/org/eclipse/mylyn/internal/tasks/ui/editors/FillWidthLayout.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/tasks/ui/editors/FillWidthLayout.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,209 @@ +/******************************************************************************* + * Copyright (c) 2004, 2007 Mylyn project committers 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 + *******************************************************************************/ + +package org.eclipse.mylyn.internal.tasks.ui.editors; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.swt.custom.CTabFolder; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Layout; +import org.eclipse.swt.widgets.ScrollBar; +import org.eclipse.ui.forms.widgets.Section; + +/** + * A layout that uses the width hint or client area of a composite to recommend the width of its children, allowing + * children to fill the width and specify their preferred height for a given width. + * + * Intended for use with a composite that contains a single child that should fill available horizontal space. + * + * @author David Green + */ +public class FillWidthLayout extends Layout { + + private final int marginLeft; + + private final int marginRight; + + private final int marginTop; + + private final int marginBottom; + + private int widthHintMargin = 15; + + private Composite layoutAdvisor; + + /** + * create with 0 margins + * + */ + public FillWidthLayout() { + this(0, 0, 0, 0); + } + + /** + * create while specifying margins + * + * @param marginLeft + * the left margin in pixels, or 0 if there should be none + * @param marginRight + * the right margin in pixels, or 0 if there should be none + * @param marginTop + * the top margin in pixels, or 0 if there should be none + * @param marginBottom + * the bottom margin in pixels, or 0 if there should be none + */ + public FillWidthLayout(int marginLeft, int marginRight, int marginTop, int marginBottom) { + this(null, marginLeft, marginRight, marginTop, marginBottom); + } + + /** + * create specifying margins and a {@link #getLayoutAdvisor() layout advisor}. + * + * @param layoutAdvisor + * the composite that is used to advise on layout based on its {@link Composite#getClientArea() client + * area}. + * @param marginLeft + * the left margin in pixels, or 0 if there should be none + * @param marginRight + * the right margin in pixels, or 0 if there should be none + * @param marginTop + * the top margin in pixels, or 0 if there should be none + * @param marginBottom + * the bottom margin in pixels, or 0 if there should be none + */ + public FillWidthLayout(Composite layoutAdvisor, int marginLeft, int marginRight, int marginTop, int marginBottom) { + this.layoutAdvisor = layoutAdvisor; + this.marginLeft = marginLeft; + this.marginRight = marginRight; + this.marginTop = marginTop; + this.marginBottom = marginBottom; + if (Platform.OS_MACOSX.equals(Platform.getOS())) { + widthHintMargin = 15; + } else { + widthHintMargin = 25; + } + } + + /** + * calculate the client area of the given container, accomodating for insets and margins. + */ + private int calculateWidthHint(Composite container) { + return calculateWidthHint(container, layoutAdvisor == null); + } + + /** + * calculate the client area of the given container, accomodating for insets and margins. + */ + private int calculateWidthHint(Composite container, boolean layoutAdvisorHit) { + if (container == layoutAdvisor) { + layoutAdvisorHit = true; + } + Rectangle clientArea = container.getClientArea(); + int horizontalMargin = 0; + if (clientArea.width <= 1 || !layoutAdvisorHit) { // sometimes client area is incorrectly reported as 1 + clientArea.width = calculateWidthHint(container.getParent(), layoutAdvisorHit); + } + Layout bodyLayout = container.getLayout(); + if (bodyLayout instanceof GridLayout) { + GridLayout gridLayout = (GridLayout) bodyLayout; + horizontalMargin = (gridLayout.marginWidth * 2) + gridLayout.marginLeft + gridLayout.marginRight; + } else if (bodyLayout instanceof FillLayout) { + FillLayout fillLayout = (FillLayout) bodyLayout; + horizontalMargin = fillLayout.marginWidth * 2; + } else if (container instanceof Section) { + horizontalMargin = ((Section) container).marginWidth * 2; + } else if (container instanceof CTabFolder) { + CTabFolder folder = (CTabFolder) container; + horizontalMargin = folder.marginWidth * 2; + } + if (container instanceof ScrolledComposite) { + ScrolledComposite composite = (ScrolledComposite) container; + ScrollBar verticalBar = composite.getVerticalBar(); + if (verticalBar != null) { + int verticalBarWidth = verticalBar.getSize().x; + horizontalMargin += Math.max(15, verticalBarWidth); + } + } + return clientArea.width - horizontalMargin; + } + + @Override + protected Point computeSize(Composite composite, int widthHint, int heightHint, boolean flushCache) { + int resultX = 1; + int resultY = 1; + + Control[] children = composite.getChildren(); + + if (widthHint <= 0) { + widthHint = calculateWidthHint(composite); + if (widthHint < 300) { + widthHint = 300; + } else { + widthHint -= widthHintMargin; + } + } + + int horizontalMargin = marginLeft + marginRight; + + for (Control control : children) { + Point sz = control.computeSize(widthHint - horizontalMargin, -1, flushCache); + + resultX = Math.max(resultX, sz.x); + resultY = Math.max(resultY, sz.y); + } + + return new Point(resultX + horizontalMargin, resultY + marginTop + marginBottom); + } + + @Override + protected void layout(Composite composite, boolean flushCache) { + + Rectangle area = composite.getClientArea(); + if (area.width == 0) { + area.width = calculateWidthHint(composite); + } + + // account for margins + area.x += marginLeft; + area.y += marginTop; + area.width -= marginRight; + area.height -= marginBottom; + + Control[] children = composite.getChildren(); + + for (Control control : children) { + control.setBounds(area); + } + } + + /** + * the composite that is used to advise on layout based on its {@link Composite#getClientArea() client area}. + * + * @return the layout advisor, or null if there is none + */ + public Composite getLayoutAdvisor() { + return layoutAdvisor; + } + + /** + * the composite that is used to advise on layout based on its {@link Composite#getClientArea() client area}. + * + * @param layoutAdvisor + * the layout advisor, or null if there is none + */ + public void setLayoutAdvisor(Composite layoutAdvisor) { + this.layoutAdvisor = layoutAdvisor; + } + +}