### Eclipse Workspace Patch 1.0 #P org.eclipse.mylyn.bugzilla.core Index: src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaAttribute.java =================================================================== RCS file: /cvsroot/mylyn/org.eclipse.mylyn.tasks/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaAttribute.java,v retrieving revision 1.25 diff -u -r1.25 BugzillaAttribute.java --- src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaAttribute.java 2 Sep 2010 21:38:31 -0000 1.25 +++ src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaAttribute.java 13 Mar 2011 19:44:34 -0000 @@ -94,7 +94,7 @@ FILENAME(Messages.BugzillaAttribute_filename, "filename", TaskAttribute.TYPE_SHORT_TEXT, false, false), //$NON-NLS-1$ - FLAG(Messages.BugzillaAttribute_flag, "flag", IBugzillaConstants.EDITOR_TYPE_FLAG, false, false), //$NON-NLS-1$ + FLAG(Messages.BugzillaAttribute_flag, "flag", IBugzillaConstants.EDITOR_TYPE_FLAG, true, false), //$NON-NLS-1$ GROUP(Messages.BugzillaAttribute_Group, "group", TaskAttribute.TYPE_BOOLEAN, true, true), //$NON-NLS-1$ Index: src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaFlagMapper.java =================================================================== RCS file: /cvsroot/mylyn/org.eclipse.mylyn.tasks/org.eclipse.mylyn.bugzilla.core/src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaFlagMapper.java,v retrieving revision 1.7 diff -u -r1.7 BugzillaFlagMapper.java --- src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaFlagMapper.java 2 Oct 2009 20:24:59 -0000 1.7 +++ src/org/eclipse/mylyn/internal/bugzilla/core/BugzillaFlagMapper.java 13 Mar 2011 19:44:34 -0000 @@ -109,7 +109,7 @@ } if (bugzillaVersion.compareTo(BugzillaVersion.BUGZILLA_3_2) >= 0) { - meta.setKind(TaskAttribute.KIND_DEFAULT); + meta.setKind(BugzillaAttribute.KIND_FLAG); } meta.setReadOnly(false); #P org.eclipse.mylyn.bugzilla.ui Index: src/org/eclipse/mylyn/internal/bugzilla/ui/editor/BugzillaFlagPart.java =================================================================== RCS file: src/org/eclipse/mylyn/internal/bugzilla/ui/editor/BugzillaFlagPart.java diff -N src/org/eclipse/mylyn/internal/bugzilla/ui/editor/BugzillaFlagPart.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/org/eclipse/mylyn/internal/bugzilla/ui/editor/BugzillaFlagPart.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,305 @@ +/******************************************************************************* + * Copyright (c) 2011 Frank Becker 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: + * Frank Becker - initial API and implementation + *******************************************************************************/ + +package org.eclipse.mylyn.internal.bugzilla.ui.editor; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +import org.eclipse.jface.action.ToolBarManager; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.mylyn.internal.bugzilla.core.BugzillaAttribute; +import org.eclipse.mylyn.internal.provisional.commons.ui.CommonUiUtil; +import org.eclipse.mylyn.internal.tasks.ui.editors.EditorUtil; +import org.eclipse.mylyn.internal.tasks.ui.notifications.TaskDiffUtil; +import org.eclipse.mylyn.tasks.core.data.TaskAttribute; +import org.eclipse.mylyn.tasks.ui.editors.AbstractAttributeEditor; +import org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorPart; +import org.eclipse.mylyn.tasks.ui.editors.LayoutHint; +import org.eclipse.mylyn.tasks.ui.editors.LayoutHint.ColumnSpan; +import org.eclipse.mylyn.tasks.ui.editors.LayoutHint.RowSpan; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.ui.forms.IFormColors; +import org.eclipse.ui.forms.events.ExpansionAdapter; +import org.eclipse.ui.forms.events.ExpansionEvent; +import org.eclipse.ui.forms.widgets.ExpandableComposite; +import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.Section; + +@SuppressWarnings("restriction") +public class BugzillaFlagPart extends AbstractTaskEditorPart { + private static final int LABEL_WIDTH = 110; + + private static final int COLUMN_WIDTH = 140; + + private static final int COLUMN_GAP = 20; + + private static final int MULTI_COLUMN_WIDTH = COLUMN_WIDTH + 5 + COLUMN_GAP + LABEL_WIDTH + 5 + COLUMN_WIDTH; + + private static final int MULTI_ROW_HEIGHT = 55; + + private boolean hasIncoming; + + private List flagEditors; + + private String infoOverlayText = null; + + private String infoOverlayTooltipText = null; + + public BugzillaFlagPart() { + setPartName(Messages.BugzillaFlagPart_Flags_PartName); + } + + @Override + public void createControl(Composite parent, FormToolkit toolkit) { + initialize(); + int style = ExpandableComposite.TWISTIE; + if (hasIncoming) { + style |= ExpandableComposite.EXPANDED; + } + Section flagSection = createSection(parent, toolkit, style); + EditorUtil.setTitleBarForeground(flagSection, toolkit.getColors().getColor(IFormColors.TITLE)); + + GridLayout gl = new GridLayout(); + GridData gd = new GridData(SWT.FILL, SWT.NONE, false, false); + gd.horizontalSpan = 4; + flagSection.setLayout(gl); + flagSection.setLayoutData(gd); + + Composite flagComposite = toolkit.createComposite(flagSection); + + GridLayout flagsLayout = EditorUtil.createSectionClientLayout(); + flagsLayout.numColumns = 4; + flagsLayout.horizontalSpacing = 7; + flagsLayout.verticalSpacing = 6; + flagComposite.setLayout(flagsLayout); + + GridData flagsData = new GridData(GridData.FILL_BOTH); + flagsData.horizontalSpan = 1; + flagsData.grabExcessVerticalSpace = false; + flagComposite.setLayoutData(flagsData); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP).grab(true, false).applyTo(flagComposite); + + createAttributeControls(flagComposite, toolkit, flagsLayout.numColumns); + flagSection.setClient(flagComposite); + toolkit.paintBordersFor(flagComposite); + setSection(toolkit, flagSection); + } + + private void initialize() { + hasIncoming = false; + flagEditors = new ArrayList(); + int used = 0; + int unused = 0; + String usedDetail = ""; //$NON-NLS-1$ + String unusedDetail = ""; //$NON-NLS-1$ + Map attributes = getTaskData().getRoot().getAttributes(); + for (TaskAttribute attribute : attributes.values()) { + if (!BugzillaAttribute.KIND_FLAG.equals(attribute.getMetaData().getKind())) { + continue; + } + + TaskAttribute stateAttribute = attribute.getAttribute("state"); //$NON-NLS-1$ + if (stateAttribute == null) { + continue; + } + String val = stateAttribute.getValue(); + if (val != null && !val.equals("") && !val.equals(" ")) { //$NON-NLS-1$ //$NON-NLS-2$ + if (used > 0) { + usedDetail += ", "; //$NON-NLS-1$ + } + used++; + usedDetail += stateAttribute.getMetaData().getLabel(); + } else { + if (unused > 0) { + unusedDetail += ", "; //$NON-NLS-1$ + } + unused++; + unusedDetail += stateAttribute.getMetaData().getLabel(); + } + AbstractAttributeEditor attributeEditor = createAttributeEditor(attribute); + if (attributeEditor != null) { + flagEditors.add(attributeEditor); + if (getModel().hasIncomingChanges(attribute)) { + hasIncoming = true; + } + } + } + Comparator attributeSorter = createAttributeEditorSorter(); + if (attributeSorter != null) { + Collections.sort(flagEditors, attributeSorter); + } + if (used > 0 && unused > 0) { + infoOverlayText = NLS.bind(Messages.BugzillaFlagPart_numberof_unused_used_flags, "" + unused, "" + used); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + infoOverlayText = NLS.bind("{0} {1}", used > 0 ? "" + used : "" + unused, used > 0 //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + ? used == 1 ? "used flag" : "used flags" //$NON-NLS-1$ //$NON-NLS-2$ + : unused == 1 ? "unused flag" : "unused flags"); //$NON-NLS-1$ //$NON-NLS-2$ + } + usedDetail = NLS.bind( + "{0} {1}", used == 1 ? Messages.BugzillaFlagPart_used_flag + Messages.BugzillaFlagPart_is : Messages.BugzillaFlagPart_used_flags + Messages.BugzillaFlagPart_are, usedDetail); //$NON-NLS-1$ + unusedDetail = NLS.bind( + "{0} {1}", unused == 1 ? Messages.BugzillaFlagPart_unused_flag + Messages.BugzillaFlagPart_is : Messages.BugzillaFlagPart_unused_flags + Messages.BugzillaFlagPart_are, unusedDetail); //$NON-NLS-1$ + if (used > 0 && unused > 0) { + infoOverlayTooltipText = NLS.bind("{0}\n{1}", usedDetail, unusedDetail); //$NON-NLS-1$ + } else { + infoOverlayTooltipText = used > 0 ? usedDetail : unusedDetail; + } + } + + /** + * Create a comparator by which attribute editors will be sorted. By default attribute editors are sorted by layout + * hint priority. Subclasses may override this method to sort attribute editors in a custom way. + * + * @return comparator for {@link AbstractAttributeEditor} objects + */ + protected Comparator createAttributeEditorSorter() { + return new Comparator() { + public int compare(AbstractAttributeEditor o1, AbstractAttributeEditor o2) { + int p1 = (o1.getLayoutHint() != null) ? o1.getLayoutHint().getPriority() : LayoutHint.DEFAULT_PRIORITY; + int p2 = (o2.getLayoutHint() != null) ? o2.getLayoutHint().getPriority() : LayoutHint.DEFAULT_PRIORITY; + return p1 - p2; + } + }; + } + + private void createAttributeControls(Composite attributesComposite, FormToolkit toolkit, int columnCount) { + int currentColumn = 1; + int currentPriority = 0; + for (AbstractAttributeEditor attributeEditor : flagEditors) { + int priority = (attributeEditor.getLayoutHint() != null) + ? attributeEditor.getLayoutHint().getPriority() + : LayoutHint.DEFAULT_PRIORITY; + if (priority != currentPriority) { + currentPriority = priority; + if (currentColumn > 1) { + while (currentColumn <= columnCount) { + getManagedForm().getToolkit().createLabel(attributesComposite, ""); //$NON-NLS-1$ + currentColumn++; + } + currentColumn = 1; + } + } + + if (attributeEditor.hasLabel()) { + attributeEditor.createLabelControl(attributesComposite, toolkit); + Label label = attributeEditor.getLabelControl(); + String text = label.getText(); + String shortenText = TaskDiffUtil.shortenText(label, text, LABEL_WIDTH); + label.setText(shortenText); + if (!text.equals(shortenText)) { + label.setToolTipText(text); + } + GridData gd = GridDataFactory.fillDefaults() + .align(SWT.RIGHT, SWT.CENTER) + .hint(LABEL_WIDTH, SWT.DEFAULT) + .create(); + if (currentColumn > 1) { + gd.horizontalIndent = COLUMN_GAP; + gd.widthHint = LABEL_WIDTH + COLUMN_GAP; + } + label.setLayoutData(gd); + currentColumn++; + } + + attributeEditor.createControl(attributesComposite, toolkit); + LayoutHint layoutHint = attributeEditor.getLayoutHint(); + GridData gd = new GridData(SWT.FILL, SWT.CENTER, false, false); + if (layoutHint != null + && !(layoutHint.rowSpan == RowSpan.SINGLE && layoutHint.columnSpan == ColumnSpan.SINGLE)) { + if (layoutHint.rowSpan == RowSpan.MULTIPLE) { + gd.heightHint = MULTI_ROW_HEIGHT; + } + if (layoutHint.columnSpan == ColumnSpan.SINGLE) { + gd.widthHint = COLUMN_WIDTH; + gd.horizontalSpan = 1; + } else { + gd.widthHint = MULTI_COLUMN_WIDTH; + gd.horizontalSpan = columnCount - currentColumn + 1; + } + } else { + gd.widthHint = COLUMN_WIDTH; + gd.horizontalSpan = 1; + } + attributeEditor.getControl().setLayoutData(gd); + + getTaskEditorPage().getAttributeEditorToolkit().adapt(attributeEditor); + + currentColumn += gd.horizontalSpan; + currentColumn %= columnCount; + } + } + + protected String getInfoOverlayText() { + return infoOverlayText; + } + + protected String getInfoOverlayTooltipText() { + return infoOverlayTooltipText; + } + + private void createInfoOverlay(Composite composite, Section section, FormToolkit toolkit) { + String text = getInfoOverlayText(); + if (text == null) { + return; + } + + final Label label = toolkit.createLabel(composite, CommonUiUtil.toLabel(text)); + label.setForeground(toolkit.getColors().getColor(IFormColors.TITLE)); + label.setBackground(null); + label.setVisible(!section.isExpanded()); + label.setToolTipText(getInfoOverlayTooltipText()); + + section.addExpansionListener(new ExpansionAdapter() { + @Override + public void expansionStateChanging(ExpansionEvent e) { + label.setVisible(!e.getState()); + } + }); + } + + @Override + protected void setSection(FormToolkit toolkit, Section section) { + if (section.getTextClient() == null) { + ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT); + fillToolBar(toolBarManager); + + if (toolBarManager.getSize() > 0 || getInfoOverlayText() != null) { + Composite toolbarComposite = toolkit.createComposite(section); + toolbarComposite.setBackground(null); + RowLayout rowLayout = new RowLayout(); + rowLayout.marginLeft = 0; + rowLayout.marginRight = 0; + rowLayout.marginTop = 0; + rowLayout.marginBottom = 0; + rowLayout.center = true; + toolbarComposite.setLayout(rowLayout); + + createInfoOverlay(toolbarComposite, section, toolkit); + + toolBarManager.createControl(toolbarComposite); + section.clientVerticalSpacing = 0; + section.descriptionVerticalSpacing = 0; + section.setTextClient(toolbarComposite); + } + } + setControl(section); + } +} Index: src/org/eclipse/mylyn/internal/bugzilla/ui/editor/BugzillaTaskEditorPage.java =================================================================== RCS file: /cvsroot/mylyn/org.eclipse.mylyn.tasks/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/editor/BugzillaTaskEditorPage.java,v retrieving revision 1.53 diff -u -r1.53 BugzillaTaskEditorPage.java --- src/org/eclipse/mylyn/internal/bugzilla/ui/editor/BugzillaTaskEditorPage.java 10 Dec 2010 22:28:31 -0000 1.53 +++ src/org/eclipse/mylyn/internal/bugzilla/ui/editor/BugzillaTaskEditorPage.java 13 Mar 2011 19:44:35 -0000 @@ -66,6 +66,8 @@ public static final String ID_PART_BUGZILLA_FLAGS = "org.eclipse.mylyn.bugzilla.ui.editors.part.flags"; //$NON-NLS-1$ + public static final String PATH_FLAGS = "flags"; //$NON-NLS-1$ + private final Map attributeEditorMap; private TaskDataModelListener productListener; @@ -99,6 +101,14 @@ } } + // Add Bugzilla Flag part + descriptors.add(new TaskEditorPartDescriptor(ID_PART_BUGZILLA_FLAGS) { + @Override + public AbstractTaskEditorPart createPart() { + return new BugzillaFlagPart(); + } + }.setPath(ID_PART_ATTRIBUTES + "/" + PATH_FLAGS)); //$NON-NLS-1$ + // Add Bugzilla Planning part try { TaskData data = TasksUi.getTaskDataManager().getTaskData(getTask()); Index: src/org/eclipse/mylyn/internal/bugzilla/ui/editor/Messages.java =================================================================== RCS file: /cvsroot/mylyn/org.eclipse.mylyn.tasks/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/editor/Messages.java,v retrieving revision 1.12 diff -u -r1.12 Messages.java --- src/org/eclipse/mylyn/internal/bugzilla/ui/editor/Messages.java 8 Jun 2010 23:05:42 -0000 1.12 +++ src/org/eclipse/mylyn/internal/bugzilla/ui/editor/Messages.java 13 Mar 2011 19:44:35 -0000 @@ -25,6 +25,22 @@ NLS.initializeMessages(BUNDLE_NAME, Messages.class); } + public static String BugzillaFlagPart_are; + + public static String BugzillaFlagPart_Flags_PartName; + + public static String BugzillaFlagPart_is; + + public static String BugzillaFlagPart_numberof_unused_used_flags; + + public static String BugzillaFlagPart_unused_flag; + + public static String BugzillaFlagPart_unused_flags; + + public static String BugzillaFlagPart_used_flag; + + public static String BugzillaFlagPart_used_flags; + public static String BugzillaPeoplePart_People; public static String BugzillaPeoplePart__Select_to_remove_; Index: src/org/eclipse/mylyn/internal/bugzilla/ui/editor/messages.properties =================================================================== RCS file: /cvsroot/mylyn/org.eclipse.mylyn.tasks/org.eclipse.mylyn.bugzilla.ui/src/org/eclipse/mylyn/internal/bugzilla/ui/editor/messages.properties,v retrieving revision 1.12 diff -u -r1.12 messages.properties --- src/org/eclipse/mylyn/internal/bugzilla/ui/editor/messages.properties 8 Jun 2010 23:05:42 -0000 1.12 +++ src/org/eclipse/mylyn/internal/bugzilla/ui/editor/messages.properties 13 Mar 2011 19:44:35 -0000 @@ -8,6 +8,14 @@ # Contributors: # Tasktop Technologies - initial API and implementation ############################################################################### +BugzillaFlagPart_are=\ are +BugzillaFlagPart_Flags_PartName=Flags +BugzillaFlagPart_is=\ is +BugzillaFlagPart_numberof_unused_used_flags={0} unused / {1} used flags +BugzillaFlagPart_unused_flag=unused flag +BugzillaFlagPart_unused_flags=unused flags +BugzillaFlagPart_used_flag=used flag +BugzillaFlagPart_used_flags=used flags BugzillaPeoplePart_People=People BugzillaPeoplePart__Select_to_remove_=(Select to remove)