This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 218850
Collapse All | Expand All

(-)a/versioning.util/src/org/netbeans/modules/versioning/history/RevisionItemCell.java (+141 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2012 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2012 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.modules.versioning.history;
43
44
import java.awt.BorderLayout;
45
import java.awt.Color;
46
import java.awt.Container;
47
import java.awt.Rectangle;
48
import javax.swing.BorderFactory;
49
import javax.swing.JPanel;
50
import javax.swing.JTextPane;
51
import org.netbeans.modules.versioning.util.VCSHyperlinkSupport;
52
53
/**
54
 * Composite panel for displaying revision, author, commit message and other
55
 * info.
56
 */
57
public class RevisionItemCell extends JPanel implements VCSHyperlinkSupport.BoundsTranslator {
58
    private JTextPane authorControl=new JTextPane();
59
    private JTextPane dateControl=new JTextPane();
60
    private JTextPane revisionControl=new JTextPane();
61
    private JTextPane commitMessageControl=new JTextPane();
62
    private JPanel northPanel=new JPanel();
63
    private JPanel authorDatePanel=new JPanel();
64
65
    public RevisionItemCell () {
66
        this.setBorder(null);
67
        this.setLayout(new BorderLayout(0, 0));
68
        this.add(commitMessageControl, java.awt.BorderLayout.CENTER);
69
        this.add(northPanel, java.awt.BorderLayout.NORTH);
70
        northPanel.setBorder(BorderFactory.createEmptyBorder());
71
        northPanel.setLayout(new BorderLayout(5, 0));
72
        northPanel.add(authorDatePanel, java.awt.BorderLayout.EAST);
73
        northPanel.add(revisionControl, java.awt.BorderLayout.CENTER);
74
        authorDatePanel.setLayout(new BorderLayout(5, 0));
75
        authorDatePanel.setBorder(BorderFactory.createEmptyBorder());
76
        authorDatePanel.add(authorControl, BorderLayout.CENTER);
77
        authorDatePanel.add(dateControl, BorderLayout.EAST);
78
79
        //
80
        initTextPane(dateControl);
81
        initTextPane(authorControl);
82
        initTextPane(revisionControl);
83
        initTextPane(commitMessageControl);
84
        northPanel.setOpaque(false);
85
        authorDatePanel.setOpaque(false);
86
        this.setFocusable(false);
87
        northPanel.setFocusable(false);
88
        authorDatePanel.setFocusable(false);
89
    }
90
    /**
91
     * Corrects the bounding rectangle of nested textpanes.
92
     * @param startComponent
93
     * @param r 
94
     */
95
    @Override
96
    public void correctTranslation (final Container startComponent, final Rectangle r) {
97
        if (null == startComponent) {
98
            return;
99
        }
100
        if (null == r) {
101
            return;
102
        }
103
        
104
        final RevisionItemCell stopComponent = this;
105
        Container current=startComponent;
106
        while (current != stopComponent) {
107
            r.translate(current.getX(), current.getY());
108
            current = current.getParent();
109
        }
110
        r.translate(current.getX(), current.getY());
111
    }
112
113
    public JTextPane getAuthorControl () {
114
        return authorControl;
115
    }
116
117
    public JTextPane getDateControl () {
118
        return dateControl;
119
    }
120
121
    public JTextPane getRevisionControl () {
122
        return revisionControl;
123
    }
124
125
    public JTextPane getCommitMessageControl () {
126
        return commitMessageControl;
127
    }
128
129
    public JPanel getNorthPanel () {
130
        return northPanel;
131
    }
132
133
    private void initTextPane (JTextPane pane) {
134
        pane.setBorder(null);
135
        pane.setLayout(null);
136
        //fix for nimbus laf
137
        pane.setOpaque(false);
138
        pane.setBackground(new Color(0, 0, 0, 0));
139
    }
140
    
141
}
(-)a/versioning.util/src/org/netbeans/modules/versioning/history/SummaryCellRenderer.java (-216 / +336 lines)
Lines 85-98 Link Here
85
import org.netbeans.api.editor.mimelookup.MimeLookup;
85
import org.netbeans.api.editor.mimelookup.MimeLookup;
86
import org.netbeans.api.editor.mimelookup.MimePath;
86
import org.netbeans.api.editor.mimelookup.MimePath;
87
import org.netbeans.api.editor.settings.FontColorSettings;
87
import org.netbeans.api.editor.settings.FontColorSettings;
88
import org.netbeans.modules.versioning.history.AbstractSummaryView.LogEntry;
88
import org.netbeans.modules.versioning.history.AbstractSummaryView.LogEntry.Event;
89
import org.netbeans.modules.versioning.history.AbstractSummaryView.LogEntry.Event;
89
import org.netbeans.modules.versioning.history.AbstractSummaryView.RevisionItem;
90
import org.netbeans.modules.versioning.history.AbstractSummaryView.RevisionItem;
90
import org.netbeans.modules.versioning.history.AbstractSummaryView.SummaryViewMaster.SearchHighlight;
91
import org.netbeans.modules.versioning.history.AbstractSummaryView.SummaryViewMaster.SearchHighlight;
91
import org.netbeans.modules.versioning.util.Utils;
92
import org.netbeans.modules.versioning.util.Utils;
92
import org.netbeans.modules.versioning.util.VCSHyperlinkProvider;
93
import org.netbeans.modules.versioning.util.VCSHyperlinkProvider;
93
import org.netbeans.modules.versioning.util.VCSHyperlinkSupport;
94
import org.netbeans.modules.versioning.util.VCSHyperlinkSupport;
95
import org.netbeans.modules.versioning.util.VCSHyperlinkSupport.AuthorLinker;
96
import org.netbeans.modules.versioning.util.VCSHyperlinkSupport.IssueLinker;
94
import org.netbeans.modules.versioning.util.VCSKenaiAccessor;
97
import org.netbeans.modules.versioning.util.VCSKenaiAccessor;
95
import org.openide.ErrorManager;
98
import org.openide.ErrorManager;
99
import org.openide.util.Exceptions;
96
import org.openide.util.Lookup;
100
import org.openide.util.Lookup;
97
import org.openide.util.NbBundle;
101
import org.openide.util.NbBundle;
98
102
Lines 253-270 Link Here
253
    private class RevisionRenderer extends JPanel implements ListCellRenderer {
257
    private class RevisionRenderer extends JPanel implements ListCellRenderer {
254
258
255
        private String id;
259
        private String id;
256
        private final Style selectedStyle;
257
        private final Style normalStyle;
258
        private final Style indentStyle;
259
        private final Style noindentStyle;
260
        private final Style issueHyperlinkStyle;
261
        private final Style linkStyle;
262
        private final Style authorStyle;
263
        private final Style hiliteStyle;
264
        private boolean lastSelection = false;
260
        private boolean lastSelection = false;
265
        private final JTextPane textPane;
261
        private final RevisionItemCell revisionCell = new RevisionItemCell();
266
        private final JButton expandButton;
262
        private final JButton expandButton;
267
        private String commitMessage = ""; //NOI18N
268
        private boolean lastMessageExpanded;
263
        private boolean lastMessageExpanded;
269
        private boolean lastRevisionExpanded;
264
        private boolean lastRevisionExpanded;
270
        private int lastWidth;
265
        private int lastWidth;
Lines 272-317 Link Here
272
267
273
        public RevisionRenderer() {
268
        public RevisionRenderer() {
274
            selectionForeground = new JList().getSelectionForeground();
269
            selectionForeground = new JList().getSelectionForeground();
275
            textPane = new JTextPane();
276
            expandButton = new LinkButton(ICON_COLLAPSED);
270
            expandButton = new LinkButton(ICON_COLLAPSED);
277
            expandButton.setBorder(BorderFactory.createEmptyBorder());
271
            expandButton.setBorder(BorderFactory.createEmptyBorder());
278
272
279
            selectedStyle = textPane.addStyle("selected", null); //NOI18N
273
            this.setBorder(BorderFactory.createMatteBorder(3, 0, 0, 0, UIManager.getColor("List.background"))); //NOI18N
280
            StyleConstants.setForeground(selectedStyle, selectionForeground);
274
            this.setLayout(new BorderLayout(3, 0));
281
            StyleConstants.setBackground(selectedStyle, selectionBackground);
282
            normalStyle = textPane.addStyle("normal", null); //NOI18N
283
            StyleConstants.setForeground(normalStyle, UIManager.getColor("List.foreground")); //NOI18N
284
            indentStyle = textPane.addStyle("indent", null); //NOI18N
285
            StyleConstants.setLeftIndent(indentStyle, 50);
286
            noindentStyle = textPane.addStyle("noindent", null); //NOI18N
287
            StyleConstants.setLeftIndent(noindentStyle, 0);
288
275
289
            issueHyperlinkStyle = textPane.addStyle("issuehyperlink", normalStyle); //NOI18N
290
            StyleConstants.setForeground(issueHyperlinkStyle, Color.BLUE);
291
            StyleConstants.setUnderline(issueHyperlinkStyle, true);
292
293
            linkStyle = textPane.addStyle("link", normalStyle); //NOI18N
294
            StyleConstants.setForeground(linkStyle, Color.BLUE);
295
            StyleConstants.setBold(linkStyle, true);
296
297
            authorStyle = textPane.addStyle("author", normalStyle); //NOI18N
298
            StyleConstants.setForeground(authorStyle, Color.BLUE);
299
300
            hiliteStyle = textPane.addStyle("hilite", normalStyle); //NOI18N
301
            
302
            Color c = (Color) searchHiliteAttrs.getAttribute(StyleConstants.Background);
303
            if (c != null) StyleConstants.setBackground(hiliteStyle, c);
304
            c = (Color) searchHiliteAttrs.getAttribute(StyleConstants.Foreground);
305
            if (c != null) StyleConstants.setForeground(hiliteStyle, c);
306
307
            textPane.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
308
            setLayout(new BorderLayout(0, 0));
309
            setBorder(BorderFactory.createMatteBorder(3, 0, 0, 0, UIManager.getColor("List.background"))); //NOI18N
310
            
311
            add(expandButton, BorderLayout.WEST);
312
            expandButton.setMaximumSize(expandButton.getPreferredSize());
276
            expandButton.setMaximumSize(expandButton.getPreferredSize());
313
            expandButton.setMinimumSize(expandButton.getPreferredSize());
277
            expandButton.setMinimumSize(expandButton.getPreferredSize());
314
            add(textPane, BorderLayout.CENTER);
278
            this.add(expandButton, BorderLayout.WEST);
279
            this.add(revisionCell, BorderLayout.CENTER);
315
        }
280
        }
316
281
317
        @Override
282
        @Override
Lines 319-350 Link Here
319
            AbstractSummaryView.RevisionItem item = (AbstractSummaryView.RevisionItem) value;
284
            AbstractSummaryView.RevisionItem item = (AbstractSummaryView.RevisionItem) value;
320
            AbstractSummaryView.LogEntry entry = item.getUserData();
285
            AbstractSummaryView.LogEntry entry = item.getUserData();
321
286
322
            StyledDocument sd = textPane.getStyledDocument();
323
            Collection<SearchHighlight> highlights = summaryView.getMaster().getSearchHighlights();
287
            Collection<SearchHighlight> highlights = summaryView.getMaster().getSearchHighlights();
324
            if (sd.getLength() == 0 || selected != lastSelection || item.messageExpanded != lastMessageExpanded || item.revisionExpanded != lastRevisionExpanded
288
            if (revisionCell.getRevisionControl().getStyledDocument().getLength() == 0 || revisionCell.getDateControl().getStyledDocument().getLength() == 0 || revisionCell.getAuthorControl().getStyledDocument().getLength() == 0 || revisionCell.getCommitMessageControl().getStyledDocument().getLength() == 0 || selected != lastSelection || item.messageExpanded != lastMessageExpanded || item.revisionExpanded != lastRevisionExpanded
325
                    || !highlights.equals(lastHighlights)) {
289
                    || !highlights.equals(lastHighlights)) {
326
                lastSelection = selected;
290
                lastSelection = selected;
327
                lastMessageExpanded = item.messageExpanded;
291
                lastMessageExpanded = item.messageExpanded;
328
                lastRevisionExpanded = item.revisionExpanded;
292
                lastRevisionExpanded = item.revisionExpanded;
329
                lastHighlights = highlights;
293
                lastHighlights = highlights;
330
294
331
                Style style;
332
                Color backgroundColor;
295
                Color backgroundColor;
333
                Color foregroundColor;
334
296
335
                if (selected) {
297
                if (selected) {
336
                    foregroundColor = selectionForeground;
337
                    backgroundColor = selectionBackground;
298
                    backgroundColor = selectionBackground;
338
                    style = selectedStyle;
339
                } else {
299
                } else {
340
                    foregroundColor = UIManager.getColor("List.foreground"); //NOI18N
341
                    backgroundColor = UIManager.getColor("List.background"); //NOI18N
300
                    backgroundColor = UIManager.getColor("List.background"); //NOI18N
342
                    backgroundColor = entry.isLessInteresting() ? darkerUninteresting(backgroundColor) : darker(backgroundColor);
301
                    backgroundColor = entry.isLessInteresting() ? darkerUninteresting(backgroundColor) : darker(backgroundColor);
343
                    style = normalStyle;
344
                }
302
                }
345
                textPane.setOpaque(false);
303
                this.setBackground(backgroundColor);
346
                textPane.setBackground(new Color(0, 0, 0, 0));
304
                revisionCell.setBackground(backgroundColor);
347
                setBackground(backgroundColor);
305
348
                if (item.revisionExpanded) {
306
                if (item.revisionExpanded) {
349
                    expandButton.setIcon(ICON_EXPANDED);
307
                    expandButton.setIcon(ICON_EXPANDED);
350
                } else {
308
                } else {
Lines 357-522 Link Here
357
                }
315
                }
358
316
359
                try {
317
                try {
360
                    // clear document
318
                    addRevision(revisionCell.getRevisionControl(), item, selected, highlights);
361
                    sd.remove(0, sd.getLength());
319
                    addCommitMessage(revisionCell.getCommitMessageControl(), item, selected, highlights);
362
                    sd.setParagraphAttributes(0, sd.getLength(), noindentStyle, false);
320
                    addAuthor(revisionCell.getAuthorControl(), item, selected, highlights);
363
321
                    addDate(revisionCell.getDateControl(), item, selected, highlights);
364
                    // add revision
365
                    sd.insertString(0, item.getUserData().getRevision(), null);
366
                    sd.setCharacterAttributes(0, sd.getLength(), normalStyle, false);
367
                    if (!selected) {
368
                        for (AbstractSummaryView.LogEntry.RevisionHighlight highlight : item.getUserData().getRevisionHighlights()) {
369
                            Style s = textPane.addStyle(null, normalStyle);
370
                            StyleConstants.setForeground(s, highlight.getForeground());
371
                            StyleConstants.setBackground(s, highlight.getBackground());
372
                            sd.setCharacterAttributes(highlight.getStart(), highlight.getLength(), s, false);
373
                        }
374
                        for (SearchHighlight highlight : highlights) {
375
                            if (highlight.getKind() == SearchHighlight.Kind.REVISION) {
376
                                int doclen = sd.getLength();
377
                                String highlightMessage = highlight.getSearchText();
378
                                String revisionText = item.getUserData().getRevision().toLowerCase();
379
                                int idx = revisionText.indexOf(highlightMessage);
380
                                if (idx > -1) {
381
                                    sd.setCharacterAttributes(doclen - revisionText.length() + idx, highlightMessage.length(), hiliteStyle, false);
382
                                }
383
                            }
384
                        }
385
                    }
386
387
                    // add author
388
                    sd.insertString(sd.getLength(), FIELDS_SEPARATOR, style);
389
                    String author = entry.getAuthor();
390
                    VCSHyperlinkSupport.StyledDocumentHyperlink l = linkerSupport.getLinker(VCSHyperlinkSupport.AuthorLinker.class, id);
391
                    if(l == null) {
392
                        VCSKenaiAccessor.KenaiUser kenaiUser = getKenaiUser(author);
393
                        if (kenaiUser != null) {
394
                            l = new VCSHyperlinkSupport.AuthorLinker(kenaiUser, authorStyle, sd, author);
395
                            linkerSupport.add(l, id);
396
                        }
397
                    }
398
                    int pos = sd.getLength();
399
                    if(l != null) {
400
                        l.insertString(sd, selected ? style : null);
401
                    } else {
402
                        sd.insertString(sd.getLength(), author, style);
403
                    }
404
                    if (!selected) {
405
                        for (SearchHighlight highlight : highlights) {
406
                            if (highlight.getKind() == SearchHighlight.Kind.AUTHOR) {
407
                                int doclen = sd.getLength();
408
                                String highlightMessage = highlight.getSearchText();
409
                                String authorText = sd.getText(pos, doclen - pos).toLowerCase();
410
                                int idx = authorText.indexOf(highlightMessage);
411
                                if (idx > -1) {
412
                                    sd.setCharacterAttributes(doclen - authorText.length() + idx, highlightMessage.length(), hiliteStyle, false);
413
                                }
414
                            }
415
                        }
416
                    }
417
418
                    // add date
419
                    sd.insertString(sd.getLength(), FIELDS_SEPARATOR + entry.getDate(), null);
420
421
                    // add commit msg
422
                    boolean messageChanged = !entry.getMessage().equals(commitMessage);
423
                    commitMessage = entry.getMessage();
424
                    if (commitMessage.endsWith("\n")) commitMessage = commitMessage.substring(0, commitMessage.length() - 1); //NOI18N
425
                    sd.insertString(sd.getLength(), "\n", null); //NOI18N
426
                    int nlc, i;
427
                    for (i = 0, nlc = -1; i != -1 ; i = commitMessage.indexOf('\n', i + 1), nlc++);
428
                    if (nlc > 0 && !item.messageExpanded) {
429
                        commitMessage = commitMessage.substring(0, commitMessage.indexOf("\n")); //NOI18N
430
                    }
431
432
                    // compute issue hyperlinks
433
                    l = linkerSupport.getLinker(VCSHyperlinkSupport.IssueLinker.class, id);
434
                    if (messageChanged) {
435
                        lastWidth = -1;
436
                        if (l != null) {
437
                            // must reinitialize issue linker to paint the new message
438
                            linkerSupport.remove(l, id);
439
                            l = null;
440
                        }
441
                    }
442
                    if(l == null) {
443
                        for (VCSHyperlinkProvider hp : getHyperlinkProviders()) {
444
                            l = VCSHyperlinkSupport.IssueLinker.create(hp, issueHyperlinkStyle, summaryView.getRoot(), sd, commitMessage);
445
                            if(l != null) {
446
                                linkerSupport.add(l, id);
447
                                break; // get the first one
448
                            }
449
                        }
450
                    }
451
                    pos = sd.getLength();
452
                    if(l != null) {
453
                        l.insertString(sd, style);
454
                    } else {
455
                        sd.insertString(sd.getLength(), commitMessage, style);
456
                    }
457
458
                    // tooltip for message
459
                    MessageTooltip mtt = linkerSupport.getLinker(MessageTooltip.class, id);
460
                    if (messageChanged) {
461
                        linkerSupport.remove(mtt, id);
462
                        mtt = null;
463
                    }
464
                    if (mtt == null) {
465
                        linkerSupport.add(new MessageTooltip(entry.getMessage(), pos, sd.getLength()), id);
466
                    }
467
                    
468
                    // paint first line of commit message bold
469
                    int lineEnd = sd.getText(pos, sd.getLength() - pos).indexOf("\n");
470
                    if (lineEnd == -1) {
471
                        lineEnd = sd.getLength() - pos;
472
                    }
473
                    Style s = textPane.addStyle(null, style);
474
                    StyleConstants.setBold(s, true);
475
                    sd.setCharacterAttributes(pos, lineEnd, s, false);
476
                    int msglen = commitMessage.length();
477
                    int doclen = sd.getLength();
478
479
                    if (nlc > 0 && !item.messageExpanded) {
480
                        l = linkerSupport.getLinker(ExpandMsgHyperlink.class, id);
481
                        if (l == null) {
482
                            l = new ExpandMsgHyperlink(item, sd.getLength(), id);
483
                            linkerSupport.add(l, id);
484
                        }
485
                        l.insertString(sd, linkStyle);
486
                    }
487
                    
488
489
                    if (!selected) {
490
                        for (SearchHighlight highlight : highlights) {
491
                            if (highlight.getKind() == SearchHighlight.Kind.MESSAGE) {
492
                                String highlightMessage = highlight.getSearchText();
493
                                int idx = commitMessage.toLowerCase().indexOf(highlightMessage);
494
                                if (idx == -1) {
495
                                    if (nlc > 0 && !item.messageExpanded && entry.getMessage().toLowerCase().contains(highlightMessage)) {
496
                                        sd.setCharacterAttributes(doclen, sd.getLength(), hiliteStyle, false);
497
                                    }
498
                                } else {
499
                                    sd.setCharacterAttributes(doclen - msglen + idx, highlightMessage.length(), hiliteStyle, false);
500
                                }
501
                            }
502
                        }
503
                    }
504
505
                    if (selected) {
506
                        sd.setCharacterAttributes(0, Integer.MAX_VALUE, style, false);
507
                    }
508
                } catch (BadLocationException e) {
322
                } catch (BadLocationException e) {
509
                    ErrorManager.getDefault().notify(e);
323
                    ErrorManager.getDefault().notify(e);
510
                }
324
                }
511
            }
325
            }
512
            lastWidth = resizePane(textPane.getText(), list, lastWidth);
326
            lastWidth = resizePane(revisionCell.getCommitMessageControl().getText(), list, lastWidth);
513
327
514
            return this;
328
            return this;
515
        }
329
        }
516
        
330
517
        @SuppressWarnings("empty-statement")
331
        @SuppressWarnings("empty-statement")
518
        private int resizePane(String text, JList list, int lastWidth) {
332
        private int resizePane (String text, JList list, int lastWidth) {
519
            if(text == null) {
333
            if (text == null) {
520
                text = ""; //NOI18N
334
                text = ""; //NOI18N
521
            }
335
            }
522
            int width = summaryView.getMaster().getComponent().getWidth();
336
            int width = summaryView.getMaster().getComponent().getWidth();
Lines 525-549 Link Here
525
                FontMetrics fm = list.getFontMetrics(list.getFont());
339
                FontMetrics fm = list.getFontMetrics(list.getFont());
526
                int lines = 0;
340
                int lines = 0;
527
                for (String row : rows) {
341
                for (String row : rows) {
528
                    Rectangle2D rect = fm.getStringBounds(row, textPane.getGraphics());
342
                    Rectangle2D rect = fm.getStringBounds(row, revisionCell.getGraphics());
529
                    lines += (int) (rect.getWidth() / (width - 80) + 1);
343
                    lines += (int) (rect.getWidth() / (width - 80) + 1);
530
                }
344
                }
531
                int ph = fm.getHeight() * lines + 9;
345
                int ph = fm.getHeight() * (lines + 1) + 4;
532
                textPane.setPreferredSize(new Dimension(width - 50 - ICON_COLLAPSED.getIconWidth(), ph));
346
                revisionCell.setPreferredSize(new Dimension(width - 50 - ICON_COLLAPSED.getIconWidth(), ph));
533
                setPreferredSize(textPane.getPreferredSize());
347
                setPreferredSize(revisionCell.getPreferredSize());
534
            }
348
            }
535
            return width;
349
            return width;
536
        }
