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