| /******************************************************************************* |
| * Copyright (c) 2011 Ericsson Research Canada 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 |
| * |
| * Ericsson - Initial API and implementation |
| ******************************************************************************/ |
| |
| package org.eclipse.mylyn.internal.subclipse.ui; |
| |
| import java.text.SimpleDateFormat; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IStorage; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.mylyn.commons.core.StatusHandler; |
| import org.eclipse.mylyn.internal.subclipse.ui.connector.SVNConnectorUi; |
| import org.eclipse.mylyn.versions.core.Change; |
| import org.eclipse.mylyn.versions.core.ChangeSet; |
| import org.eclipse.mylyn.versions.core.ChangeType; |
| import org.eclipse.mylyn.versions.core.ScmCore; |
| import org.eclipse.mylyn.versions.core.ScmRepository; |
| import org.eclipse.mylyn.versions.core.spi.ScmConnector; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.custom.CCombo; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.team.core.history.IFileRevision; |
| import org.eclipse.team.core.history.provider.FileRevision; |
| import org.eclipse.ui.forms.FormDialog; |
| import org.eclipse.ui.forms.IManagedForm; |
| 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.ScrolledForm; |
| import org.eclipse.ui.forms.widgets.Section; |
| |
| /** |
| * This class implements the dialog used to fill-in the Find review items details This is a modeless-like dialog. |
| * |
| * @author Alvaro Sanhez-Leon |
| */ |
| public class GetChangeSetDialog extends FormDialog { |
| |
| /** |
| * Field FIND_REVIEW_ITEMS_DIALOG_TITLE. (value is ""Find Review Items"") |
| */ |
| private static final String FIND_REVIEW_ITEMS_DIALOG_TITLE = "Find Review Items"; |
| |
| /** |
| * Field FIND_REVIEW_ITEMS_DIALOG_VALUE. (value is ""Review Item Info"") |
| */ |
| private static final String FIND_REVIEW_ITEMS_DIALOG_VALUE = "Review Item Info"; |
| |
| /** |
| * Field FIND_REVIEW_ITEMS_DESCRIPTION_DIALOG_VALUE. (value is ""Review Item Components"") |
| */ |
| private static final String FIND_REVIEW_ITEMS_DESCRIPTION_DIALOG_VALUE = "Review Item Components"; |
| |
| /** |
| * Field COMMIT_INFO_HEADER_MSG. (value is ""Commit Information"") |
| */ |
| private static final String COMMIT_INFO_HEADER_MSG = "Commit Information"; |
| |
| /** |
| * Field COMMIT_COMPONENTS_HEADER_MSG. (value is ""Committed Components"") |
| */ |
| private static final String COMMIT_COMPONENTS_HEADER_MSG = "Committed Components"; |
| |
| /** |
| * Field DIALOG_COMBO_MAX_CHARACTERS. (value is 80) |
| */ |
| private static final int DIALOG_COMBO_MAX_CHARACTERS = 80; |
| |
| /** |
| * Field NEWLINE. (value is "\n") |
| */ |
| private static final String NEWLINE = "\n"; |
| |
| /** |
| * Field COMMIT_CHUNK_SIZE. |
| */ |
| private static final int COMMIT_CHUNK_SIZE = 9; |
| |
| /** |
| * Field NUM_COMMIT_SHOWN. (value is 10) |
| */ |
| private static final int NUM_COMMIT_SHOWN = 10; |
| |
| /** |
| * Field MORE_ITEMS_LABEL. (value is ""<more items>"") |
| */ |
| private static final String MORE_ITEMS_LABEL = "<more items>"; |
| |
| /** |
| * Field inputProject - Input project |
| */ |
| protected final IProject inputProject; |
| |
| /** |
| * Field commitList |
| */ |
| private CCombo commitList = null; |
| |
| /** |
| * Field selectedChangeSet. |
| */ |
| protected ChangeSet selectedChangeSet = null; |
| |
| /** |
| * Field messageText. |
| */ |
| Label messageText = null; |
| |
| /** |
| * Field idText. |
| */ |
| Label idText = null; |
| |
| /** |
| * Field authorNameText. |
| */ |
| Label authorNameText = null; |
| |
| /** |
| * Field authorEmailText. |
| */ |
| Label authorEmailText = null; |
| |
| /** |
| * Field dateText. |
| */ |
| Label dateText = null; |
| |
| /** |
| * Field repositoryNameText. |
| */ |
| Label repositoryNameText = null; |
| |
| /** |
| * Field changeList. |
| */ |
| org.eclipse.swt.widgets.List changeList = null; |
| |
| /** |
| * Field dateFormat. |
| */ |
| final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MMM-dd hh:mm:ss"); |
| |
| /** |
| * Field connector |
| */ |
| private ScmConnector connector = null; |
| |
| /** |
| * Field repository |
| */ |
| private ScmRepository repository = null; |
| |
| private Iterator<ChangeSet> changeSetsIter = null; |
| |
| /** |
| * Field filteredChangeSets - The ChangeSets that will be displayed |
| */ |
| private final List<ChangeSet> filteredChangeSets = new ArrayList<ChangeSet>(); |
| |
| private final IProgressMonitor changeSetIterMonitor; |
| |
| /** |
| * Constructor for R4EReviewGroupInputDialog. |
| * |
| * @param aParentShell |
| * Shell |
| * @param aInputProject |
| * IProject |
| * @param monitor |
| */ |
| public GetChangeSetDialog(Shell aParentShell, IProject aInputProject, IProgressMonitor monitor) { |
| super(aParentShell); |
| setBlockOnOpen(true); |
| inputProject = aInputProject; |
| if (monitor == null) { |
| changeSetIterMonitor = new NullProgressMonitor(); |
| } else { |
| changeSetIterMonitor = monitor; |
| } |
| } |
| |
| /** |
| * @param shell |
| * Shell |
| * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell) |
| */ |
| @Override |
| protected void configureShell(Shell aShell) { |
| super.configureShell(aShell); |
| aShell.setText(FIND_REVIEW_ITEMS_DIALOG_TITLE); |
| } |
| |
| /** |
| * Configures the dialog form and creates form content. Clients should override this method. |
| * |
| * @param mform |
| * - the dialog form |
| */ |
| @Override |
| protected void createFormContent(final IManagedForm mform) { |
| |
| try { |
| connector = ScmCore.getConnector(inputProject); |
| repository = connector.getRepository(inputProject, new NullProgressMonitor()); |
| changeSetsIter = connector.getChangeSetsIterator(repository, changeSetIterMonitor); |
| |
| final FormToolkit toolkit = mform.getToolkit(); |
| final ScrolledForm sform = mform.getForm(); |
| sform.setExpandVertical(true); |
| |
| // Main dialog composite |
| final Composite composite = sform.getBody(); |
| composite.setLayout(new GridLayout(4, false)); |
| |
| // Add Commit List in drop-down menu |
| final Label label = toolkit.createLabel(composite, "Available Commits: "); |
| label.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false)); |
| commitList = new CCombo(composite, SWT.WRAP | SWT.READ_ONLY); |
| populateNextChangeSets(); |
| |
| commitList.setTextLimit(DIALOG_COMBO_MAX_CHARACTERS); |
| commitList.setVisibleItemCount(NUM_COMMIT_SHOWN); |
| commitList.select(0); |
| selectedChangeSet = filteredChangeSets.get(0); |
| final GridData textGridData = new GridData(GridData.FILL, GridData.FILL, true, false); |
| textGridData.horizontalSpan = 3; |
| commitList.setLayoutData(textGridData); |
| commitList.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| int selectedIndex = commitList.getSelectionIndex(); |
| if (commitList.getItem(selectedIndex).equals(MORE_ITEMS_LABEL)) { |
| try { |
| populateNextChangeSets(); |
| } catch (CoreException e1) { |
| StatusHandler.log(new Status(IStatus.ERROR, SVNConnectorUi.ID_PLUGIN, IStatus.OK, |
| e.toString(), e1)); |
| return; |
| } |
| commitList.select(selectedIndex); |
| selectedChangeSet = filteredChangeSets.get(selectedIndex); |
| } else { |
| selectedChangeSet = filteredChangeSets.get(selectedIndex); |
| } |
| refresh(); |
| } |
| }); |
| |
| createReviewItemDetails(toolkit, sform); |
| createReviewItemComponents(toolkit, sform); |
| |
| } catch (CoreException e) { |
| StatusHandler.log(new Status(IStatus.ERROR, SVNConnectorUi.ID_PLUGIN, IStatus.OK, e.toString(), e)); |
| } |
| return; |
| } |
| |
| /** |
| * Gets the information and populates the local data structure with the next round of commit informations |
| * |
| * @throws CoreException |
| */ |
| protected void populateNextChangeSets() throws CoreException { |
| ChangeSet updatedChangeSet = null; |
| String repoProject = null; |
| int addedCount = 0; |
| |
| // Remove more items entry |
| int selIndex = commitList.getSelectionIndex(); |
| if (selIndex > 0) { |
| commitList.remove(selIndex); |
| } |
| |
| while (changeSetsIter.hasNext()) { |
| updatedChangeSet = changeSetsIter.next(); |
| if (updatedChangeSet == null) { |
| String message = "No input received, check connectivity"; |
| commitList.add(message); |
| commitList.select(0); |
| |
| //Error case |
| throw new CoreException(new Status(IStatus.ERROR, SVNConnectorUi.ID_PLUGIN, message)); |
| } |
| |
| // Only display commits that contains at least one file from the |
| // selected project |
| for (Change change : updatedChangeSet.getChanges()) { |
| if (change.getTarget() != null) { |
| repoProject = change.getTarget().getProjectName(); |
| } else if (change.getBase() != null) { |
| repoProject = change.getBase().getProjectName(); |
| } |
| if (repoProject != null && repoProject.equals(inputProject.getName())) { |
| String[] tokens = updatedChangeSet.getMessage().split(NEWLINE, 2); |
| commitList.add((tokens[0].length() > DIALOG_COMBO_MAX_CHARACTERS) ? tokens[0].substring(0, |
| DIALOG_COMBO_MAX_CHARACTERS - 3) + "..." : tokens[0]); |
| filteredChangeSets.add(updatedChangeSet); |
| |
| addedCount++; |
| |
| // If we already have all the commits from the current batch |
| // exit |
| if (addedCount % COMMIT_CHUNK_SIZE == 0) { |
| commitList.add(MORE_ITEMS_LABEL); |
| return; |
| } |
| break; |
| } |
| } |
| } |
| return; |
| } |
| |
| /** |
| * Creates the Currently Selected Review Items Details Expandable Composite |
| * |
| * @param aToolkit |
| * FormToolkit |
| * @param aParent |
| * Composite |
| */ |
| private void createReviewItemDetails(FormToolkit aToolkit, final ScrolledForm aParent) { |
| |
| GridData textGridData = null; |
| |
| // Basic parameters section |
| final Section basicSection = aToolkit.createSection(aParent.getBody(), Section.DESCRIPTION |
| | ExpandableComposite.TITLE_BAR | ExpandableComposite.TWISTIE | ExpandableComposite.EXPANDED); |
| final GridData basicSectionGridData = new GridData(GridData.FILL, GridData.FILL, true, false); |
| basicSectionGridData.horizontalSpan = 4; |
| basicSection.setLayoutData(basicSectionGridData); |
| basicSection.setText(COMMIT_INFO_HEADER_MSG); |
| basicSection.setDescription(FIND_REVIEW_ITEMS_DIALOG_VALUE); |
| basicSection.addExpansionListener(new ExpansionAdapter() { |
| @Override |
| public void expansionStateChanged(ExpansionEvent e) { |
| aParent.reflow(true); |
| getShell().setSize(getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT)); |
| } |
| }); |
| final Composite basicSectionClient = aToolkit.createComposite(basicSection); |
| basicSectionClient.setLayout(new GridLayout(4, false)); |
| basicSection.setClient(basicSectionClient); |
| |
| // Message |
| final Label titleLabel = aToolkit.createLabel(basicSectionClient, "Title: ", SWT.WRAP); |
| titleLabel.setLayoutData(new GridData(GridData.FILL, GridData.FILL, false, false)); |
| messageText = aToolkit.createLabel(basicSectionClient, selectedChangeSet.getMessage(), SWT.NONE); |
| textGridData = new GridData(GridData.FILL, GridData.FILL, true, false); |
| textGridData.horizontalSpan = 3; |
| messageText.setLayoutData(textGridData); |
| |
| // Id |
| final Label idLabel = aToolkit.createLabel(basicSectionClient, "ID: ", SWT.WRAP); |
| idLabel.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false)); |
| idText = aToolkit.createLabel(basicSectionClient, selectedChangeSet.getId(), SWT.NONE); |
| textGridData = new GridData(GridData.FILL, GridData.FILL, true, false); |
| textGridData.horizontalSpan = 3; |
| idText.setLayoutData(textGridData); |
| |
| // Author Name |
| final Label authorNameLabel = aToolkit.createLabel(basicSectionClient, "Author Name: ", SWT.WRAP); |
| authorNameLabel.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false)); |
| authorNameText = aToolkit.createLabel(basicSectionClient, selectedChangeSet.getAuthor().getName(), SWT.NONE); |
| textGridData = new GridData(GridData.FILL, GridData.FILL, true, false); |
| textGridData.horizontalSpan = 3; |
| authorNameText.setLayoutData(textGridData); |
| |
| // Author Email |
| final Label authorEmailLabel = aToolkit.createLabel(basicSectionClient, "Author Email: ", SWT.WRAP); |
| authorEmailLabel.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false)); |
| authorEmailText = aToolkit.createLabel(basicSectionClient, selectedChangeSet.getAuthor().getEmail(), SWT.NONE); |
| textGridData = new GridData(GridData.FILL, GridData.FILL, true, false); |
| textGridData.horizontalSpan = 3; |
| authorEmailText.setLayoutData(textGridData); |
| |
| // Date |
| final Label dateLabel = aToolkit.createLabel(basicSectionClient, "Date: ", SWT.WRAP); |
| dateLabel.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false)); |
| final String dateStr = dateFormat.format(selectedChangeSet.getDate()); |
| dateText = aToolkit.createLabel(basicSectionClient, dateStr, SWT.NONE); |
| textGridData = new GridData(GridData.FILL, GridData.FILL, true, false); |
| textGridData.horizontalSpan = 3; |
| dateText.setLayoutData(textGridData); |
| |
| // Repository Name |
| final Label messageLabel = aToolkit.createLabel(basicSectionClient, "Repository: ", SWT.WRAP); |
| messageLabel.setLayoutData(new GridData(GridData.BEGINNING, GridData.BEGINNING, false, false)); |
| repositoryNameText = aToolkit.createLabel(basicSectionClient, selectedChangeSet.getRepository().getName(), |
| SWT.NONE); |
| textGridData = new GridData(GridData.FILL, GridData.FILL, true, false); |
| textGridData.horizontalSpan = 3; |
| repositoryNameText.setLayoutData(textGridData); |
| |
| basicSectionClient.layout(); |
| } |
| |
| /** |
| * Creates the Review Items Components Expandable Composite |
| * |
| * @param aToolkit |
| * FormToolkit |
| * @param aParent |
| * Composite |
| */ |
| private void createReviewItemComponents(FormToolkit aToolkit, final ScrolledForm aParent) { |
| |
| // Extra parameters section |
| final Section extraSection = aToolkit.createSection(aParent.getBody(), Section.DESCRIPTION |
| | ExpandableComposite.TITLE_BAR | ExpandableComposite.TWISTIE | ExpandableComposite.EXPANDED); |
| final GridData extraSectionGridData = new GridData(GridData.FILL, GridData.FILL, true, true); |
| extraSectionGridData.horizontalSpan = 4; |
| extraSection.setLayoutData(extraSectionGridData); |
| extraSection.setText(COMMIT_COMPONENTS_HEADER_MSG); |
| extraSection.setDescription(FIND_REVIEW_ITEMS_DESCRIPTION_DIALOG_VALUE); |
| extraSection.addExpansionListener(new ExpansionAdapter() { |
| @Override |
| public void expansionStateChanged(ExpansionEvent e) { |
| aParent.reflow(true); |
| getShell().setSize(getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT)); |
| } |
| }); |
| |
| final Composite extraSectionClient = aToolkit.createComposite(extraSection); |
| extraSectionClient.setLayout(new GridLayout(4, false)); |
| extraSectionClient.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true)); |
| extraSection.setClient(extraSectionClient); |
| |
| // Components List |
| changeList = new org.eclipse.swt.widgets.List(extraSectionClient, SWT.V_SCROLL | SWT.H_SCROLL); |
| for (Change change : selectedChangeSet.getChanges()) { |
| changeList.add(getAdjustedPath(change)); |
| } |
| final GridData data = new GridData(GridData.FILL, GridData.FILL, true, true); |
| changeList.setLayoutData(data); |
| } |
| |
| /** |
| * Fetches and updates the local ChangeSet information with resolution of base changes |
| * |
| * @param aSelectedChangeSet |
| * ChangeSet |
| * @throws CoreException |
| */ |
| private ChangeSet updateChangeSet(ChangeSet aSelectedChangeSet) { |
| String changeSetId = aSelectedChangeSet.getId(); |
| ChangeSet updatedChangeSet = null; |
| |
| // IFileRevision |
| IFileRevision fileRevision = createFileRevision(changeSetId); |
| try { |
| updatedChangeSet = connector.getChangeSet(repository, fileRevision, new NullProgressMonitor()); |
| } catch (CoreException e) { |
| StatusHandler.log(new Status(IStatus.ERROR, SVNConnectorUi.ID_PLUGIN, "Unable to resolve changeSet " //$NON-NLS-1$ |
| + changeSetId, e)); |
| return aSelectedChangeSet; // return non-updated ChangeSet |
| } |
| return updatedChangeSet; |
| } |
| |
| /** |
| * @param changeSetId |
| * String |
| * @return IFileRevision |
| */ |
| private IFileRevision createFileRevision(final String changeSetId) { |
| IFileRevision fileRevision = new FileRevision() { |
| |
| public IFileRevision withAllProperties(IProgressMonitor monitor) throws CoreException { |
| return null; |
| } |
| |
| public boolean isPropertyMissing() { |
| return false; |
| } |
| |
| public IStorage getStorage(IProgressMonitor monitor) throws CoreException { |
| return null; |
| } |
| |
| @Override |
| public String getContentIdentifier() { |
| return changeSetId; |
| } |
| |
| public String getName() { |
| return null; |
| } |
| }; |
| return fileRevision; |
| } |
| |
| /** |
| * Refreshes the Form. |
| */ |
| void refresh() { |
| messageText.setText(selectedChangeSet.getMessage()); |
| idText.setText(selectedChangeSet.getId()); |
| dateText.setText(dateFormat.format(selectedChangeSet.getDate())); // BUG! |
| authorNameText.setText(selectedChangeSet.getAuthor().getName()); |
| authorEmailText.setText(selectedChangeSet.getAuthor().getEmail()); |
| repositoryNameText.setText(selectedChangeSet.getRepository().getUrl()); |
| changeList.removeAll(); |
| for (Change change : selectedChangeSet.getChanges()) { |
| changeList.add(getAdjustedPath(change)); |
| } |
| } |
| |
| /** |
| * @return boolean |
| * @see org.eclipse.jface.dialogs.Dialog#isResizable() |
| */ |
| @Override |
| protected boolean isResizable() { |
| return true; |
| } |
| |
| public ChangeSet getChangeSet() { |
| if (selectedChangeSet == null) { |
| return null; |
| } |
| |
| //return a deep parsed version of the changeset |
| return updateChangeSet(selectedChangeSet); |
| } |
| |
| /** |
| * Add a little Text Decoration if the File was Added or Removed |
| * |
| * @param aChange |
| * Change |
| * @return String |
| */ |
| private String getAdjustedPath(Change aChange) { |
| String path = aChange.getTarget().getPath(); |
| if (aChange.getChangeType().equals(ChangeType.DELETED)) { |
| return "[-] " + path; |
| } else if (aChange.getChangeType().equals(ChangeType.ADDED)) { |
| return "[+] " + path; |
| } else { |
| return " " + path; |
| } |
| } |
| } |