Cleanup code whitespace
[nbgit.git] / src / org / nbgit / ui / log / SummaryView.java
blobf923a4cf628800e5f0aa803aa23cba462f738276
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.BorderLayout;
45 import java.awt.Color;
46 import java.awt.Component;
47 import java.awt.Cursor;
48 import java.awt.Dimension;
49 import java.awt.FlowLayout;
50 import java.awt.FontMetrics;
51 import java.awt.Graphics;
52 import java.awt.Point;
53 import java.awt.Rectangle;
54 import java.awt.event.ActionEvent;
55 import java.awt.event.ComponentEvent;
56 import java.awt.event.ComponentListener;
57 import java.awt.event.KeyEvent;
58 import java.awt.event.MouseEvent;
59 import java.awt.event.MouseListener;
60 import java.awt.event.MouseMotionListener;
61 import java.awt.geom.Rectangle2D;
62 import java.io.File;
63 import java.io.IOException;
64 import java.text.DateFormat;
65 import java.util.ArrayList;
66 import java.util.Collection;
67 import java.util.HashMap;
68 import java.util.HashSet;
69 import java.util.List;
70 import java.util.Map;
71 import java.util.Set;
72 import javax.swing.AbstractAction;
73 import javax.swing.AbstractListModel;
74 import javax.swing.BorderFactory;
75 import javax.swing.JComponent;
76 import javax.swing.JLabel;
77 import javax.swing.JList;
78 import javax.swing.JMenuItem;
79 import javax.swing.JPanel;
80 import javax.swing.JPopupMenu;
81 import javax.swing.JScrollPane;
82 import javax.swing.JTextPane;
83 import javax.swing.KeyStroke;
84 import javax.swing.ListCellRenderer;
85 import javax.swing.UIManager;
86 import javax.swing.text.AttributeSet;
87 import javax.swing.text.BadLocationException;
88 import javax.swing.text.Style;
89 import javax.swing.text.StyleConstants;
90 import javax.swing.text.StyledDocument;
91 import org.nbgit.Git;
92 import org.nbgit.GitModuleConfig;
93 import org.nbgit.GitProgressSupport;
94 import org.nbgit.ui.diff.DiffSetupSource;
95 import org.nbgit.ui.update.RevertModificationsAction;
96 import org.nbgit.util.GitUtils;
97 import org.netbeans.api.editor.mimelookup.MimeLookup;
98 import org.netbeans.api.editor.mimelookup.MimePath;
99 import org.netbeans.api.editor.settings.FontColorSettings;
100 import org.openide.ErrorManager;
101 import org.openide.filesystems.FileObject;
102 import org.openide.filesystems.FileUtil;
103 import org.openide.nodes.Node;
104 import org.openide.util.NbBundle;
105 import org.openide.util.RequestProcessor;
106 import org.openide.windows.TopComponent;
109 * Shows Search History results in a JList.
111 * @author Maros Sandor
113 class SummaryView implements MouseListener, ComponentListener, MouseMotionListener, DiffSetupSource {
115 private static final String SUMMARY_DIFF_PROPERTY = "Summary-Diff-";
116 private static final String SUMMARY_REVERT_PROPERTY = "Summary-Revert-";
117 private static final String SUMMARY_EXPORTDIFFS_PROPERTY = "Summary-ExportDiffs-";
118 private final SearchHistoryPanel master;
119 private JList resultsList;
120 private JScrollPane scrollPane;
121 private final List dispResults;
122 private String message;
123 private AttributeSet searchHiliteAttrs;
124 private List<RepositoryRevision> results;
126 public SummaryView(SearchHistoryPanel master, List<RepositoryRevision> results)
128 this.master = master;
129 this.results = results;
130 this.dispResults = expandResults(results);
131 FontColorSettings fcs = MimeLookup.getLookup(MimePath.get("text/x-java")).lookup(FontColorSettings.class); // NOI18N
132 searchHiliteAttrs = fcs.getFontColors("highlight-search"); // NOI18N
133 message = master.getCriteria().getCommitMessage();
134 resultsList = new JList(new SummaryListModel());
135 resultsList.setFixedCellHeight(-1);
136 resultsList.addMouseListener(this);
137 resultsList.addMouseMotionListener(this);
138 resultsList.setCellRenderer(new SummaryCellRenderer());
139 resultsList.getAccessibleContext().setAccessibleName(NbBundle.getMessage(SummaryView.class, "ACSN_SummaryView_List")); // NOI18N
140 resultsList.getAccessibleContext().setAccessibleDescription(NbBundle.getMessage(SummaryView.class, "ACSD_SummaryView_List")); // NOI18N
141 scrollPane = new JScrollPane(resultsList, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
142 master.addComponentListener(this);
143 resultsList.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
144 KeyStroke.getKeyStroke(KeyEvent.VK_F10, KeyEvent.SHIFT_DOWN_MASK), "org.openide.actions.PopupAction");
145 resultsList.getActionMap().put("org.openide.actions.PopupAction", new AbstractAction() {
147 public void actionPerformed(ActionEvent e)
149 onPopup(org.netbeans.modules.versioning.util.Utils.getPositionForPopup(resultsList));
155 public void componentResized(ComponentEvent e)
157 int[] selection = resultsList.getSelectedIndices();
158 resultsList.setModel(new SummaryListModel());
159 resultsList.setSelectedIndices(selection);
162 public void componentHidden(ComponentEvent e)
164 // not interested
167 public void componentMoved(ComponentEvent e)
169 // not interested
172 public void componentShown(ComponentEvent e)
174 // not interested
177 @SuppressWarnings("unchecked")
178 private List expandResults(List<RepositoryRevision> results)
180 ArrayList newResults = new ArrayList(results.size());
181 for (RepositoryRevision repositoryRevision : results) {
182 newResults.add(repositoryRevision);
183 List<RepositoryRevision.Event> events = repositoryRevision.getEvents();
184 for (RepositoryRevision.Event event : events) {
185 newResults.add(event);
188 return newResults;
191 public void mouseClicked(MouseEvent e)
193 int idx = resultsList.locationToIndex(e.getPoint());
194 if (idx == -1)
195 return;
196 Rectangle rect = resultsList.getCellBounds(idx, idx);
197 Point p = new Point(e.getX() - rect.x, e.getY() - rect.y);
198 Rectangle diffBounds = (Rectangle) resultsList.getClientProperty(SUMMARY_DIFF_PROPERTY + idx); // NOI18N
199 if (diffBounds != null && diffBounds.contains(p))
200 diffPrevious(idx);
201 diffBounds = (Rectangle) resultsList.getClientProperty(SUMMARY_REVERT_PROPERTY + idx); // NOI18N
202 if (diffBounds != null && diffBounds.contains(p))
203 revertModifications(new int[]{idx});
206 public void mouseEntered(MouseEvent e)
208 // not interested
211 public void mouseExited(MouseEvent e)
213 // not interested
216 public void mousePressed(MouseEvent e)
218 if (!master.isIncomingSearch() && e.isPopupTrigger())
219 onPopup(e);
222 public void mouseReleased(MouseEvent e)
224 if (!master.isIncomingSearch() && e.isPopupTrigger())
225 onPopup(e);
228 public void mouseDragged(MouseEvent e)
232 public void mouseMoved(MouseEvent e)
234 int idx = resultsList.locationToIndex(e.getPoint());
235 if (idx == -1)
236 return;
237 Rectangle rect = resultsList.getCellBounds(idx, idx);
238 Point p = new Point(e.getX() - rect.x, e.getY() - rect.y);
239 Rectangle diffBounds = (Rectangle) resultsList.getClientProperty(SUMMARY_DIFF_PROPERTY + idx); // NOI18N
240 if (diffBounds != null && diffBounds.contains(p)) {
241 resultsList.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
242 return;
244 diffBounds = (Rectangle) resultsList.getClientProperty(SUMMARY_REVERT_PROPERTY + idx); // NOI18N
245 if (diffBounds != null && diffBounds.contains(p)) {
246 resultsList.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
247 return;
249 diffBounds = (Rectangle) resultsList.getClientProperty(SUMMARY_EXPORTDIFFS_PROPERTY + idx); // NOI18N
250 if (diffBounds != null && diffBounds.contains(p)) {
251 resultsList.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
252 return;
254 resultsList.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
257 public Collection getSetups()
259 Node[] nodes = TopComponent.getRegistry().getActivatedNodes();
260 if (nodes.length == 0)
261 return master.getSetups(results.toArray(new RepositoryRevision[results.size()]), new RepositoryRevision.Event[0]);
263 Set<RepositoryRevision.Event> events = new HashSet<RepositoryRevision.Event>();
264 Set<RepositoryRevision> revisions = new HashSet<RepositoryRevision>();
266 int[] sel = resultsList.getSelectedIndices();
267 for (int i : sel) {
268 Object revCon = dispResults.get(i);
269 if (revCon instanceof RepositoryRevision)
270 revisions.add((RepositoryRevision) revCon);
271 else
272 events.add((RepositoryRevision.Event) revCon);
274 return master.getSetups(revisions.toArray(new RepositoryRevision[revisions.size()]), events.toArray(new RepositoryRevision.Event[events.size()]));
277 public String getSetupDisplayName()
279 return null;
282 private void onPopup(MouseEvent e)
284 onPopup(e.getPoint());
287 private void onPopup(Point p)
289 int[] sel = resultsList.getSelectedIndices();
290 if (sel.length == 0) {
291 int idx = resultsList.locationToIndex(p);
292 if (idx == -1)
293 return;
294 resultsList.setSelectedIndex(idx);
295 sel = new int[]{idx};
297 final int[] selection = sel;
299 JPopupMenu menu = new JPopupMenu();
301 String previousRevision = null;
302 RepositoryRevision container = null;
303 final RepositoryRevision.Event[] drev;
305 Object revCon = dispResults.get(selection[0]);
308 boolean noExDeletedExistingFiles = true;
309 boolean revisionSelected;
310 boolean missingFile = false;
311 boolean oneRevisionMultiselected = true;
313 if (revCon instanceof RepositoryRevision) {
314 revisionSelected = true;
315 container = (RepositoryRevision) dispResults.get(selection[0]);
316 drev = new RepositoryRevision.Event[0];
317 oneRevisionMultiselected = true;
318 noExDeletedExistingFiles = true;
319 } else {
320 revisionSelected = false;
321 drev = new RepositoryRevision.Event[selection.length];
323 for (int i = 0; i < selection.length; i++) {
324 drev[i] = (RepositoryRevision.Event) dispResults.get(selection[i]);
326 if (!missingFile && drev[i].getFile() == null)
327 missingFile = true;
328 if (oneRevisionMultiselected && i > 0 &&
329 drev[0].getLogInfoHeader().getRevision().equals(drev[i].getLogInfoHeader().getRevision()))
330 oneRevisionMultiselected = false;
331 if (drev[i].getFile() != null && drev[i].getFile().exists() && drev[i].getChangedPath().getAction() == 'D')
332 noExDeletedExistingFiles = false;
334 container = drev[0].getLogInfoHeader();
336 long revision = 0; //Long.parseLong(container.getLog().getRevision());
338 final boolean rollbackToEnabled = !missingFile && !revisionSelected && oneRevisionMultiselected;
339 final boolean rollbackChangeEnabled = !missingFile && oneRevisionMultiselected && (drev.length == 0 || noExDeletedExistingFiles); // drev.length == 0 => the whole revision was selected
340 final boolean viewEnabled = selection.length == 1 && !revisionSelected && drev[0].getFile() != null && drev[0].getFile().exists() && !drev[0].getFile().isDirectory();
341 final boolean diffToPrevEnabled = selection.length == 1;
343 if (revision > 0)
344 menu.add(new JMenuItem(new AbstractAction(NbBundle.getMessage(SummaryView.class, "CTL_SummaryView_DiffToPrevious", "" + previousRevision)) { // NOI18N
347 setEnabled(diffToPrevEnabled);
350 public void actionPerformed(ActionEvent e)
352 diffPrevious(selection[0]);
355 }));
357 /* TBD - Support Rollback Changes:
358 * Need to figure out how to implement SVN functionality to allow you to rollback a change
359 * currently for svn this cmd runs: merge -R <revX>:<revY> it basically diffs the two revs
360 * and creates a patch which is then applied ot the file in the working dir, effectively removing
361 * the change applied between revX and revY
362 * In hg we'd need to do a hg diff -r revX -r revY, generate a patch and then apply it to the working dir copy
364 menu.add(new JMenuItem(new AbstractAction(NbBundle.getMessage(SummaryView.class, "CTL_SummaryView_RollbackChange")) { // NOI18N
366 setEnabled(false); // rollbackChangeEnabled);
368 public void actionPerformed(ActionEvent e) {
369 revertModifications(selection);
371 }));
373 if (!revisionSelected) {
374 menu.add(new JMenuItem(new AbstractAction(NbBundle.getMessage(SummaryView.class, "CTL_SummaryView_RollbackTo", "" + revision)) { // NOI18N
377 setEnabled(rollbackToEnabled);
380 public void actionPerformed(ActionEvent e)
382 revertModifications(selection);
385 /*public void actionPerformed(ActionEvent e) {
386 RequestProcessor.getDefault().post(new Runnable() {
387 public void run() {
388 rollback(drev);
392 }));
393 menu.add(new JMenuItem(new AbstractAction(NbBundle.getMessage(SummaryView.class, "CTL_SummaryView_View")) { // NOI18N
396 setEnabled(viewEnabled);
399 public void actionPerformed(ActionEvent e)
401 RequestProcessor.getDefault().post(new Runnable() {
403 public void run()
405 view(selection[0]);
411 }));
414 menu.show(resultsList, p.x, p.y);
418 * Overwrites local file with this revision.
420 * @param event
422 static void rollback(RepositoryRevision.Event event)
424 rollback(new RepositoryRevision.Event[]{event});
428 * Overwrites local file with this revision.
430 * @param event
432 static void rollback(final RepositoryRevision.Event[] events)
434 String repository = events[0].getLogInfoHeader().getRepositoryRootUrl();
435 RequestProcessor rp = Git.getInstance().getRequestProcessor(repository);
436 GitProgressSupport support = new GitProgressSupport() {
438 public void perform()
440 for (RepositoryRevision.Event event : events) {
441 rollback(event, this);
446 support.start(rp, repository, NbBundle.getMessage(SummaryView.class, "MSG_Rollback_Progress")); // NOI18N
450 private static void rollback(RepositoryRevision.Event event, GitProgressSupport progress)
452 File file = event.getFile();
453 File parent = file.getParentFile();
454 parent.mkdirs();
455 try {
456 File oldFile = GitUtils.getFileRevision(event.getFile(), event.getLogInfoHeader().getRevision());
457 file.delete();
458 FileUtil.copyFile(FileUtil.toFileObject(oldFile), FileUtil.toFileObject(parent), file.getName(), "");
459 } catch (IOException e) {
460 ErrorManager.getDefault().notify(e);
464 private void revertModifications(int[] selection)
466 Set<RepositoryRevision.Event> events = new HashSet<RepositoryRevision.Event>();
467 Set<RepositoryRevision> revisions = new HashSet<RepositoryRevision>();
468 for (int idx : selection) {
469 Object o = dispResults.get(idx);
470 if (o instanceof RepositoryRevision)
471 revisions.add((RepositoryRevision) o);
472 else
473 events.add((RepositoryRevision.Event) o);
475 revert(master, revisions.toArray(new RepositoryRevision[revisions.size()]), events.toArray(new RepositoryRevision.Event[events.size()]));
478 static void revert(final SearchHistoryPanel master, final RepositoryRevision[] revisions, final RepositoryRevision.Event[] events)
480 String url = master.getSearchRepositoryRootUrl();
481 RequestProcessor rp = Git.getInstance().getRequestProcessor(url);
482 GitProgressSupport support = new GitProgressSupport() {
484 public void perform()
486 revertImpl(master, revisions, events, this);
490 support.start(rp, url, NbBundle.getMessage(SummaryView.class, "MSG_Revert_Progress")); // NOI18N
493 private static void revertImpl(SearchHistoryPanel master, RepositoryRevision[] revisions, RepositoryRevision.Event[] events, GitProgressSupport progress)
495 List<File> revertFiles = new ArrayList<File>();
496 boolean doBackup = GitModuleConfig.getDefault().getBackupOnRevertModifications();
497 for (RepositoryRevision revision : revisions) {
498 File root = new File(revision.getRepositoryRootUrl());
499 for (RepositoryRevision.Event event : revision.getEvents()) {
500 if (event.getFile() == null)
501 continue;
502 revertFiles.add(event.getFile());
504 RevertModificationsAction.performRevert(
505 root, revision.getRevision(), revertFiles, doBackup, progress.getLogger());
507 revertFiles.clear();
510 Map<File, List<RepositoryRevision.Event>> revertMap = new HashMap<File, List<RepositoryRevision.Event>>();
511 for (RepositoryRevision.Event event : events) {
512 if (event.getFile() == null)
513 continue;
515 File root = Git.getInstance().getTopmostManagedParent(event.getFile());
516 if (revertMap == null)
517 revertMap = new HashMap<File, List<RepositoryRevision.Event>>();
518 List<RepositoryRevision.Event> revEvents = revertMap.get(root);
519 if (revEvents == null) {
520 revEvents = new ArrayList<RepositoryRevision.Event>();
521 revertMap.put(root, revEvents);
523 revEvents.add(event);
525 if (events != null && events.length > 0 && revertMap != null && !revertMap.isEmpty()) {
526 Set<File> roots = revertMap.keySet();
527 for (File root : roots) {
528 List<RepositoryRevision.Event> revEvents = revertMap.get(root);
529 for (RepositoryRevision.Event event : revEvents) {
530 if (event.getFile() == null)
531 continue;
532 revertFiles.add(event.getFile());
534 if (revEvents != null && !revEvents.isEmpty()) {
535 // Assuming all files in a given repository reverting to same revision
537 RevertModificationsAction.performRevert(
538 root, revEvents.get(0).getLogInfoHeader().getLog().getRevision(), revertFiles, doBackup, progress.getLogger());
546 private void view(int idx)
548 Object o = dispResults.get(idx);
549 if (o instanceof RepositoryRevision.Event)
550 try {
551 RepositoryRevision.Event drev = (RepositoryRevision.Event) o;
552 File file = GitUtils.getFileRevision(drev.getFile(), drev.getLogInfoHeader().getRevision());
554 FileObject fo = FileUtil.toFileObject(FileUtil.normalizeFile(file));
555 org.netbeans.modules.versioning.util.Utils.openFile(fo, drev.getLogInfoHeader().getRevision());
556 } catch (IOException ex) {
557 // Ignore if file not available in cache
561 private void diffPrevious(int idx)
563 Object o = dispResults.get(idx);
564 if (o instanceof RepositoryRevision.Event) {
565 RepositoryRevision.Event drev = (RepositoryRevision.Event) o;
566 master.showDiff(drev);
567 } else {
568 RepositoryRevision container = (RepositoryRevision) o;
569 master.showDiff(container);
573 public JComponent getComponent()
575 return scrollPane;
578 private class SummaryListModel extends AbstractListModel {
580 public int getSize()
582 return dispResults.size();
585 public Object getElementAt(int index)
587 return dispResults.get(index);
592 private class SummaryCellRenderer extends JPanel implements ListCellRenderer {
594 private static final String FIELDS_SEPARATOR = " "; // NOI18N
595 private static final double DARKEN_FACTOR = 0.95;
596 private Style selectedStyle;
597 private Style normalStyle;
598 private Style filenameStyle;
599 private Style indentStyle;
600 private Style noindentStyle;
601 private Style hiliteStyle;
602 private JTextPane textPane = new JTextPane();
603 private JPanel actionsPane = new JPanel();
604 private DateFormat defaultFormat;
605 private int index;
606 private HyperlinkLabel diffLink;
607 private HyperlinkLabel revertLink;
609 public SummaryCellRenderer()
611 selectedStyle = textPane.addStyle("selected", null); // NOI18N
612 StyleConstants.setForeground(selectedStyle, UIManager.getColor("List.selectionForeground")); // NOI18N
613 normalStyle = textPane.addStyle("normal", null); // NOI18N
614 StyleConstants.setForeground(normalStyle, UIManager.getColor("List.foreground")); // NOI18N
615 filenameStyle = textPane.addStyle("filename", normalStyle); // NOI18N
616 StyleConstants.setBold(filenameStyle, true);
617 indentStyle = textPane.addStyle("indent", null); // NOI18N
618 StyleConstants.setLeftIndent(indentStyle, 50);
619 noindentStyle = textPane.addStyle("noindent", null); // NOI18N
620 StyleConstants.setLeftIndent(noindentStyle, 0);
621 defaultFormat = DateFormat.getDateTimeInstance();
623 hiliteStyle = textPane.addStyle("hilite", normalStyle); // NOI18N
624 Color c = (Color) searchHiliteAttrs.getAttribute(StyleConstants.Background);
625 if (c != null)
626 StyleConstants.setBackground(hiliteStyle, c);
627 c = (Color) searchHiliteAttrs.getAttribute(StyleConstants.Foreground);
628 if (c != null)
629 StyleConstants.setForeground(hiliteStyle, c);
631 setLayout(new BorderLayout());
632 add(textPane);
633 add(actionsPane, BorderLayout.PAGE_END);
634 actionsPane.setLayout(new FlowLayout(FlowLayout.TRAILING, 2, 5));
636 diffLink = new HyperlinkLabel();
637 diffLink.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 8));
638 actionsPane.add(diffLink);
640 revertLink = new HyperlinkLabel();
641 revertLink.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 8));
642 //actionsPane.add(revertLink);
644 textPane.setBorder(null);
647 public Color darker(Color c)
649 return new Color(Math.max((int) (c.getRed() * DARKEN_FACTOR), 0),
650 Math.max((int) (c.getGreen() * DARKEN_FACTOR), 0),
651 Math.max((int) (c.getBlue() * DARKEN_FACTOR), 0));
654 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)
656 if (value instanceof RepositoryRevision)
657 renderContainer(list, (RepositoryRevision) value, index, isSelected);
658 else
659 renderRevision(list, (RepositoryRevision.Event) value, index, isSelected);
660 return this;
663 private void renderContainer(JList list, RepositoryRevision container, int index, boolean isSelected)
666 StyledDocument sd = textPane.getStyledDocument();
668 Style style;
669 Color backgroundColor;
670 Color foregroundColor;
672 if (isSelected) {
673 foregroundColor = UIManager.getColor("List.selectionForeground"); // NOI18N
674 backgroundColor = UIManager.getColor("List.selectionBackground"); // NOI18N
675 style = selectedStyle;
676 } else {
677 foregroundColor = UIManager.getColor("List.foreground"); // NOI18N
678 backgroundColor = UIManager.getColor("List.background"); // NOI18N
679 backgroundColor = darker(backgroundColor);
680 style = normalStyle;
682 textPane.setBackground(backgroundColor);
683 actionsPane.setBackground(backgroundColor);
685 this.index = index;
687 try {
688 sd.remove(0, sd.getLength());
689 sd.setParagraphAttributes(0, sd.getLength(), noindentStyle, false);
691 sd.insertString(0, container.getRevision(), null); // NOI18N
692 sd.setCharacterAttributes(0, sd.getLength(), filenameStyle, false);
693 sd.insertString(sd.getLength(), FIELDS_SEPARATOR + container.getAuthor(), null);
694 sd.insertString(sd.getLength(), FIELDS_SEPARATOR + defaultFormat.format(container.getDate()), null);
696 String commitMessage = container.getMessage();
697 if (commitMessage.endsWith("\n"))
698 commitMessage = commitMessage.substring(0, commitMessage.length() - 1); // NOI18N
699 sd.insertString(sd.getLength(), "\n", null);
701 sd.insertString(sd.getLength(), commitMessage, null);
703 if (message != null && !isSelected) {
704 int idx = commitMessage.indexOf(message);
705 if (idx != -1) {
706 int len = commitMessage.length();
707 int doclen = sd.getLength();
708 sd.setCharacterAttributes(doclen - len + idx, message.length(), hiliteStyle, false);
712 resizePane(commitMessage, list.getFontMetrics(list.getFont()));
713 sd.setCharacterAttributes(0, Integer.MAX_VALUE, style, false);
714 } catch (BadLocationException e) {
715 ErrorManager.getDefault().notify(e);
718 actionsPane.setVisible(true);
719 if (!master.isIncomingSearch()) {
720 diffLink.set(NbBundle.getMessage(SummaryView.class, "CTL_Action_Diff"), foregroundColor, backgroundColor);// NOI18N
721 revertLink.set(NbBundle.getMessage(SummaryView.class, "CTL_Action_Revert"), foregroundColor, backgroundColor); // NOI18N
725 private void renderRevision(JList list, RepositoryRevision.Event dispRevision, final int index, boolean isSelected)
727 Style style;
728 StyledDocument sd = textPane.getStyledDocument();
730 Color backgroundColor;
731 Color foregroundColor;
733 if (isSelected) {
734 foregroundColor = UIManager.getColor("List.selectionForeground"); // NOI18N
735 backgroundColor = UIManager.getColor("List.selectionBackground"); // NOI18N
736 style = selectedStyle;
737 } else {
738 foregroundColor = UIManager.getColor("List.foreground"); // NOI18N
739 backgroundColor = UIManager.getColor("List.background"); // NOI18N
740 style = normalStyle;
742 textPane.setBackground(backgroundColor);
743 actionsPane.setVisible(false);
745 this.index = -1;
746 try {
747 sd.remove(0, sd.getLength());
748 sd.setParagraphAttributes(0, sd.getLength(), indentStyle, false);
750 sd.insertString(sd.getLength(), String.valueOf(dispRevision.getChangedPath().getAction()), null);
751 sd.insertString(sd.getLength(), FIELDS_SEPARATOR + dispRevision.getChangedPath().getPath(), null);
753 sd.setCharacterAttributes(0, Integer.MAX_VALUE, style, false);
754 resizePane(sd.getText(0, sd.getLength() - 1), list.getFontMetrics(list.getFont()));
755 } catch (BadLocationException e) {
756 ErrorManager.getDefault().notify(e);
760 @SuppressWarnings("empty-statement")
761 private void resizePane(String text, FontMetrics fm)
763 if (text == null)
764 text = "";
765 int width = master.getWidth();
766 if (width > 0) {
767 Rectangle2D rect = fm.getStringBounds(text, textPane.getGraphics());
768 int nlc, i;
769 for (nlc = -1 , i = 0; i != -1; i = text.indexOf('\n', i + 1), nlc++);
770 nlc++;
771 int lines = (int) (rect.getWidth() / (width - 80) + 1);
772 int ph = fm.getHeight() * (lines + nlc) + 0;
773 textPane.setPreferredSize(new Dimension(width - 50, ph));
777 @Override
778 protected void paintComponent(Graphics g)
780 super.paintComponent(g);
781 if (index == -1)
782 return;
783 Rectangle apb = actionsPane.getBounds();
786 Rectangle bounds = diffLink.getBounds();
787 bounds.setBounds(bounds.x, bounds.y + apb.y, bounds.width, bounds.height);
788 resultsList.putClientProperty(SUMMARY_DIFF_PROPERTY + index, bounds); // NOI18N
791 Rectangle bounds = revertLink.getBounds();
792 bounds.setBounds(bounds.x, bounds.y + apb.y, bounds.width, bounds.height);
793 resultsList.putClientProperty(SUMMARY_REVERT_PROPERTY + index, bounds); // NOI18N
798 private static class HyperlinkLabel extends JLabel {
800 public HyperlinkLabel()
802 setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
805 public void set(String text, Color foreground, Color background)
807 StringBuilder sb = new StringBuilder(100);
808 if (foreground.equals(UIManager.getColor("List.foreground"))) { // NOI18N
809 sb.append("<html><a href=\"\">"); // NOI18N
810 sb.append(text);
811 sb.append("</a>"); // NOI18N
812 } else {
813 sb.append("<html><a href=\"\" style=\"color:"); // NOI18N
814 sb.append("rgb("); // NOI18N
815 sb.append(foreground.getRed());
816 sb.append(","); // NOI18N
817 sb.append(foreground.getGreen());
818 sb.append(","); // NOI18N
819 sb.append(foreground.getBlue());
820 sb.append(")"); // NOI18N
821 sb.append("\">"); // NOI18N
822 sb.append(text);
823 sb.append("</a>"); // NOI18N
825 setText(sb.toString());
826 setBackground(background);