KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > subversion > ui > commit > CommitAction


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.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 JavaDoc;
36 import java.util.*;
37 import java.util.List JavaDoc;
38 import java.text.MessageFormat JavaDoc;
39 import javax.swing.event.TableModelEvent JavaDoc;
40 import javax.swing.event.TableModelListener JavaDoc;
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 /**
54  * Commit action
55  *
56  * @author Petr Kuzel
57  */

58     public class CommitAction extends ContextAction {
59     
60     static final String JavaDoc RECENT_COMMIT_MESSAGES = "recentCommitMessage";
61
62     protected String JavaDoc getBaseName(Node[] nodes) {
63         return "CTL_MenuItem_Commit"; // NOI18N
64
}
65
66     protected boolean enable(Node[] nodes) {
67         // XXX could be a performace issue, maybe a msg box in commit would be enough
68
FileStatusCache cache = Subversion.getInstance().getStatusCache();
69         File JavaDoc[] files = cache.listFiles(getContext(nodes), FileInformation.STATUS_LOCAL_CHANGE);
70         return files.length > 0;
71     }
72
73     /** Run commit action. Shows UI */
74     public static void commit(String JavaDoc contentTitle, final Context ctx) {
75         FileStatusCache cache = Subversion.getInstance().getStatusCache();
76         File JavaDoc[] roots = ctx.getFiles();
77         if (roots.length == 0) {
78             return;
79         }
80         
81         List JavaDoc<File JavaDoc> tagsFiles = new ArrayList<File JavaDoc>();
82         for (int i = 0; i < roots.length; i++) {
83             String JavaDoc tag = SvnUtils.getCopy(roots[i]);
84             if(tag!=null && !tag.equals("")) {
85                 tagsFiles.add(roots[i]);
86             }
87         }
88         
89         File JavaDoc[][] split = Utils.splitFlatOthers(roots);
90         List JavaDoc<File JavaDoc> fileList = new ArrayList<File JavaDoc>();
91         for (int c = 0; c < split.length; c++) {
92             roots = split[c];
93             boolean recursive = c == 1;
94             if (recursive) {
95                 File JavaDoc[] 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 JavaDoc[] 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         // show commit dialog
120
final CommitPanel panel = new CommitPanel();
121         final CommitTable data = new CommitTable(panel.filesLabel, CommitTable.COMMIT_COLUMNS, new String JavaDoc[] { 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 JavaDoc> it = fileList.iterator(); it.hasNext();) {
127             File JavaDoc 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)); // NOI18N
139
dd.setModal(true);
140         final JButton commitButton = new JButton(org.openide.util.NbBundle.getMessage(CommitAction.class, "CTL_Commit_Action_Commit")); // NOI18N
141
commitButton.setEnabled(false);
142         dd.setOptions(new Object JavaDoc[] {commitButton, org.openide.util.NbBundle.getMessage(CommitAction.class, "CTL_Commit_Action_Cancel")}); // NOI18N
143
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 JavaDoc() {
150             public void tableChanged(TableModelEvent JavaDoc e) {
151                 refreshCommitDialog(panel, data, commitButton);
152             }
153         });
154         commitButton.setEnabled(containsCommitable(data));
155                 
156         panel.putClientProperty("contentTitle", contentTitle); // NOI18N
157
panel.putClientProperty("DialogDescriptor", dd); // NOI18N
158
final Dialog dialog = DialogDisplayer.getDefault().createDialog(dd);
159         dialog.addWindowListener(new DialogBoundsPreserver(SvnModuleConfig.getDefault().getPreferences(), "svn.commit.dialog")); // NOI18N
160
dialog.pack();
161         dialog.setVisible(true);
162
163         if (dd.getValue() == commitButton) {
164             
165             //SvnModuleConfig.getDefault().setCommitTableSorter(data.getSorter());
166

167             final Map<SvnFileNode, CommitOptions> commitFiles = data.getCommitFiles();
168             final String JavaDoc 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")); // NOI18N
179
}
180         // if OK setup sequence of add, remove and commit calls
181

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     /**
195      * User changed a commit action.
196      *
197      * @param panel
198      * @param commit
199      */

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 JavaDoc> stickyTags = new HashSet<String JavaDoc>();
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 JavaDoc 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>"); // NOI18N
219
conflicts = true;
220             }
221             stickyTags.add(SvnUtils.getCopy(fileNode.getFile()));
222         }
223         
224         if (stickyTags.size() > 1) {
225             table.setColumns(new String JavaDoc [] { 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 JavaDoc [] { CommitTableModel.COLUMN_NAME_NAME, CommitTableModel.COLUMN_NAME_STATUS,
229                                                 CommitTableModel.COLUMN_NAME_ACTION, CommitTableModel.COLUMN_NAME_PATH });
230         }
231         
232         String JavaDoc contentTitle = (String JavaDoc) panel.getClientProperty("contentTitle"); // NOI18N
233
DialogDescriptor dd = (DialogDescriptor) panel.getClientProperty("DialogDescriptor"); // NOI18N
234
String JavaDoc errorLabel;
235         if (stickyTags.size() <= 1) {
236             String JavaDoc stickyTag = stickyTags.size() == 0 ? null : (String JavaDoc) stickyTags.iterator().next();
237             if (stickyTag == null) {
238                 dd.setTitle(MessageFormat.format(loc.getString("CTL_CommitDialog_Title"), new Object JavaDoc [] { contentTitle }));
239                 errorLabel = ""; // NOI18N
240
} else {
241                 dd.setTitle(MessageFormat.format(loc.getString("CTL_CommitDialog_Title_Branch"), new Object JavaDoc [] { contentTitle, stickyTag }));
242                 String JavaDoc msg = MessageFormat.format(loc.getString("MSG_CommitForm_InfoBranch"), new Object JavaDoc [] { stickyTag });
243                 errorLabel = "<html><font color=\"#002080\">" + msg + "</font></html>"; // NOI18N
244
}
245         } else {
246             dd.setTitle(MessageFormat.format(loc.getString("CTL_CommitDialog_Title_Branches"), new Object JavaDoc [] { contentTitle }));
247             String JavaDoc msg = loc.getString("MSG_CommitForm_ErrorMultipleBranches");
248             errorLabel = "<html><font color=\"#CC0000\">" + msg + "</font></html>"; // NOI18N
249
}
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 JavaDoc message, Map<SvnFileNode, CommitOptions> commitFiles, Context ctx, SvnProgressSupport support) {
263         performCommit(message, commitFiles, ctx, support, false);
264     }
265     
266     public static void performCommit(String JavaDoc 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); // should not hapen
274
return;
275             }
276             support.setDisplayName(org.openide.util.NbBundle.getMessage(CommitAction.class, "LBL_Commit_Progress")); // NOI18N
277