350
        }
351
352
        private void addRevision (JTextPane pane, RevisionItem item, boolean selected, Collection<SearchHighlight> highlights) throws BadLocationException {
353
            StyledDocument sd = pane.getStyledDocument();
354
            // clear document
355
            clearSD(pane, sd);
356
357
            Style selectedStyle = createSelectedStyle(pane);
358
            Style normalStyle = createNormalStyle(pane);
359
            Style hiliteStyle = createHiliteStyleStyle(pane, normalStyle, searchHiliteAttrs);
360
            Style style;
361
            if (selected) {
362
                style = selectedStyle;
363
            } else {
364
                style = normalStyle;
365
            }
366
367
368
            // add revision
369
            sd.insertString(0, item.getUserData().getRevision(), style);
370
            if (!selected) {
371
                for (AbstractSummaryView.LogEntry.RevisionHighlight highlight : item.getUserData().getRevisionHighlights()) {
372
                    Style s = pane.addStyle(null, normalStyle);
373
                    StyleConstants.setForeground(s, highlight.getForeground());
374
                    StyleConstants.setBackground(s, highlight.getBackground());
375
                    sd.setCharacterAttributes(highlight.getStart(), highlight.getLength(), s, false);
376
                }
377
                for (SearchHighlight highlight : highlights) {
378
                    if (highlight.getKind() == SearchHighlight.Kind.REVISION) {
379
                        int doclen = sd.getLength();
380
                        String highlightMessage = highlight.getSearchText();
381
                        String revisionText = item.getUserData().getRevision().toLowerCase();
382
                        int idx = revisionText.indexOf(highlightMessage);
383
                        if (idx > -1) {
384
                            sd.setCharacterAttributes(doclen - revisionText.length() + idx, highlightMessage.length(), hiliteStyle, false);
385
                        }
386
                    }
387
                }
388
            }
389
        }
