1 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 ; 48 import java.awt.event.ActionListener ; 49 import java.awt.event.ActionEvent ; 50 import java.awt.*; 51 import org.netbeans.modules.subversion.FileStatusCache; 52 53 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 getBaseName(Node [] activatedNodes) { 77 return "CTL_MenuItem_ExportDiff"; } 79 80 83 public String getName() { 84 TopComponent activated = TopComponent.getRegistry().getActivated(); 85 if (activated instanceof DiffSetupSource) { 86 String setupName = ((DiffSetupSource)activated).getSetupDisplayName(); 87 if (setupName != null) { 88 return NbBundle.getMessage(this.getClass(), getBaseName(getActivatedNodes()) + "_Context", 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 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 [] old = chooser.getChoosableFileFilters(); 131 for (int i = 0; i < old.length; i++) { 132 javax.swing.filechooser.FileFilter fileFilter = old[i]; 133 chooser.removeChoosableFileFilter(fileFilter); 134 135 } 136 chooser.setCurrentDirectory(new File(SvnModuleConfig.getDefault().getPreferences().get("ExportDiff.saveFolder", System.getProperty("user.home")))); chooser.addChoosableFileFilter(new javax.swing.filechooser.FileFilter () { 138 public boolean accept(File f) { 139 return f.getName().endsWith("diff") || f.getName().endsWith("patch") || f.isDirectory(); } 141 public String 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 [0]); 151 final Dialog dialog = DialogDisplayer.getDefault().createDialog(dd); 152 153 chooser.addActionListener(new ActionListener () { 154 public void actionPerformed(ActionEvent e) { 155 String state = e.getActionCommand(); 156 if (state.equals(JFileChooser.APPROVE_SELECTION)) { 157 File destination = chooser.getSelectedFile(); 158 String name = destination.getName(); 159 boolean requiredExt = false; 160 requiredExt |= name.endsWith(".diff"); requiredExt |= name.endsWith(".dif"); requiredExt |= name.endsWith(".patch"); if (requiredExt == false) { 164 File parent = destination.getParentFile(); 165 destination = new File(parent, name + ".patch"); } 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()); 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 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 <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 sep = System.getProperty("line.separator"); out = new BufferedOutputStream(new FileOutputStream(destination)); 239 out.write(("# This patch file was generated by NetBeans IDE" + sep).getBytes("utf8")); out.write(("# Following Index: paths are relative to: " + root.getAbsolutePath() + sep).getBytes("utf8")); out.write(("# This patch can be applied using context Tools: Patch action on respective folder." + sep).getBytes("utf8")); out.write(("# It uses platform neutral UTF-8 encoding and \\n newlines." + sep).getBytes("utf8")); out.write(("# Above lines and this line are ignored by the patching process." + sep).getBytes("utf8")); 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 index = "Index: "; String rootPath = root.getAbsolutePath(); 257 String 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")); } 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); ErrorManager.getDefault().notify(ErrorManager.USER, ex); } 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 (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 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(""); Reader r2 = setup.getSecondSource().createReader(); 309 if (r2 == null) r2 = new StringReader(""); Difference[] differences = diff.computeDiff(r1, r2); 311 312 File file = setup.getBaseFile(); 313 String name = file.getAbsolutePath(); 314 r1 = setup.getFirstSource().createReader(); 315 if (r1 == null) r1 = new StringReader(""); r2 = setup.getSecondSource().createReader(); 317 if (r2 == null) r2 = new StringReader(""); TextDiffVisualizer.TextDiffInfo info = new TextDiffVisualizer.TextDiffInfo( 319 name + " " + setup.getFirstSource().getTitle(), name + " " + setup.getSecondSource().getTitle(), 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 344 public static File [] getModifiedFiles(Context context, int includeStatus) { 345 File[] all = Subversion.getInstance().getStatusCache().listFiles(context, includeStatus); 346 List <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 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 |