KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > subversion > ui > diff > ExportDiffAction


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.subversion.ui.diff;
21
22 import org.netbeans.modules.diff.builtin.visualizer.TextDiffVisualizer;
23 import org.netbeans.modules.subversion.FileInformation;
24 import org.netbeans.modules.subversion.Subversion;
25 import org.netbeans.modules.subversion.SvnModuleConfig;
26 import org.netbeans.modules.subversion.client.SvnProgressSupport;
27 import org.netbeans.modules.subversion.util.Context;
28 import org.netbeans.modules.subversion.util.SvnUtils;
29 import org.netbeans.modules.subversion.ui.actions.ContextAction;
30 import org.netbeans.modules.versioning.util.AccessibleJFileChooser;
31 import org.netbeans.modules.versioning.util.Utils;
32 import org.netbeans.api.diff.Difference;
33 import org.netbeans.spi.diff.DiffProvider;
34 import org.openide.windows.TopComponent;
35 import org.openide.util.Lookup;
36 import org.openide.util.RequestProcessor;
37 import org.openide.util.NbBundle;
38 import org.openide.ErrorManager;
39 import org.openide.NotifyDescriptor;
40 import org.openide.DialogDisplayer;
41 import org.openide.DialogDescriptor;
42 import org.openide.nodes.Node;
43 import org.openide.awt.StatusDisplayer;
44 import javax.swing.*;
45 import java.io.*;
46 import java.util.*;
47 import java.util.List JavaDoc;
48 import java.awt.event.ActionListener JavaDoc;
49 import java.awt.event.ActionEvent JavaDoc;
50 import java.awt.*;
51 import org.netbeans.modules.subversion.FileStatusCache;
52
53 /**
54  * Exports diff to file:
55  *
56  * <ul>
57  * <li>for components that implements {@link DiffSetupSource} interface
58  * exports actually displayed diff.
59  *
60  * <li>for DataNodes <b>local</b> differencies between the current
61  * working copy and BASE repository version.
62  * </ul>
63  *
64  * @author Petr Kuzel
65  */

