/******************************************************************************* * Copyright (c) 2010, 2014 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 * Jan Lohre (SAP) - improvements * Sascha Scholz (SAP) - improvements *******************************************************************************/ package org.eclipse.mylyn.reviews.ui.spi.editor; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; import org.apache.commons.lang.StringUtils; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.mylyn.commons.ui.CommonImages; import org.eclipse.mylyn.internal.reviews.ui.ReviewsImages; import org.eclipse.mylyn.reviews.core.model.IApprovalType; import org.eclipse.mylyn.reviews.core.model.IChange; import org.eclipse.mylyn.reviews.core.model.IRequirementEntry; import org.eclipse.mylyn.reviews.core.model.IReview; import org.eclipse.mylyn.reviews.core.model.IReviewerEntry; import org.eclipse.mylyn.reviews.core.model.IUser; import org.eclipse.mylyn.reviews.core.model.RequirementStatus; import org.eclipse.mylyn.reviews.ui.spi.factories.AbstractUiFactoryProvider; import org.eclipse.mylyn.tasks.ui.TasksUiUtil; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CLabel; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Link; import org.eclipse.ui.forms.IFormColors; import org.eclipse.ui.forms.widgets.ExpandableComposite; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.Section; /** * Displays basic information about a given review corresponding to top sections of Gerrit web interface. * * @author Steffen Pingel * @author Miles Parker */ public abstract class ReviewDetailSection extends AbstractReviewSection { public ReviewDetailSection() { setPartName(Messages.ReviewDetailSection_Review); } @Override protected Control createContent(FormToolkit toolkit, Composite parent) { Control content = super.createContent(toolkit, parent); createReviewersSubSection(composite); createDependenciesSubSection(toolkit, composite, Messages.ReviewDetailSection_Depends_On, getReview().getParents()); createDependenciesSubSection(toolkit, composite, Messages.ReviewDetailSection_Needed_By, getReview().getChildren()); return content; } protected void createReviewersSubSection(Composite parent) { if (getReview().getReviewerApprovals().isEmpty() && !canAddReviewers()) { return; } int style = ExpandableComposite.TWISTIE | ExpandableComposite.CLIENT_INDENT | ExpandableComposite.LEFT_TEXT_CLIENT_ALIGNMENT | ExpandableComposite.EXPANDED; final Section subSection = toolkit.createSection(parent, style); GridDataFactory.fillDefaults().grab(true, false).applyTo(subSection); subSection.setTitleBarForeground(toolkit.getColors().getColor(IFormColors.TITLE)); subSection.setText(Messages.ReviewDetailSection_Reviewers); Composite composite = toolkit.createComposite(subSection); List<IApprovalType> approvalTypes = getModelRepository().getApprovalTypes(); List<IApprovalType> approvalTypesWithLabel = new ArrayList<IApprovalType>(approvalTypes.size()); for (IApprovalType approvalType : approvalTypes) { if (!approvalType.getName().equals(approvalType.getKey())) { approvalTypesWithLabel.add(approvalType); } } int numColumns = approvalTypesWithLabel.size() + 1; GridLayoutFactory.fillDefaults() .numColumns(numColumns) .extendedMargins(0, 0, 0, 5) .equalWidth(true) .spacing(4, 5) .applyTo(composite); subSection.setClient(composite); if (!approvalTypesWithLabel.isEmpty()) { StringBuilder names = new StringBuilder(); Label headerLabel = new Label(composite, SWT.NONE); headerLabel.setText(" "); //$NON-NLS-1$ StringBuilder needs = new StringBuilder(); for (IApprovalType approvalType : approvalTypesWithLabel) { IRequirementEntry requirementEntry = getReview().getRequirements().get(approvalType); Composite headerContainer = new Composite(composite, SWT.NONE); headerContainer.setForeground(toolkit.getColors().getColor(IFormColors.TB_BG)); GridLayoutFactory.fillDefaults().numColumns(2).applyTo(headerContainer); GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.FILL).applyTo(headerContainer); CLabel approvalHeaderLabel = new CLabel(headerContainer, SWT.NONE); approvalHeaderLabel.setForeground(toolkit.getColors().getColor(IFormColors.TITLE)); approvalHeaderLabel.setText(approvalType.getName()); GridDataFactory.fillDefaults().align(SWT.RIGHT, SWT.CENTER).applyTo(approvalHeaderLabel); RequirementStatus status = null; if (requirementEntry != null) { status = requirementEntry.getStatus(); switch (status) { case SATISFIED: approvalHeaderLabel.setImage(CommonImages.getImage(ReviewsImages.APPROVED)); break; case NOT_SATISFIED: approvalHeaderLabel.setImage(CommonImages.getImage(ReviewsImages.UNKNOWN)); break; case REJECTED: approvalHeaderLabel.setImage(CommonImages.getImage(ReviewsImages.REJECTED)); break; default: //To ensure that label is aligned properly approvalHeaderLabel.setImage(CommonImages.getImage(ReviewsImages.BLANK)); break; } } if (status != null && (status == RequirementStatus.UNKNOWN || status == RequirementStatus.REJECTED)) { if (needs.length() > 0) { needs.append(", "); //$NON-NLS-1$ } needs.append(approvalType.getName()); } } AbstractUiFactoryProvider<IUser> reviewerUiFactoryProvider = getReviewerUiFactoryProvider(); Map<IUser, IReviewerEntry> sortedReviewerApprovals = new TreeMap<>( (u1, u2) -> u1.getDisplayName().compareTo(u2.getDisplayName())); sortedReviewerApprovals.putAll(getReview().getReviewerApprovals()); for (Entry<IUser, IReviewerEntry> approval : sortedReviewerApprovals.entrySet()) { IUser currentUser = approval.getKey(); createReviewerLabelAndControls(composite, reviewerUiFactoryProvider, currentUser); for (IApprovalType approvalType : approvalTypesWithLabel) { Integer value = approval.getValue().getApprovals().get(approvalType); Label approvalValueLabel = new Label(composite, SWT.NONE); GridDataFactory.fillDefaults().align(SWT.CENTER, SWT.FILL).applyTo(approvalValueLabel); String rankingText = " "; //$NON-NLS-1$ if (value != null && value != 0) { if (value > 0) { rankingText += "+"; //$NON-NLS-1$ approvalValueLabel.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_DARK_GREEN)); } else if (value < 0) { approvalValueLabel.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED)); } rankingText += value; approvalValueLabel.setToolTipText(value + " " + approvalType.getName()); //$NON-NLS-1$ } approvalValueLabel.setText(rankingText); } if (names.length() > 0) { names.append(", "); //$NON-NLS-1$ } names.append(currentUser.getDisplayName()); } String headerText = names.toString(); if (needs.length() > 0) { headerText += NLS.bind(Messages.ReviewDetailSection_Needs_X, needs); } if (headerText.length() > 0) { addTextClient(toolkit, subSection, headerText); } } if (getUiFactoryProvider() != null) { Composite actionComposite = getUiFactoryProvider().createControls(this, composite, getToolkit(), getReview()); GridDataFactory.fillDefaults().span(2, 1).applyTo(actionComposite); } } private void createReviewerLabelAndControls(Composite parent, AbstractUiFactoryProvider<IUser> reviewerUiFactoryProvider, IUser user) { Composite reviewerComp = toolkit.createComposite(parent, SWT.NONE); GridLayoutFactory.fillDefaults().numColumns(2).equalWidth(false).applyTo(reviewerComp); if (reviewerUiFactoryProvider != null) { createReviewerControls(reviewerComp, user, reviewerUiFactoryProvider); } createReviewerLabel(reviewerComp, user); } private void createReviewerLabel(Composite reviewerComposite, IUser user) { Label reviewerRowLabel = new Label(reviewerComposite, SWT.NONE); reviewerRowLabel.setForeground(toolkit.getColors().getColor(IFormColors.TITLE)); reviewerRowLabel.setText(user.getDisplayName()); } private void createReviewerControls(Composite reviewerComposite, IUser user, AbstractUiFactoryProvider<IUser> reviewerUiFactoryProvider) { Composite controlComposite = reviewerUiFactoryProvider.createControls(this, reviewerComposite, getToolkit(), user); GridDataFactory.fillDefaults().applyTo(controlComposite); } protected boolean canAddReviewers() { return true; } protected void createDependenciesSubSection(final FormToolkit toolkit, final Composite parent, String title, List<IChange> changes) { if (changes.isEmpty()) { return; } int style = ExpandableComposite.TWISTIE | ExpandableComposite.CLIENT_INDENT; final Section subSection = toolkit.createSection(parent, style); GridDataFactory.fillDefaults().grab(true, false).applyTo(subSection); subSection.setTitleBarForeground(toolkit.getColors().getColor(IFormColors.TITLE)); subSection.setText(title); Composite composite = toolkit.createComposite(subSection); GridLayoutFactory.fillDefaults().extendedMargins(0, 0, 0, 5).applyTo(composite); subSection.setClient(composite); for (final IChange change : changes) { Link link = new Link(composite, SWT.NONE); String changeStatus = change.getState() != null ? NLS.bind(Messages.ReviewDetailSection_Bracket_X_bracket, String.valueOf(change.getState().getName())) : " "; //$NON-NLS-1$ String ownerName = change.getOwner().getDisplayName(); link.setText(NLS.bind(Messages.ReviewDetailSection_Link_W_X_Y_by_Z, new String[] { StringUtils.left(change.getKey(), 9), change.getSubject(), ownerName, changeStatus })); link.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { TasksUiUtil.openTask(getTaskEditorPage().getTaskRepository(), change.getId()); } }); } } protected abstract AbstractUiFactoryProvider<IReview> getUiFactoryProvider(); protected AbstractUiFactoryProvider<IUser> getReviewerUiFactoryProvider() { return null; }; @Override protected boolean shouldExpandOnCreate() { return true; } }