390
391
        private void addAuthor (JTextPane pane, RevisionItem item, boolean selected, Collection<SearchHighlight> highlights) throws BadLocationException {
392
            LogEntry entry = item.getUserData();
393
            StyledDocument sd = pane.getStyledDocument();
394
            clearSD(pane, sd);
395
            Style selectedStyle = createSelectedStyle(pane);
396
            Style normalStyle = createNormalStyle(pane);
397
            Style style;
398
            if (selected) {
399
                style = selectedStyle;
400
            } else {
401
                style = normalStyle;
402
            }
403
            Style authorStyle = createAuthorStyle(pane, normalStyle);
404
            Style hiliteStyle = createHiliteStyleStyle(pane, normalStyle, searchHiliteAttrs);
405
            String author = entry.getAuthor();
406
            VCSHyperlinkSupport.StyledDocumentHyperlink l = linkerSupport.getLinker(VCSHyperlinkSupport.AuthorLinker.class, id);
407
            if(l == null) {
408
                VCSKenaiAccessor.KenaiUser kenaiUser = getKenaiUser(author);
409
                if (kenaiUser != null) {
410
                    AuthorLinker a = new VCSHyperlinkSupport.AuthorLinker(kenaiUser, authorStyle, sd, author);
411
                    linkerSupport.add(a, id);
412
                }
413
            }
414
            int pos = sd.getLength();
415
            if(l != null) {
416
                l.insertString(sd, selected ? style : null);
417
            } else {
418
                sd.insertString(sd.getLength(), author, style);
419
            }
420
            if (!selected) {
421
                for (SearchHighlight highlight : highlights) {
422
                    if (highlight.getKind() == SearchHighlight.Kind.AUTHOR) {
423
                        int doclen = sd.getLength();
424
                        String highlightMessage = highlight.getSearchText();
425
                        String authorText = sd.getText(pos, doclen - pos).toLowerCase();
426
                        int idx = authorText.indexOf(highlightMessage);
427
                        if (idx > -1) {
428
                            sd.setCharacterAttributes(doclen - authorText.length() + idx, highlightMessage.length(), hiliteStyle, false);
429
                        }
430
                    }
431
                }
432
            }
433
        }