278             List JavaDoc<SvnFileNode> addCandidates = new ArrayList<SvnFileNode>();
279             List JavaDoc<SvnFileNode> removeCandidates = new ArrayList<SvnFileNode>();
280             Set<File JavaDoc> commitCandidates = new LinkedHashSet<File JavaDoc>();
281             Set<File JavaDoc> binnaryCandidates = new HashSet<File JavaDoc>();
282             
283             Iterator<SvnFileNode> it = commitFiles.keySet().iterator();
284             // XXX refactor the olowing loop. there seem to be redundant blocks
285
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 JavaDoc<File JavaDoc> l = listUnmanagedParents(node);
293                     Iterator<File JavaDoc> dit = l.iterator();
294                     while (dit.hasNext()) {
295                         if(support.isCanceled()) {
296                             return;
297                         }
298                         File JavaDoc 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                     // assute no MIME property or startin gwith text
312
List JavaDoc<File JavaDoc> l = listUnmanagedParents(node);
313                     Iterator<File JavaDoc> dit = l.iterator();
314                     while (dit.hasNext()) {
315                         if(support.isCanceled()) {
316                             return;
317                         }
318                         File JavaDoc 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             // perform adds
336

337             List JavaDoc<File JavaDoc> addFiles = new ArrayList<File JavaDoc>();
338             List JavaDoc<File JavaDoc> addDirs = new ArrayList<File JavaDoc>();
339             // XXX waht if user denied directory add but wants to add a file in it?
340
it = addCandidates.iterator();
341             while (it.hasNext()) {
342                 if(support.isCanceled()) {
343                     return;
344                 }
345                 SvnFileNode svnFileNode = it.next();
346                 File JavaDoc 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 JavaDoc> itFiles = addDirs.iterator();
358             List JavaDoc<File JavaDoc> dirsToAdd = new ArrayList<File JavaDoc>();
359             while (itFiles.hasNext()) {
360                 File JavaDoc 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 JavaDoc[dirsToAdd.size()]), false);
367             }
368             if(support.isCanceled()) {
369                 return;
370             }
371
372             if(addFiles.size() > 0) {
373                 client.addFile(addFiles.toArray(new File JavaDoc[addFiles.size()]), false);
374             }
375             
376             // TODO perform removes. especialy package removes where
377
// metadata must be replied from SvnMetadata (hold by FileSyatemHandler)
378

379             // set binary mimetype and group commitCandidates by managed trees
380
FileStatusCache cache = Subversion.getInstance().getStatusCache();
381             List JavaDoc<List JavaDoc<File JavaDoc>> managedTrees = new ArrayList<List JavaDoc<File JavaDoc>>();
382             for (Iterator<File JavaDoc> itCommitCandidates = commitCandidates.iterator(); itCommitCandidates.hasNext();) {
383                 File JavaDoc commitCandidateFile = itCommitCandidates.next();
384                 
385                 // set MIME property application/octet-stream
386
if(binnaryCandidates.contains(commitCandidateFile)) {
387                     ISVNProperty prop = client.propertyGet(commitCandidateFile, ISVNProperty.MIME_TYPE);
388                     if(prop != null) {
389                         String JavaDoc s = prop.getValue();
390                         if (s == null || s.startsWith("text/")) { // NOI18N
391
client.propertySet(commitCandidateFile, ISVNProperty.MIME_TYPE, "application/octet-stream", false); // NOI18N
392
}
393                     } else {
394                          client.propertySet(commitCandidateFile, ISVNProperty.MIME_TYPE, "application/octet-stream", false); // NOI18N
395
}
396                 }
397                 
398                 List JavaDoc<File JavaDoc> managedTreesList = null;
399                 for (Iterator<List JavaDoc<File JavaDoc>> itManagedTrees = managedTrees.iterator(); itManagedTrees.hasNext();) {
400                     List JavaDoc<File JavaDoc> list = itManagedTrees.next();
401                     File JavaDoc managedTreeFile = list.get(0);
402
403                     File JavaDoc base = SVNBaseDir.getRootDir(new File JavaDoc[] {commitCandidateFile, managedTreeFile});
404                     if(base != null) {
405                         FileInformation status = cache.getStatus(base);
406                         if ((status.getStatus() & FileInformation.STATUS_MANAGED) != 0) {
407                             // found a list with files from the same working copy
408
managedTreesList = list;
409                             break;
410                         }
411                     }
412                 }
413                 if(managedTreesList == null) {
414                     // no list for files from the same wc as commitCandidateFile created yet
415
managedTreesList = new ArrayList<File JavaDoc>();
416                     managedTrees.add(managedTreesList);
417                 }
418                 managedTreesList.add(commitCandidateFile);
419             }
420
421             // finally commit
422
for (Iterator<List JavaDoc<File JavaDoc>> itCandidates = managedTrees.iterator(); itCandidates.hasNext();) {
423                 // one commit for each wc
424
List JavaDoc<File JavaDoc> list = itCandidates.next();
425                 File JavaDoc[] files = list.toArray(new File JavaDoc[list.size()]);
426                 
427                 client.commit(files, message, false);
428                 
429                 if(rootUpdate) {
430                     File JavaDoc[] 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                 // XXX it's probably already catched by cache's onNotify()
440
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 JavaDoc<File JavaDoc> listUnmanagedParents(SvnFileNode node) {
454         List JavaDoc<File JavaDoc> unmanaged = new ArrayList<File JavaDoc>();
455         File JavaDoc file = node.getFile();
456         File JavaDoc parent = file.getParentFile();
457         while (true) {
458             if (new File JavaDoc(parent, ".svn/entries").canRead() || new File JavaDoc(parent, "_svn/entries").canRead()) { // NOI18N
459
break;
460             }
461             unmanaged.add(0, parent);
462             parent = parent.getParentFile();
463             if (parent == null) {
464                 break;
465             }
466         }
467
468         List JavaDoc<File JavaDoc> ret = new ArrayList<File JavaDoc>();
469         Iterator<File JavaDoc> it = unmanaged.iterator();
470         while (it.hasNext()) {
471             File JavaDoc un = it.next();
472             ret.add(un);
473         }
474
475         return ret;
476     }
477 }
478
Popular Tags