KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > htmlparser > lexerapplications > thumbelina > PicturePanel


1 // HTMLParser Library $Name: v1_5_20050313 $ - A java-based parser for HTML
2
// http://sourceforge.org/projects/htmlparser
3
// Copyright (C) 2003 Derrick Oswald
4
//
5
// Revision Control Information
6
//
7
// $Source: /cvsroot/htmlparser/htmlparser/src/org/htmlparser/lexerapplications/thumbelina/PicturePanel.java,v $
8
// $Author: derrickoswald $
9
// $Date: 2003/09/21 18:20:56 $
10
// $Revision: 1.1 $
11
//
12
// This library is free software; you can redistribute it and/or
13
// modify it under the terms of the GNU Lesser General Public
14
// License as published by the Free Software Foundation; either
15
// version 2.1 of the License, or (at your option) any later version.
16
//
17
// This library is distributed in the hope that it will be useful,
18
// but WITHOUT ANY WARRANTY; without even the implied warranty of
19
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20
// Lesser General Public License for more details.
21
//
22
// You should have received a copy of the GNU Lesser General Public
23
// License along with this library; if not, write to the Free Software
24
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
//
26

27 package org.htmlparser.lexerapplications.thumbelina;
28
29 import java.awt.Component JavaDoc;
30 import java.awt.Dimension JavaDoc;
31 import java.awt.Graphics JavaDoc;
32 import java.awt.Image JavaDoc;
33 import java.awt.Insets JavaDoc;
34 import java.awt.Point JavaDoc;
35 import java.awt.Rectangle JavaDoc;
36 import java.awt.event.ComponentEvent JavaDoc;
37 import java.awt.event.ComponentListener JavaDoc;
38 import java.awt.event.HierarchyEvent JavaDoc;
39 import java.awt.event.HierarchyListener JavaDoc;
40 import java.awt.event.MouseEvent JavaDoc;
41 import java.awt.event.MouseListener JavaDoc;
42 import java.util.Enumeration JavaDoc;
43 import java.util.HashSet JavaDoc;
44 import javax.swing.JPanel JavaDoc;
45 import javax.swing.JViewport JavaDoc;
46 import javax.swing.Scrollable JavaDoc;
47 import javax.swing.border.BevelBorder JavaDoc;
48
49 /**
50  * Hold and display a group of pictures.
51  * @author derrick
52  */

