| 1 27 package org.htmlparser.lexerapplications.thumbelina; 28 29 import java.awt.BorderLayout ; 30 import java.awt.Component ; 31 import java.awt.Image ; 32 import java.awt.event.ItemEvent ; 33 import java.awt.event.ItemListener ; 34 import java.awt.event.WindowAdapter ; 35 import java.awt.event.WindowEvent ; 36 import java.awt.image.ImageObserver ; 37 import java.beans.PropertyChangeListener ; 38 import java.beans.PropertyChangeSupport ; 39 import java.io.IOException ; 40 import java.net.MalformedURLException ; 41 import java.net.URL ; 42 import java.util.ArrayList ; 43 import java.util.HashMap ; 44 45 import javax.swing.BoxLayout ; 46 import javax.swing.DefaultListModel ; 47 import javax.swing.JCheckBox ; 48 import javax.swing.JFrame ; 49 import javax.swing.JLabel ; 50 import javax.swing.JList ; 51 import javax.swing.JOptionPane ; 52 import javax.swing.JPanel ; 53 import javax.swing.JProgressBar ; 54 import javax.swing.JScrollPane ; 55 import javax.swing.JSlider ; 56 import javax.swing.JSplitPane ; 57 import javax.swing.JTextField ; 58 import javax.swing.ListSelectionModel ; 59 import javax.swing.ScrollPaneConstants ; 60 import javax.swing.border.BevelBorder ; 61 import javax.swing.event.ChangeEvent ; 62 import javax.swing.event.ChangeListener ; 63 import javax.swing.event.ListSelectionEvent ; 64 import javax.swing.event.ListSelectionListener ; 65 66 import org.htmlparser.Node; 67 import org.htmlparser.Tag; 68 import org.htmlparser.lexer.Lexer; 69 import org.htmlparser.util.ParserException; 70 71 74 public class Thumbelina 75 extends 76 JPanel implements 78 Runnable , 79 ItemListener , 80 ChangeListener , 81 ListSelectionListener  82 { 83 86 public static final String PROP_CURRENT_URL_PROPERTY = "currentURL"; 87 90 public static final String PROP_URL_QUEUE_PROPERTY = "queueSize"; 91 94 public static final String PROP_URL_VISITED_PROPERTY = "visitedSize"; 95 96 99 private ArrayList mUrls; 100 101 104 protected HashMap mVisited; 105 106 109 protected HashMap mRequested; 110 111 114 protected HashMap mTracked; 115 116 119 protected Thread mThread; 120 121 125 protected boolean mActive; 126 127 130 protected Sequencer mSequencer; 131 132 135 protected PicturePanel mPicturePanel; 136 137 140 protected static final URL [][] NONE = { { }, { } }; 141 142 145 protected PropertyChangeSupport mPropertySupport; 146 147 150 protected String mCurrentURL; 151 152 155 protected boolean mDiscardCGI; 156 157 160 protected boolean mDiscardQueries; 161 162 165 protected JCheckBox mBackgroundToggle; 166 167 170 protected JList mHistory; 171 172 175 protected JScrollPane mPicturePanelScroller; 176 177 180 protected JScrollPane mHistoryScroller; 181 182 185 protected JSplitPane mMainArea; 186 187 190 protected JPanel mPowerBar; 191 192 195 protected JProgressBar mQueueProgress; 196 197 200 protected JProgressBar mReadyProgress; 201 202 205 protected JCheckBox mRunToggle; 206 207 210 protected JSlider mSpeedSlider; 211 212 215 protected JTextField mUrlText; 216 217 220 protected JLabel mQueueSize; 221 222 225 protected JLabel mVisitedSize; 226 227 230 public Thumbelina () 231 { 232 this ((URL )null); 233 } 234 235 240 public Thumbelina (final String url) 241 throws 242 MalformedURLException  243 { 244 this (null == url ? null : new URL (url)); 245 } 246 247 251 public Thumbelina (final URL url) 252 { 253 mUrls = new ArrayList (); 254 mVisited = new HashMap (); 255 mRequested = new HashMap (); 256 mTracked = new HashMap (); 257 mThread = null; 258 mActive = true; 259 mPicturePanel = new PicturePanel (this); 260 mSequencer = new Sequencer (this); 261 mPropertySupport = new PropertyChangeSupport (this); 262 mCurrentURL = null; 263 mDiscardCGI = true; 264 mDiscardQueries = true; 265 266 setDoubleBuffered (false); 268 setLayout (new java.awt.BorderLayout ()); 269 mPicturePanel.setDoubleBuffered (false); 270 271 mThread = new Thread (this); 272 mThread.setName ("BackgroundThread"); 273 mThread.start (); 274 initComponents (); 275 276 mRunToggle.addItemListener (this); 277 mBackgroundToggle.addItemListener (this); 278 mSpeedSlider.addChangeListener (this); 279 mHistory.addListSelectionListener (this); 280 281 memCheck (); 282 283 if (null != url) 284 append (url); 285 } 286 287 291 protected void memCheck () 292 { 293 Runtime runtime; 294 long maximum; 295 296 if (System.getProperty ("java.version").startsWith ("1.4")) 297 { 298 runtime = Runtime.getRuntime (); 299 runtime.gc (); 300 maximum = runtime.maxMemory (); 301 if (maximum < 67108864L) JOptionPane.showMessageDialog ( 303 null, 304 "Maximum available memory is low (" + maximum + " bytes).\n" 305 + "\n" 306 + "It is strongly suggested to increase the maximum memory\n" 307 + "available by using the JVM command line switch -Xmx with\n" 308 + "a suitable value, such as -Xmx256M for example.", 309 "Thumbelina - Low memory", 310 JOptionPane.WARNING_MESSAGE, 311 null ); 312 } 313 } 314 315 320 public void reset () 321 { 322 int oldsize; 323 324 synchronized (mUrls) 325 { 326 mSequencer.reset (); 327 mPicturePanel.reset (); 328 oldsize = mUrls.size (); 329 mUrls.clear (); 330 } 331 updateQueueSize (oldsize, mUrls.size ()); 332 } 333 334 340 public void append (final URL url) 341 { 342 String href; 343 boolean found; 344 URL u; 345 int oldsize; 346 347 href = url.toExternalForm (); 348 found = false; 349 oldsize = -1; 350 synchronized (mUrls) 351 { 352 for (int i = 0; !found && (i < mUrls.size ()); i++) 353 { 354 u = (URL )mUrls.get (i); 355 if (href.equals (u.toExternalForm ())) 356 found = true; 357 } 358 if (!found) 359 { 360 oldsize = mUrls.size (); 361 mUrls.add (url); 362 mUrls.notify (); 363 } 364 } 365 if (-1 != oldsize) 366 updateQueueSize (oldsize, mUrls.size ()); 367 } 368 369 373 public void append (final ArrayList list) 374 { 375 for (int i = 0; i < list.size (); i++) 376 append ((URL )list.get (i)); 377 } 378 379 386 protected ArrayList filter (final URL [] urls) 387 { 388 ArrayList list; 389 URL url; 390 String ref; 391 392 list = new ArrayList (); 393 for (int i = 0; i < urls.length; i++) 394 { 395 url = urls[i]; 396 ref = url.toExternalForm (); 397 if (!mDiscardCGI || (-1 == ref.indexOf ("/cgi-bin/"))) 399 if (!mDiscardQueries || (-1 == ref.indexOf ("?"))) 401 if (!mVisited.containsKey (ref)) 403 { 404 try 405 { 406 url.openConnection (); 407 list.add (url); 408 } 409 catch (IOException ioe) 410 { 411 } 413 } 414 } 415 416 return (list); 417 } 418 419 422 private void initComponents () 423 { 424 mPowerBar = new JPanel (); 425 mUrlText = new JTextField (); 426 mRunToggle = new JCheckBox (); 427 mSpeedSlider = new JSlider (); 428 mReadyProgress = new JProgressBar (); 429 mQueueProgress = new JProgressBar (); 430 mBackgroundToggle = new JCheckBox (); 431 mMainArea = new JSplitPane (); 432 mPicturePanelScroller = new JScrollPane (); 433 mHistoryScroller = new JScrollPane (); 434 mHistory = new JList (); 435 mQueueSize = new JLabel (); 436 mVisitedSize = new JLabel (); 437 438 mPowerBar.setLayout (new BoxLayout (mPowerBar, BoxLayout.X_AXIS)); 439 440 mPowerBar.setBorder (new BevelBorder (BevelBorder.LOWERED)); 441 mPowerBar.add (mUrlText); 442 443 mRunToggle.setSelected (true); 444 mRunToggle.setText ("On/Off"); 445 mRunToggle.setToolTipText ("Starts/stops the image presentation."); 446 mPowerBar.add (mRunToggle); 447 448 mSpeedSlider.setMajorTickSpacing (1000); 449 mSpeedSlider.setMaximum (5000); 450 mSpeedSlider.setPaintTicks (true); 451 mSpeedSlider.setToolTipText ("Set inter-image delay."); 452 mSpeedSlider.setValue (500); 453 mSpeedSlider.setInverted (true); 454 mPowerBar.add (mSpeedSlider); 455 456 mReadyProgress.setToolTipText ("Pending images.."); 457 mReadyProgress.setStringPainted (true); 458 mPowerBar.add (mReadyProgress); 459 460 mQueueProgress.setToolTipText ("Outstanding image fetches.."); 461 mQueueProgress.setStringPainted (true); 462 mPowerBar.add (mQueueProgress); 463 464 mBackgroundToggle.setSelected (true); 465 mBackgroundToggle.setText ("On/Off"); 466 mBackgroundToggle.setToolTipText ("Starts/stops background fetching."); 467 mPowerBar.add (mBackgroundToggle); 468 469 mVisitedSize.setBorder (new BevelBorder (BevelBorder.LOWERED)); 470 mVisitedSize.setText ("00000"); 471 mVisitedSize.setToolTipText ("Number of URLs examined."); 472 mPowerBar.add (mVisitedSize); 473 mQueueSize.setBorder (new BevelBorder (BevelBorder.LOWERED)); 474 mQueueSize.setText ("00000"); 475 mQueueSize.setToolTipText ("Number of URLs in queue."); 476 mPowerBar.add (mQueueSize); 477 478 mHistory.setModel (new DefaultListModel ()); 479 mHistory.setToolTipText ("History"); 480 mHistory.setDoubleBuffered (false); 481 mHistory.setSelectionMode ( 482 ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 483 mHistoryScroller.setViewportView (mHistory); 484 mHistoryScroller.setDoubleBuffered (false); 485 mPicturePanelScroller.setViewportView (mPicturePanel); 486 mPicturePanelScroller.setDoubleBuffered (false); 487 mPicturePanelScroller.setHorizontalScrollBarPolicy ( 488 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); 489 mPicturePanelScroller.setVerticalScrollBarPolicy ( 490 ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); 491 492 add (mMainArea, java.awt.BorderLayout.CENTER); 493 mMainArea.setLeftComponent (mHistoryScroller); 494 mMainArea.setRightComponent (mPicturePanelScroller); 495 add (mPowerBar, java.awt.BorderLayout.SOUTH); 496 } 497 498 502 public boolean getStatusBarVisible () 503 { 504 boolean ret; 505 506 ret = false; 507 508 for (int i = 0; !ret && (i < getComponentCount ()); i++) 509 if (mPowerBar == getComponent (i)) 510 ret = true; 511 512 return (ret); 513 } 514 515 520 public void setStatusBarVisible (final boolean visible) 521 { 522 int index; 523 524 index = -1; 525 for (int i = 0; (-1 == index) && (i < getComponentCount ()); i++) 526 if (mPowerBar == getComponent (i)) 527 index = i; 528 if (visible) 529 { 530 if (-1 == index) 531 { 532 add (mPowerBar, java.awt.BorderLayout.SOUTH); 533 invalidate (); 534 validate (); 535 } 536 } 537 else 538 if (-1 != index) 539 { 540 remove (index); 541 invalidate (); 542 validate (); 543 } 544 } 545 546 550 public boolean getHistoryListVisible () 551 { 552 boolean ret; 553 554 ret = false; 555 556 for (int i = 0; !ret && (i < getComponentCount ()); i++) 557 if (mMainArea == getComponent (i)) 559 ret = true; 560 561 return (ret); 562 } 563 564 569 public void setHistoryListVisible (final boolean visible) 570 { 571 int pictpanel; 572 int splitter; 573 Component component; 574 575 pictpanel = -1; 576 splitter = -1; 577 for (int i = 0; i < getComponentCount (); i++) 578 { 579 component = getComponent (i); 580 if (mPicturePanelScroller == component) 581 pictpanel = i; 582 else if (mMainArea == component) 583 splitter = i; 584 } 585 if (visible) 586 { 587 if (-1 != pictpanel) 588 { 589 remove (pictpanel); 590 add (mMainArea, java.awt.BorderLayout.CENTER); 591 mMainArea.setLeftComponent (mHistoryScroller); 592 mMainArea.setRightComponent (mPicturePanelScroller); 594 invalidate (); 595 validate (); 596 } 597 } 598 else 599 if (-1 != splitter) 600 { 601 remove (splitter); 602 add (mPicturePanelScroller, java.awt.BorderLayout.CENTER); 603 invalidate (); 604 validate (); 605 } 606 } 607 608 612 public boolean getSequencerActive () 613 { 614 return (mSequencer.mActive); 615 } 616 617 625 public void setSequencerActive (final boolean active) 626 { 627 if (0 == getSpeed ()) 629 setSpeed (Sequencer.DEFAULT_DELAY); 630 mSequencer.mActive = active; 631 if (active) 632 synchronized (mSequencer.mPending) 633 { 634 mSequencer.mPending.notify (); 635 } 636 if (active != mRunToggle.isSelected ()) 637 mRunToggle.setSelected (active); 638 } 639 640 644 public boolean getBackgroundThreadActive () 645 { 646 return (mActive); 647 } 648 649 656 public void setBackgroundThreadActive (final boolean active) 657 { 658 mActive = active; 659 if (active) 660 synchronized (mUrls) 661 { 662 mUrls.notify (); 663 } 664 if (active != mBackgroundToggle.isSelected ()) 665 mBackgroundToggle.setSelected (active); 666 } 667 668 672 public int getSpeed () 673 { 674 return (mSequencer.getDelay ()); 675 } 676 677 685 public void setSpeed (final int speed) 686 { 687 if (0 == speed) 688 mRunToggle.setSelected (false); 689 else 690 { 691 mRunToggle.setSelected (true); 692 mSequencer.setDelay (speed); 693 } 694 if (speed != mSpeedSlider.getValue ()) 695 mSpeedSlider.setValue (speed); 696 } 697 698 703 public boolean isDiscardCGI () 704 { 705 return (mDiscardCGI); 706 } 707 708 713 public void setDiscardCGI (final boolean discard) 714 { 715 mDiscardCGI = discard; 716 } 717 718 723 public boolean isDiscardQueries () 724 { 725 return (mDiscardQueries); 726 } 727 728 733 public void setDiscardQueries (final boolean discard) 734 { 735 mDiscardQueries = discard; 736 } 737 738 744 protected boolean isImage (final String url) 745 { 746 String lower = url.toLowerCase (); 747 return (lower.endsWith (".jpg") || lower.endsWith (".gif") 748 || lower.endsWith (".png")); 749 } 750 751 761 protected URL [][] extractImageLinks (final Lexer lexer, final URL docbase) 762 throws 763 IOException , 764 ParserException 765 { 766 HashMap images; 767 HashMap links; 768 boolean ina; Node node; 770 Tag tag; 771 String name; 772 Tag startatag; 773 Tag imgtag; 774 String href; 775 String src; 776 URL url; 777 URL [][] ret; 778 779 images = new HashMap (); 780 links = new HashMap (); 781 ina = false; 782 startatag = null; 783 imgtag = null; 784 while (null != (node = lexer.nextNode ())) 785 { 786 if (node instanceof Tag) 787 { 788 tag = (Tag)node; 789 name = tag.getTagName (); 790 if ("A".equals (name)) 791 { 792 if (tag.isEndTag ()) 793 { 794 ina = false; 795 if (null != imgtag) 796 { 797 href = startatag.getAttribute ("HREF"); 799 if (null != href) 800 { 801 if (isImage (href)) 802 { 803 src = imgtag.getAttribute ("SRC"); 804 if (null != src) 805 try 806 { 807 url = new URL (docbase, href); 808 href = url.toExternalForm (); 810 if (!images.containsKey (href)) 811 images.put (href, url); 812 } 813 catch (MalformedURLException murle) 814 { 815 } 817 } 818 } 819 } 820 } 821 else 822 { 823 startatag = tag; 824 imgtag = null; 825 ina = true; 826 href = startatag.getAttribute ("HREF"); 827 if (null != href) 828 { 829 if (!isImage (href)) 830 try 831 { 832 url = new URL (docbase, href); 833 href = url.toExternalForm (); 835 if (!links.containsKey (href)) 836 links.put (href, url); 837 &nb
|