434
435
        private void addDate (JTextPane pane, RevisionItem item, boolean selected, Collection<SearchHighlight> highlights) throws BadLocationException {
436
437
            LogEntry entry = item.getUserData();
438
            StyledDocument sd = pane.getStyledDocument();
439
            // clear document
440
            clearSD(pane, sd);
441
442
            Style selectedStyle = createSelectedStyle(pane);
443
            Style normalStyle = createNormalStyle(pane);
444
            Style style;
445
            if (selected) {
446
                style = selectedStyle;
447
            } else {
448
                style = normalStyle;
449
            }
450
451
            // add date
452
            sd.insertString(sd.getLength(), entry.getDate(), style);
453
        }
454
455
        private void addCommitMessage (JTextPane pane, RevisionItem item, boolean selected, Collection<SearchHighlight> highlights) throws BadLocationException {
456
            LogEntry entry = item.getUserData();
457
            StyledDocument sd = pane.getStyledDocument();
458
            clearSD(pane, sd);
459
            Style selectedStyle = createSelectedStyle(pane);
460
            Style normalStyle = createNormalStyle(pane);
461
            Style linkStyle = createLinkStyle(pane, normalStyle);
462
            Style hiliteStyle = createHiliteStyleStyle(pane, normalStyle, searchHiliteAttrs);
463
            Style issueHyperlinkStyle = createIssueHyperlinkStyle(pane, normalStyle);
464
            Style style;
465
            if (selected) {
466
                style = selectedStyle;
467
            } else {
468
                style = normalStyle;
469
            }
470
            boolean messageChanged = !entry.getMessage().isEmpty();
471
            String commitMessage = entry.getMessage().trim();
472
            int nlc;
473
            int i;
474
            for (i = 0, nlc = -1; i != -1; i = commitMessage.indexOf('\n', i + 1), nlc++);
475
            
476
            if (nlc > 0 && !item.messageExpanded) {
477
                //get first line of comment if collapsed
478
                commitMessage = commitMessage.substring(0, commitMessage.indexOf("\n")); //NOI18N
479
            }
480
            IssueLinker l = linkerSupport.getLinker(VCSHyperlinkSupport.IssueLinker.class, id);
481
            if (messageChanged) {
482
                lastWidth = -1;
483
                if (l != null) {
484
                    // must reinitialize issue linker to paint the new message
485
                    linkerSupport.remove(l, id);
486
                    l = null;
487
                }
488
            }
489
            if(l == null) {
490
                for (VCSHyperlinkProvider hp : getHyperlinkProviders()) {
491
                    l = VCSHyperlinkSupport.IssueLinker.create(hp, issueHyperlinkStyle, summaryView.getRoot(), sd, commitMessage);
492
                    if(l != null) {
493
                        linkerSupport.add(l, id);
494
                        break; // get the first one
495
                    }
496
                }
497
            }
498
            if(l != null) {
499
                l.insertString(sd, style);
500
            } else {
501
                sd.insertString(0, commitMessage, style);
502
            }
503
504
            {
505
                //make the first line bold
506
                int lineEnd = sd.getText(0, sd.getLength()).indexOf("\n");
507
                if (lineEnd == -1) {
508
                    lineEnd = sd.getLength();
509
                }
510
                Style s = pane.addStyle(null, style);
511
                StyleConstants.setBold(s, true);
512
                sd.setCharacterAttributes(0, lineEnd, s, false);
513
            }
514
            
515
            int msglen = commitMessage.length();
516
            int doclen = sd.getLength();
517
518
            
519
            if (nlc > 0 && !item.messageExpanded) 
520
            {
521
                //insert expand link
522
                ExpandMsgHyperlink el = linkerSupport.getLinker(ExpandMsgHyperlink.class, id);
523
                if (el == null) {
524
                    el = new ExpandMsgHyperlink(item, sd.getLength(), id);
525
                    linkerSupport.add(el, id);
526
                }
527
                el.insertString(sd, linkStyle);
528
529
            }
530
531
            {
532
                // remove previous tooltips
533
                MessageTooltip mtt = linkerSupport.getLinker(MessageTooltip.class, id);
534
                linkerSupport.remove(mtt, id);
535
                //insert commit message tooltip
536
                MessageTooltip messageTooltip = new MessageTooltip(entry.getMessage(), 0, sd.getLength());
537
                linkerSupport.add(messageTooltip, id);
538
            }
539
            
540
            if (!selected) {
541
                for (SearchHighlight highlight : highlights) {
542
                    if (highlight.getKind() == SearchHighlight.Kind.MESSAGE) {
543
                        String highlightMessage = highlight.getSearchText();
544
                        int idx = commitMessage.toLowerCase().indexOf(highlightMessage);
545
                        if (idx == -1) {
546
                            if (nlc > 0 && !item.messageExpanded && entry.getMessage().toLowerCase().contains(highlightMessage)) {
547
                                sd.setCharacterAttributes(doclen, sd.getLength(), hiliteStyle, false);
548
                            }
549
                        } else {
550
                            sd.setCharacterAttributes(doclen - msglen + idx, highlightMessage.length(), hiliteStyle, false);
551
                        }
552
                    }
553
                }
554
            }
555
556
            if (selected) {
557
                sd.setCharacterAttributes(0, Integer.MAX_VALUE, style, false);
558
            }
559
        }
