Java tutorial
/******************************************************************************* * Copyright (c) 2003, 2006 Subclipse project 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: * Subclipse project committers - initial API and implementation ******************************************************************************/ package org.tigris.subversion.subclipse.ui.actions; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceVisitor; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jface.action.IAction; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.MessageDialogWithToggle; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.team.core.RepositoryProvider; import org.eclipse.team.core.TeamException; import org.eclipse.team.internal.core.subscribers.ActiveChangeSet; import org.eclipse.team.internal.core.subscribers.ChangeSet; import org.tigris.subversion.subclipse.core.ISVNCoreConstants; import org.tigris.subversion.subclipse.core.ISVNLocalResource; import org.tigris.subversion.subclipse.core.SVNException; import org.tigris.subversion.subclipse.core.SVNProviderPlugin; import org.tigris.subversion.subclipse.core.commands.GetStatusCommand; import org.tigris.subversion.subclipse.core.resources.SVNWorkspaceRoot; import org.tigris.subversion.subclipse.core.util.File2Resource; import org.tigris.subversion.subclipse.core.util.Util; import org.tigris.subversion.subclipse.ui.ISVNUIConstants; import org.tigris.subversion.subclipse.ui.Policy; import org.tigris.subversion.subclipse.ui.SVNUIPlugin; import org.tigris.subversion.subclipse.ui.dialogs.CommitToTagsWarningDialog; import org.tigris.subversion.subclipse.ui.operations.CommitOperation; import org.tigris.subversion.subclipse.ui.settings.ProjectProperties; import org.tigris.subversion.subclipse.ui.wizards.dialogs.SvnWizard; import org.tigris.subversion.subclipse.ui.wizards.dialogs.SvnWizardCommitPage; import org.tigris.subversion.subclipse.ui.wizards.dialogs.SvnWizardDialog; import org.tigris.subversion.svnclientadapter.ISVNStatus; import org.tigris.subversion.svnclientadapter.utils.SVNStatusUtils; /** * Action for checking in files to a subversion provider * Prompts the user for a release comment, and shows a selection * list of added and modified resources, including unversioned resources. * If selected, unversioned resources will be added to version control, * and committed. */ public class CommitAction extends WorkbenchWindowAction { protected String commitComment; protected IResource[] resourcesToCommit; protected String url; protected boolean hasUnaddedResources; protected boolean commit; protected boolean keepLocks; protected IResource[] selectedResources; private String proposedComment; private boolean canRunAsJob = true; // private boolean sharing; private HashMap statusMap; public CommitAction() { } public CommitAction(String proposedComment) { this.proposedComment = proposedComment; } /* * get non added resources and prompts for resources to be added * prompts for comments * add non added files * commit selected files * @see SVNAction#execute(IAction) */ public void execute(IAction action) throws InvocationTargetException, InterruptedException { statusMap = new HashMap(); final IResource[] resources = getSelectedResources(); final List resourcesToBeAdded = new ArrayList(); final List resourcesToBeDeleted = new ArrayList(); if (action != null && !action.isEnabled()) { action.setEnabled(true); } else { run(new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException { try { // search for modified or added, non-ignored resources in the selection. IResource[] modified = getChangeSetResources(getModifiedResources(resources, monitor)); // if no changes since last commit, do not show commit dialog. if (modified.length == 0) { MessageDialog.openInformation(getShell(), Policy.bind("CommitDialog.title"), //$NON-NLS-1$ Policy.bind("CommitDialog.noChanges")); //$NON-NLS-1$ commit = false; } else { ProjectProperties projectProperties = ProjectProperties .getProjectProperties(modified[0]); commit = confirmCommit(modified, projectProperties); } // if commit was not canceled, create a list of any // unversioned resources that were selected and a list of any missing // resources that were selected. if (commit) { for (int i = 0; i < resourcesToCommit.length; i++) { IResource resource = resourcesToCommit[i]; ISVNLocalResource svnResource = SVNWorkspaceRoot.getSVNResourceFor(resource); if (svnResource.exists() && !svnResource.isManaged()) resourcesToBeAdded.add(resource); if (svnResource.getStatus().isMissing()) resourcesToBeDeleted.add(resource); } } } catch (TeamException e) { throw new InvocationTargetException(e); } } }, true /* cancelable */, PROGRESS_BUSYCURSOR); //$NON-NLS-1$ if (!commit) { return; // user canceled } CommitOperation commitOperation = new CommitOperation(getTargetPart(), resources, (IResource[]) resourcesToBeAdded.toArray(new IResource[resourcesToBeAdded.size()]), (IResource[]) resourcesToBeDeleted.toArray(new IResource[resourcesToBeDeleted.size()]), resourcesToCommit, commitComment, keepLocks); commitOperation.setCanRunAsJob(canRunAsJob); commitOperation.run(); } } /** * get the modified and unadded resources in resources parameter */ protected IResource[] getModifiedResources(IResource[] resources, IProgressMonitor iProgressMonitor) throws SVNException { boolean ignoreHiddenChanges = SVNProviderPlugin.getPlugin().getPluginPreferences() .getBoolean(ISVNCoreConstants.PREF_IGNORE_HIDDEN_CHANGES); IResource[] allResources = getSelectedResources(true); List allSelections = new ArrayList(); for (int i = 0; i < allResources.length; i++) allSelections.add(allResources[i]); List conflictFiles = new ArrayList(); final List modified = new ArrayList(); List unversionedFolders = new ArrayList(); hasUnaddedResources = false; for (int i = 0; i < resources.length; i++) { IResource resource = resources[i]; ISVNLocalResource svnResource = SVNWorkspaceRoot.getSVNResourceFor(resource); // This check is for when the action is called with unmanaged resources if (svnResource.getRepository() == null) { continue; } // if only one resource selected, get url. Commit dialog displays this. if (resources.length == 1) { url = svnResource.getStatus().getUrlString(); if ((url == null) || (resource.getType() == IResource.FILE)) url = Util.getParentUrl(svnResource); } boolean descend = true; if (resource instanceof IContainer) { outer: for (int j = 0; j < allResources.length; j++) { if (allResources[j] == resource) continue; IContainer parent = allResources[j].getParent(); while (parent != null) { if (parent.equals(resource)) { descend = false; break outer; } parent = parent.getParent(); } } } // get adds, deletes, updates and property updates. GetStatusCommand command = new GetStatusCommand(svnResource, descend, false); command.run(iProgressMonitor); ISVNStatus[] statuses = command.getStatuses(); boolean switched = false; for (int j = 0; j < statuses.length; j++) { if (SVNStatusUtils.isReadyForCommit(statuses[j]) || SVNStatusUtils.isMissing(statuses[j])) { IResource currentResource = SVNWorkspaceRoot.getResourceFor(resource, statuses[j]); if (currentResource != null && (descend == true || allSelections.contains(currentResource))) { SVNProviderPlugin.getPlugin().getStatusCacheManager().updateCache(currentResource, statuses[j]); ISVNLocalResource localResource = SVNWorkspaceRoot.getSVNResourceFor(currentResource); if (!localResource.isIgnored()) { if (!SVNStatusUtils.isManaged(statuses[j])) { if (!Util.isHidden(currentResource)) { hasUnaddedResources = true; if ((currentResource.getType() != IResource.FILE) && !isSymLink(currentResource)) unversionedFolders.add(currentResource); else { if (!modified.contains(currentResource)) { modified.add(currentResource); if (currentResource instanceof IContainer) statusMap.put(currentResource, statuses[j].getPropStatus()); else statusMap.put(currentResource, statuses[j].getTextStatus()); } } } } else if (!ignoreHiddenChanges || !Util.isHidden(currentResource)) { if (!modified.contains(currentResource)) { if (statuses[j].isSwitched()) { switched = true; url = statuses[j].getUrlString(); } modified.add(currentResource); if (currentResource instanceof IContainer) statusMap.put(currentResource, statuses[j].getPropStatus()); else { statusMap.put(currentResource, statuses[j].getTextStatus()); if (SVNStatusUtils.isTextConflicted(statuses[j])) { IFile conflictNewFile = (IFile) File2Resource .getResource(statuses[j].getConflictNew()); if (conflictNewFile != null) conflictFiles.add(conflictNewFile); IFile conflictOldFile = (IFile) File2Resource .getResource(statuses[j].getConflictOld()); if (conflictOldFile != null) conflictFiles.add(conflictOldFile); IFile conflictWorkingFile = (IFile) File2Resource .getResource(statuses[j].getConflictWorking()); if (conflictWorkingFile != null) conflictFiles.add(conflictWorkingFile); } } } } } } } } if (switched && modified.size() > 1) { url = null; } } IResource[] unaddedResources = getUnaddedResources(unversionedFolders, iProgressMonitor); for (int i = 0; i < unaddedResources.length; i++) if (!modified.contains(unaddedResources[i])) modified.add(unaddedResources[i]); Iterator iter = conflictFiles.iterator(); while (iter.hasNext()) { IFile conflictFile = (IFile) iter.next(); modified.remove(conflictFile); statusMap.remove(conflictFile); } return (IResource[]) modified.toArray(new IResource[modified.size()]); } public int getHighestProblemSeverity(IResource[] resources) { int mostSeriousSeverity = -1; for (int i = 0; i < resources.length; i++) { IResource resource = resources[i]; try { IMarker[] problems = resource.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_ZERO); for (int j = 0; j < problems.length; j++) { IMarker problem = problems[j]; int severity = problem.getAttribute(IMarker.SEVERITY, 0); if (severity > mostSeriousSeverity) { mostSeriousSeverity = severity; } } } catch (CoreException e) { } } return mostSeriousSeverity; } /** * prompt commit of selected resources. * @throws SVNException */ protected boolean confirmCommit(IResource[] modifiedResources, ProjectProperties projectProperties) throws SVNException { IPreferenceStore preferenceStore = SVNUIPlugin.getPlugin().getPreferenceStore(); boolean commitToTagsPathWithoutWarning = preferenceStore .getBoolean(ISVNUIConstants.PREF_COMMIT_TO_TAGS_PATH_WITHOUT_WARNING); if (!commitToTagsPathWithoutWarning && onTagPath(modifiedResources)) { // Warning - working copy appears to be on a tag path. CommitToTagsWarningDialog dialog = new CommitToTagsWarningDialog(getShell()); if (dialog.open() != CommitToTagsWarningDialog.OK) { return false; } } int highestProblemSeverity = getHighestProblemSeverity(modifiedResources); switch (highestProblemSeverity) { case IMarker.SEVERITY_WARNING: String allowCommitsWithWarnings = preferenceStore .getString(ISVNUIConstants.PREF_ALLOW_COMMIT_WITH_WARNINGS); if (MessageDialogWithToggle.PROMPT.equals(allowCommitsWithWarnings) || MessageDialogWithToggle.NEVER.equals(allowCommitsWithWarnings)) { MessageDialogWithToggle warningDialog = MessageDialogWithToggle.openYesNoQuestion(shell, Policy.bind("CommitWizard.commitResources"), Policy.bind("CommitWizard.warningMarkers"), //$NON-NLS-1$//$NON-NLS-2$ Policy.bind("CommitWizard.warningQuestion"), false, preferenceStore, //$NON-NLS-1$ ISVNUIConstants.PREF_ALLOW_COMMIT_WITH_WARNINGS); if (IDialogConstants.YES_ID != warningDialog.getReturnCode()) { return false; } } break; case IMarker.SEVERITY_ERROR: String allowCommitsWithErrors = preferenceStore .getString(ISVNUIConstants.PREF_ALLOW_COMMIT_WITH_ERRORS); if (MessageDialogWithToggle.PROMPT.equals(allowCommitsWithErrors) || MessageDialogWithToggle.NEVER.equals(allowCommitsWithErrors)) { MessageDialogWithToggle errorDialog = MessageDialogWithToggle.openYesNoQuestion(shell, Policy.bind("CommitWizard.commitResources"), Policy.bind("CommitWizard.errorMarkers"), //$NON-NLS-1$//$NON-NLS-2$ Policy.bind("CommitWizard.errorQuestion"), false, preferenceStore, //$NON-NLS-1$ ISVNUIConstants.PREF_ALLOW_COMMIT_WITH_ERRORS); if (IDialogConstants.YES_ID != errorDialog.getReturnCode()) { return false; } } break; } SvnWizardCommitPage commitPage = new SvnWizardCommitPage(modifiedResources, url, projectProperties, statusMap, null, false); // commitPage.setSharing(sharing); SvnWizard wizard = new SvnWizard(commitPage); SvnWizardDialog dialog = new SvnWizardDialog(getShell(), wizard); if (proposedComment == null || proposedComment.length() == 0) { commitPage.setComment(getProposedComment(modifiedResources)); } else { commitPage.setComment(proposedComment); } wizard.setParentDialog(dialog); boolean commitOK = (dialog.open() == SvnWizardDialog.OK); url = null; commitComment = commitPage.getComment(); resourcesToCommit = commitPage.getSelectedResources(); keepLocks = commitPage.isKeepLocks(); return commitOK; } private boolean onTagPath(IResource[] modifiedResources) throws SVNException { // Multiple resources selected. if (url == null) { IResource resource = modifiedResources[0]; ISVNLocalResource svnResource = SVNWorkspaceRoot.getSVNResourceFor(resource); String firstUrl = svnResource.getStatus().getUrlString(); if ((firstUrl == null) || (resource.getType() == IResource.FILE)) firstUrl = Util.getParentUrl(svnResource); if (firstUrl.indexOf("/tags/") != -1) //$NON-NLS-1$ return true; } // One resource selected. else if (url.indexOf("/tags/") != -1) //$NON-NLS-1$ return true; return false; } /** * @see org.tigris.subversion.subclipse.ui.actions.SVNAction#getErrorTitle() */ protected String getErrorTitle() { return Policy.bind("CommitAction.commitFailed"); //$NON-NLS-1$ } /** * @see org.tigris.subversion.subclipse.ui.actions.WorkspaceAction#isEnabledForUnmanagedResources() */ protected boolean isEnabledForUnmanagedResources() { return true; } protected boolean isEnabled() throws TeamException { // invoke the inherited method so that overlaps are maintained IResource[] resources = super.getSelectedResources(); // disable if no resources are selected if (resources.length == 0) return false; // validate enabled for each resource in the selection for (int i = 0; i < resources.length; i++) { IResource resource = resources[i]; // no SVN actions are enabled if the selection contains a linked resource if (SVNWorkspaceRoot.isLinkedResource(resource)) return false; // only enable for resources in a project shared with SVN if (RepositoryProvider.getProvider(resource.getProject(), SVNProviderPlugin.getTypeId()) == null) { return false; } // ensure that resource management state matches what the action requires ISVNLocalResource svnResource = SVNWorkspaceRoot.getSVNResourceFor(resource); if (!isEnabledForSVNResource(svnResource)) { return false; } } return true; } /** * get the unadded resources in resources parameter */ private IResource[] getUnaddedResources(List resources, IProgressMonitor iProgressMonitor) throws SVNException { final List unadded = new ArrayList(); final SVNException[] exception = new SVNException[] { null }; for (Iterator iter = resources.iterator(); iter.hasNext();) { IResource resource = (IResource) iter.next(); if (resource.exists()) { // visit each resource deeply try { resource.accept(new IResourceVisitor() { public boolean visit(IResource aResource) { ISVNLocalResource svnResource = SVNWorkspaceRoot.getSVNResourceFor(aResource); // skip ignored resources and their children try { if (svnResource.isIgnored()) return false; // visit the children of shared resources if (svnResource.isManaged()) return true; if ((aResource.getType() == IResource.FOLDER) && isSymLink(aResource)) // don't traverse into symlink folders return false; } catch (SVNException e) { exception[0] = e; } // file/folder is unshared so record it unadded.add(aResource); return aResource.getType() == IResource.FOLDER; } }, IResource.DEPTH_INFINITE, false /* include phantoms */); } catch (CoreException e) { throw SVNException.wrapException(e); } if (exception[0] != null) throw exception[0]; } } if (unadded.size() > 0) hasUnaddedResources = true; return (IResource[]) unadded.toArray(new IResource[unadded.size()]); } protected boolean isSymLink(IResource resource) { File file = resource.getLocation().toFile(); try { if (!file.exists()) return true; else { String cnnpath = file.getCanonicalPath(); String abspath = file.getAbsolutePath(); return !abspath.equals(cnnpath); } } catch (IOException ex) { return true; } } protected IResource[] getSelectedResources() { if (selectedResources == null) return super.getSelectedResources(); else return selectedResources; } public void setSelectedResources(IResource[] selectedResources) { this.selectedResources = selectedResources; } /* * Get a proposed comment by looking at the active change sets */ private String getProposedComment(IResource[] resourcesToCommit) { StringBuffer comment = new StringBuffer(); ChangeSet[] sets = SVNProviderPlugin.getPlugin().getChangeSetManager().getSets(); int numMatchedSets = 0; for (int i = 0; i < sets.length; i++) { ChangeSet set = sets[i]; if (isUserSet(set) && containsOne(set, resourcesToCommit)) { if (numMatchedSets > 0) comment.append(System.getProperty("line.separator")); //$NON-NLS-1$ comment.append(set.getComment()); numMatchedSets++; } } return comment.toString(); } private IResource[] getChangeSetResources(IResource[] allResources) { ActiveChangeSet changeSet = SVNProviderPlugin.getPlugin().getChangeSetManager().getDefaultSet(); if (changeSet != null && !("<No Active Task>".equals(changeSet.getName()))) { List<IResource> changeSetResourceList = new ArrayList<IResource>(); for (IResource resource : allResources) { if (changeSet.contains(resource)) { changeSetResourceList.add(resource); } } IResource[] changeSetResources = new IResource[changeSetResourceList.size()]; changeSetResourceList.toArray(changeSetResources); return changeSetResources; } return allResources; } private boolean isUserSet(ChangeSet set) { if (set instanceof ActiveChangeSet) { ActiveChangeSet acs = (ActiveChangeSet) set; return acs.isUserCreated(); } return false; } private boolean containsOne(ChangeSet set, IResource[] resourcesToCommit) { for (int j = 0; j < resourcesToCommit.length; j++) { IResource resource = resourcesToCommit[j]; if (set.contains(resource)) { return true; } if (set instanceof ActiveChangeSet) { ActiveChangeSet acs = (ActiveChangeSet) set; if (acs.getDiffTree().members(resource).length > 0) return true; } } return false; } public boolean hasOutgoingChanges() { try { return getModifiedResources(selectedResources, new NullProgressMonitor()).length > 0; } catch (SVNException e) { } return false; } // public void setSharing(boolean sharing) { // this.sharing = sharing; // } protected String getImageId() { return ISVNUIConstants.IMG_MENU_COMMIT; } public void setCanRunAsJob(boolean canRunAsJob) { this.canRunAsJob = canRunAsJob; } }