Cleaned up whitespace, fix DOS line endings
[nbgit.git] / src / org / nbgit / ui / log / SearchHistoryPanel.java
blob9363397a3820422704b462a02cd99be799b7a756
1 /*
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]"
24 * Contributor(s):
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.
29 * Portions Copyright 2008 Alexander Coles (Ikonoklastik Productions).
31 * If you wish your version of this file to be governed by only the CDDL
32 * or only the GPL Version 2, indicate your decision by adding
33 * "[Contributor] elects to include this software in this distribution
34 * under the [CDDL or GPL Version 2] license." If you do not indicate a
35 * single choice of license, a recipient has the option to distribute
36 * your version of this file under either the CDDL, the GPL Version 2 or
37 * to extend the choice of license to its licensees as provided above.
38 * However, if you add GPL Version 2 code and therefore, elected the GPL
39 * Version 2 license, then the option applies only if the new code is
40 * made subject to such option by the copyright holder.
42 package org.nbgit.ui.log;
44 import java.awt.Dimension;
45 import java.awt.event.ActionEvent;
46 import java.awt.event.ActionListener;
47 import java.awt.event.KeyEvent;
48 import java.beans.PropertyChangeEvent;
49 import java.beans.PropertyChangeListener;
50 import java.io.File;
51 import java.util.ArrayList;
52 import java.util.Collection;
53 import java.util.Collections;
54 import java.util.HashSet;
55 import java.util.List;
56 import java.util.Set;
57 import java.util.StringTokenizer;
58 import javax.swing.AbstractAction;
59 import javax.swing.Action;
60 import javax.swing.KeyStroke;
61 import javax.swing.SwingUtilities;
62 import javax.swing.event.DocumentEvent;
63 import javax.swing.event.DocumentListener;
64 import org.nbgit.Git;
65 import org.nbgit.GitModuleConfig;
66 import org.nbgit.ui.diff.DiffSetupSource;
67 import org.nbgit.ui.diff.Setup;
68 import org.netbeans.modules.versioning.util.NoContentPanel;
69 import org.openide.awt.Mnemonics;
70 import org.openide.explorer.ExplorerManager;
71 import org.openide.nodes.Node;
72 import org.openide.util.NbBundle;
73 import org.openide.util.RequestProcessor;
74 import org.openide.windows.TopComponent;
76 /**
77 * Contains all components of the Search History panel.
79 * @author Maros Sandor
81 class SearchHistoryPanel extends javax.swing.JPanel implements ExplorerManager.Provider, PropertyChangeListener, ActionListener, DiffSetupSource, DocumentListener {
83 private final File[] roots;
84 private final String repositoryUrl;
85 private final SearchCriteriaPanel criteria;
86 private Divider divider;
87 private Action searchAction;
88 private SearchExecutor currentSearch;
89 private RequestProcessor.Task currentSearchTask;
90 private boolean criteriaVisible;
91 private boolean searchInProgress;
92 private List<RepositoryRevision> results;
93 private SummaryView summaryView;
94 private DiffResultsView diffView;
95 private boolean bOutSearch;
96 private boolean bIncomingSearch;
97 private AbstractAction nextAction;
98 private AbstractAction prevAction;
100 /** Creates new form SearchHistoryPanel */
101 public SearchHistoryPanel(File[] roots, SearchCriteriaPanel criteria) {
102 this.bOutSearch = false;
103 this.bIncomingSearch = false;
104 this.roots = roots;
105 this.repositoryUrl = null;
106 this.criteria = criteria;
107 criteriaVisible = true;
108 explorerManager = new ExplorerManager();
109 initComponents();
110 setupComponents();
111 refreshComponents(true);
114 public SearchHistoryPanel(String repositoryUrl, File localRoot, SearchCriteriaPanel criteria) {
115 this.bOutSearch = false;
116 this.bIncomingSearch = false;
117 this.repositoryUrl = repositoryUrl;
118 this.roots = new File[]{localRoot};
119 this.criteria = criteria;
120 criteriaVisible = true;
121 explorerManager = new ExplorerManager();
122 initComponents();
123 setupComponents();
124 refreshComponents(true);
127 void setOutSearch() {
128 criteria.setForOut();
129 bOutSearch = true;
130 divider.setVisible(false);
131 tbSummary.setToolTipText(NbBundle.getMessage(SearchHistoryPanel.class, "TT_OutSummary"));
132 showMergesChkBox.setToolTipText(NbBundle.getMessage(SearchHistoryPanel.class, "TT_OutShowMerges"));
133 tbDiff.setToolTipText(NbBundle.getMessage(SearchHistoryPanel.class, "TT_OutShowDiff"));
136 boolean isOutSearch() {
137 return bOutSearch;
140 boolean isShowMerges() {
141 return showMergesChkBox.isSelected();
144 void setIncomingSearch() {
145 criteria.setForIncoming();
146 bIncomingSearch = true;
147 tbDiff.setVisible(false);
148 bNext.setVisible(false);
149 bPrev.setVisible(false);
150 showMergesChkBox.setToolTipText(NbBundle.getMessage(SearchHistoryPanel.class, "TT_IncomingShowMerges"));
151 tbSummary.setToolTipText(NbBundle.getMessage(SearchHistoryPanel.class, "TT_IncomingSummary"));
154 boolean isIncomingSearch() {
155 return bIncomingSearch;
158 void setSearchCriteria(boolean b) {
159 criteriaVisible = b;
160 refreshComponents(false);
163 private void setupComponents() {
164 remove(jPanel1);
166 divider = new Divider(this);
167 java.awt.GridBagConstraints gridBagConstraints;
168 gridBagConstraints = new java.awt.GridBagConstraints();
169 gridBagConstraints.gridy = 2;
170 gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
171 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
172 gridBagConstraints.weightx = 1.0;
173 gridBagConstraints.insets = new java.awt.Insets(2, 0, 2, 0);
174 add(divider, gridBagConstraints);
176 searchCriteriaPanel.add(criteria);
177 searchAction = new AbstractAction(NbBundle.getMessage(SearchHistoryPanel.class, "CTL_Search")) { // NOI18N
180 putValue(Action.SHORT_DESCRIPTION, NbBundle.getMessage(SearchHistoryPanel.class, "TT_Search")); // NOI18N
183 public void actionPerformed(ActionEvent e) {
184 search();
187 getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "search"); // NOI18N
188 getActionMap().put("search", searchAction); // NOI18N
189 bSearch.setAction(searchAction);
190 Mnemonics.setLocalizedText(bSearch, NbBundle.getMessage(SearchHistoryPanel.class, "CTL_Search")); // NOI18N
192 Dimension d1 = tbSummary.getPreferredSize();
193 Dimension d2 = tbDiff.getPreferredSize();
194 if (d1.width > d2.width) {
195 tbDiff.setPreferredSize(d1);
198 nextAction = new AbstractAction(null, new javax.swing.ImageIcon(getClass().getResource("/org/nbgit/resources/icons/diff-next.png"))) { // NOI18N
201 putValue(Action.SHORT_DESCRIPTION, java.util.ResourceBundle.getBundle("org/nbgit/ui/diff/Bundle"). // NOI18N
202 getString("CTL_DiffPanel_Next_Tooltip")); // NOI18N
205 public void actionPerformed(ActionEvent e) {
206 diffView.onNextButton();
209 prevAction = new AbstractAction(null, new javax.swing.ImageIcon(getClass().getResource("/org/nbgit/resources/icons/diff-prev.png"))) { // NOI18N
212 putValue(Action.SHORT_DESCRIPTION, java.util.ResourceBundle.getBundle("org/nbgit/ui/diff/Bundle"). // NOI18N
213 getString("CTL_DiffPanel_Prev_Tooltip")); // NOI18N
216 public void actionPerformed(ActionEvent e) {
217 diffView.onPrevButton();
220 bNext.setAction(nextAction);
221 bPrev.setAction(prevAction);
223 criteria.tfFrom.getDocument().addDocumentListener(this);
224 criteria.tfTo.getDocument().addDocumentListener(this);
226 getActionMap().put("jumpNext", nextAction); // NOI18N
227 getActionMap().put("jumpPrev", prevAction); // NOI18N
229 showMergesChkBox.setSelected(GitModuleConfig.getDefault().getShowHistoryMerges());
230 showMergesChkBox.setOpaque(false);
233 public void actionPerformed(ActionEvent e) {
234 if (e.getID() == Divider.DIVIDER_CLICKED) {
235 criteriaVisible = !criteriaVisible;
236 refreshComponents(false);
239 private ExplorerManager explorerManager;
241 public void propertyChange(PropertyChangeEvent evt) {
242 if (ExplorerManager.PROP_SELECTED_NODES.equals(evt.getPropertyName())) {
243 TopComponent tc = (TopComponent) SwingUtilities.getAncestorOfClass(TopComponent.class, this);
244 if (tc == null) {
245 return;
247 tc.setActivatedNodes((Node[]) evt.getNewValue());
251 public void addNotify() {
252 super.addNotify();
253 explorerManager.addPropertyChangeListener(this);
256 public void removeNotify() {
257 explorerManager.removePropertyChangeListener(this);
258 super.removeNotify();
261 public ExplorerManager getExplorerManager() {
262 return explorerManager;
265 final void refreshComponents(boolean refreshResults) {
266 if (refreshResults) {
267 resultsPanel.removeAll();
268 if (results == null) {
269 if (searchInProgress) {
270 resultsPanel.add(new NoContentPanel(NbBundle.getMessage(SearchHistoryPanel.class, "LBL_SearchHistory_Searching"))); // NOI18N
271 } else {
272 resultsPanel.add(new NoContentPanel(NbBundle.getMessage(SearchHistoryPanel.class, "LBL_SearchHistory_NoResults"))); // NOI18N
274 } else {
275 if (tbSummary.isSelected()) {
276 if (summaryView == null) {
277 summaryView = new SummaryView(this, results);
279 resultsPanel.add(summaryView.getComponent());
280 } else {
281 if (diffView == null) {
282 diffView = new DiffResultsView(this, results);
284 resultsPanel.add(diffView.getComponent());
287 resultsPanel.revalidate();
288 resultsPanel.repaint();
290 nextAction.setEnabled(!tbSummary.isSelected() && diffView != null && diffView.isNextEnabled());
291 prevAction.setEnabled(!tbSummary.isSelected() && diffView != null && diffView.isPrevEnabled());
293 divider.setArrowDirection(criteriaVisible ? Divider.UP : Divider.DOWN);
294 searchCriteriaPanel.setVisible(criteriaVisible);
295 bSearch.setVisible(criteriaVisible);
296 revalidate();
297 repaint();
300 public void setResults(List<RepositoryRevision> newResults) {
301 setResults(newResults, false);
304 private void setResults(List<RepositoryRevision> newResults, boolean searching) {
305 this.results = newResults;
306 this.searchInProgress = searching;
307 summaryView = null;
308 diffView = null;
309 refreshComponents(true);
312 public String getRepositoryUrl() {
313 return repositoryUrl;
316 public String getSearchRepositoryRootUrl() {
317 if (repositoryUrl != null) {
318 return repositoryUrl;
320 File root = Git.getInstance().getTopmostManagedParent(roots[0]);
321 return root.toString();
324 public File[] getRoots() {
325 return roots;
328 public SearchCriteriaPanel getCriteria() {
329 return criteria;
332 private synchronized void search() {
333 if (currentSearchTask != null) {
334 currentSearchTask.cancel();
336 setResults(null, true);
337 currentSearch = new SearchExecutor(this);
338 currentSearchTask = RequestProcessor.getDefault().create(currentSearch);
339 currentSearchTask.schedule(0);
342 void executeSearch() {
343 search();
346 void showDiff(RepositoryRevision.Event revision) {
347 tbDiff.setSelected(true);
348 refreshComponents(true);
349 diffView.select(revision);
352 public void showDiff(RepositoryRevision container) {
353 tbDiff.setSelected(true);
354 refreshComponents(true);
355 diffView.select(container);
359 * Return diff setup describing shown history.
360 * It return empty collection on non-atomic
361 * revision ranges. XXX move this logic to clients?
363 public Collection getSetups() {
364 if (results == null) {
365 return Collections.EMPTY_SET;
367 if (tbDiff.isSelected()) {
368 return diffView.getSetups();
369 } else {
370 return summaryView.getSetups();
374 Collection getSetups(RepositoryRevision[] revisions, RepositoryRevision.Event[] events) {
375 long fromRevision = Long.MAX_VALUE;
376 long toRevision = Long.MIN_VALUE;
377 Set<File> filesToDiff = new HashSet<File>();
379 for (RepositoryRevision revision : revisions) {
380 long rev = 0; //Long.parseLong(revision.getLog().getRevision());
381 if (rev > toRevision) {
382 toRevision = rev;
384 if (rev < fromRevision) {
385 fromRevision = rev;
387 List<RepositoryRevision.Event> evs = revision.getEvents();
388 for (RepositoryRevision.Event event : evs) {
389 File file = event.getFile();
390 if (file != null) {
391 filesToDiff.add(file);
396 for (RepositoryRevision.Event event : events) {
397 long rev = 0; //Long.parseLong(event.getLogInfoHeader().getLog().getRevision());
398 if (rev > toRevision) {
399 toRevision = rev;
401 if (rev < fromRevision) {
402 fromRevision = rev;
404 if (event.getFile() != null) {
405 filesToDiff.add(event.getFile());
409 List<Setup> setups = new ArrayList<Setup>();
410 for (File file : filesToDiff) {
411 Setup setup = new Setup(file, Long.toString(fromRevision - 1), Long.toString(toRevision));
412 setups.add(setup);
414 return setups;
417 public String getSetupDisplayName() {
418 return null;
421 public static int compareRevisions(String r1, String r2) {
422 StringTokenizer st1 = new StringTokenizer(r1, "."); // NOI18N
423 StringTokenizer st2 = new StringTokenizer(r2, "."); // NOI18N
424 for (;;) {
425 if (!st1.hasMoreTokens()) {
426 return st2.hasMoreTokens() ? -1 : 0;
428 if (!st2.hasMoreTokens()) {
429 return st1.hasMoreTokens() ? 1 : 0;
431 int n1 = Integer.parseInt(st1.nextToken());
432 int n2 = Integer.parseInt(st2.nextToken());
433 if (n1 != n2) {
434 return n2 - n1;
439 /** This method is called from within the constructor to
440 * initialize the form.
441 * WARNING: Do NOT modify this code. The content of this method is
442 * always regenerated by the Form Editor.
444 // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
445 private void initComponents() {
446 java.awt.GridBagConstraints gridBagConstraints;
448 buttonGroup1 = new javax.swing.ButtonGroup();
449 searchCriteriaPanel = new javax.swing.JPanel();
450 bSearch = new javax.swing.JButton();
451 jPanel1 = new javax.swing.JPanel();
452 jToolBar1 = new javax.swing.JToolBar();
453 tbSummary = new javax.swing.JToggleButton();
454 tbDiff = new javax.swing.JToggleButton();
455 jSeparator2 = new javax.swing.JSeparator();
456 bNext = new javax.swing.JButton();
457 bPrev = new javax.swing.JButton();
458 jSeparator3 = new javax.swing.JToolBar.Separator();
459 showMergesChkBox = new javax.swing.JCheckBox();
460 resultsPanel = new javax.swing.JPanel();
462 setBorder(javax.swing.BorderFactory.createEmptyBorder(8, 8, 0, 8));
463 setLayout(new java.awt.GridBagLayout());
465 searchCriteriaPanel.setLayout(new java.awt.BorderLayout());
466 gridBagConstraints = new java.awt.GridBagConstraints();
467 gridBagConstraints.gridx = 0;
468 gridBagConstraints.gridy = 0;
469 gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
470 gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
471 gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START;
472 gridBagConstraints.weightx = 1.0;
473 add(searchCriteriaPanel, gridBagConstraints);
475 java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("org/nbgit/ui/log/Bundle"); // NOI18N
476 bSearch.setToolTipText(bundle.getString("TT_Search")); // NOI18N
477 gridBagConstraints = new java.awt.GridBagConstraints();
478 gridBagConstraints.gridx = 0;
479 gridBagConstraints.gridy = 1;
480 gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START;
481 add(bSearch, gridBagConstraints);
483 jPanel1.setPreferredSize(new java.awt.Dimension(10, 6));
484 gridBagConstraints = new java.awt.GridBagConstraints();
485 gridBagConstraints.gridy = 2;
486 gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
487 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
488 gridBagConstraints.weightx = 1.0;
489 gridBagConstraints.insets = new java.awt.Insets(0, 0, 2, 0);
490 add(jPanel1, gridBagConstraints);
492 jToolBar1.setFloatable(false);
493 jToolBar1.setRollover(true);
495 buttonGroup1.add(tbSummary);
496 tbSummary.setSelected(true);
497 org.openide.awt.Mnemonics.setLocalizedText(tbSummary, bundle.getString("CTL_ShowSummary")); // NOI18N
498 tbSummary.setToolTipText(bundle.getString("TT_Summary")); // NOI18N
499 tbSummary.addActionListener(new java.awt.event.ActionListener() {
500 public void actionPerformed(java.awt.event.ActionEvent evt) {
501 onViewToggle(evt);
504 jToolBar1.add(tbSummary);
505 tbSummary.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(SearchHistoryPanel.class, "CTL_ShowSummary")); // NOI18N
507 buttonGroup1.add(tbDiff);
508 org.openide.awt.Mnemonics.setLocalizedText(tbDiff, bundle.getString("CTL_ShowDiff")); // NOI18N
509 tbDiff.setToolTipText(bundle.getString("TT_ShowDiff")); // NOI18N
510 tbDiff.addActionListener(new java.awt.event.ActionListener() {
511 public void actionPerformed(java.awt.event.ActionEvent evt) {
512 onViewToggle(evt);
515 jToolBar1.add(tbDiff);
517 jSeparator2.setOrientation(javax.swing.SwingConstants.VERTICAL);
518 jSeparator2.setMaximumSize(new java.awt.Dimension(2, 32767));
519 jToolBar1.add(jSeparator2);
520 jToolBar1.add(bNext);
521 bNext.getAccessibleContext().setAccessibleName("null");
522 bNext.getAccessibleContext().setAccessibleDescription("null");
524 jToolBar1.add(bPrev);
525 bPrev.getAccessibleContext().setAccessibleName("null");
526 bPrev.getAccessibleContext().setAccessibleDescription("null");
528 jToolBar1.add(jSeparator3);
530 showMergesChkBox.setSelected(true);
531 org.openide.awt.Mnemonics.setLocalizedText(showMergesChkBox, org.openide.util.NbBundle.getMessage(SearchHistoryPanel.class, "CTL_ShowMerge")); // NOI18N
532 showMergesChkBox.setToolTipText(org.openide.util.NbBundle.getMessage(SearchHistoryPanel.class, "TT_ShowMerges")); // NOI18N
533 showMergesChkBox.setFocusable(false);
534 showMergesChkBox.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT);
535 showMergesChkBox.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
536 showMergesChkBox.addChangeListener(new javax.swing.event.ChangeListener() {
537 public void stateChanged(javax.swing.event.ChangeEvent evt) {
538 showMergesChkBoxStateChanged(evt);
541 jToolBar1.add(showMergesChkBox);
543 gridBagConstraints = new java.awt.GridBagConstraints();
544 gridBagConstraints.gridy = 3;
545 gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
546 gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
547 add(jToolBar1, gridBagConstraints);
549 resultsPanel.setLayout(new java.awt.BorderLayout());
550 gridBagConstraints = new java.awt.GridBagConstraints();
551 gridBagConstraints.gridx = 0;
552 gridBagConstraints.gridy = 4;
553 gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER;
554 gridBagConstraints.gridheight = java.awt.GridBagConstraints.REMAINDER;
555 gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
556 gridBagConstraints.weightx = 1.0;
557 gridBagConstraints.weighty = 1.0;
558 gridBagConstraints.insets = new java.awt.Insets(8, 0, 8, 0);
559 add(resultsPanel, gridBagConstraints);
560 }// </editor-fold>//GEN-END:initComponents
562 private void onViewToggle(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_onViewToggle
563 refreshComponents(true);
564 }//GEN-LAST:event_onViewToggle
566 private void showMergesChkBoxStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_showMergesChkBoxStateChanged
567 GitModuleConfig.getDefault().setShowHistoryMerges(showMergesChkBox.isSelected());
568 }//GEN-LAST:event_showMergesChkBoxStateChanged
570 public void insertUpdate(DocumentEvent e) {
571 validateUserInput();
574 public void removeUpdate(DocumentEvent e) {
575 validateUserInput();
578 public void changedUpdate(DocumentEvent e) {
579 validateUserInput();
582 private void validateUserInput() {
583 String from = criteria.getFrom();
584 if(from == null && criteria.tfFrom.getText().trim().length() > 0) {
585 bSearch.setEnabled(false);
586 return;
588 String to = criteria.getTo();
589 if(to == null && criteria.tfTo.getText().trim().length() > 0) {
590 bSearch.setEnabled(false);
591 return;
593 bSearch.setEnabled(true);
596 // Variables declaration - do not modify//GEN-BEGIN:variables
597 private javax.swing.JButton bNext;
598 private javax.swing.JButton bPrev;
599 private javax.swing.JButton bSearch;
600 private javax.swing.ButtonGroup buttonGroup1;
601 private javax.swing.JPanel jPanel1;
602 private javax.swing.JSeparator jSeparator2;
603 private javax.swing.JToolBar.Separator jSeparator3;
604 private javax.swing.JToolBar jToolBar1;
605 private javax.swing.JPanel resultsPanel;
606 private javax.swing.JPanel searchCriteriaPanel;
607 private javax.swing.JCheckBox showMergesChkBox;
608 private javax.swing.JToggleButton tbDiff;
609 private javax.swing.JToggleButton tbSummary;
610 // End of variables declaration//GEN-END:variables