560
561
        private Style createNormalStyle (JTextPane textPane) {
562
            Style normalStyle = textPane.addStyle("normal", null); //NOI18N
563
            StyleConstants.setForeground(normalStyle, UIManager.getColor("List.foreground")); //NOI18N
564
            return normalStyle;
565
        }
566
567
        private Style createIssueHyperlinkStyle (JTextPane textPane, Style normalStyle) {
568
            Style issueHyperlinkStyle = textPane.addStyle("issuehyperlink", normalStyle); //NOI18N
569
            StyleConstants.setForeground(issueHyperlinkStyle, Color.BLUE);
570
            StyleConstants.setUnderline(issueHyperlinkStyle, true);
571
            return issueHyperlinkStyle;
572
        }
573
574
        private Style createAuthorStyle (JTextPane textPane, Style normalStyle) {
575
            Style authorStyle = textPane.addStyle("author", normalStyle); //NOI18N
576
            StyleConstants.setForeground(authorStyle, Color.BLUE);
577
            return authorStyle;
578
        }
579
580
        private Style createLinkStyle (JTextPane textPane, Style normalStyle) {
581
            Style linkStyle = textPane.addStyle("link", normalStyle); //NOI18N
582
            StyleConstants.setForeground(linkStyle, Color.BLUE);
583
            StyleConstants.setBold(linkStyle, true);
584
            return linkStyle;
585
        }
