1 /* 2 * $Id$ 3 * 4 * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. 5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 * 7 * This code is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 only, as 9 * published by the Free Software Foundation. Oracle designates this 10 * particular file as subject to the "Classpath" exception as provided 11 * by Oracle in the LICENSE file that accompanied this code. 12 * 13 * This code is distributed in the hope that it will be useful, but WITHOUT 14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 * version 2 for more details (a copy is included in the LICENSE file that 17 * accompanied this code). 18 * 19 * You should have received a copy of the GNU General Public License version 20 * 2 along with this work; if not, write to the Free Software Foundation, 21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 22 * 23 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 24 * or visit www.oracle.com if you need additional information or have any 25 * questions. 26 */ 27 package com.sun.javatest.exec; 28 29 import com.sun.javatest.tool.UIFactory; 30 import com.sun.javatest.report.HTMLWriterEx; 31 32 import java.awt.*; 33 import java.awt.event.ActionEvent; 34 import java.awt.event.ActionListener; 35 import java.awt.print.PageFormat; 36 import java.awt.print.Printable; 37 import java.io.*; 38 import java.net.MalformedURLException; 39 import java.net.URL; 40 import java.nio.charset.StandardCharsets; 41 import java.util.HashMap; 42 import java.util.Iterator; 43 import javax.imageio.ImageIO; 44 import javax.imageio.ImageReader; 45 import javax.imageio.stream.ImageInputStream; 46 import javax.sound.midi.InvalidMidiDataException; 47 import javax.sound.midi.MidiFileFormat; 48 import javax.sound.midi.MidiSystem; 49 import javax.sound.midi.Sequence; 50 import javax.sound.midi.Sequencer; 51 import javax.sound.sampled.AudioFileFormat; 52 import javax.sound.sampled.AudioFormat; 53 import javax.sound.sampled.AudioInputStream; 54 import javax.sound.sampled.AudioSystem; 55 import javax.sound.sampled.Clip; 56 import javax.sound.sampled.DataLine; 57 import javax.sound.sampled.LineEvent; 58 import javax.sound.sampled.LineListener; 59 import javax.sound.sampled.UnsupportedAudioFileException; 60 import javax.swing.*; 61 import javax.swing.event.HyperlinkEvent; 62 import javax.swing.event.HyperlinkListener; 63 import javax.swing.text.*; 64 import javax.swing.text.html.HTML; 65 import javax.swing.text.html.HTMLDocument; 66 import javax.swing.text.html.HTMLEditorKit; 67 import javax.swing.text.html.HTMLFrameHyperlinkEvent; 68 import javax.swing.text.rtf.RTFEditorKit; 69 70 /** 71 * A panel to display files which may be linked together by hyperlinks. 72 * This panel can also display a list of local files. The type of the file 73 * to be shown is identified if possible and the display panel put into the 74 * right mode to show an image, rendered HTML, etc. If the file is not known, 75 * the user may be prompted to display the file as raw text. 76 */ 77 public class MultiFormatPane extends JPanel implements Printable { 78 79 public MultiFormatPane(UIFactory uif) { 80 this.uif = uif; 81 82 listener = new Listener(); 83 initGUI(); 84 85 modesToPanes = new HashMap<>(); 86 87 addMediaPane(TEXT, textPane); 88 addMediaPane(AUDIO, musicPane); 89 addMediaPane(IMAGE, imagePane); 90 addMediaPane(ERROR, errorPane); 91 92 } 93 94 public void setNoteField(JTextField noteField) { 95 this.noteField = noteField; 96 } 97 98 public void setNavigationPane(NavigationPane navPane) { 99 this.navPane = navPane; 100 } 101 102 public void addMediaPane(int mode, MediaPane pane) { 103 modesToPanes.put(mode, pane); 104 } 105 106 public MediaPane getMediaPane(int mode) { 107 return modesToPanes.get(mode); 108 } 109 110 public void clear() { 111 currURL = null; 112 if(navPane != null) { 113 navPane.clear(); 114 } 115 musicPane.stopAudio(); 116 } 117 118 public URL getPage() { 119 return currURL; 120 } 121 122 public int getCurrentMode() { 123 return getCurrentPane().getMode(); 124 } 125 126 public MediaPane getCurrentPane() { 127 return (MediaPane)scrllBody.getViewport().getComponent(0); 128 } 129 130 // Base directory is root directory for displayable content 131 // if it set, all filenames will be relative to this directory 132 void setBaseDirectory(File base) { 133 baseDir = base; 134 } 135 136 File getBaseDirectory() { 137 return baseDir; 138 } 139 140 void setDefaultView() { 141 textPane.setDocument(new HTMLDocument()); 142 textPane.showTextArea(); 143 } 144 145 private void initGUI() { 146 uif.initPanel(this, "mfp", false); 147 148 textPane = new TextPane(uif, "mfp.textPane", null); 149 textPane.addHyperlinkListener(listener); 150 151 scrllBody = uif.createScrollPane(textPane, 152 JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, 153 JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 154 155 textPane.setParent(scrllBody); 156 157 musicPane = new MusicPane(uif, "mfp.audioPane", scrllBody); 158 imagePane = new ImagePane(uif, "mfp.imagePanelbl", scrllBody); 159 errorPane = new ErrorFormatPane(uif, "mfp.errorPane", scrllBody); 160 161 scrllBody.setViewportView(textPane); 162 163 setLayout(new BorderLayout()); 164 165 add(scrllBody, BorderLayout.CENTER); 166 167 } 168 169 170 //Loads everything by URL 171 public void loadPage(URL url) { 172 // avoid recursive callbacks from updating combo 173 // URL.equals can result in a big performance hit 174 if (currURL != null && url.toString().equals(currURL.toString())) 175 return; 176 177 currURL = url; 178 179 String protocol = url.getProtocol(); 180 File file = new File(url.getFile()); 181 if (protocol.equals("https")) { 182 // JavaTestSecurityManager disallows Permission getProperty.ssl.SocketFactory.provider 183 // so https can't be processed 184 openInBrowser(url); 185 186 } else if (protocol.equals("file") && file.isDirectory()) { 187 String list = listLocalDirectory(file); 188 textPane.showText(list, "text/html"); 189 ((HTMLDocument)textPane.getDocument()).setBase(url); 190 } 191 else if (ImagePane.isImageResource(url)) { 192 imagePane.showImage(url); 193 } 194 else if(MusicPane.isAudioResource(url)) { 195 musicPane.showAudio(url); 196 } 197 else if(isMediaResourceCorrupted(url)) { 198 errorPane.showError(uif.getI18NString("mfp.errorPaneLbl.corrupted")); 199 } 200 else if(TextPane.isTextResource(url)){ 201 textPane.showText(url); 202 } 203 else if (url.getProtocol().equalsIgnoreCase("http")) { 204 textPane.showText(url); 205 } 206 else { 207 int response = uif.showYesNoDialog("mfp.unknownTypeDlg"); 208 if(response == JOptionPane.YES_OPTION) { 209 textPane.showText(url); 210 } 211 else { 212 errorPane.showError(uif.getI18NString("mfp.errorPaneLbl.unsupported")); 213 } 214 } 215 216 if(navPane != null) { 217 navPane.processURL(url); 218 } 219 } 220 221 private void openInBrowser(URL url) { 222 Desktop desktop = Desktop.isDesktopSupported() ? Desktop.getDesktop() : null; 223 if (desktop != null && desktop.isSupported(Desktop.Action.BROWSE)) { 224 try { 225 desktop.browse(url.toURI()); 226 } catch (Exception e) { 227 e.printStackTrace(); 228 } 229 } 230 } 231 232 public void showText(String text, String MIME) { 233 textPane.showText(text, MIME); 234 currURL = null; 235 } 236 237 public void showText(URL url) { 238 textPane.showText(url); 239 } 240 241 public void showAudio(URL url) { 242 musicPane.showAudio(url); 243 } 244 245 public void stopAudio() { 246 musicPane.stopAudio(); 247 } 248 249 public void showImage(URL url) { 250 imagePane.showImage(url); 251 } 252 253 public void showError(String errorMessage) { 254 errorPane.showError(errorMessage); 255 } 256 257 258 private boolean isMediaResourceSupported(URL url) { 259 return ImagePane.isImageResource(url) || MusicPane.isAudioResource(url); 260 } 261 262 private boolean isMediaResourceCorrupted(URL url) { 263 String filename = url.getFile(); 264 String ext = filename.substring(filename.lastIndexOf('.') + 1); 265 ext = ext.toLowerCase(); 266 267 return (SUPPORTED_MEDIA_RESOURCE_EXTENSIONS.indexOf(ext) != -1) && 268 !isMediaResourceSupported(url); 269 } 270 271 272 private String listLocalDirectory(File dir) { 273 if (!dir.isAbsolute()) 274 dir = dir.getAbsoluteFile(); 275 276 String displayPath = dir.getPath(); 277 // if contains base dir, only show path relative to baseDir 278 if (baseDir != null) { 279 String p = baseDir.getParent(); 280 if (p != null 281 && displayPath.startsWith(p) && 282 (displayPath.length() > p.length())) { 283 displayPath = displayPath.substring(p.length()); 284 // in case of Unix 285 if (displayPath.startsWith(File.separator)) { 286 displayPath = displayPath.substring(1); 287 } 288 } 289 } 290 291 String[] filelist = dir.list(); 292 293 StringWriter sw = new StringWriter(); 294 try { 295 HTMLWriterEx out = new HTMLWriterEx(sw, uif.getI18NResourceBundle()); 296 297 out.startTag(HTMLWriterEx.HTML); 298 out.startTag(HTMLWriterEx.HEAD); 299 out.writeContentMeta(); 300 out.startTag(HTMLWriterEx.TITLE); 301 out.write(displayPath); 302 out.endTag(HTMLWriterEx.TITLE); 303 out.endTag(HTMLWriterEx.HEAD); 304 out.startTag(HTMLWriterEx.BODY); 305 out.writeStyleAttr("font-family: SansSerif; font-size: 12pt"); 306 out.startTag(HTMLWriterEx.H3); 307 out.writeI18N("mfp.head", displayPath); 308 out.endTag(HTMLWriterEx.H3); 309 out.startTag(HTMLWriterEx.UL); 310 out.writeStyleAttr("margin-left:0"); 311 312 File parent = dir.getParentFile(); 313 if (parent != null) { 314 out.startTag(HTMLWriterEx.LI); 315 out.startTag(HTMLWriterEx.OBJECT); 316 out.writeAttr(HTMLWriterEx.CLASSID, "com.sun.javatest.tool.IconLabel"); 317 out.writeParam("type", "up"); 318 out.endTag(HTMLWriterEx.OBJECT); 319 out.writeEntity(" "); 320 try { 321 out.startTag(HTMLWriterEx.A); 322 out.writeAttr(HTMLWriterEx.HREF, parent.toURL().toString()); 323 out.writeI18N("mfp.parent"); 324 out.endTag(HTMLWriterEx.A); 325 } 326 catch (MalformedURLException e) { 327 out.writeI18N("mfp.parent"); 328 } 329 } 330 331 for (int i = 0; i < filelist.length; i++) { 332 File file = new File(dir, filelist[i]); 333 out.startTag(HTMLWriterEx.LI); 334 out.startTag(HTMLWriterEx.OBJECT); 335 out.writeAttr(HTMLWriterEx.CLASSID, "com.sun.javatest.tool.IconLabel"); 336 out.writeParam("type", (file.isDirectory() ? "folder" : "file")); 337 out.endTag(HTMLWriterEx.OBJECT); 338 out.writeEntity(" "); 339 try { 340 out.writeLink(file.toURL(), file.getName()); 341 } 342 catch (MalformedURLException e) { 343 out.write(file.getName()); 344 } 345 } 346 347 out.endTag(HTMLWriterEx.UL); 348 out.endTag(HTMLWriterEx.BODY); 349 out.endTag(HTMLWriterEx.HTML); 350 out.close(); 351 } 352 catch (IOException e) { 353 // should not happen, writing to StringWriter 354 } 355 356 return sw.toString(); 357 } 358 359 public interface MediaPane { 360 361 public int getMode(); 362 363 public void changeURL(URL url); 364 365 public void setParent(JScrollPane pane); 366 } 367 368 // Print this panel 369 public int print (Graphics g, PageFormat pf, int pageIndex) { 370 371 int response = NO_SUCH_PAGE; 372 373 Graphics2D g2 = (Graphics2D) g; 374 375 Component componentToBePrinted = scrllBody.getComponent(0); 376 int mode = getCurrentMode(); 377 switch(mode) { 378 case TEXT: 379 componentToBePrinted = textPane; 380 break; 381 case IMAGE: 382 componentToBePrinted = imagePane; 383 break; 384 default: 385 break; 386 } 387 388 // for faster printing, turn off double buffering 389 disableDoubleBuffering(componentToBePrinted); 390 391 Dimension d = componentToBePrinted.getSize(); 392 double panelWidth = d.width; 393 double panelHeight = d.height; 394 395 double pageHeight = pf.getImageableHeight(); 396 double pageWidth = pf.getImageableWidth(); 397 398 double scale = pageWidth / panelWidth; 399 int totalNumPages = (int) Math.ceil(scale * panelHeight / pageHeight); 400 401 if (pageIndex >= totalNumPages) { 402 response = NO_SUCH_PAGE; 403 } 404 else { 405 406 // shift Graphic to line up with beginning of print-imageable region 407 g2.translate(pf.getImageableX(), pf.getImageableY()); 408 409 // shift Graphic to line up with beginning of next page to print 410 g2.translate(0f, -pageIndex * pageHeight); 411 412 g2.scale(scale, scale); 413 414 componentToBePrinted.paint(g2); 415 416 enableDoubleBuffering(componentToBePrinted); 417 response = Printable.PAGE_EXISTS; 418 } 419 return response; 420 } 421 422 private void disableDoubleBuffering(Component c) { 423 RepaintManager currentManager = RepaintManager.currentManager(c); 424 currentManager.setDoubleBufferingEnabled(false); 425 } 426 427 private void enableDoubleBuffering(Component c) { 428 RepaintManager currentManager = RepaintManager.currentManager(c); 429 currentManager.setDoubleBufferingEnabled(true); 430 } 431 // END of printing 432 433 private class Listener implements HyperlinkListener { 434 public void hyperlinkUpdate(HyperlinkEvent e) { 435 HyperlinkEvent.EventType et = e.getEventType(); 436 if (et == HyperlinkEvent.EventType.ACTIVATED) { 437 if (e instanceof HTMLFrameHyperlinkEvent) { 438 // HTMLDocument doc = (HTMLDocument) 439 // ((JEditorPane) e.getSource()).getDocument(); 440 // doc.processHTMLFrameHyperlinkEvent((HTMLFrameHyperlinkEvent) e); 441 processFrameLink(e); 442 } 443 else { 444 musicPane.stopAudio(); 445 // String s = e.getDescription(); 446 // URL correctURL = e.getURL(); 447 // HTMLDocument doc = (HTMLDocument)((JEditorPane)e.getSource()).getDocument(); 448 // if(doc != null && currURL != null && !doc.getBase().equals(currURL)) 449 // currURL = doc.getBase(); 450 // // JEditorPane doesn't allows javascript, so we delete this parameter and load 451 // // root page of help package 452 // if(correctURL.getProtocol().equals("file")) { 453 454 // int pos = correctURL.toString().indexOf("?"); 455 // if (pos >= 0) { 456 // try { 457 // correctURL = new URL(correctURL.toString().substring(0, pos)); 458 // } catch (MalformedURLException ex) { 459 // // NONE 460 // } 461 // } 462 // } 463 // // end of fix 464 // loadPage(correctURL); 465 if(e.getURL() == null && e.getDescription().startsWith("#")) { 466 processSharpLink(e); 467 } 468 else { 469 processGeneralLink(e); 470 } 471 } 472 } 473 else if (et == HyperlinkEvent.EventType.ENTERED) { 474 URL u = e.getURL(); 475 if (u != null) { 476 textPane.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); 477 if(noteField != null) { 478 noteField.setText(u.toString()); 479 } 480 } 481 } 482 else if (et == HyperlinkEvent.EventType.EXITED) { 483 textPane.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 484 if(noteField != null) { 485 noteField.setText(""); 486 } 487 } 488 } 489 490 private void processFrameLink(HyperlinkEvent e) { 491 HTMLDocument doc = (HTMLDocument) 492 ((JEditorPane) e.getSource()).getDocument(); 493 doc.processHTMLFrameHyperlinkEvent((HTMLFrameHyperlinkEvent) e); 494 } 495 496 private void processSharpLink(HyperlinkEvent e) { 497 String desc = e.getDescription(); 498 if (!(desc.startsWith("#"))) { 499 return; 500 } 501 textPane.scrollToReference(desc.substring(1)); 502 } 503 504 private void processGeneralLink(HyperlinkEvent e) { 505 URL correctURL = e.getURL(); 506 507 if (correctURL == null) { 508 return; 509 } 510 511 HTMLDocument doc = (HTMLDocument)((JEditorPane)e.getSource()).getDocument(); 512 if(doc != null && currURL != null && !doc.getBase().toString().equals(currURL.toString())) { 513 currURL = doc.getBase(); 514 } 515 // fix of CR 6451318, CR 6442782 and CR 6447246 516 // JDTS use '?' notation to pass parameter (currently loaded page of one of frames) 517 // to javascript. 518 // JEditorPane doesn't allows javascript, so we delete this parameter and load 519 // root page of help package 520 if(correctURL.getProtocol().equals("file")) { 521 int pos = correctURL.toString().indexOf("?"); 522 if (pos >= 0) { 523 try { 524 correctURL = new URL(correctURL.toString().substring(0, pos)); 525 } catch (MalformedURLException ex) { 526 // NONE 527 } 528 } 529 } 530 // end of fix 531 loadPage(correctURL); 532 } 533 } 534 535 536 537 538 private static final String SUPPORTED_MEDIA_RESOURCE_EXTENSIONS = 539 ".wav .au .aif .mid .midi .rmf .jpeg .jpg .gif .png"; 540 private JScrollPane scrllBody; 541 public static final int TEXT = 0; 542 public static final int IMAGE = 1; 543 public static final int AUDIO = 2; 544 public static final int ERROR = 3; 545 546 private File baseDir; 547 private URL currURL; 548 549 private TextPane textPane; 550 private MusicPane musicPane; 551 private ImagePane imagePane; 552 private ErrorFormatPane errorPane; 553 554 private UIFactory uif; 555 private String uiKey; 556 557 private Listener listener; 558 559 private JTextField noteField; 560 private NavigationPane navPane; 561 562 private HashMap<Integer, MediaPane> modesToPanes; 563 } 564 565 566 class TextPane extends JEditorPane implements MultiFormatPane.MediaPane { 567 568 public TextPane(UIFactory uif, String uiKey, JScrollPane owner) { 569 super(); 570 571 this.uif = uif; 572 this.owner = owner; 573 574 setName("text"); 575 setEditable(false); 576 setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 577 setFont(new Font(Font.MONOSPACED, uif.getBaseFont().getStyle(), uif.getBaseFont().getSize())); 578 579 uif.setAccessibleInfo(this, uiKey); 580 581 htmlKit = new HTMLEditorKit(); 582 defaultKit = new DefaultEditorKit(); 583 rtfKit = new RTFEditorKit(); 584 585 } 586 587 public void changeURL(URL url) {} 588 589 public void setParent(JScrollPane owner) { 590 this.owner = owner; 591 } 592 593 public int getMode() { 594 return MultiFormatPane.TEXT; 595 } 596 597 public void showText(String text, String MIME) { 598 setContentType(MIME); 599 600 EditorKit kit = getKitByMIME(MIME); 601 Document doc = kit.createDefaultDocument(); 602 603 setDocument(doc); 604 605 setText(text); 606 607 showTextArea(); 608 } 609 610 public void showText(URL url) { 611 try { 612 String mimeType = getMIMEType(url); 613 if (mimeType == null) { 614 mimeType = "text/plain"; 615 } 616 617 boolean loadManually = false; 618 if (mimeType.indexOf("plain") != -1) { 619 loadManually = true; 620 } 621 622 EditorKit kit = getKitByMIME(mimeType); 623 624 setContentType(mimeType); 625 626 Document doc = kit.createDefaultDocument(); 627 setDocument(doc); 628 if (loadManually && "file".equals(url.getProtocol())) { 629 File file = new File(url.getFile()); 630 try { 631 Reader r = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)); 632 read(r, url); 633 r.close(); 634 } 635 catch (IOException e) { 636 uif.showError("mfp.load.error", new Object[] { url, e }); 637 } 638 } else { 639 setPage(url); 640 } 641 642 showTextArea(); 643 } 644 catch (IOException e) { 645 uif.showError("mfp.load.error", new Object[] { url, e }); 646 } 647 } 648 649 public static boolean isTextResource(URL url) { 650 String mimeType = getMIMEType(url); 651 if (mimeType == null) 652 return false; 653 return (mimeType.equals("text/plain") || mimeType.equals("text/html") || 654 mimeType.equals("text/rtf")); 655 } 656 657 public static String getMIMEType(URL url) { 658 String filename = url.getFile(); 659 String ext = filename.substring(filename.lastIndexOf('.') + 1); 660 ext = ext.toLowerCase(); 661 662 return extensionsToMIME.get(ext); 663 } 664 665 public void showTextArea() { 666 owner.setViewportView(this); 667 owner.revalidate(); 668 owner.repaint(); 669 } 670 671 private EditorKit getKitByMIME(String mime) { 672 if(mime.indexOf("rtf") != -1) 673 return rtfKit; 674 else if(mime.indexOf("html") != -1) 675 return htmlKit; 676 else { 677 return defaultKit; 678 } 679 } 680 681 public void scrollToReference(String reference) { 682 Document d = getDocument(); 683 if (d instanceof HTMLDocument) { 684 HTMLDocument doc = (HTMLDocument) d; 685 HTMLDocument.Iterator iter = doc.getIterator(HTML.Tag.A); 686 for (; iter.isValid(); iter.next()) { 687 AttributeSet a = iter.getAttributes(); 688 String nm = (String) a.getAttribute(HTML.Attribute.NAME); 689 if (nm == null){ 690 nm = (String) a.getAttribute(HTML.Attribute.ID); 691 } 692 if ((nm != null) && nm.equals(reference)) { 693 // found a matching reference in the document. 694 try { 695 int pos = iter.getStartOffset(); 696 Rectangle r = modelToView(pos); 697 if (r != null) { 698 // the view is visible, scroll it to the 699 // center of the current visible area. 700 Rectangle vis = getVisibleRect(); 701 //r.y -= (vis.height / 2); 702 r.height = vis.height; 703 scrollRectToVisible(r); 704 setCaretPosition(pos); 705 } 706 } catch (BadLocationException ble) { 707 UIManager.getLookAndFeel().provideErrorFeedback(TextPane.this); 708 } 709 } 710 } 711 } 712 } 713 714 private JScrollPane owner; 715 private UIFactory uif; 716 717 private HTMLEditorKit htmlKit; 718 private DefaultEditorKit defaultKit; 719 private RTFEditorKit rtfKit; 720 721 722 private static HashMap<String, String> extensionsToMIME; 723 static { 724 extensionsToMIME = new HashMap<>(); 725 extensionsToMIME.put("html", "text/html"); 726 extensionsToMIME.put("htm", "text/html"); 727 extensionsToMIME.put("htmls", "text/html"); 728 extensionsToMIME.put("htx", "text/html"); 729 extensionsToMIME.put("shtml", "text/html"); 730 extensionsToMIME.put("stm", "text/html"); 731 extensionsToMIME.put("jsp", "text/html"); 732 733 extensionsToMIME.put("text", "text/plain"); 734 extensionsToMIME.put("txt", "text/plain"); 735 extensionsToMIME.put("log", "text/plain"); 736 extensionsToMIME.put("list", "text/plain"); 737 extensionsToMIME.put("lst", "text/plain"); 738 extensionsToMIME.put("java", "text/plain"); 739 extensionsToMIME.put("xml", "text/plain"); 740 extensionsToMIME.put("jtr", "text/plain"); 741 extensionsToMIME.put("jti", "text/plain"); 742 extensionsToMIME.put("jtm", "text/plain"); 743 extensionsToMIME.put("jtx", "text/plain"); 744 extensionsToMIME.put("kfl", "text/plain"); 745 extensionsToMIME.put("css", "text/plain"); 746 extensionsToMIME.put("fx", "text/plain"); 747 extensionsToMIME.put("jasm", "text/plain"); 748 extensionsToMIME.put("jcod", "text/plain"); 749 750 extensionsToMIME.put("rtf", "text/rtf"); 751 extensionsToMIME.put("rtx", "text/rtf"); 752 753 } 754 755 756 } 757 758 class MusicPane extends JPanel implements MultiFormatPane.MediaPane { 759 public MusicPane(UIFactory uif, String uiKey, JScrollPane owner) { 760 super(); 761 762 this.uif = uif; 763 this.owner = owner; 764 765 initGUI(uiKey); 766 } 767 768 private void initGUI(String uiKey) { 769 setName(uiKey); 770 uif.setAccessibleInfo(this, uiKey); 771 772 setLayout(new GridBagLayout()); 773 GridBagConstraints gbc = new GridBagConstraints(); 774 775 btnStart = uif.createButton(uiKey + ".btnStart"); 776 btnStop = uif.createButton(uiKey + ".btnStop"); 777 btnLoop = uif.createButton(uiKey + ".btnLoop"); 778 779 add(btnStart, gbc); 780 add(btnStop, gbc); 781 add(btnLoop, gbc); 782 783 btnStart.addActionListener(new ActionListener() { 784 public void actionPerformed(ActionEvent e) { 785 if(isSampledAudioResource(currURL)) { 786 loadSample(currURL); 787 clip.start(); 788 } 789 else if(isMidiAudioResource(currURL)) { 790 loadSequence(currURL); 791 sequencer.start(); 792 } 793 } 794 }); 795 796 btnStop.addActionListener(new ActionListener() { 797 public void actionPerformed(ActionEvent e) { 798 stopAudio(); 799 } 800 }); 801 802 btnLoop.addActionListener(new ActionListener() { 803 public void actionPerformed(ActionEvent e) { 804 if(isSampledAudioResource(currURL)) { 805 loadSample(currURL); 806 clip.loop(Clip.LOOP_CONTINUOUSLY); 807 } 808 } 809 }); 810 811 } 812 813 public void showAudio(URL url) { 814 changeURL(url); 815 816 owner.setViewportView(this); 817 owner.revalidate(); 818 owner.repaint(); 819 } 820 821 public void changeURL(URL url) { 822 currURL = url; 823 824 if(isMidiAudioResource(url)) { 825 btnLoop.setEnabled(false); 826 } 827 else if(isSampledAudioResource(url)) { 828 btnLoop.setEnabled(true); 829 } 830 831 } 832 833 public void setParent(JScrollPane owner) { 834 this.owner = owner; 835 } 836 837 public int getMode() { 838 return MultiFormatPane.AUDIO; 839 } 840 841 public static boolean isAudioResource(URL url) { 842 return isSampledAudioResource(url) || isMidiAudioResource(url); 843 } 844 845 public void stopAudio() { 846 if(clip != null && clip.isRunning()) { 847 clip.stop(); 848 clip.flush(); 849 clip.close(); 850 } 851 if(sequencer != null && sequencer.isRunning()) 852 sequencer.stop(); 853 } 854 855 private void loadSample(URL url) { 856 try { 857 AudioInputStream stream = AudioSystem.getAudioInputStream(url); 858 AudioFormat format = stream.getFormat(); 859 860 DataLine.Info info = new DataLine.Info( 861 Clip.class, stream.getFormat(), ((int)stream.getFrameLength()*format.getFrameSize())); 862 863 clip = (Clip) AudioSystem.getLine(info); 864 clip.open(stream); 865 clip.addLineListener(new LineListener() { 866 public void update(LineEvent e) { 867 if(e.getType() == LineEvent.Type.STOP) { 868 clip.stop(); 869 } 870 } 871 }); 872 } catch (Exception e) { 873 clip.close(); 874 } 875 } 876 877 private void loadSequence(URL url) { 878 try { 879 Sequence sequence = MidiSystem.getSequence(url); 880 881 // Create a sequencer for the sequence 882 sequencer = MidiSystem.getSequencer(); 883 sequencer.open(); 884 sequencer.setSequence(sequence); 885 886 } catch (Exception e) {} 887 888 } 889 890 private static boolean isSampledAudioResource(URL url) { 891 try{ 892 AudioFileFormat fformat = AudioSystem.getAudioFileFormat(url); 893 return AudioSystem.isFileTypeSupported(fformat.getType()); 894 } catch (UnsupportedAudioFileException unsuppExc) { 895 return false; 896 } catch (IOException ioExc) { 897 return false; 898 } 899 } 900 901 private static boolean isMidiAudioResource(URL url) { 902 try { 903 MidiFileFormat fformat = MidiSystem.getMidiFileFormat(url); 904 Sequence sequence = MidiSystem.getSequence(url); 905 return MidiSystem.isFileTypeSupported(fformat.getType()); 906 } catch (InvalidMidiDataException invalidDataExc) { 907 return false; 908 } catch (IOException ioExc) { 909 return false; 910 } 911 catch (Exception exc) { 912 return false; 913 } 914 } 915 916 917 private UIFactory uif; 918 private JScrollPane owner; 919 920 private JButton btnStart; 921 private JButton btnStop; 922 private JButton btnLoop; 923 924 private URL currURL; 925 private Clip clip; 926 private Sequencer sequencer; 927 928 } 929 930 class ImagePane extends JLabel implements MultiFormatPane.MediaPane { 931 932 public ImagePane(UIFactory uif, String uiKey, JScrollPane owner) { 933 super(uif.getI18NString(uiKey + ".lbl")); 934 // setName(uiKey); 935 936 this.owner = owner; 937 } 938 939 public void changeURL(URL url) {} 940 941 public void setParent(JScrollPane owner) { 942 this.owner = owner; 943 } 944 945 public int getMode() { 946 return MultiFormatPane.IMAGE; 947 } 948 949 public void showImage(URL url) { 950 if(isImageFormatSupported(url)) { 951 ImageIcon img = new ImageIcon(url); 952 setIcon(img); 953 954 owner.setViewportView(this); 955 owner.revalidate(); 956 owner.repaint(); 957 } 958 } 959 960 public static boolean isImageResource(URL url) { 961 String file = url.getFile(); 962 String ext = file.substring(file.lastIndexOf('.')+1); 963 Iterator<ImageReader> iter = ImageIO.getImageReadersBySuffix(ext); 964 return iter.hasNext(); 965 } 966 967 public static boolean isImageFormatSupported(URL url) { 968 try { 969 ImageInputStream iis = ImageIO.createImageInputStream(new File(url.getFile())); 970 Iterator<ImageReader> iter = ImageIO.getImageReaders(iis); 971 if(!iter.hasNext()) 972 return false; 973 } catch (IOException exc) { 974 exc.printStackTrace(); 975 return false; 976 } 977 return true; 978 } 979 980 private JScrollPane owner; 981 } 982 983 class ErrorFormatPane extends JPanel implements MultiFormatPane.MediaPane { 984 public ErrorFormatPane(UIFactory uif, String uiKey, JScrollPane owner) { 985 super(); 986 uif.initPanel(this, uiKey, true); 987 988 this.owner = owner; 989 990 setLayout(new GridBagLayout()); 991 GridBagConstraints gbc = new GridBagConstraints(); 992 gbc.anchor = gbc.CENTER; 993 errorLabel = uif.createLabel("mfp.errorPaneLbl", true); 994 add(errorLabel, gbc); 995 996 } 997 998 public void changeURL(URL url) {} 999 1000 public void setParent(JScrollPane owner) { 1001 this.owner = owner; 1002 } 1003 1004 public int getMode() { 1005 return MultiFormatPane.ERROR; 1006 } 1007 1008 public void showError(String errorMessage) { 1009 errorLabel.setText(errorMessage); 1010 1011 owner.setViewportView(this); 1012 owner.revalidate(); 1013 owner.repaint(); 1014 } 1015 1016 private JLabel errorLabel; 1017 private JScrollPane owner; 1018 }