2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* The Original Software is NetBeans. The Initial Developer of the Original
27
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28
* Microsystems, Inc. All Rights Reserved.
30
* If you wish your version of this file to be governed by only the CDDL
31
* or only the GPL Version 2, indicate your decision by adding
32
* "[Contributor] elects to include this software in this distribution
33
* under the [CDDL or GPL Version 2] license." If you do not indicate a
34
* single choice of license, a recipient has the option to distribute
35
* your version of this file under either the CDDL, the GPL Version 2 or
36
* to extend the choice of license to its licensees as provided above.
37
* However, if you add GPL Version 2 code and therefore, elected the GPL
38
* Version 2 license, then the option applies only if the new code is
39
* made subject to such option by the copyright holder.
42
package org.netbeans.modules.subversion.ui.history;
44
import javax.swing.event.DocumentEvent;
45
import javax.swing.event.DocumentListener;
46
import org.openide.util.RequestProcessor;
47
import org.openide.util.NbBundle;
48
import org.openide.explorer.ExplorerManager;
49
import org.openide.nodes.Node;
50
import org.openide.windows.TopComponent;
51
import org.openide.awt.Mnemonics;
52
import org.netbeans.modules.subversion.ui.diff.DiffSetupSource;
53
import org.netbeans.modules.subversion.ui.diff.Setup;
54
import org.netbeans.modules.versioning.util.NoContentPanel;
55
import org.netbeans.modules.subversion.util.SvnUtils;
56
import org.tigris.subversion.svnclientadapter.SVNRevision;
57
import org.tigris.subversion.svnclientadapter.SVNUrl;
61
import java.beans.PropertyChangeEvent;
62
import java.beans.PropertyChangeListener;
63
import java.awt.event.KeyEvent;
64
import java.awt.event.ActionEvent;
65
import java.awt.event.ActionListener;
66
import java.awt.Dimension;
67
import org.tigris.subversion.svnclientadapter.SVNClientException;
70
* Contains all components of the Search History panel.
72
* @author Maros Sandor
74
class SearchHistoryPanel extends javax.swing.JPanel implements ExplorerManager.Provider, PropertyChangeListener, ActionListener, DiffSetupSource, DocumentListener {
76
private final File[] roots;
77
private final SVNUrl repositoryUrl;
78
private final SearchCriteriaPanel criteria;
80
private Divider divider;
81
private Action searchAction;
82
private SearchExecutor currentSearch;
83
private RequestProcessor.Task currentSearchTask;
85
private boolean criteriaVisible;
86
private boolean searchInProgress;
87
private List<RepositoryRevision> results;
88
private SummaryView summaryView;
89
private DiffResultsView diffView;
91
private AbstractAction nextAction;
92
private AbstractAction prevAction;
94
/** Creates new form SearchHistoryPanel */
95
public SearchHistoryPanel(File [] roots, SearchCriteriaPanel criteria) {
97
this.repositoryUrl = null;
98
this.criteria = criteria;
99
criteriaVisible = true;
100
explorerManager = new ExplorerManager ();
103
refreshComponents(true);
106
public SearchHistoryPanel(SVNUrl repositoryUrl, File localRoot, SearchCriteriaPanel criteria) {
107
this.repositoryUrl = repositoryUrl;
108
this.roots = new File[] { localRoot };
109
this.criteria = criteria;
110
criteriaVisible = true;
111
explorerManager = new ExplorerManager ();
114
refreshComponents(true);
117
void setSearchCriteria(boolean b) {
119
refreshComponents(false);
122
private void setupComponents() {
125
divider = new Divider(this);
126
java.awt.GridBagConstraints gridBagConstraints;
127
gridBagConstraints = new java.awt.GridBagConstraints();
128
gridBagConstraints.gridy = 2;
129
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
130
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
131
gridBagConstraints.weightx = 1.0;
132
gridBagConstraints.insets = new java.awt.Insets(2, 0, 2, 0);
133
add(divider, gridBagConstraints);
135
searchCriteriaPanel.add(criteria);
136
searchAction = new AbstractAction(NbBundle.getMessage(SearchHistoryPanel.class, "CTL_Search")) { // NOI18N
138
putValue(Action.SHORT_DESCRIPTION, NbBundle.getMessage(SearchHistoryPanel.class, "TT_Search")); // NOI18N
140
public void actionPerformed(ActionEvent e) {
144
getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "search"); // NOI18N
145
getActionMap().put("search", searchAction); // NOI18N
146
bSearch.setAction(searchAction);
147
Mnemonics.setLocalizedText(bSearch, NbBundle.getMessage(SearchHistoryPanel.class, "CTL_Search")); // NOI18N
149
Dimension d1 = tbSummary.getPreferredSize();
150
Dimension d2 = tbDiff.getPreferredSize();
151
if (d1.width > d2.width) {
152
tbDiff.setPreferredSize(d1);
155
nextAction = new AbstractAction(null, new javax.swing.ImageIcon(getClass().getResource("/org/netbeans/modules/subversion/resources/icons/diff-next.png"))) { // NOI18N
157
putValue(Action.SHORT_DESCRIPTION, java.util.ResourceBundle.getBundle("org/netbeans/modules/subversion/ui/diff/Bundle"). // NOI18N
158
getString("CTL_DiffPanel_Next_Tooltip")); // NOI18N
160
public void actionPerformed(ActionEvent e) {
161
diffView.onNextButton();
164
prevAction = new AbstractAction(null, new javax.swing.ImageIcon(getClass().getResource("/org/netbeans/modules/subversion/resources/icons/diff-prev.png"))) { // NOI18N
166
putValue(Action.SHORT_DESCRIPTION, java.util.ResourceBundle.getBundle("org/netbeans/modules/subversion/ui/diff/Bundle"). // NOI18N
167
getString("CTL_DiffPanel_Prev_Tooltip")); // NOI18N
169
public void actionPerformed(ActionEvent e) {
170
diffView.onPrevButton();
173
bNext.setAction(nextAction);
174
bPrev.setAction(prevAction);
176
criteria.tfFrom.getDocument().addDocumentListener(this);
177
criteria.tfTo.getDocument().addDocumentListener(this);
179
getActionMap().put("jumpNext", nextAction); // NOI18N
180
getActionMap().put("jumpPrev", prevAction); // NOI18N
183
public void actionPerformed(ActionEvent e) {
184
if (e.getID() == Divider.DIVIDER_CLICKED) {
185
criteriaVisible = !criteriaVisible;
186
refreshComponents(false);
190
private ExplorerManager explorerManager;
192
public void propertyChange(PropertyChangeEvent evt) {
193
if (ExplorerManager.PROP_SELECTED_NODES.equals(evt.getPropertyName())) {
194
TopComponent tc = (TopComponent) SwingUtilities.getAncestorOfClass(TopComponent.class, this);
195
if (tc == null) return;
196
tc.setActivatedNodes((Node[]) evt.getNewValue());
200
public void addNotify() {
202
explorerManager.addPropertyChangeListener(this);
205
public void removeNotify() {
206
explorerManager.removePropertyChangeListener(this);
207
super.removeNotify();
210
public ExplorerManager getExplorerManager () {
211
return explorerManager;
214
final void refreshComponents(boolean refreshResults) {
215
if (refreshResults) {
216
resultsPanel.removeAll();
217
if (results == null) {
218
if (searchInProgress) {
219
resultsPanel.add(new NoContentPanel(NbBundle.getMessage(SearchHistoryPanel.class, "LBL_SearchHistory_Searching"))); // NOI18N
221
resultsPanel.add(new NoContentPanel(NbBundle.getMessage(SearchHistoryPanel.class, "LBL_SearchHistory_NoResults"))); // NOI18N
224
if (tbSummary.isSelected()) {
225
if (summaryView == null) {
226
summaryView = new SummaryView(this, results);
228
resultsPanel.add(summaryView.getComponent());
230
if (diffView == null) {
231
diffView = new DiffResultsView(this, results);
233
resultsPanel.add(diffView.getComponent());
236
resultsPanel.revalidate();
237
resultsPanel.repaint();
239
nextAction.setEnabled(!tbSummary.isSelected() && diffView != null && diffView.isNextEnabled());
240
prevAction.setEnabled(!tbSummary.isSelected() && diffView != null && diffView.isPrevEnabled());
242
divider.setArrowDirection(criteriaVisible ? Divider.UP : Divider.DOWN);
243
searchCriteriaPanel.setVisible(criteriaVisible);
244
bSearch.setVisible(criteriaVisible);
249
public void setResults(List<RepositoryRevision> newResults) {
250
setResults(newResults, false);
253
private void setResults(List<RepositoryRevision> newResults, boolean searching) {
254
this.results = newResults;
255
this.searchInProgress = searching;
258
refreshComponents(true);
261
public SVNUrl getRepositoryUrl() {
262
return repositoryUrl;
265
public SVNUrl getSearchRepositoryRootUrl() throws SVNClientException {
266
if (repositoryUrl != null) return repositoryUrl;
267
return SvnUtils.getRepositoryRootUrl(roots[0]);
270
public File[] getRoots() {
274
public SearchCriteriaPanel getCriteria() {
278
private synchronized void search() {
279
if (currentSearchTask != null) {
280
currentSearchTask.cancel();
282
setResults(null, true);
283
currentSearch = new SearchExecutor(this);
284
currentSearchTask = RequestProcessor.getDefault().create(currentSearch);
285
currentSearchTask.schedule(0);
288
void executeSearch() {
292
void showDiff(RepositoryRevision.Event revision) {
293
tbDiff.setSelected(true);
294
refreshComponents(true);
295
diffView.select(revision);
298
public void showDiff(RepositoryRevision container) {
299
tbDiff.setSelected(true);
300
refreshComponents(true);
301
diffView.select(container);
305
* Return diff setup describing shown history.
306
* It return empty collection on non-atomic
307
* revision ranges. XXX move this logic to clients?
309
public Collection getSetups() {
310
if (results == null) {
311
return Collections.EMPTY_SET;
313
if (tbDiff.isSelected()) {
314
return diffView.getSetups();
316
return summaryView.getSetups();
320
Collection getSetups(RepositoryRevision [] revisions, RepositoryRevision.Event [] events) {
321
long fromRevision = Long.MAX_VALUE;
322
long toRevision = Long.MIN_VALUE;
323
Set<File> filesToDiff = new HashSet<File>();
325
for (RepositoryRevision revision : revisions) {
326
long rev = revision.getLog().getRevision().getNumber();
327
if (rev > toRevision) toRevision = rev;
328
if (rev < fromRevision) fromRevision = rev;
329
List<RepositoryRevision.Event> evs = revision.getEvents();
330
for (RepositoryRevision.Event event : evs) {
331
File file = event.getFile();
333
filesToDiff.add(file);
338
for (RepositoryRevision.Event event : events) {
339
long rev = event.getLogInfoHeader().getLog().getRevision().getNumber();
340
if (rev > toRevision) toRevision = rev;
341
if (rev < fromRevision) fromRevision = rev;
342
if (event.getFile() != null) {
343
filesToDiff.add(event.getFile());
347
List<Setup> setups = new ArrayList<Setup>();
348
for (File file : filesToDiff) {
349
Setup setup = new Setup(file, Long.toString(fromRevision - 1), Long.toString(toRevision));
355
public String getSetupDisplayName() {
359
public static int compareRevisions(String r1, String r2) {
360
StringTokenizer st1 = new StringTokenizer(r1, "."); // NOI18N
361
StringTokenizer st2 = new StringTokenizer(r2, "."); // NOI18N
363
if (!st1.hasMoreTokens()) {
364
return st2.hasMoreTokens() ? -1 : 0;
366
if (!st2.hasMoreTokens()) {
367
return st1.hasMoreTokens() ? 1 : 0;
369
int n1 = Integer.parseInt(st1.nextToken());
370
int n2 = Integer.parseInt(st2.nextToken());
371
if (n1 != n2) return n2 - n1;
375
/** This method is called from within the constructor to
376
* initialize the form.
377
* WARNING: Do NOT modify this code. The content of this method is
378
* always regenerated by the Form Editor.
380
// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
381
private void initComponents() {
382
java.awt.GridBagConstraints gridBagConstraints;
384
buttonGroup1 = new javax.swing.ButtonGroup();
385
searchCriteriaPanel = new javax.swing.JPanel();
386
bSearch = new javax.swing.JButton();
387
jPanel1 = new javax.swing.JPanel();
388
jToolBar1 = new javax.swing.JToolBar();
389
tbSummary = new javax.swing.JToggleButton();
390
tbDiff = new javax.swing.JToggleButton();
391
jSeparator2 = new javax.swing.JSeparator();
392
bNext = new javax.swing.JButton();
393
bPrev = new javax.swing.JButton();
394
resultsPanel = new javax.swing.JPanel();
396
setBorder(javax.swing.BorderFactory.createEmptyBorder(8, 8, 0, 8));
397
setLayout(new java.awt.GridBagLayout());
399
searchCriteriaPanel.setLayout(new java.awt.BorderLayout());
400
gridBagConstraints = new java.awt.GridBagConstraints();
401
gridBagConstraints.gridx = 0;
402
gridBagConstraints.gridy = 0;
403
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
404
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
405
gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
406
gridBagConstraints.weightx = 1.0;
407
add(searchCriteriaPanel, gridBagConstraints);
409
java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("org/netbeans/modules/subversion/ui/history/Bundle"); // NOI18N
410
bSearch.setToolTipText(bundle.getString("TT_Search")); // NOI18N
411
gridBagConstraints = new java.awt.GridBagConstraints();
412
gridBagConstraints.gridx = 0;
413
gridBagConstraints.gridy = 1;
414
gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
415
add(bSearch, gridBagConstraints);
417
jPanel1.setPreferredSize(new java.awt.Dimension(10, 6));
418
gridBagConstraints = new java.awt.GridBagConstraints();
419
gridBagConstraints.gridy = 2;
420
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
421
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
422
gridBagConstraints.weightx = 1.0;
423
gridBagConstraints.insets = new java.awt.Insets(0, 0, 2, 0);
424
add(jPanel1, gridBagConstraints);
426
jToolBar1.setFloatable(false);
427
jToolBar1.setRollover(true);
429
buttonGroup1.add(tbSummary);
430
tbSummary.setSelected(true);
431
org.openide.awt.Mnemonics.setLocalizedText(tbSummary, bundle.getString("CTL_ShowSummary")); // NOI18N
432
tbSummary.setToolTipText(bundle.getString("TT_Summary")); // NOI18N
433
tbSummary.addActionListener(new java.awt.event.ActionListener() {
434
public void actionPerformed(java.awt.event.ActionEvent evt) {
438
jToolBar1.add(tbSummary);
440
buttonGroup1.add(tbDiff);
441
org.openide.awt.Mnemonics.setLocalizedText(tbDiff, bundle.getString("CTL_ShowDiff")); // NOI18N
442
tbDiff.setToolTipText(bundle.getString("TT_ShowDiff")); // NOI18N
443
tbDiff.addActionListener(new java.awt.event.ActionListener() {
444
public void actionPerformed(java.awt.event.ActionEvent evt) {
448
jToolBar1.add(tbDiff);
450
jSeparator2.setOrientation(javax.swing.SwingConstants.VERTICAL);
451
jSeparator2.setMaximumSize(new java.awt.Dimension(2, 32767));
452
jToolBar1.add(jSeparator2);
454
bNext.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/netbeans/modules/subversion/resources/icons/diff-next.png"))); // NOI18N
455
jToolBar1.add(bNext);
456
bNext.getAccessibleContext().setAccessibleName(bundle.getString("ACSN_NextDifference")); // NOI18N
457
bNext.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(SearchHistoryPanel.class, "ACSD_NextDifference")); // NOI18N
459
bPrev.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/netbeans/modules/subversion/resources/icons/diff-prev.png"))); // NOI18N
460
jToolBar1.add(bPrev);
461
bPrev.getAccessibleContext().setAccessibleName(bundle.getString("ACSN_PrevDifference")); // NOI18N
462
bPrev.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(SearchHistoryPanel.class, "ACSD_PrevDifference")); // NOI18N
464
gridBagConstraints = new java.awt.GridBagConstraints();
465
gridBagConstraints.gridy = 3;
466
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
467
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
468
add(jToolBar1, gridBagConstraints);
470
resultsPanel.setLayout(new java.awt.BorderLayout());
471
gridBagConstraints = new java.awt.GridBagConstraints();
472
gridBagConstraints.gridx = 0;
473
gridBagConstraints.gridy = 4;
474
gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
475
gridBagConstraints.gridheight = java.awt.GridBagConstraints.REMAINDER;
476
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
477
gridBagConstraints.weightx = 1.0;
478
gridBagConstraints.weighty = 1.0;
479
gridBagConstraints.insets = new java.awt.Insets(8, 0, 8, 0);
480
add(resultsPanel, gridBagConstraints);
481
}// </editor-fold>//GEN-END:initComponents
483
private void onViewToggle(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_onViewToggle
484
refreshComponents(true);
485
}//GEN-LAST:event_onViewToggle
487
public void insertUpdate(DocumentEvent e) {
491
public void removeUpdate(DocumentEvent e) {
495
public void changedUpdate(DocumentEvent e) {
499
private void validateUserInput() {
500
SVNRevision from = criteria.getFrom();
501
if(from == null && criteria.tfFrom.getText().trim().length() > 0) {
502
bSearch.setEnabled(false);
505
SVNRevision to = criteria.getTo();
506
if(to == null && criteria.tfTo.getText().trim().length() > 0) {
507
bSearch.setEnabled(false);
510
bSearch.setEnabled(true);
513
// Variables declaration - do not modify//GEN-BEGIN:variables
514
private javax.swing.JButton bNext;
515
private javax.swing.JButton bPrev;
516
private javax.swing.JButton bSearch;
517
private javax.swing.ButtonGroup buttonGroup1;
518
private javax.swing.JPanel jPanel1;
519
private javax.swing.JSeparator jSeparator2;
520
private javax.swing.JToolBar jToolBar1;
521
private javax.swing.JPanel resultsPanel;
522
private javax.swing.JPanel searchCriteriaPanel;
523
private javax.swing.JToggleButton tbDiff;
524
private javax.swing.JToggleButton tbSummary;
525
// End of variables declaration//GEN-END:variables