586
587
        private Style createNoindentStyle (JTextPane textPane) {
588
            Style noindentStyle = textPane.addStyle("noindent", null); //NOI18N
589
            StyleConstants.setLeftIndent(noindentStyle, 0);
590
            return noindentStyle;
591
        }
592
593
        private Style createSelectedStyle (JTextPane textPane) {
594
            Style selectedStyle = textPane.addStyle("selected", null); //NOI18N
595
            StyleConstants.setForeground(selectedStyle, selectionForeground);
596
            StyleConstants.setBackground(selectedStyle, selectionBackground);
597
            return selectedStyle;
598
        }
599
600
        private Style createHiliteStyleStyle (JTextPane textPane, Style normalStyle, AttributeSet searchHiliteAttrs) {
601
            Style hiliteStyle = textPane.addStyle("hilite", normalStyle); //NOI18N
602
603
            Color c = (Color) searchHiliteAttrs.getAttribute(StyleConstants.Background);
604
            if (c != null) {
605
                StyleConstants.setBackground(hiliteStyle, c);
606
            }
607
            c = (Color) searchHiliteAttrs.getAttribute(StyleConstants.Foreground);
608
            if (c != null) {
609
                StyleConstants.setForeground(hiliteStyle, c);
610
            }
611
612
            return hiliteStyle;
613
        }
