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-2007 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.diff;
043:
044: import org.netbeans.api.diff.StreamSource;
045: import org.netbeans.api.diff.Difference;
046: import org.netbeans.modules.subversion.*;
047: import org.netbeans.modules.subversion.client.PropertiesClient;
048: import org.netbeans.modules.versioning.util.Utils;
049:
050: import java.io.*;
051: import java.util.*;
052: import org.netbeans.modules.subversion.util.SvnUtils;
053:
054: import org.openide.util.*;
055: import org.openide.util.lookup.Lookups;
056: import org.openide.filesystems.FileObject;
057: import org.openide.filesystems.FileUtil;
058: import org.openide.loaders.DataObject;
059: import org.openide.loaders.DataObjectNotFoundException;
060:
061: /**
062: * Stream source for diffing CVS managed files.
063: *
064: * @author Maros Sandor
065: */
066: public class DiffStreamSource extends StreamSource {
067:
068: private final File baseFile;
069: private final String propertyName;
070: private final String revision;
071: private final String title;
072: private String mimeType;
073:
074: /**
075: * Null is a valid value if base file does not exist in this revision.
076: */
077: private File remoteFile;
078: private MultiDiffPanel.Property propertyValue;
079:
080: /**
081: * Creates a new StreamSource implementation for Diff engine.
082: *
083: * @param baseFile
084: * @param revision file revision, may be null if the revision does not exist (ie for new files)
085: * @param title title to use in diff panel
086: */
087: public DiffStreamSource(File baseFile, String propertyName,
088: String revision, String title) {
089: this .baseFile = baseFile;
090: this .propertyName = propertyName;
091: this .revision = revision;
092: this .title = title;
093: }
094:
095: public String getName() {
096: if (baseFile != null) {
097: return baseFile.getName();
098: } else {
099: return NbBundle.getMessage(DiffStreamSource.class,
100: "LBL_Diff_Anonymous"); // NOI18N
101: }
102: }
103:
104: public String getTitle() {
105: return title;
106: }
107:
108: public synchronized String getMIMEType() {
109: try {
110: init();
111: } catch (IOException e) {
112: return null; // XXX use error manager HACK null potentionally kills DiffViewImpl, NPE while constructing EditorKit
113: }
114: return mimeType;
115: }
116:
117: public synchronized Reader createReader() throws IOException {
118: init();
119: if (propertyName != null) {
120: if (propertyValue != null) {
121: return propertyValue.toReader();
122: } else {
123: return null;
124: }
125: } else {
126: if (revision == null || remoteFile == null)
127: return null;
128: if (!mimeType.startsWith("text/")) {
129: return null;
130: } else {
131: return Utils.createReader(remoteFile);
132: }
133: }
134: }
135:
136: public Writer createWriter(Difference[] conflicts)
137: throws IOException {
138: throw new IOException("Operation not supported"); // NOI18N
139: }
140:
141: public boolean isEditable() {
142: return propertyName == null
143: && Setup.REVISION_CURRENT.equals(revision)
144: && isPrimary();
145: }
146:
147: private boolean isPrimary() {
148: FileObject fo = FileUtil.toFileObject(baseFile);
149: if (fo != null) {
150: try {
151: DataObject dao = DataObject.find(fo);
152: return fo.equals(dao.getPrimaryFile());
153: } catch (DataObjectNotFoundException e) {
154: // no dataobject, never mind
155: }
156: }
157: return true;
158: }
159:
160: public synchronized Lookup getLookup() {
161: try {
162: init();
163: } catch (IOException e) {
164: return Lookups.fixed();
165: }
166: if (propertyName != null || remoteFile == null || !isPrimary())
167: return Lookups.fixed();
168: FileObject remoteFo = FileUtil.toFileObject(remoteFile);
169: if (remoteFo == null)
170: return Lookups.fixed();
171:
172: return Lookups.fixed(remoteFo);
173: }
174:
175: /**
176: * Loads data over network.
177: */
178: synchronized void init() throws IOException {
179: if (propertyValue != null || remoteFile != null
180: || revision == null)
181: return;
182: if (propertyName != null) {
183: initProperty();
184: return;
185: }
186: if (baseFile.isDirectory()) {
187: mimeType = "content/unknown"; // NOI18N
188: return;
189: }
190: mimeType = SvnUtils.getMimeType(baseFile);
191: try {
192: if (isEditable()) {
193: // we cannot move editable documents because that would break Document sharing
194: remoteFile = VersionsCache.getInstance()
195: .getFileRevision(baseFile, revision);
196: } else {
197: File tempFolder = Utils.getTempFolder();
198: // To correctly get content of the base file, we need to checkout all files that belong to the same
199: // DataObject. One example is Form files: data loader removes //GEN:BEGIN comments from the java file but ONLY
200: // if it also finds associate .form file in the same directory
201: Set<File> allFiles = Utils
202: .getAllDataObjectFiles(baseFile);
203: for (File file : allFiles) {
204: boolean isBase = file.equals(baseFile);
205: try {
206: File rf = VersionsCache.getInstance()
207: .getFileRevision(file, revision);
208: if (rf == null) {
209: remoteFile = null;
210: return;
211: }
212: File newRemoteFile = new File(tempFolder, file
213: .getName());
214: newRemoteFile.deleteOnExit();
215: Utils
216: .copyStreamsCloseAll(
217: new FileOutputStream(
218: newRemoteFile),
219: new FileInputStream(rf));
220: if (isBase) {
221: remoteFile = newRemoteFile;
222: Utils
223: .associateEncoding(file,
224: newRemoteFile);
225: }
226: } catch (Exception e) {
227: if (isBase)
228: throw e;
229: // we cannot check out peer file so the dataobject will not be constructed properly
230: }
231: }
232: }
233: if (!baseFile.exists() && remoteFile != null
234: && remoteFile.exists()) {
235: mimeType = SvnUtils.getMimeType(remoteFile);
236: }
237: } catch (Exception e) {
238: // TODO detect interrupted IO (exception subclass), i.e. user cancel
239: IOException failure = new IOException(
240: "Can not load remote file for " + baseFile); // NOI18N
241: failure.initCause(e);
242: throw failure;
243: }
244: }
245:
246: private void initProperty() throws IOException {
247: PropertiesClient client = new PropertiesClient(baseFile);
248: if (Setup.REVISION_BASE.equals(revision)) {
249: byte[] value = client.getBaseProperties().get(propertyName);
250: propertyValue = value != null ? new MultiDiffPanel.Property(
251: value)
252: : null;
253: } else if (Setup.REVISION_CURRENT.equals(revision)) {
254: byte[] value = client.getProperties().get(propertyName);
255: propertyValue = value != null ? new MultiDiffPanel.Property(
256: value)
257: : null;
258: }
259: mimeType = propertyValue != null ? propertyValue.getMIME()
260: : "content/unknown"; // NOI18N
261: }
262: }
|