/*******************************************************************************
* Copyright (c) 2000, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.team.internal.ccvs.ui;
import java.util.*;
import java.util.List;
import org.eclipse.core.resources.IProject;
import org.eclipse.jface.action.*;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.viewers.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.*;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
import org.eclipse.team.internal.ccvs.core.*;
import org.eclipse.team.internal.ccvs.core.resources.CVSWorkspaceRoot;
import org.eclipse.team.internal.ccvs.ui.actions.CVSAction;
import org.eclipse.team.internal.ccvs.ui.merge.ProjectElement;
import org.eclipse.team.internal.ccvs.ui.merge.TagElement;
import org.eclipse.team.internal.ccvs.ui.merge.ProjectElement.ProjectElementSorter;
import org.eclipse.team.internal.ccvs.ui.repo.*;
import org.eclipse.ui.help.WorkbenchHelp;
import org.eclipse.ui.model.WorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;
/**
* Dialog to prompt the user to choose a tag for a selected resource
*/
public class TagSelectionDialog extends Dialog{
private ICVSFolder[] folders;
private int includeFlags;
private CVSTag result;
private String helpContext;
private IStructuredSelection selection;
public static final int INCLUDE_HEAD_TAG = ProjectElement.INCLUDE_HEAD_TAG;
public static final int INCLUDE_BASE_TAG = ProjectElement.INCLUDE_BASE_TAG;
public static final int INCLUDE_BRANCHES = ProjectElement.INCLUDE_BRANCHES;
public static final int INCLUDE_VERSIONS = ProjectElement.INCLUDE_VERSIONS;
public static final int INCLUDE_DATES = ProjectElement.INCLUDE_DATES;
public static final int INCLUDE_ALL_TAGS = ProjectElement.INCLUDE_ALL_TAGS;
// widgets;
private TreeViewer tagTree;
private Button okButton;
// dialog title, should indicate the action in which the tag selection
// dialog is being shown
private String title;
private String message;
private boolean recurse = true;
private boolean showRecurse;
// constants
private static final int SIZING_DIALOG_WIDTH = 400;
private static final int SIZING_DIALOG_HEIGHT = 250;
public static CVSTag getTagToCompareWith(Shell shell, IProject[] projects) {
return getTagToCompareWith(shell, getCVSFoldersFor(projects));
}
public static CVSTag getTagToCompareWith(Shell shell, ICVSFolder[] folders) {
TagSelectionDialog dialog = new TagSelectionDialog(shell, folders,
Policy.bind("CompareWithTagAction.message"), //$NON-NLS-1$
Policy.bind("TagSelectionDialog.Select_a_Tag_1"), //$NON-NLS-1$
TagSelectionDialog.INCLUDE_ALL_TAGS,
false, /* show recurse*/
IHelpContextIds.COMPARE_TAG_SELECTION_DIALOG);
dialog.setBlockOnOpen(true);
int result = dialog.open();
if (result == Dialog.CANCEL) {
return null;
}
return dialog.getResult();
}
/**
* Creates a new TagSelectionDialog.
* @param resource The resource to select a version for.
*/
public TagSelectionDialog(Shell parentShell, IProject[] projects, String title, String message, int includeFlags, boolean showRecurse, String helpContext) {
this(parentShell, getCVSFoldersFor(projects), title, message, includeFlags, showRecurse, helpContext); //$NON-NLS-1$
}
private static ICVSFolder[] getCVSFoldersFor(IProject[] projects) {
ICVSFolder[] folders = new ICVSFolder[projects.length];
for (int i = 0; i < projects.length; i++) {
folders[i] = CVSWorkspaceRoot.getCVSFolderFor(projects[i]);
}
return folders;
}
/**
* Creates a new TagSelectionDialog.
* @param resource The resource to select a version for.
*/
public TagSelectionDialog(Shell parentShell, ICVSFolder[] folders, String title, String message, int includeFlags, boolean showRecurse, String helpContext) {
super(parentShell);
this.folders = folders;
this.title = title;
this.message = message;
this.includeFlags = includeFlags;
this.showRecurse = showRecurse;
this.helpContext = helpContext;
setShellStyle(getShellStyle() | SWT.RESIZE);
}
/* (non-Javadoc)
* Method declared on Window.
*/
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
newShell.setText(title);
}
/**
* 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 the parent composite to contain the dialog area
* @return the dialog area control
*/
protected Control createDialogArea(Composite parent) {
Composite top = (Composite)super.createDialogArea(parent);
// Add F1 help
if (helpContext != null) {
WorkbenchHelp.setHelp(top, helpContext);
}
Composite inner = new Composite(top, SWT.NULL);
GridData data = new GridData(GridData.FILL_BOTH);
data.widthHint = SIZING_DIALOG_WIDTH;
data.heightHint = SIZING_DIALOG_HEIGHT;
inner.setLayoutData(data);
GridLayout layout = new GridLayout();
inner.setLayout(layout);
Label l = new Label (inner, SWT.NONE);
l.setText(message); //$NON-NLS-1$
tagTree = createTree(inner);
tagTree.setInput(new ProjectElement(folders[0], includeFlags));
tagTree.setSorter(new ProjectElementSorter());
Runnable refresh = new Runnable() {
public void run() {
getShell().getDisplay().syncExec(new Runnable() {
public void run() {
tagTree.refresh();
}
});
}
};
// Create the popup menu
MenuManager menuMgr = new MenuManager();
Tree tree = tagTree.getTree();
Menu menu = menuMgr.createContextMenu(tree);
menuMgr.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
addMenuItemActions(manager);
}
});
menuMgr.setRemoveAllWhenShown(true);
tree.setMenu(menu);
if(showRecurse) {
final Button recurseCheck = new Button(top, SWT.CHECK);
recurseCheck.setText(Policy.bind("TagSelectionDialog.recurseOption")); //$NON-NLS-1$
recurseCheck.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
recurse = recurseCheck.getSelection();
}
});
recurseCheck.setSelection(true);
}
TagConfigurationDialog.createTagDefinitionButtons(getShell(), top, folders,
convertVerticalDLUsToPixels(IDialogConstants.BUTTON_HEIGHT),
convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH),
refresh, refresh);
Label seperator = new Label(top, SWT.SEPARATOR | SWT.HORIZONTAL);
data = new GridData (GridData.FILL_BOTH);
data.horizontalSpan = 2;
seperator.setLayoutData(data);
updateEnablement();
Dialog.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;
}
protected TreeViewer createTree(Composite parent) {
Tree tree = new Tree(parent, SWT.MULTI | SWT.BORDER);
tree.setLayoutData(new GridData(GridData.FILL_BOTH));
TreeViewer result = new TreeViewer(tree);
result.setContentProvider(new WorkbenchContentProvider());
result.setLabelProvider(new WorkbenchLabelProvider());
result.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
updateEnablement();
}
});
// select and close on double click
// To do: use defaultselection instead of double click
result.getTree().addMouseListener(new MouseAdapter() {
public void mouseDoubleClick(MouseEvent e) {
IStructuredSelection selection = (IStructuredSelection)tagTree.getSelection();
if (!selection.isEmpty() && (selection.getFirstElement() instanceof TagElement)) {
okPressed();
}
}
});
result.getControl().addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent event) {
handleKeyPressed(event);
}
public void keyReleased(KeyEvent event) {
handleKeyReleased(event);
}
});
result.setSorter(new RepositorySorter());
return result;
}
/**
* Returns the selected tag.
*/
public CVSTag getResult() {
return result;
}
public boolean getRecursive() {
return recurse;
}
/**
* Initializes the dialog contents.
*/
protected void initialize() {
okButton.setEnabled(false);
}
/**
* Notifies that the ok button of this dialog has been pressed.
*
* The default implementation of this framework method sets
* this dialog's return code to Window.OK
* and closes the dialog. Subclasses may override.
*
*/
protected void okPressed() {
IStructuredSelection selection = (IStructuredSelection)tagTree.getSelection();
Object o = selection.getFirstElement();
TagElement element = (TagElement)o;
result = element.getTag();
super.okPressed();
}
/**
* Updates the dialog enablement.
*/
protected void updateEnablement() {
selection = (IStructuredSelection)tagTree.getSelection();
if(okButton!=null) {
if (selection.isEmpty() || selection.size() != 1 || !(selection.getFirstElement() instanceof TagElement)) {
okButton.setEnabled(false);
} else {
okButton.setEnabled(true);
}
}
}
public void handleKeyPressed(KeyEvent event) {
if (event.character == SWT.DEL && event.stateMask == 0) {
deleteDateTag();
}
}
private void deleteDateTag() {
TagElement[] selectedDateTagElements = getSelectedDateTagElement();
if (selectedDateTagElements.length == 0) return;
for(int i = 0; i < selectedDateTagElements.length; i++){
RepositoryManager mgr = CVSUIPlugin.getPlugin().getRepositoryManager();
CVSTag tag = selectedDateTagElements[i].getTag();
if(tag.getType() == CVSTag.DATE){
mgr.removeDateTag(getLocation(),tag);
}
}
tagTree.refresh();
updateEnablement();
}
protected void handleKeyReleased(KeyEvent event) {
}
private ICVSRepositoryLocation getLocation(){
RepositoryManager mgr = CVSUIPlugin.getPlugin().getRepositoryManager();
ICVSRepositoryLocation location = mgr.getRepositoryLocationFor( folders[0]);
return location;
}
/**
* Returns the selected date tag elements
*/
private TagElement[] getSelectedDateTagElement() {
ArrayList dateTagElements = null;
if (selection!=null && !selection.isEmpty()) {
dateTagElements = new ArrayList();
Iterator elements = selection.iterator();
while (elements.hasNext()) {
Object next = CVSAction.getAdapter(elements.next(), TagElement.class);
if (next instanceof TagElement) {
if(((TagElement)next).getTag().getType() == CVSTag.DATE){
dateTagElements.add(next);
}
}
}
}
if (dateTagElements != null && !dateTagElements.isEmpty()) {
TagElement[] result = new TagElement[dateTagElements.size()];
dateTagElements.toArray(result);
return result;
}
return new TagElement[0];
}
private void addDateTag(CVSTag tag){
if(tag == null) return;
List dateTags = new ArrayList();
dateTags.addAll(Arrays.asList(CVSUIPlugin.getPlugin().getRepositoryManager().getKnownTags(folders[0],CVSTag.DATE)));
if(!dateTags.contains( tag)){
CVSUIPlugin.getPlugin().getRepositoryManager().addDateTag(getLocation(),tag);
}
try {
tagTree.getControl().setRedraw(false);
tagTree.refresh();
// TODO: Hack to instantiate the model before revealing the selection
Object[] expanded = tagTree.getExpandedElements();
tagTree.expandToLevel(2);
tagTree.collapseAll();
for (int i = 0; i < expanded.length; i++) {
Object object = expanded[i];
tagTree.expandToLevel(object, 1);
}
// Reveal the selection
tagTree.reveal(new TagElement(tag));
tagTree.setSelection(new StructuredSelection(new TagElement(tag)));
} finally {
tagTree.getControl().setRedraw(true);
}
updateEnablement();
}
private void addMenuItemActions(IMenuManager manager) {
manager.add(new Action(Policy.bind("TagSelectionDialog.0")) { //$NON-NLS-1$
public void run() {
CVSTag dateTag = NewDateTagAction.getDateTag(getShell(), CVSUIPlugin.getPlugin().getRepositoryManager().getRepositoryLocationFor(folders[0]));
addDateTag(dateTag);
}
});
if(getSelectedDateTagElement().length > 0){
manager.add(new Action(Policy.bind("TagSelectionDialog.1")) { //$NON-NLS-1$
public void run() {
deleteDateTag();
}
});
}
}
}