537
        
614
        
538
        @Override
615
        @Override
539
        public void paint(Graphics g) {
616
        public void paint(Graphics g) {
540
            super.paint(g);
617
            super.paint(g);
541
            linkerSupport.computeBounds(textPane, id);
618
            AuthorLinker author = linkerSupport.getLinker(AuthorLinker.class, id);
619
            if (author != null) {
620
                author.computeBounds(revisionCell.getAuthorControl(), revisionCell);
621
            }
622
            IssueLinker issue = linkerSupport.getLinker(IssueLinker.class, id);
623
            if (issue != null) {
624
                issue.computeBounds(revisionCell.getCommitMessageControl(), revisionCell);
625
            }
626
            ExpandMsgHyperlink expandMsg = linkerSupport.getLinker(ExpandMsgHyperlink.class, id);
627
            if (expandMsg != null) {
628
                expandMsg.computeBounds(revisionCell.getCommitMessageControl(), revisionCell);
629
            }
630
            MessageTooltip tt = linkerSupport.getLinker(MessageTooltip.class, id);
631
            if (tt != null) {
632
                tt.computeBounds(revisionCell.getCommitMessageControl(), revisionCell);
633
            }
542
            ExpandLink link = linkerSupport.getLinker(ExpandLink.class, id);
634
            ExpandLink link = linkerSupport.getLinker(ExpandLink.class, id);
543
            if (link != null) {
635
            if (link != null) {
544
                link.computeBounds(expandButton);
636
                link.computeBounds(expandButton);
545
            }
637
            }
546
        }
638
        }
639
640
        private void clearSD (JTextPane pane, StyledDocument sd) {
641
            try {
642
                Style noindentStyle = createNoindentStyle(pane);
643
                sd.remove(0, sd.getLength());
644
                sd.setParagraphAttributes(0, sd.getLength(), noindentStyle, false);
645
            } catch (BadLocationException ex) {
646
                Exceptions.printStackTrace(ex);
647
            }
648
        }
547
    }
649
    }
548
    
650
    
549
    private static class MessageTooltip extends VCSHyperlinkSupport.Hyperlink {
651
    private static class MessageTooltip extends VCSHyperlinkSupport.Hyperlink {
Lines 575-583 Link Here
575
        public boolean mouseClicked (Point p) {
677
        public boolean mouseClicked (Point p) {
576
            return false;
678
            return false;
577
        }
679
        }
578
680
        
579
        @Override
681
        @Override
580
        public void computeBounds (JTextPane textPane) {
682
        public void computeBounds(JTextPane textPane) {
683
            computeBounds(textPane, null);
684
        }
685
        
686
        public void computeBounds(JTextPane textPane, VCSHyperlinkSupport.BoundsTranslator translator) {
581
            Rectangle tpBounds = textPane.getBounds();
687
            Rectangle tpBounds = textPane.getBounds();
582
            TextUI tui = textPane.getUI();
688
            TextUI tui = textPane.getUI();
583
            try {
689
            try {
Lines 588-593 Link Here
588
                for (int pos = start; pos <= end; ++pos) {
694
                for (int pos = start; pos <= end; ++pos) {
589
                    Rectangle startr = tui.modelToView(textPane, pos, Position.Bias.Forward);
695
                    Rectangle startr = tui.modelToView(textPane, pos, Position.Bias.Forward);
590
                    Rectangle endr = tui.modelToView(textPane, pos + 1, Position.Bias.Backward);
696
                    Rectangle endr = tui.modelToView(textPane, pos + 1, Position.Bias.Backward);
697
                    //prevent NPE if width is too small
698
                    if (null == startr) {continue;}
699
                    if (null == endr) {continue;}
591
                    if (startr.y > lastY) {
700
                    if (startr.y > lastY) {
592
                        rects.add(rec);
701
                        rects.add(rec);
593
                        rec = new Rectangle(tpBounds.x + startr.x, startr.y, endr.x - startr.x, startr.height);
702
                        rec = new Rectangle(tpBounds.x + startr.x, startr.y, endr.x - startr.x, startr.height);
Lines 596-601 Link Here
596
                        rec.setSize(rec.width + endr.x - startr.x, rec.height);
705
                        rec.setSize(rec.width + endr.x - startr.x, rec.height);
597
                    }
706
                    }
598
                }
707
                }
708
                // NOTE the textPane is positioned within a parent panel so the relative bound has to be modified too
709
                if (null != translator){
710
                    translator.correctTranslation(textPane, rec);
711
                }
599
                rects.add(rec);
712
                rects.add(rec);
600
                rects.remove(0);
713
                rects.remove(0);
601
                bounds = rects.toArray(new Rectangle[rects.size()]);
714
                bounds = rects.toArray(new Rectangle[rects.size()]);
Lines 1000-1006 Link Here
1000
        }
1113
        }
1001
    }
1114
    }
1002
1115
1003
    private static final String LINK_STRING = "..."; //NOI18N
1116
    private static final String LINK_STRING = " ..."; //NOI18N
1004
    private static final int LINK_STRING_LEN = LINK_STRING.length();
1117
    private static final int LINK_STRING_LEN = LINK_STRING.length();
1005
    private class ExpandMsgHyperlink extends VCSHyperlinkSupport.StyledDocumentHyperlink {
1118
    private class ExpandMsgHyperlink extends VCSHyperlinkSupport.StyledDocumentHyperlink {
1006
        private Rectangle bounds;
1119
        private Rectangle bounds;
Lines 1034-1042 Link Here
1034
            }
1147
            }
1035
            return false;
1148
            return false;
1036
        }
1149
        }