66 public class ExportDiffAction extends ContextAction {
67     
68     private static final int enabledForStatus =
69             FileInformation.STATUS_VERSIONED_MERGE |
70             FileInformation.STATUS_VERSIONED_MODIFIEDLOCALLY |
71             FileInformation.STATUS_VERSIONED_DELETEDLOCALLY |
72             FileInformation.STATUS_VERSIONED_REMOVEDLOCALLY |
73             FileInformation.STATUS_NOTVERSIONED_NEWLOCALLY |
74             FileInformation.STATUS_VERSIONED_ADDEDLOCALLY;
75
76     protected String JavaDoc getBaseName(Node [] activatedNodes) {
77         return "CTL_MenuItem_ExportDiff"; // NOI18N
78
}
79
80     /**
81      * First look for DiffSetupSource name then for super (context name).
82      */

83     public String JavaDoc getName() {
84         TopComponent activated = TopComponent.getRegistry().getActivated();
85         if (activated instanceof DiffSetupSource) {
86             String JavaDoc setupName = ((DiffSetupSource)activated).getSetupDisplayName();
87             if (setupName != null) {
88                 return NbBundle.getMessage(this.getClass(), getBaseName(getActivatedNodes()) + "_Context", // NOI18N
89
setupName);
90             }
91         }
92         return super.getName();
93     }
94     
95     public boolean enable(Node[] nodes) {
96         Context ctx = SvnUtils.getCurrentContext(nodes);
97         File[] files = getModifiedFiles(ctx, enabledForStatus);
98         if(files.length < 1) {
99             return false;
100         }
101         TopComponent activated = TopComponent.getRegistry().getActivated();
102         if (activated instanceof DiffSetupSource) {
103             return true;
104         }
105         return super.enable(nodes) && Lookup.getDefault().lookup(DiffProvider.class) != null;
106     }
107
108     protected void performContextAction(final Node[] nodes) {
109
110         // reevaluate fast enablement logic guess
111

112         boolean noop;
113         TopComponent activated = TopComponent.getRegistry().getActivated();
114         if (activated instanceof DiffSetupSource) {
115             noop = ((DiffSetupSource) activated).getSetups().isEmpty();
116         } else {
117             Context context = getContext(nodes);
118             File [] files = SvnUtils.getModifiedFiles(context, FileInformation.STATUS_LOCAL_CHANGE);
119             noop = files.length == 0;
120         }
121         if (noop) {
122             NotifyDescriptor msg = new NotifyDescriptor.Message(NbBundle.getMessage(ExportDiffAction.class, "BK3001"), NotifyDescriptor.INFORMATION_MESSAGE);
123             DialogDisplayer.getDefault().notify(msg);
124             return;
125         }
126
127         final JFileChooser chooser = new AccessibleJFileChooser(NbBundle.getMessage(ExportDiffAction.class, "ACSD_Export"));
128         chooser.setDialogTitle(NbBundle.getMessage(ExportDiffAction.class, "CTL_Export_Title"));
129         chooser.setMultiSelectionEnabled(false);
130         javax.swing.filechooser.FileFilter JavaDoc[] old = chooser.getChoosableFileFilters();
131         for (int i = 0; i < old.length; i++) {
132             javax.swing.filechooser.FileFilter JavaDoc fileFilter = old[i];
133             chooser.removeChoosableFileFilter(fileFilter);
134
135         }
136         chooser.setCurrentDirectory(new File(SvnModuleConfig.getDefault().getPreferences().get("ExportDiff.saveFolder", System.getProperty("user.home")))); // NOI18N
137
chooser.addChoosableFileFilter(new javax.swing.filechooser.FileFilter JavaDoc() {
138             public boolean accept(File f) {
139                 return f.getName().endsWith("diff") || f.getName().endsWith("patch") || f.isDirectory(); // NOI18N
140
}
141             public String JavaDoc getDescription() {
142                 return NbBundle.getMessage(ExportDiffAction.class, "BK3002");
143             }
144         });
145         
146         chooser.setDialogType(JFileChooser.SAVE_DIALOG);
147         chooser.setApproveButtonMnemonic(NbBundle.getMessage(ExportDiffAction.class, "MNE_Export_ExportAction").charAt(0));
148         chooser.setApproveButtonText(NbBundle.getMessage(ExportDiffAction.class, "CTL_Export_ExportAction"));
149         DialogDescriptor dd = new DialogDescriptor(chooser, NbBundle.getMessage(ExportDiffAction.class, "CTL_Export_Title"));
150         dd.setOptions(new Object JavaDoc[0]);
151         final Dialog dialog = DialogDisplayer.getDefault().createDialog(dd);
152
153         chooser.addActionListener(new ActionListener JavaDoc() {
154             public void actionPerformed(ActionEvent JavaDoc e) {
155                 String JavaDoc state = e.getActionCommand();
156                 if (state.equals(JFileChooser.APPROVE_SELECTION)) {
157                     File destination = chooser.getSelectedFile();
158                     String JavaDoc name = destination.getName();
159                     boolean requiredExt = false;
160                     requiredExt |= name.endsWith(".diff"); // NOI18N
161
requiredExt |= name.endsWith(".dif"); // NOI18N
162
requiredExt |= name.endsWith(".patch"); // NOI18N
163
if (requiredExt == false) {
164                         File parent = destination.getParentFile();
165                         destination = new File(parent, name + ".patch"); // NOI18N
166
}
167
168                     if (destination.exists()) {
169                         NotifyDescriptor nd = new NotifyDescriptor.Confirmation(NbBundle.getMessage(ExportDiffAction.class, "BK3005", destination.getAbsolutePath()));
170                         nd.setOptionType(NotifyDescriptor.YES_NO_OPTION);
171                         DialogDisplayer.getDefault().notify(nd);
172                         if (nd.getValue().equals(NotifyDescriptor.OK_OPTION) == false) {
173                             return;
174                         }
175                     }
176                     SvnModuleConfig.getDefault().getPreferences().put("ExportDiff.saveFolder", destination.getParent()); // NOI18N
177
final File out = destination;
178                     RequestProcessor rp = Subversion.getInstance().getRequestProcessor();
179                     SvnProgressSupport ps = new SvnProgressSupport() {
180                         protected void perform() {
181                             async(this, nodes, out);
182                         }
183                     };
184                     ps.start(rp, null, getRunningName(nodes));
185                 }
186                 dialog.dispose();
187             }
188         });
189         dialog.setVisible(true);
190
191     }
192
193     protected boolean asynchronous() {
194         return false;
195     }
196     
197     private void async(SvnProgressSupport progress, Node[] nodes, File destination) {
198         boolean success = false;
199         OutputStream out = null;
200         int exportedFiles = 0;
201         try {
202
203             // prepare setups and common parent - root
204

205             File root;
206             Collection<Setup> setups;
207
208             TopComponent activated = TopComponent.getRegistry().getActivated();
209             if (activated instanceof DiffSetupSource) {
210                 setups = ((DiffSetupSource) activated).getSetups();
211                 List JavaDoc<File> setupFiles = new ArrayList<File>(setups.size());
212                 for (Iterator i = setups.iterator(); i.hasNext();) {
213                     Setup setup = (Setup) i.next();
214                     setupFiles.add(setup.getBaseFile());
215                 }
216                 root = getCommonParent(setupFiles.toArray(new File[setupFiles.size()]));
217             } else {
218                 Context context = getContext(nodes);
219                 File [] files = SvnUtils.getModifiedFiles(context, FileInformation.STATUS_LOCAL_CHANGE);
220                 root = getCommonParent(context.getRootFiles());
221                 setups = new ArrayList<Setup>(files.length);
222                 for (int i = 0; i < files.length; i++) {
223                     File file = files[i];
224                     Setup setup = new Setup(file, Setup.DIFFTYPE_LOCAL);
225                     setups.add(setup);
226                 }
227             }
228             if (root == null) {
229                 NotifyDescriptor nd = new NotifyDescriptor(
230                         NbBundle.getMessage(ExportDiffAction.class, "MSG_BadSelection_Prompt"),
231                         NbBundle.getMessage(ExportDiffAction.class, "MSG_BadSelection_Title"),
232                         NotifyDescriptor.DEFAULT_OPTION, NotifyDescriptor.ERROR_MESSAGE, null, null);
233                 DialogDisplayer.getDefault().notify(nd);
234                 return;
235             }
236
237             String JavaDoc sep = System.getProperty("line.separator"); // NOI18N
238
out = new BufferedOutputStream(new FileOutputStream(destination));
239             // Used by PatchAction as MAGIC to detect right encoding
240
out.write(("# This patch file was generated by NetBeans IDE" + sep).getBytes("utf8")); // NOI18N
241
out.write(("# Following Index: paths are relative to: " + root.getAbsolutePath() + sep).getBytes("utf8")); // NOI18N
242
out.write(("# This patch can be applied using context Tools: Patch action on respective folder." + sep).getBytes("utf8")); // NOI18N
243
out.write(("# It uses platform neutral UTF-8 encoding and \\n newlines." + sep).getBytes("utf8")); // NOI18N
244
out.write(("# Above lines and this line are ignored by the patching process." + sep).getBytes("utf8")); // NOI18N
245

246
247             Iterator<Setup> it = setups.iterator();
248             int i = 0;
249             while (it.hasNext()) {
250                 Setup setup = it.next();
251                 File file = setup.getBaseFile();
252                 progress.setRepositoryRoot(SvnUtils.getRepositoryRootUrl(file));
253                 progress.setDisplayName(file.getName());
254
255                 String JavaDoc index = "Index: "; // NOI18N
256
String JavaDoc rootPath = root.getAbsolutePath();
257                 String JavaDoc filePath = file.getAbsolutePath();
258                 if (filePath.startsWith(rootPath)) {
259                     index += filePath.substring(rootPath.length() + 1).replace(File.separatorChar, '/') + sep;
260                     out.write(index.getBytes("utf8")); // NOI18N
261
}
262                 exportDiff(setup, out);
263                 i++;
264             }
265
266             exportedFiles = i;
267             success = true;
268         } catch (IOException ex) {
269             ErrorManager.getDefault().annotate(ex, NbBundle.getMessage(ExportDiffAction.class, "BK3003"));
270             ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); // stack trace to log
271
ErrorManager.getDefault().notify(ErrorManager.USER, ex); // message to user
272
} finally {
273             if (out != null) {
274                 try {
275                     out.flush();
276                     out.close();
277                 } catch (IOException alreadyClsoed) {
278                 }
279             }
280             if (success) {
281                 StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage(ExportDiffAction.class, "BK3004", new Integer JavaDoc(exportedFiles)));
282                 if (exportedFiles == 0) {
283                     destination.delete();
284                 }
285             } else {
286                 destination.delete();
287             }
288
289         }
290     }
291
292     private static File getCommonParent(File [] files) {
293         File root = files[0];
294         if (root.isFile()) root = root.getParentFile();
295         for (int i = 1; i < files.length; i++) {
296             root = Utils.getCommonParent(root, files[i]);
297             if (root == null) return null;
298         }
299         return root;
300     }
301
302     /** Writes contextual diff into given stream.*/
303     private void exportDiff(Setup setup, OutputStream out) throws IOException {
304         setup.initSources();
305         DiffProvider diff = (DiffProvider) Lookup.getDefault().lookup(DiffProvider.class);
306         Reader r1 = setup.getFirstSource().createReader();
307         if (r1 == null) r1 = new StringReader(""); // NOI18N
308
Reader r2 = setup.getSecondSource().createReader();
309         if (r2 == null) r2 = new StringReader(""); // NOI18N
310
Difference[] differences = diff.computeDiff(r1, r2);
311
312         File file = setup.getBaseFile();
313         String JavaDoc name = file.getAbsolutePath();
314         r1 = setup.getFirstSource().createReader();
315         if (r1 == null) r1 = new StringReader(""); // NOI18N
316
r2 = setup.getSecondSource().createReader();
317         if (r2 == null) r2 = new StringReader(""); // NOI18N
318
TextDiffVisualizer.TextDiffInfo info = new TextDiffVisualizer.TextDiffInfo(
319             name + " " + setup.getFirstSource().getTitle(), // NOI18N
320
name + " " + setup.getSecondSource().getTitle(), // NOI18N
321
null,
322             null,
323             r1,
324             r2,
325             differences
326         );
327         info.setContextMode(true, 3);
328         InputStream is = TextDiffVisualizer.differenceToContextDiffText(info);
329         while(true) {
330             int i = is.read();
331             if (i == -1) break;
332             out.write(i);
333         }
334     }
335
336     /**
337      * Utility method that returns all non-excluded modified files that are
338      * under given roots (folders) and have one of specified statuses.
339      *
340      * @param context context to search
341      * @param includeStatus bit mask of file statuses to include in result
342      * @return File [] array of Files having specified status
343      */

344     public static File [] getModifiedFiles(Context context, int includeStatus) {
345         File[] all = Subversion.getInstance().getStatusCache().listFiles(context, includeStatus);
346         List JavaDoc<File> files = new ArrayList<File>();
347         for (int i = 0; i < all.length; i++) {
348             File file = all[i];
349             files.add(file);
350         }
351         
352         // ensure that command roots (files that were explicitly selected by user) are included in Diff
353
FileStatusCache cache = Subversion.getInstance().getStatusCache();
354         File [] rootFiles = context.getRootFiles();
355         for (int i = 0; i < rootFiles.length; i++) {
356             File file = rootFiles[i];
357             if (file.isFile() && (cache.getStatus(file).getStatus() & includeStatus) != 0 && !files.contains(file)) {
358                 files.add(file);
359             }
360         }
361         return files.toArray(new File[files.size()]);
362     }
363         
364 }
365
Popular Tags