53 public class PicturePanel
54     extends
55         JPanel JavaDoc
56     implements
57         MouseListener JavaDoc,
58         Scrollable JavaDoc,
59         ComponentListener JavaDoc,
60         HierarchyListener JavaDoc
61 {
62     /**
63      * Scrolling unit increment (both directions).
64      */

65     protected static final int UNIT_INCREMENT = 10;
66
67     /**
68      * Scrolling block increment (both directions).
69      */

70     protected static final int BLOCK_INCREMENT = 100;
71
72     /**
73      * The thumbelina object in use.
74      */

75     protected Thumbelina mThumbelina;
76
77     /**
78      * The display mosaic.
79      */

80     protected TileSet mMosaic;
81
82     /**
83      * The preferred size of this component.
84      * <code>null</code> initially, caches the results of
85      * <code>calculatePreferredSize ()</code>.
86      */

87     protected Dimension JavaDoc mPreferredSize;
88
89     /**
90      * Creates a new instance of PicturePanel
91      * @param thumbelina The <code>Thumeblina</code> this panel is associated
92      * with.
93      */

94     public PicturePanel (final Thumbelina thumbelina)
95     {
96         mThumbelina = thumbelina;
97         mMosaic = new TileSet ();
98         mPreferredSize = null;
99         setBorder (new BevelBorder JavaDoc (BevelBorder.LOWERED));
100         addMouseListener (this);
101         addHierarchyListener (this);
102     }
103
104     /**
105      * Clears the panel, discarding any existing images.
106      */

107     public void reset ()
108     {
109         mMosaic = new TileSet ();
110         repaint ();
111     }
112
113     /**
114      * Move the given picture to the top of the Z order.
115      * Adds it, even it if it doesn't exist.
116      * Also puts the URL in the url text of the status bar.
117      * @param picture The picture being brought forward.
118      */

119     public void bringToTop (final Picture picture)
120     {
121         picture.reset ();
122         mMosaic.bringToTop (picture);
123         repaint (picture.x, picture.y, picture.width, picture.height);
124         mThumbelina.mUrlText.setText (picture.getURL ().toExternalForm ());
125     }
126
127     /**
128      * Find a picture with the given URL in the panel.
129      * This should really only be used to discover if the picture is still
130      * visible. There could be more than one picture with the given URL
131      * because it may be partially obscured by another picture, in which
132      * case the pieces are each given their own picture object, but all
133      * point at the same <code>URL</code> and <code>Image</code>.
134      * @param url The url to locate.
135      * @return The first picture encountered in the panel,
136      * or null if the picture was not found.
137      */

138     public Picture find (final String JavaDoc url)
139     {
140         Enumeration JavaDoc enumeration;
141         Picture picture;
142         Picture ret;
143
144         ret = null;
145         enumeration = mMosaic.getPictures ();
146         while ((null == ret) && enumeration.hasMoreElements ())
147         {
148             picture = (Picture)enumeration.nextElement ();
149             if (url.equals (picture.getURL ().toExternalForm ()))
150                 ret = picture;
151         }
152
153         return (ret);
154     }
155
156     /**
157      * Draw an image on screen.
158      * @param picture The picture to draw.
159      * @param add If <code>true</code>, the picture is added to the history.
160      */

161     protected void draw (final Picture picture, final boolean add)
162     {
163         Component JavaDoc parent;
164         boolean dolayout;
165         Dimension JavaDoc before;
166         Dimension JavaDoc after;
167
168         parent = getParent ();
169         dolayout = false;
170         synchronized (mMosaic)
171         {
172             if (parent instanceof JViewport JavaDoc)
173             {
174                 before = getPreferredSize ();
175                 mMosaic.add (picture);
176                 after = calculatePreferredSize ();
177                 if (after.width > before.width)
178                     dolayout = true;
179                 else
180                     after.width = before.width;
181                 if (after.height > before.height)
182                     dolayout = true;
183                 else
184                     after.height = before.height;
185                 if (dolayout)
186                     mPreferredSize = after;
187             }
188             else
189                 mMosaic.add (picture);
190         }
191         if (dolayout)
192             revalidate ();
193         repaint (picture.x, picture.y, picture.width, picture.height);
194         if (add)
195             mThumbelina.addHistory (picture.getURL ().toExternalForm ());
196     }
197
198     /**
199      * Updates this component.
200      * @param graphics The graphics context in which to update the component.
201      */

202     public void update (final Graphics JavaDoc graphics)
203     {
204         paint (graphics);
205     }
206
207     /**
208      * Adjust the graphics clip region to account for insets.
209      * @param graphics The graphics object to set the clip region for.
210      */

211     public void adjustClipForInsets (final Graphics JavaDoc graphics)
212     {
213         Dimension JavaDoc dim;
214         Insets JavaDoc insets;
215         Rectangle JavaDoc clip;
216
217         dim = getSize ();
218         insets = getInsets ();
219         clip = graphics.getClipBounds ();
220         if (clip.x < insets.left)
221             clip.x = insets.left;
222         if (clip.y < insets.top)
223             clip.y = insets.top;
224         if (clip.x + clip.width > dim.width - insets.right)
225             clip.width = dim.width - insets.right - clip.x;
226         if (clip.y + clip.height > dim.height - insets.bottom)
227             clip.height = dim.height - insets.bottom - clip.y;
228         graphics.setClip (clip.x, clip.y, clip.width, clip.height);
229     }
230
231     /**
232      * Paints this component.
233      * Runs through the list of tiles and for every one that intersects
234      * the clip region performs a <code>drawImage()</code>.
235      */

236     public void paint (final Graphics JavaDoc graphics)
237     {
238         Rectangle JavaDoc clip;
239         Enumeration JavaDoc enumeration;
240         HashSet JavaDoc set; // just so we don't draw things twice
241
Picture picture;
242         Image JavaDoc image;
243         Point JavaDoc origin;
244         int width;
245         int height;
246
247         adjustClipForInsets (graphics);
248         clip = graphics.getClipBounds ();
249         synchronized (mMosaic)
250         {
251             if (0 == mMosaic.getSize ())
252                 super.paint (graphics);
253             else
254             {
255                 super.paint (graphics);
256                 enumeration = mMosaic.getPictures ();
257                 set = new HashSet JavaDoc ();
258                 while (enumeration.hasMoreElements ())
259                 {
260                     picture = (Picture)enumeration.nextElement ();
261                     if ((null == clip) || (clip.intersects (picture)))
262                     {
263                         image = picture.getImage ();
264                         if (!set.contains (image))
265                         {
266                             origin = picture.getOrigin ();
267                             width = image.getWidth (this);
268                             height = image.getHeight (this);
269                             graphics.drawImage (picture.getImage (),
270                                 origin.x, origin.y,
271                                 origin.x + width, origin.y + height,
272                                 0, 0, width, height,
273                                 this);
274                             set.add (image);
275                         }
276                     }
277                 }
278             }
279         }
280     }
281
282
283     /**
284      * Get the preferred size of the component.
285      * @return The dimension of this component.
286      */

287     public Dimension JavaDoc getPreferredSize ()
288     {
289         if (null == mPreferredSize)
290             setPreferredSize (calculatePreferredSize ());
291         else
292             if ((0 == mPreferredSize.width) || (0 == mPreferredSize.height))
293                 setPreferredSize (calculatePreferredSize ());
294         return (mPreferredSize);
295     }
296
297     /**
298      * Sets the preferred size of this component.
299      * @param dimension The new value to use for
300      * <code>getPreferredSize()</code> until recalculated.
301      */

302     public void setPreferredSize (final Dimension JavaDoc dimension)
303     {
304         mPreferredSize = dimension;
305     }
306
307     /**
308      * Compute the preferred size of the component.
309      * Computes the minimum bounding rectangle covering all the pictures in
310      * the panel. It then does some funky stuff to handle
311      * embedding in the view port of a scroll pane, basically asking
312      * up the ancestor heirarchy what size is available, and filling it.
313      * @return The optimal dimension for this component.
314      */

315     protected Dimension JavaDoc calculatePreferredSize ()
316     {
317         Enumeration JavaDoc enumeration;
318         int x;
319         int y;
320         Picture picture;
321         Component JavaDoc parent;
322         Insets JavaDoc insets;
323         Dimension JavaDoc ret;
324
325         enumeration = mMosaic.getPictures ();
326         x = 0;
327         y = 0;
328         picture = null;
329         while (enumeration.hasMoreElements ())
330         {
331             picture = (Picture)enumeration.nextElement ();
332             if (picture.x + picture.width > x)
333                 x = picture.x + picture.width;
334             if (picture.y + picture.height > y)
335                 y = picture.y + picture.height;
336         }
337         parent = getParent ();
338         if (parent instanceof JViewport JavaDoc)
339         {
340             ret = parent.getSize ();
341             insets = ((JViewport JavaDoc)parent).getInsets ();
342             ret.width -= insets.left + insets.right;
343             ret.height -= insets.top + insets.bottom;
344             if ((0 != ret.width) || (0 != ret.height))
345                 ret.width -= 2; // ... I dunno why, it just needs it
346
if (ret.width < x)
347                 ret.width = x;
348             if (ret.height < y)
349                 ret.height = y;
350         }
351         else
352         {
353             insets = getInsets ();
354             x += insets.left + insets.right;
355             y += insets.top + insets.bottom;
356             ret = new Dimension JavaDoc (x, y);
357         }
358
359         return (ret);
360     }
361
362     //
363
// MouseListener Interface
364
//
365

366     /**
367      * Invoked when the mouse button has been clicked
368      * (pressed and released) on a component.
369      * <i>Not used.</i>
370      * @param event The object providing details of the mouse event.
371      */

372     public void mouseClicked (final MouseEvent JavaDoc event)
373     {
374     }
375
376     /**
377      *Invoked when a mouse button has been released on a component.
378      * <i>Not used.</i>
379      * @param event The object providing details of the mouse event.
380      */

381     public void mouseReleased (final MouseEvent JavaDoc event)
382     {
383     }
384
385     /**
386      * Invoked when the mouse enters a component.
387      * <i>Not used.</i>
388      * @param event The object providing details of the mouse event.
389      */

390     public void mouseEntered (final MouseEvent JavaDoc event)
391     {
392     }
393
394     /**
395      * Invoked when the mouse exits a component.
396      * <i>Not used.</i>
397      * @param event The object providing details of the mouse event.
398      */

399     public void mouseExited (final MouseEvent JavaDoc event)
400     {
401     }
402
403     /**
404      * Handle left click on a picture by bringing it to the top.
405      * @param event The object providing details of the mouse event.
406      */

407     public void mousePressed (final MouseEvent JavaDoc event)
408     {
409         Picture picture;
410
411         if (!event.isMetaDown ())
412         {
413             picture = mMosaic.pictureAt (event.getX (), event.getY ());
414             if (null != picture)
415                 bringToTop (picture);
416         }
417     }
418
419     //
420
// Scrollable interface
421
//
422

423     /**
424      * Returns the preferred size of the viewport for a view component.
425      * For example the preferredSize of a JList component is the size
426      * required to accommodate all of the cells in its list however the
427      * value of preferredScrollableViewportSize is the size required for
428      * JList.getVisibleRowCount() rows. A component without any properties
429      * that would effect the viewport size should just return
430      * getPreferredSize() here.
431      *
432      * @return The preferredSize of a JViewport whose view is this Scrollable.
433      * @see JViewport#getPreferredSize
434      */

435     public Dimension JavaDoc getPreferredScrollableViewportSize ()
436     {
437         return (getPreferredSize ());
438     }
439
440
441     /**
442      * Components that display logical rows or columns should compute
443      * the scroll increment that will completely expose one new row
444      * or column, depending on the value of orientation. Ideally,
445      * components should handle a partially exposed row or column by
446      * returning the distance required to completely expose the item.
447      * <p>
448      * Scrolling containers, like JScrollPane, will use this method
449      * each time the user requests a unit scroll.
450      *
451      * @param visibleRect The view area visible within the viewport
452      * @param orientation Either SwingConstants.VERTICAL or
453      * SwingConstants.HORIZONTAL.
454      * @param direction Less than zero to scroll up/left,
455      * greater than zero for down/right.
456      * @return The "unit" increment for scrolling in the specified direction.
457      * This value should always be positive.
458      */

459     public int getScrollableUnitIncrement (
460         final Rectangle JavaDoc visibleRect,
461         final int orientation,
462         final int direction)
463     {
464         return (UNIT_INCREMENT);
465     }
466
467
468     /**
469      * Components that display logical rows or columns should compute
470      * the scroll increment that will completely expose one block
471      * of rows or columns, depending on the value of orientation.
472      * <p>
473      * Scrolling containers, like JScrollPane, will use this method
474      * each time the user requests a block scroll.
475      *
476      * @param visibleRect The view area visible within the viewport
477      * @param orientation Either SwingConstants.VERTICAL or
478      * SwingConstants.HORIZONTAL.
479      * @param direction Less than zero to scroll up/left,
480      * greater than zero for down/right.
481      * @return The "block" increment for scrolling in the specified direction.
482      * This value should always be positive.
483      */

484     public int getScrollableBlockIncrement (
485         final Rectangle JavaDoc visibleRect,
486         final int orientation,
487         final int direction)
488     {
489         return (BLOCK_INCREMENT);
490     }
491
492
493     /**
494      * Return true if a viewport should always force the width of this
495      * <code>Scrollable</code> to match the width of the viewport.
496      * For example a normal
497      * text view that supported line wrapping would return true here, since it
498      * would be undesirable for wrapped lines to disappear beyond the right
499      * edge of the viewport. Note that returning true for a Scrollable
500      * whose ancestor is a JScrollPane effectively disables horizontal
501      * scrolling.
502      * <p>
503      * Scrolling containers, like JViewport, will use this method each
504      * time they are validated.
505      *
506      * @return <code>true</code> if a viewport should force the Scrollables
507      * width to match its own.
508      */

509     public boolean getScrollableTracksViewportWidth ()
510     {
511         return (false);
512     }
513
514     /**
515      * Return true if a viewport should always force the height of this
516      * Scrollable to match the height of the viewport. For example a
517      * columnar text view that flowed text in left to right columns
518      * could effectively disable vertical scrolling by returning
519      * true here.
520      * <p>
521      * Scrolling containers, like JViewport, will use this method each
522      * time they are validated.
523      *
524      * @return <code>true</code> if a viewport should force the Scrollables
525      * height to match its own.
526      */

527     public boolean getScrollableTracksViewportHeight ()
528     {
529         return (false);
530     }
531
532     //
533
// ComponentListener interface
534
//
535

536     /**
537      * Invoked when the container's size changes.
538      * Un-caches the preferred size.
539      * @param event The resize event.
540      */

541     public void componentResized (final ComponentEvent JavaDoc event)
542     {
543         setPreferredSize (null);
544     }
545
546     /**
547      * Invoked when the component's position changes.
548      * <i>Not used.</I>
549      * @param event The component event.
550      */

551     public void componentMoved (final ComponentEvent JavaDoc event)
552     {
553     }
554
555     /**
556      * Invoked when the component has been made visible.
557      * <i>Not used.</I>
558      * @param event The component event.
559      */

560     public void componentShown (final ComponentEvent JavaDoc event)
561     {
562     }
563
564     /**
565      * Invoked when the component has been made invisible.
566      * <i>Not used.</I>
567      * @param event The component event.
568      */

569     public void componentHidden (final ComponentEvent JavaDoc event)
570     {
571     }
572
573     //
574
// HierarchyListener interface
575
//
576

577     /**
578      * Handles this components ancestor being added to a container.
579      * Registers this component as a listener for size changes on the
580      * ancestor so that we may un-cache the prefereed size and force
581      * a recalculation.
582      * @param event The heirarchy event.
583      */

584     public void hierarchyChanged (final HierarchyEvent JavaDoc event)
585     {
586         if (0 != (event.getChangeFlags () & HierarchyEvent.PARENT_CHANGED))
587         {
588             Component JavaDoc dad = event.getChanged ();
589             Component JavaDoc parent = getParent ();
590             if ((null != parent) && (parent.getParent () == dad))
591                 dad.addComponentListener (this);
592         }
593     }
594 }
595
596 /*
597  * Revision Control Modification History
598  *
599  * $Log: PicturePanel.java,v $
600  * Revision 1.1 2003/09/21 18:20:56 derrickoswald
601  * Thumbelina
602  * Created a lexer GUI application to extract images behind thumbnails.
603  * Added a task in the ant build script - thumbelina - to create the jar file.
604  * You need JDK 1.4.x to build it. It can be run on JDK 1.3.x in crippled mode.
605  * Usage: java -Xmx256M thumbelina.jar [URL]
606  *
607  *
608  */

609
Popular Tags