001package com.ganteater.ae.desktop.view; 002 003import java.awt.BorderLayout; 004import java.awt.Color; 005import java.awt.Desktop; 006import java.awt.FileDialog; 007import java.awt.Font; 008import java.awt.event.ActionEvent; 009import java.awt.event.ActionListener; 010import java.awt.event.ComponentAdapter; 011import java.awt.event.ComponentEvent; 012import java.awt.event.KeyAdapter; 013import java.awt.event.KeyEvent; 014import java.awt.event.MouseAdapter; 015import java.awt.event.MouseEvent; 016import java.io.File; 017import java.io.FileOutputStream; 018import java.io.IOException; 019import java.io.PrintWriter; 020import java.io.StringReader; 021import java.io.StringWriter; 022import java.io.UnsupportedEncodingException; 023import java.net.URI; 024import java.net.URISyntaxException; 025import java.net.URL; 026import java.util.ArrayList; 027import java.util.List; 028import java.util.Map; 029import java.util.Set; 030 031import javax.swing.AbstractButton; 032import javax.swing.BorderFactory; 033import javax.swing.JButton; 034import javax.swing.JComboBox; 035import javax.swing.JComponent; 036import javax.swing.JOptionPane; 037import javax.swing.JPanel; 038import javax.swing.JScrollPane; 039import javax.swing.JTextArea; 040import javax.swing.JTextField; 041import javax.swing.ScrollPaneConstants; 042import javax.swing.SwingUtilities; 043import javax.swing.border.BevelBorder; 044import javax.swing.text.BadLocationException; 045import javax.swing.text.DefaultCaret; 046import javax.swing.text.Utilities; 047import javax.xml.XMLConstants; 048import javax.xml.transform.OutputKeys; 049import javax.xml.transform.Source; 050import javax.xml.transform.Transformer; 051import javax.xml.transform.TransformerFactory; 052import javax.xml.transform.stream.StreamResult; 053import javax.xml.transform.stream.StreamSource; 054 055import org.apache.commons.io.IOUtils; 056import org.apache.commons.lang.ArrayUtils; 057import org.apache.commons.lang.ObjectUtils; 058import org.apache.commons.lang.StringEscapeUtils; 059import org.apache.commons.lang.StringUtils; 060import org.apache.http.NameValuePair; 061import org.apache.http.client.utils.URLEncodedUtils; 062import org.apache.sling.commons.json.JSONObject; 063 064import com.ganteater.ae.desktop.editor.TaskEditor; 065import com.ganteater.ae.desktop.ui.AEFrame; 066import com.ganteater.ae.desktop.ui.TextPrompt; 067import com.ganteater.ae.desktop.view.ListLogPresenter.LogRecord; 068import com.ganteater.ae.processor.Processor; 069import com.ganteater.ae.util.AEUtils; 070 071public class TextLogPresenter extends LogPresenter { 072 073 private static final long serialVersionUID = 1L; 074 075 private static final int MAX_FORMAT_LENGTH = 10240; 076 077 private JTextArea fLogTextArea; 078 079 private JPanel toolBar = new JPanel(new BorderLayout()); 080 private JTextField statusLineLable = new JTextField(""); 081 private JButton emailMaskButton = new JButton(AEFrame.getIcon("email-mask.png")); 082 private JScrollPane fLogScrollPanel; 083 084 private List<String> supportedTypes = new ArrayList<>(); 085 { 086 supportedTypes.add("txt"); 087 supportedTypes.add("html"); 088 supportedTypes.add("xml"); 089 supportedTypes.add("json"); 090 supportedTypes.add("~json"); 091 supportedTypes.add("url"); 092 supportedTypes.add("path"); 093 supportedTypes.add("uri"); 094 supportedTypes.add("csv"); 095 } 096 097 private JTextField fFindText = new JTextField(12); 098 099 JButton formatButton = new JButton(AEFrame.getIcon("format.png")); 100 101 private Processor processor; 102 103 private FileDialog fileDialog; 104 105 private JComboBox<String> propertiesNames = new JComboBox<String>(); 106 107 private JComboBox<String> typeBox = new JComboBox<>(supportedTypes.toArray(new String[supportedTypes.size()])); 108 109 private Object originData; 110 111 public TextLogPresenter(TaskEditor aTaskEditor, String aName) { 112 super(aName, aTaskEditor.getConfigNode()); 113 114 fLogTextArea = new JTextArea(); 115 DefaultCaret c = new DefaultCaret() { 116 @Override 117 public void setSelectionVisible(boolean visible) { 118 super.setSelectionVisible(true); 119 } 120 }; 121 fLogTextArea.setCaret(c); 122 123 fLogTextArea.setFont(new Font("Courier New", Font.PLAIN, 12)); 124 fLogTextArea.setEditable(true); 125 fLogTextArea.addKeyListener(new KeyAdapter() { 126 @Override 127 public void keyTyped(KeyEvent e) { 128 printStatusLine(); 129 } 130 }); 131 132 fLogTextArea.addMouseListener(new MouseAdapter() { 133 @Override 134 public void mouseReleased(MouseEvent e) { 135 printStatusLine(); 136 } 137 }); 138 139 fLogTextArea.addComponentListener(new ComponentAdapter() { 140 @Override 141 public void componentResized(ComponentEvent e) { 142 if (fLogTextArea.getLineWrap()) { 143 printStatusLine(); 144 } 145 } 146 }); 147 148 fLogScrollPanel = new JScrollPane(); 149 fLogScrollPanel.getViewport().add(fLogTextArea); 150 151 add(fLogScrollPanel, BorderLayout.CENTER); 152 153 formatButton.setToolTipText("Pretty print"); 154 155 JPanel bar = new JPanel(); 156 formatButton.addActionListener(new ActionListener() { 157 public void actionPerformed(ActionEvent e) { 158 format(); 159 } 160 }); 161 162 bar.add(propertiesNames); 163 bar.add(typeBox); 164 bar.add(formatButton); 165 166 JButton button = new JButton(AEFrame.getIcon("placeholder.png")); 167 button.setToolTipText("Placeholder parsing"); 168 169 button.addActionListener(new ActionListener() { 170 public void actionPerformed(ActionEvent e) { 171 String text = fLogTextArea.getText(); 172 try { 173 int caretPosition = fLogTextArea.getCaretPosition(); 174 String replaceProperties = processor.replaceProperties(text); 175 replaceProperties = replaceProperties.replaceAll("<br/>", "\n"); 176 // replaceProperties = 177 // EasyParser.replaseReferense(replaceProperties); 178 setText(replaceProperties); 179 printStatusLine(); 180 fLogTextArea.setCaretPosition(0); 181 if (caretPosition < replaceProperties.length()) 182 fLogTextArea.setCaretPosition(caretPosition); 183 } catch (Exception e1) { 184 e1.printStackTrace(); 185 JOptionPane.showMessageDialog(JOptionPane.getFrameForComponent(TextLogPresenter.this), 186 "$...{} replacer failed."); 187 } 188 } 189 }); 190 191 propertiesNames.addActionListener(new ActionListener() { 192 public void actionPerformed(ActionEvent e) { 193 print(); 194 } 195 }); 196 197 bar.add(button); 198 199 button = new JButton(AEFrame.getIcon("open.png")); 200 button.setToolTipText("Open in defaulf editor"); 201 202 button.addActionListener(new ActionListener() { 203 public void actionPerformed(ActionEvent e) { 204 try { 205 String selectedItem = (String) typeBox.getSelectedItem(); 206 String text = fLogTextArea.getText(); 207 openFile(text, selectedItem); 208 } catch (IOException e1) { 209 JOptionPane.showMessageDialog(JOptionPane.getFrameForComponent(TextLogPresenter.this), 210 "File opening failed."); 211 } 212 } 213 214 }); 215 bar.add(button); 216 217 button = new JButton(AEFrame.getIcon("save.png")); 218 button.setToolTipText("Save to file"); 219 220 button.addActionListener(new ActionListener() { 221 public void actionPerformed(ActionEvent e) { 222 saveToFile(); 223 } 224 }); 225 bar.add(button); 226 227 emailMaskButton.setToolTipText("Masking"); 228 emailMaskButton.setVisible(log.isFilterEnabled()); 229 230 emailMaskButton.addActionListener(new ActionListener() { 231 public void actionPerformed(ActionEvent e) { 232 String text = fLogTextArea.getText(); 233 String maskedText = log.filter(text); 234 setText(maskedText); 235 printStatusLine(); 236 fLogTextArea.setCaretPosition(0); 237 } 238 }); 239 bar.add(emailMaskButton); 240 241 button = new JButton(AEFrame.getIcon("unescape.png")); 242 button.setToolTipText("Unescape"); 243 244 button.addActionListener(new ActionListener() { 245 public void actionPerformed(ActionEvent e) { 246 String text = fLogTextArea.getText(); 247 text = StringEscapeUtils.unescapeXml(text).trim(); 248 text = text.replace("\\n", "\n"); 249 text = text.replace("\\r", "\r"); 250 text = text.replace("\\\"", "\""); 251 setText(text); 252 } 253 254 }); 255 bar.add(button); 256 257 bar.add(fFindText); 258 new TextPrompt("Search", fFindText); 259 260 fFindText.addKeyListener(new KeyAdapter() { 261 @Override 262 public void keyPressed(KeyEvent e) { 263 switch (e.getKeyChar()) { 264 case KeyEvent.VK_ESCAPE: 265 fFindText.setText(""); 266 break; 267 268 case KeyEvent.VK_ENTER: 269 findText(); 270 } 271 } 272 }); 273 274 add(toolBar, BorderLayout.NORTH); 275 276 statusLineLable.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED)); 277 statusLineLable.setEditable(false); 278 add(statusLineLable, BorderLayout.SOUTH); 279 280 fLogTextArea.setEditable(true); 281 282 toolBar.add(bar, BorderLayout.WEST); 283 } 284 285 public void saveToFile() { 286 try { 287 String text = fLogTextArea.getText(); 288 289 text = filter(text); 290 291 if (fileDialog == null) 292 fileDialog = new FileDialog(JOptionPane.getRootFrame(), "Save log record.", FileDialog.SAVE); 293 294 String type = getType(); 295 if (StringUtils.startsWith(type, "~")) { 296 type = StringUtils.substringAfter(type, "~"); 297 } 298 299 String fileName = StringUtils.defaultString(super.getName()); 300 301 if (StringUtils.isNotEmpty(type)) { 302 fileName = fileName + "." + StringUtils.defaultString(type, "txt"); 303 } 304 305 fileDialog.setFile(fileName); 306 fileDialog.setVisible(true); 307 if (fileDialog.getFile() != null) { 308 File theFile = new File(fileDialog.getDirectory(), fileDialog.getFile()); 309 FileOutputStream theFileOutputStream = new FileOutputStream(theFile); 310 theFileOutputStream.write(text.getBytes("UTF-8")); 311 theFileOutputStream.close(); 312 } 313 } catch (Exception e1) { 314 e1.printStackTrace(); 315 JOptionPane.showMessageDialog(JOptionPane.getFrameForComponent(this), "File is not saved."); 316 } 317 } 318 319 protected void printStatusLine() { 320 321 String text = fLogTextArea.getText(); 322 formatButton.setEnabled(text.length() < MAX_FORMAT_LENGTH); 323 int count = countLines(text); 324 325 if (fLogTextArea.getLineWrap() && text.length() < 100000) { 326 int totalCharacters = fLogTextArea.getText().length(); 327 count = (totalCharacters == 0) ? 1 : 0; 328 329 try { 330 int offset = totalCharacters; 331 while (offset > 0) { 332 offset = Utilities.getRowStart(fLogTextArea, offset) - 1; 333 count++; 334 } 335 } catch (BadLocationException e) { 336 e.printStackTrace(); 337 } 338 339 statusLineLable.setText("Lines: " + count + " (Wrapped)"); 340 341 } else { 342 int selectedCount = 0; 343 String selectedText = fLogTextArea.getSelectedText(); 344 if (selectedText != null) { 345 selectedCount = countLines(selectedText); 346 } 347 348 statusLineLable 349 .setText("Lines: " + count + (selectedCount > 0 ? "; Selected lines: " + selectedCount : "")); 350 } 351 } 352 353 private int countLines(String text) { 354 char someChar = '\n'; 355 int count = 0; 356 357 if (text != null) { 358 if (text.length() > 0) { 359 count = 1; 360 } 361 362 for (int i = 0; i < text.length(); i++) { 363 if (text.charAt(i) == someChar) { 364 count++; 365 } 366 } 367 } 368 return count; 369 } 370 371 public void info(Object o, Processor processor) { 372 this.processor = processor; 373 setType(o); 374 appendText(o); 375 } 376 377 public void format() { 378 SwingUtilities.invokeLater(() -> { 379 String text = fLogTextArea.getText(); 380 if (text.length() < MAX_FORMAT_LENGTH) { 381 382 String type = StringUtils.upperCase(getType()); 383 384 switch (type) { 385 case "XML": 386 xmlPrettyPrint(text); 387 break; 388 389 case "JSON": 390 try { 391 String jsonBody = StringUtils.trim(text); 392 setText(new JSONObject(jsonBody).toString(4)); 393 printStatusLine(); 394 fLogTextArea.setCaretPosition(0); 395 396 } catch (Exception e1) { 397 setText(text); 398 printStatusLine(); 399 fLogTextArea.setCaretPosition(0); 400 JOptionPane.showMessageDialog(JOptionPane.getFrameForComponent(this), "JSON formating failed."); 401 } 402 break; 403 404 case "~JSON": 405 try { 406 setText(AEUtils.format(text)); 407 printStatusLine(); 408 fLogTextArea.setCaretPosition(0); 409 } catch (Exception e1) { 410 setText(text); 411 printStatusLine(); 412 fLogTextArea.setCaretPosition(0); 413 JOptionPane.showMessageDialog(JOptionPane.getFrameForComponent(this), "JSON formating failed."); 414 } 415 break; 416 417 case "URL": 418 try { 419 StringBuilder formatedText = new StringBuilder(); 420 String trim = text.replace(" ", ""); 421 trim = trim.replace("\n", ""); 422 URL url = new URL(trim); 423 formatedText.append(url.getProtocol() + "://"); 424 formatedText.append(url.getHost()); 425 if (url.getPort() > 0) 426 formatedText.append(":" + url.getPort()); 427 formatedText.append(url.getPath()); 428 429 List<NameValuePair> parse = URLEncodedUtils.parse(url.toURI(), "UTF-8"); 430 if (parse.size() > 0) { 431 formatedText.append("\n"); 432 String delim = "?"; 433 for (NameValuePair nameValuePair : parse) { 434 formatedText.append( 435 delim + nameValuePair.getName() + "=" + nameValuePair.getValue() + "\n"); 436 delim = "&"; 437 } 438 } 439 setText(formatedText.toString()); 440 printStatusLine(); 441 fLogTextArea.setCaretPosition(0); 442 } catch (Exception e1) { 443 JOptionPane.showMessageDialog(JOptionPane.getFrameForComponent(this), 444 "URI transformation failed.\n" + e1.getMessage()); 445 } 446 break; 447 448 case "TXT": 449 if (fLogTextArea.getText().length() < MAX_FORMAT_LENGTH) { 450 boolean wrap = !fLogTextArea.getLineWrap(); 451 fLogScrollPanel 452 .setHorizontalScrollBarPolicy(wrap ? ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER 453 : ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); 454 455 fLogTextArea.setLineWrap(wrap); 456 } else { 457 fLogTextArea.setLineWrap(false); 458 } 459 break; 460 461 } 462 } 463 printStatusLine(); 464 }); 465 } 466 467 private void xmlPrettyPrint(String text) { 468 try { 469 Source xmlInput = new StreamSource(new StringReader(text)); 470 StringWriter stringWriter = new StringWriter(); 471 StreamResult xmlOutput = new StreamResult(stringWriter); 472 TransformerFactory transformerFactory = TransformerFactory.newInstance(); 473 transformerFactory.setAttribute("indent-number", 2); 474 transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); 475 transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); 476 Transformer transformer = transformerFactory.newTransformer(); 477 transformer.setOutputProperty(OutputKeys.INDENT, "yes"); 478 transformer.transform(xmlInput, xmlOutput); 479 480 setText(xmlOutput.getWriter().toString()); 481 printStatusLine(); 482 fLogTextArea.setCaretPosition(0); 483 484 } catch (Exception e1) { 485 setText(text); 486 printStatusLine(); 487 fLogTextArea.setCaretPosition(0); 488 JOptionPane.showMessageDialog(JOptionPane.getFrameForComponent(this), "XML formating failed."); 489 } 490 } 491 492 private void setText(String text) { 493 String trim = text.trim(); 494 fLogTextArea.setText(trim); 495 } 496 497 protected void setType(Object o) { 498 String type = StringUtils.defaultString(((LogRecord) o).getType(), "txt"); 499 500 if (o instanceof LogRecord) { 501 if (((LogRecord) o).getMessage() instanceof String) { 502 503 if (StringUtils.startsWith((String) ((LogRecord) o).getMessage(), "<?xml")) { 504 type = "xml"; 505 } 506 507 type = StringUtils.defaultString(type, supportedTypes.get(0)); 508 if (!supportedTypes.contains(type.toLowerCase())) { 509 supportedTypes.add(type); 510 this.typeBox.addItem(type); 511 } 512 this.typeBox.setSelectedItem(type); 513 514 } else if (StringUtils.isNotBlank(type)) { 515 if (StringUtils.startsWith(ObjectUtils.toString(o), "<?xml")) { 516 type = "xml"; 517 this.typeBox.setSelectedItem(type); 518 } else { 519 this.typeBox.setSelectedItem(type); 520 if (!StringUtils.equals(this.typeBox.getSelectedItem().toString(), type)) { 521 this.typeBox.addItem(type); 522 } 523 this.typeBox.setSelectedItem(type); 524 } 525 } 526 } 527 } 528 529 private void setPropertiesList(Set keySet) { 530 for (Object object : keySet) { 531 String key = (String) object; 532 if (StringUtils.isNotBlank(key)) { 533 propertiesNames.addItem(key); 534 } 535 } 536 propertiesNames.setVisible(true); 537 } 538 539 private void cleanPropertiesList() { 540 propertiesNames.removeAllItems(); 541 propertiesNames.setVisible(false); 542 } 543 544 @Override 545 public Object debug(Object o) { 546 setType(o); 547 if (o instanceof Throwable) { 548 StringWriter theStringWriter = new StringWriter(); 549 ((Throwable) o).printStackTrace(new PrintWriter(theStringWriter)); 550 appendText(theStringWriter.toString()); 551 } else { 552 appendText(o); 553 } 554 return o; 555 } 556 557 @Override 558 public Object debug(Object o, Throwable aThrowable) { 559 print(o, aThrowable); 560 return o; 561 } 562 563 private void print(Object o, Throwable aThrowable) { 564 setType(o); 565 appendText(o); 566 567 if (aThrowable != null) { 568 StringWriter theStringWriter = new StringWriter(); 569 aThrowable.printStackTrace(new PrintWriter(theStringWriter)); 570 appendText(theStringWriter.toString()); 571 } 572 } 573 574 @Override 575 public Object error(Object o) { 576 print(o, null); 577 return o; 578 } 579 580 @Override 581 public Object error(Object o, Throwable aThrowable) { 582 print(o, aThrowable); 583 return o; 584 } 585 586 public Object warn(Object o) { 587 print(o, null); 588 return o; 589 } 590 591 private void appendText(Object o) { 592 this.originData = o; 593 cleanPropertiesList(); 594 595 LogRecord record = (LogRecord) o; 596 String type = record.getType(); 597 598 Object message = record.getMessage(); 599 if (message instanceof Map && !"json".equals(type)) { 600 Map propertiesData = (Map) ((LogRecord) o).getMessage(); 601 setPropertiesList(propertiesData.keySet()); 602 } 603 604 print(); 605 } 606 607 private void print() { 608 if (originData instanceof LogRecord) { 609 LogRecord rec = (LogRecord) originData; 610 Object data = rec.getMessage(); 611 612 String type = getType(); 613 if (data instanceof Map && "map".equals(type)) { 614 data = ((Map) data).get(propertiesNames.getSelectedItem()); 615 } 616 617 String text; 618 619 if (data instanceof byte[]) { 620 try { 621 text = new String((byte[]) data, "UTF-8"); 622 } catch (UnsupportedEncodingException e) { 623 throw new IllegalArgumentException(e); 624 } 625 } else if (data != null && data.getClass().isArray()) { 626 Object[] array = (Object[]) data; 627 text = ArrayUtils.toString(array); 628 629 } else if (data != null && data instanceof List) { 630 text = StringUtils.join((List) data, "\n"); 631 632 } else if ("json".equals(type)) { 633 if (data instanceof Map) { 634 text = new JSONObject((Map) data).toString(); 635 } else { 636 text = ObjectUtils.toString(data, "<null>"); 637 } 638 } else { 639 text = ObjectUtils.toString(data, "<null>"); 640 } 641 642 setText(text); 643 644 } else { 645 646 setText(ObjectUtils.toString(originData)); 647 } 648 649 fLogTextArea.setCaretPosition(0); 650 printStatusLine(); 651 } 652 653 public String getType() { 654 return (String) TextLogPresenter.this.typeBox.getSelectedItem(); 655 } 656 657 public void warn(Object o, Throwable aThrowable) { 658 print(o, aThrowable); 659 } 660 661 public void findText() { 662 String text = fFindText.getText(); 663 String content = fLogTextArea.getText(); 664 int caretPosition = fLogTextArea.getCaretPosition(); 665 666 int indexOf = StringUtils.indexOfIgnoreCase(content, text, caretPosition); 667 if (indexOf >= 0) { 668 fLogTextArea.setSelectionStart(indexOf); 669 int selectionEnd = indexOf + text.length(); 670 fLogTextArea.setSelectionEnd(selectionEnd); 671 672 } else { 673 caretPosition = 0; 674 indexOf = StringUtils.indexOfIgnoreCase(content, text, caretPosition); 675 676 if (indexOf >= 0) { 677 fLogTextArea.setSelectionStart(indexOf); 678 int selectionEnd = indexOf + text.length(); 679 fLogTextArea.setSelectionEnd(selectionEnd); 680 681 } else { 682 JOptionPane.showMessageDialog(JOptionPane.getFrameForComponent(this), 683 "Text: \"" + text + "\" is not found."); 684 } 685 } 686 687 } 688 689 public void setEnabled(boolean enabled) { 690 if (enabled == false) 691 fLogTextArea.setBackground(Color.lightGray); 692 else 693 fLogTextArea.setBackground(Color.white); 694 } 695 696 public void clear() { 697 setText(""); 698 printStatusLine(); 699 } 700 701 public JComponent getLogTextArea() { 702 return fLogTextArea; 703 } 704 705 public static void openFile(Object originData, String type) throws IOException { 706 707 switch (StringUtils.upperCase(StringUtils.defaultString(type, "txt"))) { 708 case "URL": 709 try { 710 String string = ObjectUtils.toString(originData, ""); 711 URL url = new URL(string); 712 URI uri = url.toURI(); 713 openWebpage(uri); 714 } catch (URISyntaxException e) { 715 new IOException(e); 716 } 717 break; 718 719 case "URI": 720 try { 721 openWebpage(new URI(ObjectUtils.toString(originData, ""))); 722 } catch (URISyntaxException e) { 723 new IOException(e); 724 } 725 break; 726 727 case "PATH": 728 Desktop.getDesktop().open(new File(ObjectUtils.toString(originData, "").trim())); 729 break; 730 731 default: 732 if (StringUtils.startsWith(type, "~")) { 733 type = StringUtils.substringAfter(type, "~"); 734 } 735 File file = File.createTempFile("anteater", "." + StringUtils.defaultString(type, "txt")); 736 byte[] data; 737 if (originData instanceof LogRecord) { 738 Object logdata = ((LogRecord) originData).getMessage(); 739 if (logdata instanceof byte[]) { 740 data = (byte[]) logdata; 741 } else { 742 data = ((LogRecord) originData).toString().getBytes(); 743 } 744 } else { 745 data = ObjectUtils.toString(originData).getBytes(); 746 } 747 748 FileOutputStream output = new FileOutputStream(file); 749 IOUtils.write(data, output); 750 output.flush(); 751 Desktop.getDesktop().open(file); 752 output.close(); 753 } 754 } 755 756 public static void openWebpage(URI uri) { 757 Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null; 758 if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) { 759 try { 760 desktop.browse(uri); 761 } catch (Exception e) { 762 e.printStackTrace(); 763 } 764 } 765 } 766 767 public void addButton(AbstractButton onTop) { 768 toolBar.add(onTop, BorderLayout.EAST); 769 } 770 771 @Override 772 public LogPresenter copyAndClean() { 773 return null; 774 } 775 776 @Override 777 public boolean isFilterEnabled() { 778 return log.isFilterEnabled(); 779 } 780 781 @Override 782 public String filter(Object message) { 783 return log.filter(message); 784 } 785}