1037
1150
        
1038
        @Override
1151
        @Override
1039
        public void computeBounds(JTextPane textPane) {
1152
        public void computeBounds(JTextPane textPane) {
1153
            computeBounds(textPane, null);
1154
        }
1155
        
1156
        public void computeBounds(JTextPane textPane, VCSHyperlinkSupport.BoundsTranslator translator) {
1040
            Rectangle tpBounds = textPane.getBounds();
1157
            Rectangle tpBounds = textPane.getBounds();
1041
            TextUI tui = textPane.getUI();
1158
            TextUI tui = textPane.getUI();
1042
            bounds = new Rectangle();
1159
            bounds = new Rectangle();
Lines 1049-1054 Link Here
1049
                Rectangle endr = mtv.getBounds();
1166
                Rectangle endr = mtv.getBounds();
1050
1167
1051
                bounds = new Rectangle(tpBounds.x + startr.x, startr.y, endr.x - startr.x, startr.height);
1168
                bounds = new Rectangle(tpBounds.x + startr.x, startr.y, endr.x - startr.x, startr.height);
1169
                if (null != translator) {
1170
                    translator.correctTranslation(textPane, bounds);
1171
                }
1052
            } catch (BadLocationException ex) {
1172
            } catch (BadLocationException ex) {
1053
                throw new RuntimeException(ex);
1173
                throw new RuntimeException(ex);
1054
            }
1174
            }
(-)a/versioning.util/src/org/netbeans/modules/versioning/util/VCSHyperlinkSupport.java (+26 lines)
Lines 42-47 Link Here
42
42
43
package org.netbeans.modules.versioning.util;
43
package org.netbeans.modules.versioning.util;
44
44
45
import java.awt.Container;
45
import java.awt.Cursor;
46
import java.awt.Cursor;
46
import java.awt.Point;
47
import java.awt.Point;
47
import java.awt.Rectangle;
48
import java.awt.Rectangle;
Lines 232-237 Link Here
232
233
233
        @Override
234
        @Override
234
        public void computeBounds(JTextPane textPane) {
235
        public void computeBounds(JTextPane textPane) {
236
            computeBounds(textPane, null);
237
        }
238
        
239
        public void computeBounds(JTextPane textPane, BoundsTranslator translator) {
235
            Rectangle tpBounds = textPane.getBounds();
240
            Rectangle tpBounds = textPane.getBounds();
236
            TextUI tui = textPane.getUI();
241
            TextUI tui = textPane.getUI();
237
            this.bounds = new Rectangle[length];
242
            this.bounds = new Rectangle[length];
Lines 240-245 Link Here
240
                    Rectangle startr = tui.modelToView(textPane, docstart[i], Position.Bias.Forward).getBounds();
245
                    Rectangle startr = tui.modelToView(textPane, docstart[i], Position.Bias.Forward).getBounds();
241
                    Rectangle endr = tui.modelToView(textPane, docend[i], Position.Bias.Backward).getBounds();
246
                    Rectangle endr = tui.modelToView(textPane, docend[i], Position.Bias.Backward).getBounds();
242
                    this.bounds[i] = new Rectangle(tpBounds.x + startr.x, startr.y, endr.x - startr.x, startr.height);
247
                    this.bounds[i] = new Rectangle(tpBounds.x + startr.x, startr.y, endr.x - startr.x, startr.height);
248
                    //NOTE the textPane is positioned within a parent panel so the origin has to be modified too
249
                    if (null != translator) {
250
                        translator.correctTranslation(textPane, this.bounds[i]);
251
                    }
243
                } catch (BadLocationException ex) { }
252
                } catch (BadLocationException ex) { }
244
            }
253
            }
245
        }
254
        }
Lines 305-310 Link Here
305
314
306
        @Override
315
        @Override
307
        public void computeBounds(JTextPane textPane) {
316
        public void computeBounds(JTextPane textPane) {
317
            computeBounds(textPane, null);
318
        }
319
        
320
        public void computeBounds(JTextPane textPane, BoundsTranslator translator) {
308
            Rectangle tpBounds = textPane.getBounds();
321
            Rectangle tpBounds = textPane.getBounds();
309
            TextUI tui = textPane.getUI();
322
            TextUI tui = textPane.getUI();
310
            this.bounds = new Rectangle();
323
            this.bounds = new Rectangle();
Lines 315-320 Link Here
315
                    endr.x += kenaiUser.getIcon().getIconWidth();
328
                    endr.x += kenaiUser.getIcon().getIconWidth();
316
                }
329
                }
317
                this.bounds = new Rectangle(tpBounds.x + startr.x, startr.y, endr.x - startr.x, startr.height);
330
                this.bounds = new Rectangle(tpBounds.x + startr.x, startr.y, endr.x - startr.x, startr.height);
331
                
332
                if (null != translator) {
333
                    translator.correctTranslation(textPane, this.bounds);
334
                }
318
            } catch (BadLocationException ex) {
335
            } catch (BadLocationException ex) {
319
                Exceptions.printStackTrace(ex);
336
                Exceptions.printStackTrace(ex);
320
            }
337
            }
Lines 360-364 Link Here
360
            sd.insertString(sd.getLength(), " ", iconStyle);
377
            sd.insertString(sd.getLength(), " ", iconStyle);
361
        }
378
        }
362
    }
379
    }
380
381
    public static interface BoundsTranslator {
382
        /**
383
         * Corrects the bounding rectangle of nested textpanes.
384
         * @param startComponent
385
         * @param r 
386
         */
387
        public void correctTranslation (final Container startComponent, final Rectangle r);
388
    }
363
}
389
}
364
390

Return to bug 218850