001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.subversion.ui.update;
043:
044: import java.io.File;
045: import java.io.IOException;
046: import java.util.*;
047: import java.util.logging.Level;
048: import org.netbeans.modules.subversion.*;
049: import org.netbeans.modules.subversion.Subversion;
050: import org.netbeans.modules.subversion.client.SvnClient;
051: import org.netbeans.modules.subversion.client.SvnClientExceptionHandler;
052: import org.netbeans.modules.subversion.client.SvnProgressSupport;
053: import org.netbeans.modules.subversion.ui.actions.ContextAction;
054: import org.netbeans.modules.subversion.util.*;
055: import org.netbeans.modules.subversion.util.Context;
056: import org.netbeans.modules.versioning.util.Utils;
057: import org.openide.filesystems.FileObject;
058: import org.openide.filesystems.FileUtil;
059: import org.openide.nodes.Node;
060: import org.tigris.subversion.svnclientadapter.ISVNInfo;
061: import org.tigris.subversion.svnclientadapter.SVNClientException;
062: import org.tigris.subversion.svnclientadapter.SVNRevision;
063: import org.tigris.subversion.svnclientadapter.SVNUrl;
064:
065: /**
066: * Reverts local changes.
067: *
068: * @author Petr Kuzel
069: */
070: public class RevertModificationsAction extends ContextAction {
071:
072: /** Creates a new instance of RevertModificationsAction */
073: public RevertModificationsAction() {
074: }
075:
076: protected String getBaseName(Node[] activatedNodes) {
077: return "CTL_MenuItem_Revert"; // NOI18N
078: }
079:
080: protected int getFileEnabledStatus() {
081: return FileInformation.STATUS_VERSIONED
082: & ~FileInformation.STATUS_VERSIONED_NEWINREPOSITORY;
083: }
084:
085: protected int getDirectoryEnabledStatus() {
086: return FileInformation.STATUS_VERSIONED
087: & ~FileInformation.STATUS_VERSIONED_NEWINREPOSITORY;
088: }
089:
090: protected void performContextAction(final Node[] nodes) {
091: if (!Subversion.getInstance().checkClientAvailable()) {
092: return;
093: }
094: final Context ctx = getContext(nodes);
095: final File root = ctx.getRootFiles()[0];
096: final SVNUrl rootUrl;
097: final SVNUrl url;
098:
099: try {
100: rootUrl = SvnUtils.getRepositoryRootUrl(root);
101: url = SvnUtils.getRepositoryUrl(root);
102: } catch (SVNClientException ex) {
103: SvnClientExceptionHandler.notifyException(ex, true, true);
104: return;
105: }
106: final RepositoryFile repositoryFile = new RepositoryFile(
107: rootUrl, url, SVNRevision.HEAD);
108:
109: final RevertModifications revertModifications = new RevertModifications(
110: repositoryFile);
111: if (!revertModifications.showDialog()) {
112: return;
113: }
114:
115: ContextAction.ProgressSupport support = new ContextAction.ProgressSupport(
116: this , nodes) {
117: public void perform() {
118: performRevert(
119: revertModifications.getRevisionInterval(),
120: revertModifications.revertNewFiles(), ctx, this );
121: }
122: };
123: support.start(createRequestProcessor(nodes));
124: }
125:
126: /** Recursive revert */
127: public static void performRevert(
128: RevertModifications.RevisionInterval revisions,
129: boolean revertNewFiles, Context ctx,
130: SvnProgressSupport support) {
131: SvnClient client;
132: try {
133: client = Subversion.getInstance().getClient(ctx, support);
134: } catch (SVNClientException ex) {
135: SvnClientExceptionHandler.notifyException(ex, true, true);
136: return;
137: }
138:
139: File files[] = ctx.getFiles();
140: File[][] split = Utils.splitFlatOthers(files);
141: for (int c = 0; c < split.length; c++) {
142: if (support.isCanceled()) {
143: return;
144: }
145: files = split[c];
146: boolean recursive = c == 1;
147: if (recursive == false) {
148: files = SvnUtils.flatten(files,
149: FileInformation.STATUS_REVERTIBLE_CHANGE);
150: }
151:
152: try {
153: if (revisions != null) {
154: for (int i = 0; i < files.length; i++) {
155: if (support.isCanceled()) {
156: return;
157: }
158: SVNUrl url = SvnUtils
159: .getRepositoryUrl(files[i]);
160: revisions = recountStartRevision(client, url,
161: revisions);
162: if (files[i].exists()) {
163: client.merge(url, revisions.endRevision,
164: url, revisions.startRevision,
165: files[i], false, recursive);
166: } else {
167: assert revisions.startRevision instanceof SVNRevision.Number : "The revision has to be a Number when trying to undelete file!";
168: client.copy(url, files[i],
169: revisions.startRevision);
170: }
171: }
172: } else {
173: if (support.isCanceled()) {
174: return;
175: }
176: if (files.length > 0) {
177: // check for deleted files, we also want to undelete their parents
178: Set<File> deletedFiles = new HashSet<File>();
179: for (File file : files) {
180: deletedFiles
181: .addAll(getDeletedParents(file));
182: }
183:
184: client.revert(files, recursive);
185:
186: // revert also deleted parent folders
187: // for all undeleted files
188: if (deletedFiles.size() > 0) {
189: client.revert(deletedFiles
190: .toArray(new File[deletedFiles
191: .size()]), false);
192: }
193: }
194: }
195: } catch (SVNClientException ex) {
196: support.annotate(ex);
197: }
198: }
199:
200: if (support.isCanceled()) {
201: return;
202: }
203:
204: if (revertNewFiles) {
205: File[] newfiles = Subversion
206: .getInstance()
207: .getStatusCache()
208: .listFiles(
209: ctx.getRootFiles(),
210: FileInformation.STATUS_NOTVERSIONED_NEWLOCALLY
211: | FileInformation.STATUS_VERSIONED_ADDEDLOCALLY);
212: for (int i = 0; i < newfiles.length; i++) {
213: FileObject fo = FileUtil.toFileObject(newfiles[i]);
214: try {
215: if (fo != null) {
216: fo.delete();
217: }
218: } catch (IOException ex) {
219: Subversion.LOG.log(Level.SEVERE, null, ex);
220: }
221: }
222: }
223: }
224:
225: private static List<File> getDeletedParents(File file) {
226: List<File> ret = new ArrayList<File>();
227: for (File parent = file.getParentFile(); parent != null; parent = parent
228: .getParentFile()) {
229: FileInformation info = Subversion.getInstance()
230: .getStatusCache().getStatus(parent);
231: if (!((info.getStatus() & FileInformation.STATUS_VERSIONED_REMOVEDLOCALLY) != 0 || (info
232: .getStatus() & FileInformation.STATUS_VERSIONED_DELETEDLOCALLY) != 0)) {
233: return ret;
234: }
235: ret.add(parent);
236: }
237: return ret;
238: }
239:
240: private static RevertModifications.RevisionInterval recountStartRevision(
241: SvnClient client, SVNUrl repository,
242: RevertModifications.RevisionInterval ret)
243: throws SVNClientException {
244: if (ret.startRevision.equals(SVNRevision.HEAD)) {
245: ISVNInfo info = client.getInfo(repository);
246: ret.startRevision = info.getRevision();
247: }
248: long start = Long.parseLong(ret.startRevision.toString());
249: if (start > 0) {
250: start = start - 1;
251: }
252: ret.startRevision = new SVNRevision.Number(start);
253: return ret;
254: }
255:
256: }
|