1 19 20 package org.netbeans.modules.subversion.ui.commit; 21 22 import org.netbeans.modules.versioning.util.DialogBoundsPreserver; 23 import org.netbeans.modules.subversion.client.SvnClient; 24 import org.netbeans.modules.subversion.ui.actions.ContextAction; 25 import org.netbeans.modules.subversion.util.Context; 26 import org.netbeans.modules.subversion.*; 27 import org.openide.DialogDescriptor; 28 import org.openide.DialogDisplayer; 29 import org.openide.ErrorManager; 30 import org.openide.nodes.Node; 31 import org.tigris.subversion.svnclientadapter.SVNBaseDir; 32 import org.tigris.subversion.svnclientadapter.SVNClientException; 33 import javax.swing.*; 34 import java.awt.*; 35 import java.io.File ; 36 import java.util.*; 37 import java.util.List ; 38 import java.text.MessageFormat ; 39 import javax.swing.event.TableModelEvent ; 40 import javax.swing.event.TableModelListener ; 41 import org.netbeans.modules.subversion.client.SvnProgressSupport; 42 import org.netbeans.modules.subversion.util.SvnUtils; 43 import org.netbeans.modules.versioning.util.VersioningListener; 44 import org.netbeans.modules.versioning.util.VersioningEvent; 45 import org.netbeans.modules.versioning.util.Utils; 46 import org.openide.util.HelpCtx; 47 import org.openide.util.RequestProcessor; 48 import org.openide.util.NbBundle; 49 import org.tigris.subversion.svnclientadapter.ISVNProperty; 50 import org.tigris.subversion.svnclientadapter.SVNRevision; 51 import org.tigris.subversion.svnclientadapter.SVNUrl; 52 53 58 public class CommitAction extends ContextAction { 59 60 static final String RECENT_COMMIT_MESSAGES = "recentCommitMessage"; 61 62 protected String getBaseName(Node[] nodes) { 63 return "CTL_MenuItem_Commit"; } 65 66 protected boolean enable(Node[] nodes) { 67 FileStatusCache cache = Subversion.getInstance().getStatusCache(); 69 File [] files = cache.listFiles(getContext(nodes), FileInformation.STATUS_LOCAL_CHANGE); 70 return files.length > 0; 71 } 72 73 74 public static void commit(String contentTitle, final Context ctx) { 75 FileStatusCache cache = Subversion.getInstance().getStatusCache(); 76 File [] roots = ctx.getFiles(); 77 if (roots.length == 0) { 78 return; 79 } 80 81 List <File > tagsFiles = new ArrayList<File >(); 82 for (int i = 0; i < roots.length; i++) { 83 String tag = SvnUtils.getCopy(roots[i]); 84 if(tag!=null && !tag.equals("")) { 85 tagsFiles.add(roots[i]); 86 } 87 } 88 89 File [][] split = Utils.splitFlatOthers(roots); 90 List <File > fileList = new ArrayList<File >(); 91 for (int c = 0; c < split.length; c++) { 92 roots = split[c]; 93 boolean recursive = c == 1; 94 if (recursive) { 95 File [] files = cache.listFiles(ctx, FileInformation.STATUS_LOCAL_CHANGE); 96 for (int i= 0; i < files.length; i++) { 97 for(int r = 0; r < roots.length; r++) { 98 if( SvnUtils.isParentOrEqual(roots[r], files[i]) ) { 99 if(!fileList.contains(files[i])) { 100 fileList.add(files[i]); 101 } 102 } 103 } 104 } 105 } else { 106 File [] files = SvnUtils.flatten(roots, FileInformation.STATUS_LOCAL_CHANGE); 107 for (int i= 0; i<files.length; i++) { 108 if(!fileList.contains(files[i])) { 109 fileList.add(files[i]); 110 } 111 } 112 } 113 } 114 115 if(fileList.size()==0) { 116 return; 117 } 118 119 final CommitPanel panel = new CommitPanel(); 121 final CommitTable data = new CommitTable(panel.filesLabel, CommitTable.COMMIT_COLUMNS, new String [] { CommitTableModel.COLUMN_NAME_PATH }); 122 panel.setCommitTable(data); 123 SvnFileNode[] nodes; 124 ArrayList<SvnFileNode> nodesList = new ArrayList<SvnFileNode>(fileList.size()); 125 126 for (Iterator<File > it = fileList.iterator(); it.hasNext();) { 127 File file = it.next(); 128 SvnFileNode node = new SvnFileNode(file); 129 nodesList.add(node); 130 } 131 nodes = nodesList.toArray(new SvnFileNode[fileList.size()]); 132 data.setNodes(nodes); 133 134 JComponent component = data.getComponent(); 135 panel.filesPanel.setLayout(new BorderLayout()); 136 panel.filesPanel.add(component, BorderLayout.CENTER); 137 138 DialogDescriptor dd = new DialogDescriptor(panel, org.openide.util.NbBundle.getMessage(CommitAction.class, "CTL_CommitDialog_Title", contentTitle)); dd.setModal(true); 140 final JButton commitButton = new JButton(org.openide.util.NbBundle.getMessage(CommitAction.class, "CTL_Commit_Action_Commit")); commitButton.setEnabled(false); 142 dd.setOptions(new Object [] {commitButton, org.openide.util.NbBundle.getMessage(CommitAction.class, "CTL_Commit_Action_Cancel")}); dd.setHelpCtx(new HelpCtx(CommitAction.class)); 144 panel.addVersioningListener(new VersioningListener() { 145 public void versioningEvent(VersioningEvent event) { 146 refreshCommitDialog(panel, data, commitButton); 147 } 148 }); 149 data.getTableModel().addTableModelListener(new TableModelListener () { 150 public void tableChanged(TableModelEvent e) { 151 refreshCommitDialog(panel, data, commitButton); 152 } 153 }); 154 commitButton.setEnabled(containsCommitable(data)); 155 156 panel.putClientProperty("contentTitle", contentTitle); panel.putClientProperty("DialogDescriptor", dd); final Dialog dialog = DialogDisplayer.getDefault().createDialog(dd); 159 dialog.addWindowListener(new DialogBoundsPreserver(SvnModuleConfig.getDefault().getPreferences(), "svn.commit.dialog")); dialog.pack(); 161 dialog.setVisible(true); 162 163 if (dd.getValue() == commitButton) { 164 165 167 final Map<SvnFileNode, CommitOptions> commitFiles = data.getCommitFiles(); 168 final String message = panel.messageTextArea.getText(); 169 org.netbeans.modules.versioning.util.Utils.insert(SvnModuleConfig.getDefault().getPreferences(), RECENT_COMMIT_MESSAGES, message, 20); 170 171 SVNUrl repository = getSvnUrl(ctx); 172 RequestProcessor rp = Subversion.getInstance().getRequestProcessor(repository); 173 SvnProgressSupport support = new SvnProgressSupport() { 174 public void perform() { 175 performCommit(message, commitFiles, ctx, this); 176 } 177 }; 178 support.start(rp, repository, org.openide.util.NbBundle.getMessage(CommitAction.class, "LBL_Commit_Progress")); } 180 182 } 183 184 private static boolean containsCommitable(CommitTable data) { 185 Map<SvnFileNode, CommitOptions> map = data.getCommitFiles(); 186 for(CommitOptions co : map.values()) { 187 if(co != CommitOptions.EXCLUDE) { 188 return true; 189 } 190 } 191 return false; 192 } 193 194 200 private static void refreshCommitDialog(CommitPanel panel, CommitTable table, JButton commit) { 201 ResourceBundle loc = NbBundle.getBundle(CommitAction.class); 202 Map<SvnFileNode, CommitOptions> files = table.getCommitFiles(); 203 Set<String > stickyTags = new HashSet<String >(); 204 boolean conflicts = false; 205 206 boolean enabled = commit.isEnabled(); 207 208 for (SvnFileNode fileNode : files.keySet()) { 209 CommitOptions options = files.get(fileNode); 210 if (options == CommitOptions.EXCLUDE) continue; 211 stickyTags.add(SvnUtils.getCopy(fileNode.getFile())); 212 int status = fileNode.getInformation().getStatus(); 213 if ((status & FileInformation.STATUS_REMOTE_CHANGE) != 0 || status == FileInformation.STATUS_VERSIONED_CONFLICT) { 214 enabled = false; 215 String msg = (status == FileInformation.STATUS_VERSIONED_CONFLICT) ? 216 loc.getString("MSG_CommitForm_ErrorConflicts") : 217 loc.getString("MSG_CommitForm_ErrorRemoteChanges"); 218 panel.setErrorLabel("<html><font color=\"#002080\">" + msg + "</font></html>"); conflicts = true; 220 } 221 stickyTags.add(SvnUtils.getCopy(fileNode.getFile())); 222 } 223 224 if (stickyTags.size() > 1) { 225 table.setColumns(new String [] { CommitTableModel.COLUMN_NAME_NAME, CommitTableModel.COLUMN_NAME_BRANCH, CommitTableModel.COLUMN_NAME_STATUS, 226 CommitTableModel.COLUMN_NAME_ACTION, CommitTableModel.COLUMN_NAME_PATH }); 227 } else { 228 table.setColumns(new String [] { CommitTableModel.COLUMN_NAME_NAME, CommitTableModel.COLUMN_NAME_STATUS, 229 CommitTableModel.COLUMN_NAME_ACTION, CommitTableModel.COLUMN_NAME_PATH }); 230 } 231 232 String contentTitle = (String ) panel.getClientProperty("contentTitle"); DialogDescriptor dd = (DialogDescriptor) panel.getClientProperty("DialogDescriptor"); String errorLabel; 235 if (stickyTags.size() <= 1) { 236 String stickyTag = stickyTags.size() == 0 ? null : (String ) stickyTags.iterator().next(); 237 if (stickyTag == null) { 238 dd.setTitle(MessageFormat.format(loc.getString("CTL_CommitDialog_Title"), new Object [] { contentTitle })); 239 errorLabel = ""; } else { 241 dd.setTitle(MessageFormat.format(loc.getString("CTL_CommitDialog_Title_Branch"), new Object [] { contentTitle, stickyTag })); 242 String msg = MessageFormat.format(loc.getString("MSG_CommitForm_InfoBranch"), new Object [] { stickyTag }); 243 errorLabel = "<html><font color=\"#002080\">" + msg + "</font></html>"; } 245 } else { 246 dd.setTitle(MessageFormat.format(loc.getString("CTL_CommitDialog_Title_Branches"), new Object [] { contentTitle })); 247 String msg = loc.getString("MSG_CommitForm_ErrorMultipleBranches"); 248 errorLabel = "<html><font color=\"#CC0000\">" + msg + "</font></html>"; } 250 if (!conflicts) { 251 panel.setErrorLabel(errorLabel); 252 enabled = true; 253 } 254 commit.setEnabled(enabled && containsCommitable(table)); 255 } 256 257 protected void performContextAction(Node[] nodes) { 258 final Context ctx = getContext(nodes); 259 commit(getContextDisplayName(nodes), ctx); 260 } 261 262 public static void performCommit(String message, Map<SvnFileNode, CommitOptions> commitFiles, Context ctx, SvnProgressSupport support) { 263 performCommit(message, commitFiles, ctx, support, false); 264 } 265 266 public static void performCommit(String message, Map<SvnFileNode, CommitOptions> commitFiles, Context ctx, SvnProgressSupport support, boolean rootUpdate) { 267 try { 268 269 SvnClient client; 270 try { 271 client = Subversion.getInstance().getClient(ctx, support); 272 } catch (SVNClientException ex) { 273 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); return; 275 } 276 support.setDisplayName(org.openide.util.NbBundle.getMessage(CommitAction.class, "LBL_Commit_Progress")); 278 List <SvnFileNode> addCandidates = new ArrayList<SvnFileNode>(); 279 List <SvnFileNode> removeCandidates = new ArrayList<SvnFileNode>(); 280 Set<File > commitCandidates = new LinkedHashSet<File >(); 281 Set<File > binnaryCandidates = new HashSet<File >(); 282 283 Iterator<SvnFileNode> it = commitFiles.keySet().iterator(); 284 while (it.hasNext()) { 286 if(support.isCanceled()) { 287 return; 288 } 289 SvnFileNode node = it.next(); 290 CommitOptions option = commitFiles.get(node); 291 if (CommitOptions.ADD_BINARY == option) { 292 List <File > l = listUnmanagedParents(node); 293 Iterator<File > dit = l.iterator(); 294 while (dit.hasNext()) { 295 if(support.isCanceled()) { 296 return; 297 } 298 File file = dit.next(); 299 addCandidates.add(new SvnFileNode(file)); 300 commitCandidates.add(file); 301 } 302 303 if(support.isCanceled()) { 304 return; 305 } 306 binnaryCandidates.add(node.getFile()); 307 308 addCandidates.add(node); 309 commitCandidates.add(node.getFile()); 310 } else if (CommitOptions.ADD_TEXT == option || CommitOptions.ADD_DIRECTORY == option) { 311 List <File > l = listUnmanagedParents(node); 313 Iterator<File > dit = l.iterator(); 314 while (dit.hasNext()) { 315 if(support.isCanceled()) { 316 return; 317 } 318 File file = dit.next(); 319 addCandidates.add(new SvnFileNode(file)); 320 commitCandidates.add(file); 321 } 322 if(support.isCanceled()) { 323 return; 324 } 325 addCandidates.add(node); 326 commitCandidates.add(node.getFile()); 327 } else if (CommitOptions.COMMIT_REMOVE == option) { 328 removeCandidates.add(node); 329 commitCandidates.add(node.getFile()); 330 } else if (CommitOptions.COMMIT == option) { 331 commitCandidates.add(node.getFile()); 332 } 333 } 334 335 337 List <File > addFiles = new ArrayList<File >(); 338 List <File > addDirs = new ArrayList<File >(); 339 it = addCandidates.iterator(); 341 while (it.hasNext()) { 342 if(support.isCanceled()) { 343 return; 344 } 345 SvnFileNode svnFileNode = it.next(); 346 File file = svnFileNode.getFile(); 347 if (file.isDirectory()) { 348 addDirs.add(file); 349 } else if (file.isFile()) { 350 addFiles.add(file); 351 } 352 } 353 if(support.isCanceled()) { 354 return; 355 } 356 357 Iterator<File > itFiles = addDirs.iterator(); 358 List <File > dirsToAdd = new ArrayList<File >(); 359 while (itFiles.hasNext()) { 360 File dir = itFiles.next(); 361 if (!dirsToAdd.contains(dir)) { 362 dirsToAdd.add(dir); 363 } 364 } 365 if(dirsToAdd.size() > 0) { 366 client.addFile(dirsToAdd.toArray(new File [dirsToAdd.size()]), false); 367 } 368 if(support.isCanceled()) { 369 return; 370 } 371 372 if(addFiles.size() > 0) { 373 client.addFile(addFiles.toArray(new File [addFiles.size()]), false); 374 } 375 376 379 FileStatusCache cache = Subversion.getInstance().getStatusCache(); 381 List <List <File >> managedTrees = new ArrayList<List <File >>(); 382 for (Iterator<File > itCommitCandidates = commitCandidates.iterator(); itCommitCandidates.hasNext();) { 383 File commitCandidateFile = itCommitCandidates.next(); 384 385 if(binnaryCandidates.contains(commitCandidateFile)) { 387 ISVNProperty prop = client.propertyGet(commitCandidateFile, ISVNProperty.MIME_TYPE); 388 if(prop != null) { 389 String s = prop.getValue(); 390 if (s == null || s.startsWith("text/")) { client.propertySet(commitCandidateFile, ISVNProperty.MIME_TYPE, "application/octet-stream", false); } 393 } else { 394 client.propertySet(commitCandidateFile, ISVNProperty.MIME_TYPE, "application/octet-stream", false); } 396 } 397 398 List <File > managedTreesList = null; 399 for (Iterator<List <File >> itManagedTrees = managedTrees.iterator(); itManagedTrees.hasNext();) { 400 List <File > list = itManagedTrees.next(); 401 File managedTreeFile = list.get(0); 402 403 File base = SVNBaseDir.getRootDir(new File [] {commitCandidateFile, managedTreeFile}); 404 if(base != null) { 405 FileInformation status = cache.getStatus(base); 406 if ((status.getStatus() & FileInformation.STATUS_MANAGED) != 0) { 407 managedTreesList = list; 409 break; 410 } 411 } 412 } 413 if(managedTreesList == null) { 414 managedTreesList = new ArrayList<File >(); 416 managedTrees.add(managedTreesList); 417 } 418 managedTreesList.add(commitCandidateFile); 419 } 420 421 for (Iterator<List <File >> itCandidates = managedTrees.iterator(); itCandidates.hasNext();) { 423 List <File > list = itCandidates.next(); 425 File [] files = list.toArray(new File [list.size()]); 426 427 client.commit(files, message, false); 428 429 if(rootUpdate) { 430 File [] rootFiles = ctx.getRootFiles(); 431 for (int i = 0; i < rootFiles.length; i++) { 432 client.update(rootFiles[i], SVNRevision.HEAD, false); 433 } 434 for (int i = 0; i < rootFiles.length; i++) { 435 cache.refresh(rootFiles[i], FileStatusCache.REPOSITORY_STATUS_UNKNOWN); 436 } 437 } 438 439 for (int i = 0; i < files.length; i++) { 441 cache.refresh(files[i], FileStatusCache.REPOSITORY_STATUS_UNKNOWN); 442 } 443 if(support.isCanceled()) { 444 return; 445 } 446 } 447 448 } catch (SVNClientException ex) { 449 support.annotate(ex); 450 } 451 } 452 453 private static List <File > listUnmanagedParents(SvnFileNode node) { 454 List <File > unmanaged = new ArrayList<File >(); 455 File file = node.getFile(); 456 File parent = file.getParentFile(); 457 while (true) { 458 if (new File (parent, ".svn/entries").canRead() || new File (parent, "_svn/entries").canRead()) { break; 460 } 461 unmanaged.add(0, parent); 462 parent = parent.getParentFile(); 463 if (parent == null) { 464 break; 465 } 466 } 467 468 List <File > ret = new ArrayList<File >(); 469 Iterator<File > it = unmanaged.iterator(); 470 while (it.hasNext()) { 471 File un = it.next(); 472 ret.add(un); 473 } 474 475 return ret; 476 } 477 } 478 | Popular Tags |