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 fLogTextArea.setText(text); 494 } 495 496 protected void setType(Object o) { 497 String type = StringUtils.defaultString(((LogRecord) o).getType(), "txt"); 498 499 if (o instanceof LogRecord) { 500 if (((LogRecord) o).getMessage() instanceof String) { 501 502 if (StringUtils.startsWith((String) ((LogRecord) o).getMessage(), "<?xml")) { 503 type = "xml"; 504 } 505 506 type = StringUtils.defaultString(type, supportedTypes.get(0)); 507 if (!supportedTypes.contains(type.toLowerCase())) { 508 supportedTypes.add(type); 509 this.typeBox.addItem(type); 510 } 511 this.typeBox.setSelectedItem(type); 512 513 } else if (StringUtils.isNotBlank(type)) { 514 if (StringUtils.startsWith(ObjectUtils.toString(o), "<?xml")) { 515 type = "xml"; 516 this.typeBox.setSelectedItem(type); 517 } else { 518 this.typeBox.setSelectedItem(type); 519 if (!StringUtils.equals(this.typeBox.getSelectedItem().toString(), type)) { 520 this.typeBox.addItem(type); 521 } 522 this.typeBox.setSelectedItem(type); 523 } 524 } 525 } 526 } 527 528 private void setPropertiesList(Set keySet) { 529 for (Object object : keySet) { 530 String key = (String) object; 531 if (StringUtils.isNotBlank(key)) { 532 propertiesNames.addItem(key); 533 } 534 } 535 propertiesNames.setVisible(true); 536 } 537 538 private void cleanPropertiesList() { 539 propertiesNames.removeAllItems(); 540 propertiesNames.setVisible(false); 541 } 542 543 @Override 544 public Object debug(Object o) { 545 setType(o); 546 if (o instanceof Throwable) { 547 StringWriter theStringWriter = new StringWriter(); 548 ((Throwable) o).printStackTrace(new PrintWriter(theStringWriter)); 549 appendText(theStringWriter.toString()); 550 } else { 551 appendText(o); 552 } 553 return o; 554 } 555 556 @Override 557 public Object debug(Object o, Throwable aThrowable) { 558 print(o, aThrowable); 559 return o; 560 } 561 562 private void print(Object o, Throwable aThrowable) { 563 setType(o); 564 appendText(o); 565 566 if (aThrowable != null) { 567 StringWriter theStringWriter = new StringWriter(); 568 aThrowable.printStackTrace(new PrintWriter(theStringWriter)); 569 appendText(theStringWriter.toString()); 570 } 571 } 572 573 @Override 574 public Object error(Object o) { 575 print(o, null); 576 return o; 577 } 578 579 @Override 580 public Object error(Object o, Throwable aThrowable) { 581 print(o, aThrowable); 582 return o; 583 } 584 585 public Object warn(Object o) { 586 print(o, null); 587 return o; 588 } 589 590 private void appendText(Object o) { 591 this.originData = o; 592 cleanPropertiesList(); 593 594 LogRecord record = (LogRecord) o; 595 String type = record.getType(); 596 597 Object message = record.getMessage(); 598 if (message instanceof Map && !"json".equals(type)) { 599 Map propertiesData = (Map) ((LogRecord) o).getMessage(); 600 setPropertiesList(propertiesData.keySet()); 601 } 602 603 print(); 604 } 605 606 private void print() { 607 if (originData instanceof LogRecord) { 608 LogRecord rec = (LogRecord) originData; 609 Object data = rec.getMessage(); 610 611 String type = getType(); 612 if (data instanceof Map && "map".equals(type)) { 613 data = ((Map) data).get(propertiesNames.getSelectedItem()); 614 } 615 616 String text; 617 618 if (data instanceof byte[]) { 619 try { 620 text = new String((byte[]) data, "UTF-8"); 621 } catch (UnsupportedEncodingException e) { 622 throw new IllegalArgumentException(e); 623 } 624 } else if (data != null && data.getClass().isArray()) { 625 Object[] array = (Object[]) data; 626 text = ArrayUtils.toString(array); 627 628 } else if (data != null && data instanceof List) { 629 text = StringUtils.join((List) data, "\n"); 630 631 } else if ("json".equals(type)) { 632 if (data instanceof Map) { 633 text = new JSONObject((Map) data).toString(); 634 } else { 635 text = ObjectUtils.toString(data, "<null>"); 636 } 637 } else { 638 text = ObjectUtils.toString(data, "<null>"); 639 } 640 641 setText(text); 642 643 } else { 644 645 setText(ObjectUtils.toString(originData)); 646 } 647 648 fLogTextArea.setCaretPosition(0); 649 printStatusLine(); 650 } 651 652 public String getType() { 653 return (String) TextLogPresenter.this.typeBox.getSelectedItem(); 654 } 655 656 public void warn(Object o, Throwable aThrowable) { 657 print(o, aThrowable); 658 } 659 660 public void findText() { 661 String text = fFindText.getText(); 662 String content = fLogTextArea.getText(); 663 int caretPosition = fLogTextArea.getCaretPosition(); 664 665 int indexOf = StringUtils.indexOfIgnoreCase(content, text, caretPosition); 666 if (indexOf >= 0) { 667 fLogTextArea.setSelectionStart(indexOf); 668 int selectionEnd = indexOf + text.length(); 669 fLogTextArea.setSelectionEnd(selectionEnd); 670 671 } else { 672 caretPosition = 0; 673 indexOf = StringUtils.indexOfIgnoreCase(content, text, caretPosition); 674 675 if (indexOf >= 0) { 676 fLogTextArea.setSelectionStart(indexOf); 677 int selectionEnd = indexOf + text.length(); 678 fLogTextArea.setSelectionEnd(selectionEnd); 679 680 } else { 681 JOptionPane.showMessageDialog(JOptionPane.getFrameForComponent(this), 682 "Text: \"" + text + "\" is not found."); 683 } 684 } 685 686 } 687 688 public void setEnabled(boolean enabled) { 689 if (enabled == false) 690 fLogTextArea.setBackground(Color.lightGray); 691 else 692 fLogTextArea.setBackground(Color.white); 693 } 694 695 public void clear() { 696 setText(""); 697 printStatusLine(); 698 } 699 700 public JComponent getLogTextArea() { 701 return fLogTextArea; 702 } 703 704 public static void openFile(Object originData, String type) throws IOException { 705 706 switch (StringUtils.upperCase(StringUtils.defaultString(type, "txt"))) { 707 case "URL": 708 try { 709 String string = ObjectUtils.toString(originData, ""); 710 URL url = new URL(string); 711 URI uri = url.toURI(); 712 openWebpage(uri); 713 } catch (URISyntaxException e) { 714 new IOException(e); 715 } 716 break; 717 718 case "URI": 719 try { 720 openWebpage(new URI(ObjectUtils.toString(originData, ""))); 721 } catch (URISyntaxException e) { 722 new IOException(e); 723 } 724 break; 725 726 case "PATH": 727 Desktop.getDesktop().open(new File(ObjectUtils.toString(originData, "").trim())); 728 break; 729 730 default: 731 if (StringUtils.startsWith(type, "~")) { 732 type = StringUtils.substringAfter(type, "~"); 733 } 734 File file = File.createTempFile("anteater", "." + StringUtils.defaultString(type, "txt")); 735 byte[] data; 736 if (originData instanceof LogRecord) { 737 Object logdata = ((LogRecord) originData).getMessage(); 738 if (logdata instanceof byte[]) { 739 data = (byte[]) logdata; 740 } else { 741 data = ((LogRecord) originData).toString().getBytes(); 742 } 743 } else { 744 data = ObjectUtils.toString(originData).getBytes(); 745 } 746 747 FileOutputStream output = new FileOutputStream(file); 748 IOUtils.write(data, output); 749 output.flush(); 750 Desktop.getDesktop().open(file); 751 output.close(); 752 } 753 } 754 755 public static void openWebpage(URI uri) { 756 Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null; 757 if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) { 758 try { 759 desktop.browse(uri); 760 } catch (Exception e) { 761 e.printStackTrace(); 762 } 763 } 764 } 765 766 public void addButton(AbstractButton onTop) { 767 toolBar.add(onTop, BorderLayout.EAST); 768 } 769 770 @Override 771 public LogPresenter copyAndClean() { 772 return null; 773 } 774 775 @Override 776 public boolean isFilterEnabled() { 777 return log.isFilterEnabled(); 778 } 779 780 @Override 781 public String filter(Object message) { 782 return log.filter(message); 783 } 784}