/******************************************************************************* * Copyright (c) 2000, 2018 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.team.internal.ccvs.ui.tags; import java.lang.reflect.InvocationTargetException; import org.eclipse.core.runtime.*; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.TrayDialog; import org.eclipse.jface.operation.IRunnableContext; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.*; import org.eclipse.team.internal.ccvs.core.CVSStatus; import org.eclipse.team.internal.ccvs.core.CVSTag; import org.eclipse.team.internal.ccvs.ui.*; /** * Dialog to prompt the user to choose a tag for a selected resource */ public class TagSelectionDialog extends TrayDialog implements IPropertyChangeListener { private TagSelectionArea tagSelectionArea; public static final int INCLUDE_HEAD_TAG = TagSourceWorkbenchAdapter.INCLUDE_HEAD_TAG; public static final int INCLUDE_BASE_TAG = TagSourceWorkbenchAdapter.INCLUDE_BASE_TAG; public static final int INCLUDE_BRANCHES = TagSourceWorkbenchAdapter.INCLUDE_BRANCHES; public static final int INCLUDE_VERSIONS = TagSourceWorkbenchAdapter.INCLUDE_VERSIONS; public static final int INCLUDE_DATES = TagSourceWorkbenchAdapter.INCLUDE_DATES; public static final int INCLUDE_ALL_TAGS = TagSourceWorkbenchAdapter.INCLUDE_ALL_TAGS; private Button okButton; // dialog title, should indicate the action in which the tag selection // dialog is being shown private String title; private boolean recurse = true; // constants private static final int SIZING_DIALOG_WIDTH = 90; private static final int SIZING_DIALOG_HEIGHT = 25; private CVSTag selection; private TagSource tagSource; private String message; private int includeFlags; private String helpContext; private boolean showRecurse; public static CVSTag getTagToCompareWith(Shell shell, TagSource tagSource, int includeFlags) { TagSelectionDialog dialog = new TagSelectionDialog(shell, tagSource, CVSUIMessages.CompareWithTagAction_message, CVSUIMessages.TagSelectionDialog_Select_a_Tag_1, includeFlags, false, /* show recurse*/ IHelpContextIds.COMPARE_TAG_SELECTION_DIALOG); dialog.setBlockOnOpen(true); int result = dialog.open(); if (result == Window.CANCEL) { return null; } return dialog.getResult(); } /** * Creates a new TagSelectionDialog. * @param resource The resource to select a version for. */ public TagSelectionDialog(Shell parentShell, TagSource tagSource, String title, String message, int includeFlags, final boolean showRecurse, String helpContext) { super(parentShell); // Create a tag selection area with a custom recurse option this.tagSource = tagSource; this.message = message; this.includeFlags = includeFlags; this.helpContext = helpContext; this.showRecurse = showRecurse; this.title = title; setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE | SWT.APPLICATION_MODAL); } protected void configureShell(Shell newShell) { super.configureShell(newShell); newShell.setText(title); } protected Point getInitialSize() { final Point size= super.getInitialSize(); size.x= convertWidthInCharsToPixels(SIZING_DIALOG_WIDTH); size.y= convertHeightInCharsToPixels(SIZING_DIALOG_HEIGHT); return size; } /** * Creates this window's widgetry. *

* The default implementation of this framework method * creates this window's shell (by calling createShell), * its control (by calling createContents), * and initializes this window's shell bounds * (by calling initializeBounds). * This framework method may be overridden; however, * super.create must be called. *

*/ public void create() { super.create(); initialize(); } /** * Add buttons to the dialog's button bar. * * @param parent the button bar composite */ protected void createButtonsForButtonBar(Composite parent) { // create OK and Cancel buttons by default okButton = createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); okButton.setEnabled(false); createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); } /** * Creates and returns the contents of the upper part * of this dialog (above the button bar). *

* The default implementation of this framework method * creates and returns a new Composite with * standard margins and spacing. * Subclasses should override. *

* * @param parent the parent composite to contain the dialog area * @return the dialog area control */ protected Control createDialogArea(Composite parent) { applyDialogFont(parent); initializeDialogUnits(parent); final Composite top = (Composite)super.createDialogArea(parent); // Delegate most of the dialog to the tag selection area tagSelectionArea = new TagSelectionArea(getShell(), tagSource, includeFlags, helpContext) { protected void createCustomArea(Composite parent) { if(showRecurse) { final Button recurseCheck = new Button(parent, SWT.CHECK); recurseCheck.setText(CVSUIMessages.TagSelectionDialog_recurseOption); recurseCheck.addListener(SWT.Selection, event -> recurse = recurseCheck.getSelection()); recurseCheck.setSelection(true); } } }; if (message != null) tagSelectionArea.setTagAreaLabel(message); tagSelectionArea.addPropertyChangeListener(this); tagSelectionArea.createArea(top); tagSelectionArea.setRunnableContext(getRunnableContext()); // Create a separator between the tag area and the button area final Label seperator = new Label(top, SWT.SEPARATOR | SWT.HORIZONTAL); final GridData data = new GridData (GridData.FILL_HORIZONTAL); data.horizontalSpan = 2; seperator.setLayoutData(data); updateEnablement(); applyDialogFont(parent); return top; } /** * Utility method that creates a label instance * and sets the default layout data. * * @param parent the parent for the new label * @param text the text for the new label * @return the new label */ protected Label createLabel(Composite parent, String text) { Label label = new Label(parent, SWT.LEFT); label.setText(text); GridData data = new GridData(); data.horizontalSpan = 1; data.horizontalAlignment = GridData.FILL; label.setLayoutData(data); return label; } /** * Returns the selected tag. */ public CVSTag getResult() { return selection; } public boolean getRecursive() { return recurse; } /** * Initializes the dialog contents. */ protected void initialize() { okButton.setEnabled(false); if (CVSUIPlugin.getPlugin().getPreferenceStore().getBoolean(ICVSUIConstants.PREF_AUTO_REFRESH_TAGS_IN_TAG_SELECTION_DIALOG)) tagSelectionArea.refreshTagList(); } /** * Updates the dialog enablement. */ protected void updateEnablement() { if(okButton!=null) { okButton.setEnabled(selection != null); } } public void propertyChange(PropertyChangeEvent event) { String property = event.getProperty(); if (property.equals(TagSelectionArea.SELECTED_TAG)) { selection = (CVSTag)event.getNewValue(); updateEnablement(); } else if (property.equals(TagSelectionArea.OPEN_SELECTED_TAG)) { okPressed(); } } /** * Creates a runnable context that allows refreshing the tags in the background. * * @since 3.1 */ private IRunnableContext getRunnableContext() { return (fork, cancelable, runnable) -> { final Job refreshJob = new Job(CVSUIMessages.TagSelectionDialog_7) { protected IStatus run(IProgressMonitor monitor) { if (monitor.isCanceled()) return Status.CANCEL_STATUS; try { setBusy(true); runnable.run(monitor); } catch (InvocationTargetException e) { return new CVSStatus(IStatus.ERROR, CVSUIMessages.TagSelectionDialog_8, e); } catch (InterruptedException e) { return new CVSStatus(IStatus.ERROR, CVSUIMessages.TagSelectionDialog_8, e); } finally { setBusy(false); } if (monitor.isCanceled()) return Status.CANCEL_STATUS; else return Status.OK_STATUS; } }; refreshJob.setUser(false); refreshJob.setPriority(Job.DECORATE); getShell().addDisposeListener(e -> refreshJob.cancel()); refreshJob.schedule(); }; } private void setBusy(final boolean busy) { final Shell shell = getShell(); if (shell != null && !shell.isDisposed()) { shell.getDisplay().asyncExec(() -> { if (!shell.isDisposed()) { Cursor cursor = null; if (busy) { cursor = shell.getDisplay().getSystemCursor(SWT.CURSOR_APPSTARTING); } shell.setCursor(cursor); } }); } } }