Lines 44-49
Link Here
|
44 |
import java.awt.BorderLayout; |
44 |
import java.awt.BorderLayout; |
45 |
import java.awt.Color; |
45 |
import java.awt.Color; |
46 |
import java.awt.Component; |
46 |
import java.awt.Component; |
|
|
47 |
import java.awt.Container; |
47 |
import java.awt.Cursor; |
48 |
import java.awt.Cursor; |
48 |
import java.awt.Dimension; |
49 |
import java.awt.Dimension; |
49 |
import java.awt.EventQueue; |
50 |
import java.awt.EventQueue; |
Lines 85-98
Link Here
|
85 |
import org.netbeans.api.editor.mimelookup.MimeLookup; |
86 |
import org.netbeans.api.editor.mimelookup.MimeLookup; |
86 |
import org.netbeans.api.editor.mimelookup.MimePath; |
87 |
import org.netbeans.api.editor.mimelookup.MimePath; |
87 |
import org.netbeans.api.editor.settings.FontColorSettings; |
88 |
import org.netbeans.api.editor.settings.FontColorSettings; |
|
|
89 |
import org.netbeans.modules.versioning.history.AbstractSummaryView.LogEntry; |
88 |
import org.netbeans.modules.versioning.history.AbstractSummaryView.LogEntry.Event; |
90 |
import org.netbeans.modules.versioning.history.AbstractSummaryView.LogEntry.Event; |
89 |
import org.netbeans.modules.versioning.history.AbstractSummaryView.RevisionItem; |
91 |
import org.netbeans.modules.versioning.history.AbstractSummaryView.RevisionItem; |
90 |
import org.netbeans.modules.versioning.history.AbstractSummaryView.SummaryViewMaster.SearchHighlight; |
92 |
import org.netbeans.modules.versioning.history.AbstractSummaryView.SummaryViewMaster.SearchHighlight; |
91 |
import org.netbeans.modules.versioning.util.Utils; |
93 |
import org.netbeans.modules.versioning.util.Utils; |
92 |
import org.netbeans.modules.versioning.util.VCSHyperlinkProvider; |
94 |
import org.netbeans.modules.versioning.util.VCSHyperlinkProvider; |
93 |
import org.netbeans.modules.versioning.util.VCSHyperlinkSupport; |
95 |
import org.netbeans.modules.versioning.util.VCSHyperlinkSupport; |
|
|
96 |
import org.netbeans.modules.versioning.util.VCSHyperlinkSupport.AuthorLinker; |
97 |
import org.netbeans.modules.versioning.util.VCSHyperlinkSupport.IssueLinker; |
94 |
import org.netbeans.modules.versioning.util.VCSKenaiAccessor; |
98 |
import org.netbeans.modules.versioning.util.VCSKenaiAccessor; |
95 |
import org.openide.ErrorManager; |
99 |
import org.openide.ErrorManager; |
|
|
100 |
import org.openide.util.Exceptions; |
96 |
import org.openide.util.Lookup; |
101 |
import org.openide.util.Lookup; |
97 |
import org.openide.util.NbBundle; |
102 |
import org.openide.util.NbBundle; |
98 |
|
103 |
|
Lines 253-270
Link Here
|
253 |
private class RevisionRenderer extends JPanel implements ListCellRenderer { |
258 |
private class RevisionRenderer extends JPanel implements ListCellRenderer { |
254 |
|
259 |
|
255 |
private String id; |
260 |
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; |
261 |
private boolean lastSelection = false; |
265 |
private final JTextPane textPane; |
262 |
private final RevisionItemCell revisionCell = new RevisionItemCell(); |
266 |
private final JButton expandButton; |
263 |
private final JButton expandButton; |
267 |
private String commitMessage = ""; //NOI18N |
|
|
268 |
private boolean lastMessageExpanded; |
264 |
private boolean lastMessageExpanded; |
269 |
private boolean lastRevisionExpanded; |
265 |
private boolean lastRevisionExpanded; |
270 |
private int lastWidth; |
266 |
private int lastWidth; |
Lines 272-317
Link Here
|
272 |
|
268 |
|
273 |
public RevisionRenderer() { |
269 |
public RevisionRenderer() { |
274 |
selectionForeground = new JList().getSelectionForeground(); |
270 |
selectionForeground = new JList().getSelectionForeground(); |
275 |
textPane = new JTextPane(); |
|
|
276 |
expandButton = new LinkButton(ICON_COLLAPSED); |
271 |
expandButton = new LinkButton(ICON_COLLAPSED); |
277 |
expandButton.setBorder(BorderFactory.createEmptyBorder()); |
272 |
expandButton.setBorder(BorderFactory.createEmptyBorder()); |
278 |
|
273 |
|
279 |
selectedStyle = textPane.addStyle("selected", null); //NOI18N |
274 |
this.setBorder(BorderFactory.createMatteBorder(3, 0, 0, 0, UIManager.getColor("List.background"))); //NOI18N |
280 |
StyleConstants.setForeground(selectedStyle, selectionForeground); |
275 |
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 |
|
276 |
|
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()); |
277 |
expandButton.setMaximumSize(expandButton.getPreferredSize()); |
313 |
expandButton.setMinimumSize(expandButton.getPreferredSize()); |
278 |
expandButton.setMinimumSize(expandButton.getPreferredSize()); |
314 |
add(textPane, BorderLayout.CENTER); |
279 |
this.add(expandButton, BorderLayout.WEST); |
|
|
280 |
this.add(revisionCell, BorderLayout.CENTER); |
315 |
} |
281 |
} |
316 |
|
282 |
|
317 |
@Override |
283 |
@Override |
Lines 319-350
Link Here
|
319 |
AbstractSummaryView.RevisionItem item = (AbstractSummaryView.RevisionItem) value; |
285 |
AbstractSummaryView.RevisionItem item = (AbstractSummaryView.RevisionItem) value; |
320 |
AbstractSummaryView.LogEntry entry = item.getUserData(); |
286 |
AbstractSummaryView.LogEntry entry = item.getUserData(); |
321 |
|
287 |
|
322 |
StyledDocument sd = textPane.getStyledDocument(); |
|
|
323 |
Collection<SearchHighlight> highlights = summaryView.getMaster().getSearchHighlights(); |
288 |
Collection<SearchHighlight> highlights = summaryView.getMaster().getSearchHighlights(); |
324 |
if (sd.getLength() == 0 || selected != lastSelection || item.messageExpanded != lastMessageExpanded || item.revisionExpanded != lastRevisionExpanded |
289 |
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)) { |
290 |
|| !highlights.equals(lastHighlights)) { |
326 |
lastSelection = selected; |
291 |
lastSelection = selected; |
327 |
lastMessageExpanded = item.messageExpanded; |
292 |
lastMessageExpanded = item.messageExpanded; |
328 |
lastRevisionExpanded = item.revisionExpanded; |
293 |
lastRevisionExpanded = item.revisionExpanded; |
329 |
lastHighlights = highlights; |
294 |
lastHighlights = highlights; |
330 |
|
295 |
|
331 |
Style style; |
|
|
332 |
Color backgroundColor; |
296 |
Color backgroundColor; |
333 |
Color foregroundColor; |
|
|
334 |
|
297 |
|
335 |
if (selected) { |
298 |
if (selected) { |
336 |
foregroundColor = selectionForeground; |
|
|
337 |
backgroundColor = selectionBackground; |
299 |
backgroundColor = selectionBackground; |
338 |
style = selectedStyle; |
|
|
339 |
} else { |
300 |
} else { |
340 |
foregroundColor = UIManager.getColor("List.foreground"); //NOI18N |
|
|
341 |
backgroundColor = UIManager.getColor("List.background"); //NOI18N |
301 |
backgroundColor = UIManager.getColor("List.background"); //NOI18N |
342 |
backgroundColor = entry.isLessInteresting() ? darkerUninteresting(backgroundColor) : darker(backgroundColor); |
302 |
backgroundColor = entry.isLessInteresting() ? darkerUninteresting(backgroundColor) : darker(backgroundColor); |
343 |
style = normalStyle; |
|
|
344 |
} |
303 |
} |
345 |
textPane.setOpaque(false); |
304 |
this.setBackground(backgroundColor); |
346 |
textPane.setBackground(new Color(0, 0, 0, 0)); |
305 |
revisionCell.setBackground(backgroundColor); |
347 |
setBackground(backgroundColor); |
306 |
|
348 |
if (item.revisionExpanded) { |
307 |
if (item.revisionExpanded) { |
349 |
expandButton.setIcon(ICON_EXPANDED); |
308 |
expandButton.setIcon(ICON_EXPANDED); |
350 |
} else { |
309 |
} else { |
Lines 357-522
Link Here
|
357 |
} |
316 |
} |
358 |
|
317 |
|
359 |
try { |
318 |
try { |
360 |
// clear document |
319 |
addRevision(revisionCell.getRevisionControl(), item, selected, highlights); |
361 |
sd.remove(0, sd.getLength()); |
320 |
addCommitMessage(revisionCell.getCommitMessageControl(), item, selected, highlights); |
362 |
sd.setParagraphAttributes(0, sd.getLength(), noindentStyle, false); |
321 |
addAuthor(revisionCell.getAuthorControl(), item, selected, highlights); |
363 |
|
322 |
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) { |
323 |
} catch (BadLocationException e) { |
509 |
ErrorManager.getDefault().notify(e); |
324 |
ErrorManager.getDefault().notify(e); |
510 |
} |
325 |
} |
511 |
} |
326 |
} |
512 |
lastWidth = resizePane(textPane.getText(), list, lastWidth); |
327 |
lastWidth = resizePane(revisionCell.getCommitMessageControl().getText(), list, lastWidth); |
513 |
|
328 |
|
514 |
return this; |
329 |
return this; |
515 |
} |
330 |
} |
516 |
|
331 |
|
517 |
@SuppressWarnings("empty-statement") |
332 |
@SuppressWarnings("empty-statement") |
518 |
private int resizePane(String text, JList list, int lastWidth) { |
333 |
private int resizePane (String text, JList list, int lastWidth) { |
519 |
if(text == null) { |
334 |
if (text == null) { |
520 |
text = ""; //NOI18N |
335 |
text = ""; //NOI18N |
521 |
} |
336 |
} |
522 |
int width = summaryView.getMaster().getComponent().getWidth(); |
337 |
int width = summaryView.getMaster().getComponent().getWidth(); |
Lines 525-549
Link Here
|
525 |
FontMetrics fm = list.getFontMetrics(list.getFont()); |
340 |
FontMetrics fm = list.getFontMetrics(list.getFont()); |
526 |
int lines = 0; |
341 |
int lines = 0; |
527 |
for (String row : rows) { |
342 |
for (String row : rows) { |
528 |
Rectangle2D rect = fm.getStringBounds(row, textPane.getGraphics()); |
343 |
Rectangle2D rect = fm.getStringBounds(row, revisionCell.getGraphics()); |
529 |
lines += (int) (rect.getWidth() / (width - 80) + 1); |
344 |
lines += (int) (rect.getWidth() / (width - 80) + 1); |
530 |
} |
345 |
} |
531 |
int ph = fm.getHeight() * lines + 9; |
346 |
int ph = fm.getHeight() * (lines + 1) + 4; |
532 |
textPane.setPreferredSize(new Dimension(width - 50 - ICON_COLLAPSED.getIconWidth(), ph)); |
347 |
revisionCell.setPreferredSize(new Dimension(width - 50 - ICON_COLLAPSED.getIconWidth(), ph)); |
533 |
setPreferredSize(textPane.getPreferredSize()); |
348 |
setPreferredSize(revisionCell.getPreferredSize()); |
534 |
} |
349 |
} |
535 |
return width; |
350 |
return width; |
536 |
} |
351 |
} |
|
|
352 |
|
353 |
private void addRevision (JTextPane pane, RevisionItem item, boolean selected, Collection<SearchHighlight> highlights) throws BadLocationException { |
354 |
StyledDocument sd = pane.getStyledDocument(); |
355 |
// clear document |
356 |
clearSD(pane, sd); |
357 |
|
358 |
Style selectedStyle = createSelectedStyle(pane); |
359 |
Style normalStyle = createNormalStyle(pane); |
360 |
Style hiliteStyle = createHiliteStyleStyle(pane, normalStyle, searchHiliteAttrs); |
361 |
Style style; |
362 |
if (selected) { |
363 |
style = selectedStyle; |
364 |
} else { |
365 |
style = normalStyle; |
366 |
} |
367 |
|
368 |
|
369 |
// add revision |
370 |
sd.insertString(0, item.getUserData().getRevision(), style); |
371 |
if (!selected) { |
372 |
for (AbstractSummaryView.LogEntry.RevisionHighlight highlight : item.getUserData().getRevisionHighlights()) { |
373 |
Style s = pane.addStyle(null, normalStyle); |
374 |
StyleConstants.setForeground(s, highlight.getForeground()); |
375 |
StyleConstants.setBackground(s, highlight.getBackground()); |
376 |
sd.setCharacterAttributes(highlight.getStart(), highlight.getLength(), s, false); |
377 |
} |
378 |
for (SearchHighlight highlight : highlights) { |
379 |
if (highlight.getKind() == SearchHighlight.Kind.REVISION) { |
380 |
int doclen = sd.getLength(); |
381 |
String highlightMessage = highlight.getSearchText(); |
382 |
String revisionText = item.getUserData().getRevision().toLowerCase(); |
383 |
int idx = revisionText.indexOf(highlightMessage); |
384 |
if (idx > -1) { |
385 |
sd.setCharacterAttributes(doclen - revisionText.length() + idx, highlightMessage.length(), hiliteStyle, false); |
386 |
} |
387 |
} |
388 |
} |
389 |
} |
390 |
} |
391 |
|
392 |
private void addAuthor (JTextPane pane, RevisionItem item, boolean selected, Collection<SearchHighlight> highlights) throws BadLocationException { |
393 |
LogEntry entry = item.getUserData(); |
394 |
StyledDocument sd = pane.getStyledDocument(); |
395 |
clearSD(pane, sd); |
396 |
Style selectedStyle = createSelectedStyle(pane); |
397 |
Style normalStyle = createNormalStyle(pane); |
398 |
Style style; |
399 |
if (selected) { |
400 |
style = selectedStyle; |
401 |
} else { |
402 |
style = normalStyle; |
403 |
} |
404 |
Style authorStyle = createAuthorStyle(pane, normalStyle); |
405 |
Style hiliteStyle = createHiliteStyleStyle(pane, normalStyle, searchHiliteAttrs); |
406 |
String author = entry.getAuthor(); |
407 |
VCSHyperlinkSupport.StyledDocumentHyperlink l = linkerSupport.getLinker(VCSHyperlinkSupport.AuthorLinker.class, id); |
408 |
if (l == null) { |
409 |
VCSKenaiAccessor.KenaiUser kenaiUser = getKenaiUser(author); |
410 |
if (kenaiUser != null) { |
411 |
AuthorLinker a = new VCSHyperlinkSupport.AuthorLinker(kenaiUser, authorStyle, sd, author); |
412 |
a.setReferenceComponent(revisionCell); |
413 |
l=a; |
414 |
linkerSupport.add(l, id); |
415 |
} |
416 |
} |
417 |
int pos = sd.getLength(); |
418 |
if (l != null) { |
419 |
l.insertString(sd, selected ? style : null); |
420 |
} else { |
421 |
sd.insertString(sd.getLength(), author, style); |
422 |
} |
423 |
if (!selected) { |
424 |
for (SearchHighlight highlight : highlights) { |
425 |
if (highlight.getKind() == SearchHighlight.Kind.AUTHOR) { |
426 |
int doclen = sd.getLength(); |
427 |
String highlightMessage = highlight.getSearchText(); |
428 |
String authorText = sd.getText(pos, doclen - pos).toLowerCase(); |
429 |
int idx = authorText.indexOf(highlightMessage); |
430 |
if (idx > -1) { |
431 |
sd.setCharacterAttributes(doclen - authorText.length() + idx, highlightMessage.length(), hiliteStyle, false); |
432 |
} |
433 |
} |
434 |
} |
435 |
} |
436 |
} |
437 |
|
438 |
private void addDate (JTextPane pane, RevisionItem item, boolean selected, Collection<SearchHighlight> highlights) throws BadLocationException { |
439 |
|
440 |
LogEntry entry = item.getUserData(); |
441 |
StyledDocument sd = pane.getStyledDocument(); |
442 |
// clear document |
443 |
clearSD(pane, sd); |
444 |
|
445 |
Style selectedStyle = createSelectedStyle(pane); |
446 |
Style normalStyle = createNormalStyle(pane); |
447 |
Style style; |
448 |
if (selected) { |
449 |
style = selectedStyle; |
450 |
} else { |
451 |
style = normalStyle; |
452 |
} |
453 |
|
454 |
// add date |
455 |
sd.insertString(sd.getLength(), entry.getDate(), style); |
456 |
} |
457 |
|
458 |
private void addCommitMessage (JTextPane pane, RevisionItem item, boolean selected, Collection<SearchHighlight> highlights) throws BadLocationException { |
459 |
LogEntry entry = item.getUserData(); |
460 |
StyledDocument sd = pane.getStyledDocument(); |
461 |
clearSD(pane, sd); |
462 |
Style selectedStyle = createSelectedStyle(pane); |
463 |
Style normalStyle = createNormalStyle(pane); |
464 |
Style linkStyle = createLinkStyle(pane, normalStyle); |
465 |
Style hiliteStyle = createHiliteStyleStyle(pane, normalStyle, searchHiliteAttrs); |
466 |
Style issueHyperlinkStyle = createIssueHyperlinkStyle(pane, normalStyle); |
467 |
Style style; |
468 |
if (selected) { |
469 |
style = selectedStyle; |
470 |
} else { |
471 |
style = normalStyle; |
472 |
} |
473 |
boolean messageChanged = !entry.getMessage().isEmpty(); |
474 |
String commitMessage = entry.getMessage().trim(); |
475 |
int nlc; |
476 |
int i; |
477 |
for (i = 0, nlc = -1; i != -1; i = commitMessage.indexOf('\n', i + 1), nlc++); |
478 |
|
479 |
if (nlc > 0 && !item.messageExpanded) { |
480 |
//get first line of comment if collapsed |
481 |
commitMessage = commitMessage.substring(0, commitMessage.indexOf("\n")); //NOI18N |
482 |
} |
483 |
IssueLinker l = linkerSupport.getLinker(VCSHyperlinkSupport.IssueLinker.class, id); |
484 |
if (messageChanged) { |
485 |
lastWidth = -1; |
486 |
if (l != null) { |
487 |
// must reinitialize issue linker to paint the new message |
488 |
linkerSupport.remove(l, id); |
489 |
l = null; |
490 |
} |
491 |
} |
492 |
if (l == null) { |
493 |
for (VCSHyperlinkProvider hp : getHyperlinkProviders()) { |
494 |
l = VCSHyperlinkSupport.IssueLinker.create(hp, issueHyperlinkStyle, summaryView.getRoot(), sd, commitMessage); |
495 |
if (l != null) { |
496 |
l.setReferenceComponent(revisionCell); |
497 |
|
498 |
linkerSupport.add(l, id); |
499 |
break; // got the first one |
500 |
} |
501 |
} |
502 |
} |
503 |
if (l != null) { |
504 |
l.insertString(sd, style); |
505 |
} else { |
506 |
sd.insertString(0, commitMessage, style); |
507 |
} |
508 |
|
509 |
{ |
510 |
//make the first line bold |
511 |
int lineEnd = sd.getText(0, sd.getLength()).indexOf("\n"); |
512 |
if (lineEnd == -1) { |
513 |
lineEnd = sd.getLength(); |
514 |
} |
515 |
Style s = pane.addStyle(null, style); |
516 |
StyleConstants.setBold(s, true); |
517 |
sd.setCharacterAttributes(0, lineEnd, s, false); |
518 |
} |
519 |
|
520 |
int msglen = commitMessage.length(); |
521 |
int doclen = sd.getLength(); |
522 |
|
523 |
// remove previous tooltips |
524 |
{ |
525 |
MessageTooltip mtt = linkerSupport.getLinker(MessageTooltip.class, id); |
526 |
linkerSupport.remove(mtt, id); |
527 |
} |
528 |
|
529 |
// insert message tooltip and expand link, only if the commit message has more than one line |
530 |
// AND if it is not fully visible |
531 |
if (nlc > 0 && !item.messageExpanded) { |
532 |
//insert expand link |
533 |
ExpandMsgHyperlink el = linkerSupport.getLinker(ExpandMsgHyperlink.class, id); |
534 |
if (el == null) { |
535 |
el = new ExpandMsgHyperlink(item, sd.getLength(), id); |
536 |
el.setReferenceComponent(revisionCell); |
537 |
linkerSupport.add(el, id); |
538 |
} |
539 |
el.insertString(sd, linkStyle); |
540 |
|
541 |
//insert commit message tooltip |
542 |
MessageTooltip messageTooltip = new MessageTooltip(entry.getMessage(), 0, sd.getLength()); |
543 |
messageTooltip.setReferenceComponent(revisionCell); |
544 |
linkerSupport.add(messageTooltip, id); |
545 |
} |
546 |
|
547 |
if (!selected) { |
548 |
for (SearchHighlight highlight : highlights) { |
549 |
if (highlight.getKind() == SearchHighlight.Kind.MESSAGE) { |
550 |
String highlightMessage = highlight.getSearchText(); |
551 |
int idx = commitMessage.toLowerCase().indexOf(highlightMessage); |
552 |
if (idx == -1) { |
553 |
if (nlc > 0 && !item.messageExpanded && entry.getMessage().toLowerCase().contains(highlightMessage)) { |
554 |
sd.setCharacterAttributes(doclen, sd.getLength(), hiliteStyle, false); |
555 |
} |
556 |
} else { |
557 |
sd.setCharacterAttributes(doclen - msglen + idx, highlightMessage.length(), hiliteStyle, false); |
558 |
} |
559 |
} |
560 |
} |
561 |
} |
562 |
if (selected) { |
563 |
sd.setCharacterAttributes(0, Integer.MAX_VALUE, style, false); |
564 |
} |
565 |
} |
566 |
|
567 |
private Style createNormalStyle (JTextPane textPane) { |
568 |
Style normalStyle = textPane.addStyle("normal", null); //NOI18N |
569 |
StyleConstants.setForeground(normalStyle, UIManager.getColor("List.foreground")); //NOI18N |
570 |
return normalStyle; |
571 |
} |
572 |
|
573 |
private Style createIssueHyperlinkStyle (JTextPane textPane, Style normalStyle) { |
574 |
Style issueHyperlinkStyle = textPane.addStyle("issuehyperlink", normalStyle); //NOI18N |
575 |
StyleConstants.setForeground(issueHyperlinkStyle, Color.BLUE); |
576 |
StyleConstants.setUnderline(issueHyperlinkStyle, true); |
577 |
return issueHyperlinkStyle; |
578 |
} |
579 |
|
580 |
private Style createAuthorStyle (JTextPane textPane, Style normalStyle) { |
581 |
Style authorStyle = textPane.addStyle("author", normalStyle); //NOI18N |
582 |
StyleConstants.setForeground(authorStyle, Color.BLUE); |
583 |
return authorStyle; |
584 |
} |
585 |
|
586 |
private Style createLinkStyle (JTextPane textPane, Style normalStyle) { |
587 |
Style linkStyle = textPane.addStyle("link", normalStyle); //NOI18N |
588 |
StyleConstants.setForeground(linkStyle, Color.BLUE); |
589 |
StyleConstants.setBold(linkStyle, true); |
590 |
return linkStyle; |
591 |
} |
592 |
|
593 |
private Style createNoindentStyle (JTextPane textPane) { |
594 |
Style noindentStyle = textPane.addStyle("noindent", null); //NOI18N |
595 |
StyleConstants.setLeftIndent(noindentStyle, 0); |
596 |
return noindentStyle; |
597 |
} |
598 |
|
599 |
private Style createSelectedStyle (JTextPane textPane) { |
600 |
Style selectedStyle = textPane.addStyle("selected", null); //NOI18N |
601 |
StyleConstants.setForeground(selectedStyle, selectionForeground); |
602 |
StyleConstants.setBackground(selectedStyle, selectionBackground); |
603 |
return selectedStyle; |
604 |
} |
605 |
|
606 |
private Style createHiliteStyleStyle (JTextPane textPane, Style normalStyle, AttributeSet searchHiliteAttrs) { |
607 |
Style hiliteStyle = textPane.addStyle("hilite", normalStyle); //NOI18N |
608 |
|
609 |
Color c = (Color) searchHiliteAttrs.getAttribute(StyleConstants.Background); |
610 |
if (c != null) { |
611 |
StyleConstants.setBackground(hiliteStyle, c); |
612 |
} |
613 |
c = (Color) searchHiliteAttrs.getAttribute(StyleConstants.Foreground); |
614 |
if (c != null) { |
615 |
StyleConstants.setForeground(hiliteStyle, c); |
616 |
} |
617 |
|
618 |
return hiliteStyle; |
619 |
} |
537 |
|
620 |
|
538 |
@Override |
621 |
@Override |
539 |
public void paint(Graphics g) { |
622 |
public void paint(Graphics g) { |
540 |
super.paint(g); |
623 |
super.paint(g); |
541 |
linkerSupport.computeBounds(textPane, id); |
624 |
linkerSupport.computeBounds(revisionCell.getCommitMessageControl(), id); |
|
|
625 |
|
542 |
ExpandLink link = linkerSupport.getLinker(ExpandLink.class, id); |
626 |
ExpandLink link = linkerSupport.getLinker(ExpandLink.class, id); |
543 |
if (link != null) { |
627 |
if (link != null) { |
|
|
628 |
|
544 |
link.computeBounds(expandButton); |
629 |
link.computeBounds(expandButton); |
545 |
} |
630 |
} |
546 |
} |
631 |
} |
|
|
632 |
|
633 |
private void clearSD (JTextPane pane, StyledDocument sd) { |
634 |
try { |
635 |
Style noindentStyle = createNoindentStyle(pane); |
636 |
|
637 |
sd.remove(0, sd.getLength()); |
638 |
sd.setParagraphAttributes(0, sd.getLength(), noindentStyle, false); |
639 |
} catch (BadLocationException ex) { |
640 |
Exceptions.printStackTrace(ex); |
641 |
} |
642 |
} |
547 |
} |
643 |
} |
548 |
|
644 |
|
549 |
private static class MessageTooltip extends VCSHyperlinkSupport.Hyperlink { |
645 |
private static class MessageTooltip extends VCSHyperlinkSupport.Hyperlink { |
Lines 551-556
Link Here
|
551 |
private final int start; |
647 |
private final int start; |
552 |
private final int end; |
648 |
private final int end; |
553 |
private final String text; |
649 |
private final String text; |
|
|
650 |
private RevisionItemCell referenceComponent; |
651 |
|
652 |
public void setReferenceComponent(RevisionItemCell referenceComponent) { |
653 |
this.referenceComponent = referenceComponent; |
654 |
} |
554 |
|
655 |
|
555 |
private MessageTooltip (String text, int start, int end) { |
656 |
private MessageTooltip (String text, int start, int end) { |
556 |
this.start = start; |
657 |
this.start = start; |
Lines 560-566
Link Here
|
560 |
|
661 |
|
561 |
@Override |
662 |
@Override |
562 |
public boolean mouseMoved (Point p, JComponent component) { |
663 |
public boolean mouseMoved (Point p, JComponent component) { |
563 |
if (bounds != null && component.getToolTipText() == null) { |
664 |
if (bounds != null /*&& component.getToolTipText() == null*/) { |
564 |
for (Rectangle b : bounds) { |
665 |
for (Rectangle b : bounds) { |
565 |
if (b.contains(p)) { |
666 |
if (b.contains(p)) { |
566 |
component.setToolTipText(text); |
667 |
component.setToolTipText(text); |
Lines 568-573
Link Here
|
568 |
} |
669 |
} |
569 |
} |
670 |
} |
570 |
} |
671 |
} |
|
|
672 |
component.setToolTipText(null); |
571 |
return false; |
673 |
return false; |
572 |
} |
674 |
} |
573 |
|
675 |
|
Lines 578-583
Link Here
|
578 |
|
680 |
|
579 |
@Override |
681 |
@Override |
580 |
public void computeBounds (JTextPane textPane) { |
682 |
public void computeBounds (JTextPane textPane) { |
|
|
683 |
if (null != referenceComponent) { |
684 |
textPane = referenceComponent.getCommitMessageControl(); |
685 |
} |
581 |
Rectangle tpBounds = textPane.getBounds(); |
686 |
Rectangle tpBounds = textPane.getBounds(); |
582 |
TextUI tui = textPane.getUI(); |
687 |
TextUI tui = textPane.getUI(); |
583 |
try { |
688 |
try { |
Lines 588-593
Link Here
|
588 |
for (int pos = start; pos <= end; ++pos) { |
693 |
for (int pos = start; pos <= end; ++pos) { |
589 |
Rectangle startr = tui.modelToView(textPane, pos, Position.Bias.Forward); |
694 |
Rectangle startr = tui.modelToView(textPane, pos, Position.Bias.Forward); |
590 |
Rectangle endr = tui.modelToView(textPane, pos + 1, Position.Bias.Backward); |
695 |
Rectangle endr = tui.modelToView(textPane, pos + 1, Position.Bias.Backward); |
|
|
696 |
//prevent NPE if width is too small |
697 |
if (null == startr) {continue;} |
698 |
if (null == endr) {continue;} |
591 |
if (startr.y > lastY) { |
699 |
if (startr.y > lastY) { |
592 |
rects.add(rec); |
700 |
rects.add(rec); |
593 |
rec = new Rectangle(tpBounds.x + startr.x, startr.y, endr.x - startr.x, startr.height); |
701 |
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); |
704 |
rec.setSize(rec.width + endr.x - startr.x, rec.height); |
597 |
} |
705 |
} |
598 |
} |
706 |
} |
|
|
707 |
// NOTE the textPane is positioned within a parent panel so the relative bound has to be modified too |
708 |
// FIXME this is an ugly hack because the public API of org.netbeans.modules.versioning.util.VCSHyperlinkSupport should stay stable |
709 |
// SOLUTION: provide a reference component which is injected via setter and |
710 |
// translate from bottom to top of the component hiearchy |
711 |
if (null != referenceComponent){ |
712 |
referenceComponent.correctTranslation(textPane, rec); |
713 |
} |
599 |
rects.add(rec); |
714 |
rects.add(rec); |
600 |
rects.remove(0); |
715 |
rects.remove(0); |
601 |
bounds = rects.toArray(new Rectangle[rects.size()]); |
716 |
bounds = rects.toArray(new Rectangle[rects.size()]); |
Lines 1000-1012
Link Here
|
1000 |
} |
1115 |
} |
1001 |
} |
1116 |
} |
1002 |
|
1117 |
|
1003 |
private static final String LINK_STRING = "..."; //NOI18N |
1118 |
private static final String LINK_STRING = " ..."; //NOI18N |
1004 |
private static final int LINK_STRING_LEN = LINK_STRING.length(); |
1119 |
private static final int LINK_STRING_LEN = LINK_STRING.length(); |
1005 |
private class ExpandMsgHyperlink extends VCSHyperlinkSupport.StyledDocumentHyperlink { |
1120 |
private class ExpandMsgHyperlink extends VCSHyperlinkSupport.StyledDocumentHyperlink { |
1006 |
private Rectangle bounds; |
1121 |
private Rectangle bounds; |
1007 |
private final int startoffset; |
1122 |
private final int startoffset; |
1008 |
private final AbstractSummaryView.RevisionItem item; |
1123 |
private final AbstractSummaryView.RevisionItem item; |
1009 |
private final String revision; |
1124 |
private final String revision; |
|
|
1125 |
private RevisionItemCell referenceComponent; |
1126 |
|
1127 |
public void setReferenceComponent (RevisionItemCell referenceComponent) { |
1128 |
this.referenceComponent = referenceComponent; |
1129 |
} |
1010 |
|
1130 |
|
1011 |
public ExpandMsgHyperlink (AbstractSummaryView.RevisionItem item, int startoffset, String revision) { |
1131 |
public ExpandMsgHyperlink (AbstractSummaryView.RevisionItem item, int startoffset, String revision) { |
1012 |
this.startoffset = startoffset; |
1132 |
this.startoffset = startoffset; |
Lines 1037-1042
Link Here
|
1037 |
|
1157 |
|
1038 |
@Override |
1158 |
@Override |
1039 |
public void computeBounds(JTextPane textPane) { |
1159 |
public void computeBounds(JTextPane textPane) { |
|
|
1160 |
if (null != referenceComponent) { |
1161 |
textPane=referenceComponent.getCommitMessageControl(); |
1162 |
} |
1040 |
Rectangle tpBounds = textPane.getBounds(); |
1163 |
Rectangle tpBounds = textPane.getBounds(); |
1041 |
TextUI tui = textPane.getUI(); |
1164 |
TextUI tui = textPane.getUI(); |
1042 |
bounds = new Rectangle(); |
1165 |
bounds = new Rectangle(); |
Lines 1049-1054
Link Here
|
1049 |
Rectangle endr = mtv.getBounds(); |
1172 |
Rectangle endr = mtv.getBounds(); |
1050 |
|
1173 |
|
1051 |
bounds = new Rectangle(tpBounds.x + startr.x, startr.y, endr.x - startr.x, startr.height); |
1174 |
bounds = new Rectangle(tpBounds.x + startr.x, startr.y, endr.x - startr.x, startr.height); |
|
|
1175 |
if (null != referenceComponent) { |
1176 |
referenceComponent.correctTranslation(textPane, bounds); |
1177 |
} |
1052 |
} catch (BadLocationException ex) { |
1178 |
} catch (BadLocationException ex) { |
1053 |
throw new RuntimeException(ex); |
1179 |
throw new RuntimeException(ex); |
1054 |
} |
1180 |
} |