| /******************************************************************************* |
| * Copyright (c) 2016 Frank Becker and others. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * https://www.eclipse.org/legal/epl-2.0 |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Frank Becker - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.mylyn.internal.bugzilla.rest.ui; |
| |
| 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.LegacyActionTools; |
| import org.eclipse.jface.action.ToolBarManager; |
| import org.eclipse.jface.layout.GridDataFactory; |
| import org.eclipse.mylyn.internal.bugzilla.rest.core.IBugzillaRestConstants; |
| 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; |
| |
| public class BugzillaRestFlagPart 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<AbstractAttributeEditor> flagEditors; |
| |
| private String infoOverlayText = null; |
| |
| private String infoOverlayTooltipText = null; |
| |
| public BugzillaRestFlagPart() { |
| setPartName("Flags"); |
| } |
| |
| @Override |
| public void createControl(Composite parent, FormToolkit toolkit) { |
| initialize(); |
| if (flagEditors.size() == 0) { |
| return; |
| } |
| int style = ExpandableComposite.TWISTIE | ExpandableComposite.LEFT_TEXT_CLIENT_ALIGNMENT; |
| 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<AbstractAttributeEditor>(); |
| int used = 0; |
| int unused = 0; |
| String usedDetail = ""; //$NON-NLS-1$ |
| String unusedDetail = ""; //$NON-NLS-1$ |
| Map<String, TaskAttribute> attributes = getTaskData().getRoot().getAttributes(); |
| for (TaskAttribute attribute : attributes.values()) { |
| if (!IBugzillaRestConstants.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<AbstractAttributeEditor> attributeSorter = createAttributeEditorSorter(); |
| if (attributeSorter != null) { |
| Collections.sort(flagEditors, attributeSorter); |
| } |
| |
| if (used > 0) { |
| infoOverlayText = NLS.bind(" " + "{0} Flags ({1} set)", "" + (unused + used), "" + used); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } else { |
| infoOverlayText = NLS.bind(" " + "{0} Flags", "" + (unused + used)); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| usedDetail = NLS.bind("{0} {1}", used == 1 ? "{0} Flags" + " is" : "set flags" + " are", usedDetail); //$NON-NLS-1$ |
| unusedDetail = NLS.bind("{0} {1}", unused == 1 ? "{0} Flags" + " is" : "unused flags" + " 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<AbstractAttributeEditor> createAttributeEditorSorter() { |
| return new Comparator<AbstractAttributeEditor>() { |
| 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, LegacyActionTools.escapeMnemonics(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); |
| } |
| } |