FilterBuilder.java
1 // HTMLParser Library $Name: v1_6_20060319 $ - A java-based parser for HTML 2 // http://sourceforge.org/projects/htmlparser 3 // Copyright (C) 2005 Derrick Oswald 4 // 5 // Revision Control Information 6 // 7 // $Source: /cvsroot/htmlparser/htmlparser/src/org/htmlparser/parserapplications/filterbuilder/FilterBuilder.java,v $ 8 // $Author: derrickoswald $ 9 // $Date: 2005/04/12 11:27:42 $ 10 // $Revision: 1.5 $ 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.parserapplications.filterbuilder; 28 29 import java.awt.BorderLayout; 30 import java.awt.Component; 31 import java.awt.Container; 32 import java.awt.Dimension; 33 import java.awt.Event; 34 import java.awt.FileDialog; 35 import java.awt.FlowLayout; 36 import java.awt.Insets; 37 import java.awt.Point; 38 import java.awt.Toolkit; 39 import java.awt.datatransfer.Clipboard; 40 import java.awt.datatransfer.ClipboardOwner; 41 import java.awt.datatransfer.DataFlavor; 42 import java.awt.datatransfer.StringSelection; 43 import java.awt.datatransfer.Transferable; 44 import java.awt.datatransfer.UnsupportedFlavorException; 45 import java.awt.dnd.DnDConstants; 46 import java.awt.dnd.DragGestureEvent; 47 import java.awt.dnd.DragGestureListener; 48 import java.awt.dnd.DragSource; 49 import java.awt.dnd.DragSourceDragEvent; 50 import java.awt.dnd.DragSourceDropEvent; 51 import java.awt.dnd.DragSourceEvent; 52 import java.awt.dnd.DragSourceListener; 53 import java.awt.dnd.DropTarget; 54 import java.awt.dnd.DropTargetContext; 55 import java.awt.dnd.DropTargetDragEvent; 56 import java.awt.dnd.DropTargetDropEvent; 57 import java.awt.dnd.DropTargetEvent; 58 import java.awt.dnd.DropTargetListener; 59 import java.awt.event.ActionEvent; 60 import java.awt.event.ActionListener; 61 import java.awt.event.InputEvent; 62 import java.awt.event.KeyEvent; 63 import java.awt.event.MouseEvent; 64 import java.awt.event.MouseListener; 65 import java.awt.event.MouseMotionListener; 66 import java.awt.event.WindowEvent; 67 import java.awt.event.WindowListener; 68 import java.beans.PropertyVetoException; 69 import java.io.File; 70 import java.io.FileReader; 71 import java.io.FileWriter; 72 import java.io.IOException; 73 import java.io.LineNumberReader; 74 import java.io.PrintWriter; 75 import java.io.StringWriter; 76 import java.lang.reflect.Method; 77 import java.net.MalformedURLException; 78 import java.net.URL; 79 import java.util.Vector; 80 81 import javax.swing.Icon; 82 import javax.swing.ImageIcon; 83 import javax.swing.JButton; 84 import javax.swing.JDesktopPane; 85 import javax.swing.JFrame; 86 import javax.swing.JInternalFrame; 87 import javax.swing.JMenu; 88 import javax.swing.JMenuBar; 89 import javax.swing.JMenuItem; 90 import javax.swing.JOptionPane; 91 import javax.swing.JPanel; 92 import javax.swing.JPopupMenu; 93 import javax.swing.JScrollPane; 94 import javax.swing.JSeparator; 95 import javax.swing.JSplitPane; 96 import javax.swing.JTextField; 97 //import javax.swing.JTextPane; 98 import javax.swing.JToolBar; 99 import javax.swing.JTree; 100 import javax.swing.KeyStroke; 101 import javax.swing.ScrollPaneConstants; 102 import javax.swing.WindowConstants; 103 104 import org.htmlparser.Parser; 105 import org.htmlparser.beans.FilterBean; 106 import org.htmlparser.parserapplications.filterbuilder.layouts.NullLayoutManager; 107 import org.htmlparser.util.EncodingChangeException; 108 import org.htmlparser.util.NodeIterator; 109 import org.htmlparser.util.NodeList; 110 import org.htmlparser.util.ParserException; 111 112 /** 113 * The main program for the FilterBuilder programming system. 114 * <p>ToDo: 115 * <ul> 116 * <li>thread the attribute fetching</li> 117 * <li>CSS selector filter</li> 118 * <li>table row filter</li> 119 * <li>table column filter</li> 120 * <li>trigger filter</li> 121 * <li>undo</li> 122 * <li>handle bad URLs</li> 123 * <li>StringBean type secondary text output</li> 124 * <li>context sensitive menus</li> 125 * </ul> 126 */ 127 public class FilterBuilder 128 extends 129 JFrame 130 implements 131 WindowListener, 132 ActionListener, 133 MouseListener, 134 MouseMotionListener, 135 DragGestureListener, 136 DragSourceListener, 137 DropTargetListener, 138 ClipboardOwner 139 { 140 static final String TITLE = "HTML Parser FilterBuilder"; 141 142 static final URL mDocumentBase; 143 144 static 145 { 146 147 String p; 148 char ps; 149 URL base; 150 151 p = System.getProperty ("user.dir"); 152 // if the system file separator isn't the URL file separator convert it. 153 try 154 { 155 ps = (System.getProperty ("file.separator")).charAt(0); 156 if ('/' != ps) 157 p.replace (ps, '/'); 158 } 159 catch (StringIndexOutOfBoundsException e) 160 { 161 } 162 163 try 164 { 165 base = new URL ("file:///" + p + "/"); 166 } 167 catch (MalformedURLException murle) 168 { 169 base = null; 170 } 171 mDocumentBase = base; 172 } 173 174 static String mHomeDir; 175 176 static 177 { 178 String dir; 179 File file; 180 181 dir = System.getProperty ("user.home") 182 + System.getProperty ("file.separator") 183 + ".htmlparser"; 184 file = new File (dir); 185 if (!file.exists ()) 186 if (!file.mkdirs ()) // make the directory if it doesn't exist 187 throw new RuntimeException ( 188 "cannot create directory " 189 + file.getAbsolutePath ()); 190 mHomeDir = file.getAbsolutePath (); 191 } 192 193 /** 194 * The relative position of the mouse while dragging. 195 */ 196 protected Point mBasePoint; 197 198 /** 199 * Selected commands. 200 */ 201 protected Vector mSelection; 202 203 /** 204 * If true selection moved. 205 */ 206 protected boolean mMoved; 207 208 /** 209 * This component is a drop target. 210 */ 211 protected DropTarget mDropTarget; 212 213 /** 214 * Enables this component to be a Drag Source. 215 */ 216 protected DragSource mDragSource; 217 218 /** 219 * Kludge: Used by actionPerformed/filterAction to remember the filter menu item. 220 */ 221 protected Component mCurrentComponent; 222 223 /** 224 * The main panel GUI component. 225 */ 226 protected JPanel mMainPanel; 227 228 /** 229 * The main panel scrolling GUI component. 230 */ 231 protected JScrollPane mMainScroller; 232 233 /** 234 * The URL input GUI component. 235 */ 236 protected JTextField mURLField; 237 238 /** 239 * The output panel GUI component. 240 */ 241 protected JDesktopPane mOutput; 242 243 /** 244 * Create an FilterBuilder programming environment. 245 */ 246 public FilterBuilder () 247 { 248 JMenuBar menubar; 249 JToolBar toolbar; 250 JMenu menu; 251 JPanel panel; 252 JScrollPane pane; 253 JSplitPane split; 254 JMenuItem item; 255 256 // drag and drop support 257 mMainPanel = new JPanel (); 258 mDropTarget = new DropTarget (mMainPanel, this); 259 mDragSource = new DragSource (); 260 261 // menu and toolbar 262 menubar = new JMenuBar(); 263 toolbar = new JToolBar (); 264 toolbar.setAlignmentY (0.222222F); 265 266 // file menu 267 menu = new JMenu (); 268 menu.setText ("File"); 269 menu.setActionCommand ("File"); 270 menu.setMnemonic ((int)'F'); 271 makeMenuButton ("New", "Create a new document", "New", 'N', KeyStroke.getKeyStroke (KeyEvent.VK_N, Event.CTRL_MASK), toolbar, menu); 272 makeMenuButton ("Open", "Open an existing document", "Open...", 'O', KeyStroke.getKeyStroke (KeyEvent.VK_O, Event.CTRL_MASK), toolbar, menu); 273 makeMenuButton ("Save", "Save the active document", "Save...", 'S', KeyStroke.getKeyStroke (KeyEvent.VK_S, Event.CTRL_MASK), toolbar, menu); 274 makeMenuButton ("SaveAs", "Save the active document", "Save As...", 'A', KeyStroke.getKeyStroke (KeyEvent.VK_A, Event.CTRL_MASK), null, menu); 275 menu.add (new JSeparator ()); 276 makeMenuButton ("Exit", "Exit the program", "Exit", 'E', KeyStroke.getKeyStroke (KeyEvent.VK_E, Event.CTRL_MASK), null, menu); 277 menubar.add (menu); 278 279 toolbar.add(new JToolBar.Separator()); 280 281 // edit menu 282 menu = new JMenu (); 283 menu.setText ("Edit"); 284 menu.setActionCommand ("Edit"); 285 menu.setMnemonic ((int)'E'); 286 makeMenuButton ("Cut", "Cut the selection and put it on the Clipboard", "Cut", 'T', KeyStroke.getKeyStroke (KeyEvent.VK_X, Event.CTRL_MASK), toolbar, menu); 287 makeMenuButton ("Copy", "Copy the selection and put it on the Clipboard", "Copy", 'C', KeyStroke.getKeyStroke (KeyEvent.VK_C, Event.CTRL_MASK), toolbar, menu); 288 makeMenuButton ("Paste", "Insert Clipboard contents", "Paste", 'P', KeyStroke.getKeyStroke (KeyEvent.VK_V, Event.CTRL_MASK), toolbar, menu); 289 makeMenuButton ("Delete", "Delete the selection", "Delete", 'D', KeyStroke.getKeyStroke (KeyEvent.VK_DELETE, 0), toolbar, menu); 290 menubar.add (menu); 291 292 // filter menu 293 menu = new JMenu (); 294 menu.setText ("Filter"); 295 menu.setActionCommand ("Filter"); 296 menu.setMnemonic ((int)'F'); 297 menubar.add (menu); 298 299 toolbar.add (new JToolBar.Separator()); 300 301 // filters menu and filters toolbar 302 addFilter (menu, toolbar, "org.htmlparser.parserapplications.filterbuilder.wrappers.AndFilterWrapper"); 303 addFilter (menu, toolbar, "org.htmlparser.parserapplications.filterbuilder.wrappers.OrFilterWrapper"); 304 addFilter (menu, toolbar, "org.htmlparser.parserapplications.filterbuilder.wrappers.NotFilterWrapper"); 305 menu.addSeparator (); 306 toolbar.add (new JToolBar.Separator ()); 307 308 addFilter (menu, toolbar, "org.htmlparser.parserapplications.filterbuilder.wrappers.StringFilterWrapper"); 309 addFilter (menu, toolbar, "org.htmlparser.parserapplications.filterbuilder.wrappers.RegexFilterWrapper"); 310 addFilter (menu, toolbar, "org.htmlparser.parserapplications.filterbuilder.wrappers.TagNameFilterWrapper"); 311 addFilter (menu, toolbar, "org.htmlparser.parserapplications.filterbuilder.wrappers.NodeClassFilterWrapper"); 312 addFilter (menu, toolbar, "org.htmlparser.parserapplications.filterbuilder.wrappers.HasAttributeFilterWrapper"); 313 menu.addSeparator (); 314 toolbar.add (new JToolBar.Separator ()); 315 316 addFilter (menu, toolbar, "org.htmlparser.parserapplications.filterbuilder.wrappers.HasParentFilterWrapper"); 317 addFilter (menu, toolbar, "org.htmlparser.parserapplications.filterbuilder.wrappers.HasChildFilterWrapper"); 318 addFilter (menu, toolbar, "org.htmlparser.parserapplications.filterbuilder.wrappers.HasSiblingFilterWrapper"); 319 menu.addSeparator (); 320 toolbar.add (new JToolBar.Separator ()); 321 322 // operation menu 323 menu = new JMenu (); 324 menu.setText ("Operation"); 325 menu.setActionCommand ("Operation"); 326 menu.setMnemonic ((int)'r'); 327 item = new JMenuItem (); 328 item.setText ("Expand"); 329 item.setActionCommand ("expandAction"); 330 item.addActionListener (this); 331 menu.add (item); 332 item = new JMenuItem (); 333 item.setText ("Collapse"); 334 item.setActionCommand ("collapseAction"); 335 item.addActionListener (this); 336 menu.add (item); 337 menu.addSeparator (); 338 item = new JMenuItem (); 339 item.setText ("Expand All"); 340 item.setActionCommand ("expandAllAction"); 341 item.addActionListener (this); 342 menu.add (item); 343 item = new JMenuItem (); 344 item.setText ("Collapse All"); 345 item.setActionCommand ("collapseAllAction"); 346 item.addActionListener (this); 347 menu.add (item); 348 menu.addSeparator (); 349 item = new JMenuItem ("Fetch Page"); 350 item.setActionCommand ("fetchAction"); 351 item.addActionListener (this); 352 menu.add (item); 353 item = new JMenuItem ("Execute Filter"); 354 item.setActionCommand ("executeAction"); 355 item.addActionListener (this); 356 menu.add (item); 357 menubar.add (menu); 358 359 // help menu 360 menu = new JMenu (); 361 menu.setText ("Help"); 362 menu.setActionCommand ("Help"); 363 menu.setMnemonic ((int)'H'); 364 item = new JMenuItem ("Filtering"); 365 item.setActionCommand ("filteringAction"); 366 item.addActionListener (this); 367 menu.add (item); 368 item = new JMenuItem ("Instructions"); 369 item.setActionCommand ("instructionsAction"); 370 item.addActionListener (this); 371 menu.add (item); 372 item = new JMenuItem ("Tutorial"); 373 item.setActionCommand ("tutorialAction"); 374 item.addActionListener (this); 375 menu.add (item); 376 item = new JMenuItem ("Hints"); 377 item.setActionCommand ("hintsAction"); 378 item.addActionListener (this); 379 menu.add (item); 380 makeMenuButton ("About", "Display program information, version number and copyright", "About", 'B', KeyStroke.getKeyStroke (KeyEvent.VK_H, Event.CTRL_MASK), toolbar, menu); 381 menubar.add (menu); 382 383 setJMenuBar (menubar); 384 385 // toolbar panel 386 panel = new JPanel (); 387 panel.setLayout (new FlowLayout (FlowLayout.LEFT,0,0)); 388 panel.add (toolbar); 389 getContentPane().setLayout (new BorderLayout (0,0)); 390 getContentPane ().add (BorderLayout.NORTH, panel); 391 392 // URL entry 393 mURLField = new JTextField (); 394 mURLField.setToolTipText ("Enter the URL to view"); 395 // mTextField.addActionListener (this); 396 mURLField.setText ("http://sourceforge.org/projects/htmlparser"); 397 getContentPane().add (BorderLayout.SOUTH, mURLField); 398 399 // application setup 400 setTitle (TITLE); 401 setDefaultCloseOperation (WindowConstants.DO_NOTHING_ON_CLOSE); 402 setSize (640, 480); 403 setVisible (false); 404 405 // main panel 406 mMainPanel.setLayout (new NullLayoutManager ()); 407 mMainScroller = new JScrollPane ( 408 mMainPanel, 409 ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, 410 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); 411 412 split = new JSplitPane (); 413 pane = new JScrollPane (); 414 pane.setViewportView (mMainScroller); 415 split.setLeftComponent (pane); 416 417 mOutput = new JDesktopPane (); 418 split.setRightComponent (mOutput); 419 420 getContentPane().add (BorderLayout.CENTER, split); 421 422 // shenanigans to get the splitter bar at the midpoint 423 setVisible (true); 424 split.setDividerLocation (0.5); 425 setVisible (false); 426 427 // listeners 428 addWindowListener (this); 429 setIconImage (Toolkit.getDefaultToolkit ().getImage ("images/program16.gif")); 430 addMouseListener (this); 431 addMouseMotionListener (this); 432 433 // clipboard buffer 434 mSelection = new Vector (); 435 } 436 437 /** 438 * Creates a new instance of an FilterBuilder environment with the given title. 439 * @param title the title for the new frame. 440 * @see #FilterBuilder() 441 */ 442 public FilterBuilder (String title) 443 { 444 this (); 445 setTitle (title); 446 } 447 448 /** 449 * Makes menu and toolbar items for commands. 450 * @param name The name of the command. 451 * @param description A description for the tooltip. 452 * @param text The text for the menu. 453 * @param mnemonic The navigation mnemonic. 454 * @param key Accelerator key. 455 * @param toolbar The toolbar to add the button to. 456 * @param menu The menu to add the menu item to. 457 */ 458 protected void makeMenuButton ( 459 String name, 460 String description, 461 String text, 462 int mnemonic, 463 KeyStroke key, 464 JToolBar toolbar, 465 JMenu menu) 466 { 467 JButton button; 468 JMenuItem item; 469 ImageIcon icon; 470 String command; 471 472 command = name.toLowerCase (); 473 try 474 { 475 icon = new ImageIcon (getURL ("images/" + command + ".gif")); 476 } 477 catch (java.net.MalformedURLException error) 478 { 479 icon = null; 480 } 481 482 item = new JMenuItem (); 483 item.setText (text); 484 item.setActionCommand (command + "Action"); 485 item.setAccelerator (key); 486 item.setMnemonic (mnemonic); 487 item.setIcon (icon); 488 item.addActionListener (this); 489 menu.add (item); 490 491 if (null != toolbar) 492 { 493 button = new JButton (); 494 button.setDefaultCapable (false); 495 button.setToolTipText (description); 496 button.setMnemonic (mnemonic); 497 button.setActionCommand (command + "Action"); 498 button.setMargin (new Insets (0, 0, 0, 0)); 499 button.setIcon (icon); 500 button.addActionListener (this); 501 toolbar.add (button); 502 } 503 } 504 505 /** 506 * Get a url for the given resource specification. 507 * @param spec The name of the resource. 508 * @return The fully formed URL. 509 * @exception MalformedURLException In the case that the document base 510 * or name of the resource cannot be turned into a URL. 511 */ 512 protected URL getURL (String spec) 513 throws MalformedURLException 514 { 515 URL ret; 516 517 if (null == (ret = getClass ().getResource (spec))) 518 if ((null != mDocumentBase) && (-1 == spec.indexOf ("//"))) 519 ret = new URL (mDocumentBase, spec); 520 else 521 ret = new URL (spec); 522 523 return ret; 524 } 525 526 /** 527 * Creates a new button for the given class. 528 * @param class_name The name of the Filter class. 529 * @return A fully functional button with name, tool tip, 530 * icon and drag recognizer. 531 */ 532 public JButton makeFilterButton (String class_name) 533 { 534 Filter filter; 535 JButton ret; 536 537 ret = new JButton (); 538 filter = Filter.instantiate (class_name); 539 if (null != filter) 540 { 541 ret.setName (class_name); // filter.getNodeFilter ().getClass ().getName ()); 542 ret.setToolTipText (filter.getDescription ()); 543 ret.setMargin (new Insets (0, 0, 0, 0)); 544 ret.setIcon (filter.getIcon ()); 545 mDragSource.createDefaultDragGestureRecognizer ( 546 ret, 547 DnDConstants.ACTION_MOVE, 548 this); 549 ret.setActionCommand ("filterAction"); 550 ret.addActionListener (this); 551 } 552 553 return (ret); 554 } 555 556 /** 557 * Add a filter to the GUI. 558 * Adds the filter specified by class_name to the menu, toolbar and 559 * starts listening for actions. 560 * @param menu The menu to add the filter to. 561 * @param toolbar The toolbar to add the filter to. 562 * @param class_name The class name for the filter wrapper. 563 * From the wrapper, the NodeFilter, description and icon can be obtained. 564 */ 565 public void addFilter (JMenu menu, JToolBar toolbar, String class_name) 566 { 567 Filter filter; 568 569 filter = Filter.instantiate (class_name); 570 if (null != filter) 571 { 572 String name; 573 String description; 574 Icon icon; 575 String text; 576 JMenuItem item; 577 578 name = filter.getNodeFilter ().getClass ().getName (); 579 description = filter.getDescription (); 580 icon = filter.getIcon (); 581 text = name.substring (name.lastIndexOf ('.') + 1); 582 583 item = new JMenuItem (); 584 item.setName (class_name); 585 item.setText (text); 586 item.setActionCommand ("filterAction"); 587 // item.setAccelerator (key); 588 // item.setMnemonic (mnemonic); 589 item.setToolTipText (description); 590 item.setIcon (icon); 591 item.addActionListener (this); 592 menu.add (item); 593 594 toolbar.add (makeFilterButton (class_name)); 595 } 596 } 597 598 /** 599 * Adds a set of filters to the main panel or a sublist. 600 * Sets up the GUI components as drop targets and mouse listeners, 601 * and performs a relayout to display them. 602 * @param filters The filter wrappers to add. 603 * @param point The point at which to start adding (list == null). 604 * @param list The list to add to (point not used), or <code>null</code> 605 * for the main panel. 606 */ 607 protected void insertFilters (Filter[] filters, Point point, SubFilterList list) 608 { 609 Dimension dimension; 610 611 if (null == list) 612 { 613 for (int i = 0; i < filters.length; i++) 614 { 615 filters[i].setLocation (point); 616 mMainPanel.add (filters[i]); 617 dimension = filters[i].getPreferredSize (); 618 point.y += dimension.height; 619 } 620 } 621 else 622 for (int i = 0; i < filters.length; i++) 623 list.addFilter (filters[i]); 624 setupDropTargets (filters); 625 setupMouseListeners (filters); 626 relayout (); 627 } 628 629 /** 630 * Sets the position of the mouse in the component. 631 * 632 * @param point The point where the mouse position is. 633 */ 634 protected void setBasePoint (Point point) 635 { 636 mBasePoint = point; 637 } 638 639 /** 640 * Gets the current base point of the mouse pointer. 641 * This value is used to offset the drag position 642 * to maintain the mouse position at the same 643 * relative position within the card while dragging. 644 * 645 * @return The current base point of the mouse pointer. 646 */ 647 protected Point getBasePoint () 648 { 649 return (mBasePoint); 650 } 651 652 /** 653 * Get the enclosing sub filter list if any. 654 * @param component The component that's supposedly enclosed. 655 * @return The enclosing component or <code>null</code> otherwise. 656 */ 657 protected SubFilterList getEnclosing (Component component) 658 { 659 do 660 component = component.getParent (); 661 while ( (null != component) 662 && !(component instanceof SubFilterList)); 663 664 return ((SubFilterList)component); 665 } 666 667 /** 668 * Get the enclosed sub filter list if any. 669 * @param component The component that's supposedly enclosing the list. 670 * @return The enclosed component or <code>null</code> otherwise. 671 */ 672 protected SubFilterList getEnclosed (Component component) 673 { 674 Component[] list; 675 676 if (component instanceof Container) 677 { 678 list = ((Container)component).getComponents (); 679 for (int i = 0; i < list.length; i++) 680 if (list[i] instanceof SubFilterList) 681 return ((SubFilterList)list[i]); 682 } 683 684 return (null); 685 } 686 687 688 /** 689 * Makes a program like: 690 * <pre> 691 * // Generated by FilterBuilder. http://htmlparser.org 692 * // [aced0005737200206f72672e68746d6c7061727365722e66696c746572732e416e6446696c74657224c30516b2b7b2120200015b000b6d5072656469636174657374001c5b4c6f72672f68746d6c7061727365722f4e6f646546696c7465723b78707572001c5b4c6f72672e68746d6c7061727365722e4e6f646546696c7465723b8f17479b1d5f7992020000787000000002737200246f72672e68746d6c7061727365722e66696c746572732e5461674e616d6546696c746572b28b2601a614890f0200014c00056d4e616d657400124c6a6176612f6c616e672f537472696e673b78707400044d455441737200296f72672e68746d6c7061727365722e66696c746572732e48617341747472696275746546696c74657296abdfb3b0714cda0200024c000a6d41747472696275746571007e00064c00066d56616c756571007e000678707400046e616d6570] 693 * 694 * import org.htmlparser.*; 695 * import org.htmlparser.filters.*; 696 * import org.htmlparser.beans.*; 697 * import org.htmlparser.util.*; 698 * 699 * public class Test 700 * { 701 * public static void main (String args[]) 702 * { 703 * TagNameFilter filter0 = new TagNameFilter (); 704 * filter0.setName ("META"); 705 * HasAttributeFilter filter1 = new HasAttributeFilter (); 706 * filter1.setAttributeName ("name"); 707 * NodeFilter[] array0 = new NodeFilter[2]; 708 * array0[0] = filter0; 709 * array0[1] = filter1; 710 * AndFilter filter2 = new AndFilter (); 711 * filter2.setPredicates (array0); 712 * NodeFilter[] array1 = new NodeFilter[1]; 713 * array1[0] = filter2; 714 * FilterBean bean = new FilterBean (); 715 * bean.setFilters (array1); 716 * if (0 != args.length) 717 * { 718 * bean.setURL (args[0]); 719 * System.out.println (bean.getNodes ().toHtml ()); 720 * } 721 * else 722 * System.out.println ("Usage: java -classpath .:htmlparser.jar Test <url>"); 723 * } 724 * } 725 * </pre> 726 * @param name The name of the class. 727 * @param out The buffer to append to. 728 * @param bean The bean to extract the filters from to make the program. 729 */ 730 protected void makeProgram (String name, StringBuffer out, FilterBean bean) 731 { 732 // so we need to keep track of filters and arrays of filters to give them unique numbers 733 // each Filter is responsible for outputting it's code and returning it's variable name 734 int[] context; // 0 - indent, 1 - next filter variable #, 2 - next array of filters variable # 735 String[] names; 736 Filter[] filters; 737 String array; 738 739 filters = (Filter[])bean.getFilters (); 740 741 context = new int[3]; 742 context[0] = 0; 743 744 Filter.spaces (out, context[0]); 745 out.append ("// Generated by FilterBuilder. http://htmlparser.org"); 746 Filter.newline (out); 747 Filter.spaces (out, context[0]); 748 out.append ("// "); 749 try 750 { 751 out.append (Filter.deconstitute (filters)); 752 } 753 catch (IOException ioe) 754 { 755 ioe.printStackTrace (); 756 } 757 Filter.newline (out); 758 Filter.newline (out); 759 760 Filter.spaces (out, context[0]); 761 out.append ("import org.htmlparser.*;"); 762 Filter.newline (out); 763 Filter.spaces (out, context[0]); 764 out.append ("import org.htmlparser.filters.*;"); 765 Filter.newline (out); 766 Filter.spaces (out, context[0]); 767 out.append ("import org.htmlparser.beans.*;"); 768 Filter.newline (out); 769 Filter.spaces (out, context[0]); 770 out.append ("import org.htmlparser.util.*;"); 771 Filter.newline (out); 772 Filter.newline (out); 773 774 Filter.spaces (out, context[0]); 775 out.append ("public class "); 776 out.append (name); 777 Filter.newline (out); 778 Filter.spaces (out, context[0]); 779 out.append ("{"); 780 781 context[0] = 4; 782 Filter.newline (out); 783 Filter.spaces (out, context[0]); 784 out.append ("public static void main (String args[])"); 785 Filter.newline (out); 786 Filter.spaces (out, context[0]); 787 out.append ("{"); 788 Filter.newline (out); 789 790 context[0] = 8; 791 names = new String [filters.length]; 792 for (int i = 0; i < names.length; i++) 793 names[i] = filters[i].toJavaCode (out, context); 794 795 array = "array" + context[2]++; 796 Filter.spaces (out, context[0]); 797 out.append ("NodeFilter[] "); 798 out.append (array); 799 out.append (" = new NodeFilter["); 800 out.append (filters.length); 801 out.append ("];"); 802 Filter.newline (out); 803 for (int i = 0; i < filters.length; i++) 804 { 805 Filter.spaces (out, context[0]); 806 out.append (array); 807 out.append ("["); 808 out.append (i); 809 out.append ("] = "); 810 out.append (names[i]); 811 out.append (";"); 812 Filter.newline (out); 813 } 814 815 Filter.spaces (out, context[0]); 816 out.append ("FilterBean bean = new FilterBean ();"); 817 Filter.newline (out); 818 Filter.spaces (out, context[0]); 819 out.append ("bean.setFilters ("); 820 out.append (array); 821 out.append (");"); 822 Filter.newline (out); 823 Filter.spaces (out, context[0]); 824 out.append ("if (0 != args.length)"); 825 Filter.newline (out); 826 Filter.spaces (out, context[0]); 827 out.append ("{"); 828 Filter.newline (out); 829 context[0] = 12; 830 Filter.spaces (out, context[0]); 831 out.append ("bean.setURL (args[0]);"); 832 Filter.newline (out); 833 Filter.spaces (out, context[0]); 834 out.append ("System.out.println (bean.getNodes ().toHtml ());"); 835 Filter.newline (out); 836 context[0] = 8; 837 Filter.spaces (out, context[0]); 838 out.append ("}"); 839 Filter.newline (out); 840 Filter.spaces (out, context[0]); 841 out.append ("else"); 842 Filter.newline (out); 843 context[0] = 12; 844 Filter.spaces (out, context[0]); 845 out.append ("System.out.println (\"Usage: java -classpath .:htmlparser.jar "); 846 out.append (name); 847 out.append (" <url>\");"); 848 Filter.newline (out); 849 850 context[0] = 4; 851 Filter.spaces (out, context[0]); 852 out.append ("}"); 853 Filter.newline (out); 854 855 context[0] = 0; 856 Filter.spaces (out, context[0]); 857 out.append ("}"); 858 Filter.newline (out); 859 } 860 861 /** 862 * Extracts a java class name from a file name. 863 * ToDo: make this package-smart somehow. 864 * @param file The name of the file. 865 * @return The name of the class. 866 */ 867 protected String classFromFile (String file) 868 { 869 String filesep; 870 int index; 871 872 // remove any path 873 filesep = System.getProperty ("file.separator"); 874 index = file.lastIndexOf (filesep); 875 if (-1 != index) 876 file = file.substring (index + filesep.length ()); 877 // remove the extension 878 index = file.indexOf ('.'); 879 if (-1 != index) 880 file = file.substring (0, index); 881 882 return (file); 883 } 884 885 /** 886 * Save the workspace contents to file. 887 * @param name The name of the file to save it under. 888 */ 889 public void save (String name) 890 { 891 Filter[] selections; 892 FilterBean bean; 893 StringBuffer buffer; 894 PrintWriter out; 895 String ok = "OK"; 896 897 selections = getFilters (); 898 if (0 != selections.length) 899 { 900 bean = new FilterBean (); 901 bean.setURL (mURLField.getText ()); 902 bean.setFilters (selections); 903 buffer = new StringBuffer (); 904 makeProgram (classFromFile (name), buffer, bean); 905 try 906 { 907 out = new PrintWriter (new FileWriter (name), true); 908 try 909 { 910 out.write (buffer.toString ()); 911 out.flush (); 912 } 913 finally 914 { 915 out.close (); 916 } 917 } 918 catch (IOException ioe) 919 { 920 ioe.printStackTrace (); 921 } 922 } 923 else // ToDo: grey out save option if nothing to save... 924 JOptionPane.showOptionDialog ( 925 mMainPanel, 926 "No filters to save.", 927 "Oops", 928 JOptionPane.DEFAULT_OPTION, 929 JOptionPane.ERROR_MESSAGE, 930 null, 931 new String[] { ok }, 932 ok); 933 } 934 935 /** 936 * The action to take when "New" menu or button pressed. 937 */ 938 protected void newAction () 939 { 940 mMainPanel.removeAll (); 941 mSelection.clear (); 942 relayout (); 943 } 944 945 /** 946 * The action to take when "Open" menu or button pressed. 947 */ 948 protected void openAction () 949 { 950 FileDialog dialog; 951 File file; 952 953 dialog = new FileDialog (this); 954 dialog.setMode (FileDialog.LOAD); 955 dialog.setTitle ("Open"); 956 dialog.setDirectory (mHomeDir); 957 dialog.setVisible (true); 958 if (null != dialog.getFile ()) 959 { 960 mHomeDir = dialog.getDirectory (); 961 file = new File (mHomeDir + dialog.getFile ()); 962 open (file.getAbsolutePath ()); 963 setTitle (TITLE + " - " + file.getAbsolutePath ()); 964 } 965 } 966 967 /** 968 * The action to take when "Save" menu or button pressed. 969 */ 970 protected void saveAction () 971 { 972 String title; 973 int index; 974 File file; 975 FileDialog dialog; 976 977 title = getTitle (); 978 index = title.indexOf (" - "); 979 if (-1 != index) 980 file = new File (title.substring (index + 3)); 981 else 982 { 983 dialog = new FileDialog (this); 984 dialog.setMode (FileDialog.SAVE); 985 dialog.setTitle ("Save"); 986 dialog.setDirectory (mHomeDir); 987 dialog.setVisible (true); 988 if (null != dialog.getFile ()) 989 { 990 mHomeDir = dialog.getDirectory (); 991 file = new File (mHomeDir + dialog.getFile ()); 992 setTitle (TITLE + " - " + file.getAbsolutePath ()); 993 } 994 else 995 file = null; 996 } 997 if (null != file) 998 save (file.getAbsolutePath ()); 999 } 1000 1001 /** 1002 * The action to take when "Save As" menu or button pressed. 1003 */ 1004 protected void saveasAction () 1005 { 1006 setTitle (TITLE); 1007 saveAction (); 1008 } 1009 1010 /** 1011 * The action to take when "Exit" menu or button pressed. 1012 */ 1013 protected void exitAction () 1014 { 1015 exitApplication (); 1016 } 1017 1018 /** 1019 * The action to take when "Cut" menu or button pressed. 1020 */ 1021 protected void cutAction () 1022 { 1023 String string; 1024 StringSelection contents; 1025 Clipboard cb; 1026 1027 // get the selection 1028 string = serializeSelection (); 1029 // copy to clipboard 1030 contents = new StringSelection (string); 1031 cb = Toolkit.getDefaultToolkit ().getSystemClipboard (); 1032 cb.setContents (contents, this); 1033 // delete the selection 1034 deleteSelection (); 1035 relayout (); 1036 } 1037 1038 /** 1039 * The action to take when "Copy" menu or button pressed. 1040 */ 1041 protected void copyAction () 1042 { 1043 String string; 1044 StringSelection contents; 1045 Clipboard cb; 1046 1047 // get the selection 1048 string = serializeSelection (); 1049 // copy to clipboard 1050 contents = new StringSelection (string); 1051 cb = Toolkit.getDefaultToolkit ().getSystemClipboard (); 1052 cb.setContents (contents, this); 1053 } 1054 1055 /** 1056 * The action to take when "Paste" menu or button pressed. 1057 */ 1058 protected void pasteAction () 1059 { 1060 Clipboard cb; 1061 Transferable content; 1062 String string; 1063 Filter[] filters; 1064 Point point; 1065 SubFilterList list; 1066 1067 // get the text 1068 cb = Toolkit.getDefaultToolkit ().getSystemClipboard (); 1069 content = cb.getContents (this); 1070 if (content.isDataFlavorSupported (DataFlavor.stringFlavor)) 1071 { 1072 try 1073 { 1074 string = (String)content.getTransferData (DataFlavor.stringFlavor); 1075 // deserialize it and add into the selection 1076 filters = Filter.reconstitute (string, new Parser (mURLField.getText ())); 1077 // add it to the (single) selected object or main panel 1078 if (isSingleSelection () 1079 && (null != (list = getEnclosed (getSelection ()[0])))) 1080 { 1081 for (int i = 0; i < filters.length; i++) 1082 list.addFilter (filters[i]); 1083 } 1084 else 1085 { 1086 point = new Point (0,0); 1087 for (int i = 0; i < filters.length; i++) 1088 { 1089 filters[i].setLocation (point); 1090 mMainPanel.add (filters[i]); 1091 point.y += filters[i].getPreferredSize ().height; 1092 } 1093 } 1094 setupMouseListeners (filters); 1095 setupDropTargets (filters); 1096 relayout (); 1097 } 1098 catch (Exception e) 1099 { 1100 e.printStackTrace (); 1101 } 1102 } 1103 } 1104 1105 /** 1106 * The action to take when "Delete" menu or button pressed. 1107 */ 1108 protected void deleteAction () 1109 { 1110 // delete the selection 1111 deleteSelection (); 1112 relayout (); 1113 } 1114 1115 /** 1116 * The action to take when a filter menu or button pressed. 1117 */ 1118 protected void filterAction () 1119 { 1120 String cls; 1121 Filter filter; 1122 SubFilterList list; 1123 Point point; 1124 1125 // retrieve the source component placed there by actionPerformed 1126 cls = mCurrentComponent.getName (); 1127 filter = Filter.instantiate (cls); 1128 // need this to get the underlying filter prepped? 1129 try 1130 { 1131 filter = Filter.wrap (filter.getNodeFilter (), new Parser (mURLField.getText ())); 1132 } 1133 catch (ParserException pe) 1134 { 1135 pe.printStackTrace (); 1136 } 1137 // add it to the (single) selected object or main panel 1138 if (isSingleSelection () 1139 && (null != (list = getEnclosed (getSelection ()[0])))) 1140 { 1141 insertFilters (new Filter[] {filter}, null, list); 1142 } 1143 else 1144 { 1145 point = new Point (50,50); // find where and who to stick it into 1146 insertFilters (new Filter[] {filter}, point, null); 1147 } 1148 } 1149 1150 /** 1151 * The action to take when "Fetch" menu pressed. 1152 */ 1153 protected void fetchAction () 1154 { 1155 JInternalFrame frame; 1156 Dimension dimension; 1157 Parser parser; 1158 NodeList list; 1159 1160 // set up an internal frame for the results 1161 frame = new JInternalFrame (mURLField.getText ()); 1162 frame.setClosable (true); 1163 frame.setResizable (true); 1164 dimension = mOutput.getSize (); 1165 frame.setBounds (0, 0, dimension.width, dimension.height); 1166 list = new NodeList (); 1167 try 1168 { 1169 parser = new Parser (mURLField.getText ()); 1170 try 1171 { 1172 for (NodeIterator iterator = parser.elements (); iterator.hasMoreNodes (); ) 1173 list.add (iterator.nextNode ()); 1174 } 1175 catch (EncodingChangeException ece) 1176 { 1177 list.removeAll (); 1178 parser.reset (); 1179 for (NodeIterator iterator = parser.elements (); iterator.hasMoreNodes (); ) 1180 list.add (iterator.nextNode ()); 1181 } 1182 } 1183 catch (ParserException pe) 1184 { 1185 pe.printStackTrace (); 1186 } 1187 JTree tree = new JTree (new HtmlTreeModel (list)); 1188 tree.setRootVisible (false); 1189 tree.setCellRenderer (new HtmlTreeCellRenderer ()); 1190 JScrollPane treeView = new JScrollPane (tree); 1191 frame.setContentPane (new JScrollPane ( 1192 treeView, 1193 ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, 1194 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED)); 1195 mOutput.add (frame, new Integer (1)); 1196 try 1197 { 1198 frame.setSelected (true); 1199 } 1200 catch (PropertyVetoException pve) 1201 { 1202 pve.printStackTrace (); 1203 } 1204 frame.show (); 1205 } 1206 1207 /** 1208 * The action to take when "Execute" menu or button pressed. 1209 */ 1210 protected void executeAction () 1211 { 1212 Filter[] selections; 1213 FilterBean bean; 1214 JInternalFrame frame; 1215 Dimension dimension; 1216 // JTextPane text; 1217 1218 selections = getSelection (); 1219 if (0 == selections.length) 1220 selections = getFilters (); 1221 if (0 != selections.length) 1222 { 1223 bean = new FilterBean (); 1224 bean.setURL (mURLField.getText ()); 1225 bean.setFilters (selections); 1226 1227 // set up an internal frame for the results 1228 frame = new JInternalFrame (bean.getURL ()); 1229 frame.setClosable (true); 1230 frame.setResizable (true); 1231 dimension = mOutput.getSize (); 1232 frame.setBounds (0, 0, dimension.width, dimension.height / 2); 1233 JTree tree = new JTree (new HtmlTreeModel (bean.getNodes ())); 1234 tree.setRootVisible (false); 1235 tree.setCellRenderer (new HtmlTreeCellRenderer ()); 1236 JScrollPane treeView = new JScrollPane (tree); 1237 frame.setContentPane (new JScrollPane ( 1238 treeView, 1239 ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, 1240 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED)); 1241 // text = new JTextPane (); 1242 // text.setText (bean.getNodes ().toHtml ()); 1243 // frame.setContentPane (new JScrollPane ( 1244 // text, 1245 // ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, 1246 // ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED)); 1247 mOutput.add (frame, new Integer(2)); // layer 2? 1248 try 1249 { 1250 frame.setSelected (true); 1251 } 1252 catch (PropertyVetoException pve) 1253 { 1254 pve.printStackTrace (); 1255 } 1256 frame.show (); 1257 } 1258 } 1259 1260 /** 1261 * The action to take when "Instructions" menu pressed. 1262 */ 1263 protected void instructionsAction () 1264 { 1265 String instructions = 1266 "<html>" + 1267 "Enter the target URL in the text box at the bottom of the window.<br>" + 1268 "Choose 'Fetch Page' from the Operations menu to see the whole page.<br>" + 1269 "Pick filters from the Filter menu or drag them from the toolbar.<br>" + 1270 "Filters such as And, Or, Not, HasParent, HasChild and HasSibling contain other filters:<br>" + 1271 "<ul><li>drag new filters into their blank areas at the bottom</li>" + 1272 "<li>cut an existing filter and paste into a selected filter</li></ul>" + 1273 "Build the filter incrementally, choosing 'Execute Filter' to test the selected filter.<br>" + 1274 "Save creates a .java file that runs the top level filter.<br>" + 1275 "Right click on a filter displays a pop-up menu.<br>" + 1276 "Double click on a blue item in the result pane expands the tree." + 1277 "</html>"; 1278 String close = "Close"; 1279 JOptionPane.showOptionDialog ( 1280 // not .showMessageDialog( 1281 mMainPanel, 1282 instructions, 1283 "FilterBuilder Instructons", 1284 // remove this: 1285 JOptionPane.DEFAULT_OPTION, 1286 JOptionPane.INFORMATION_MESSAGE, 1287 // and remove rest of these: 1288 null, 1289 new String[] { close }, 1290 close); 1291 } 1292 1293 /** 1294 * The action to take when "Filtering" menu pressed. 1295 */ 1296 protected void filteringAction () 1297 { 1298 String instructions = 1299 "<html>" + 1300 "The HTML Parser filter subsystem extracts items from a web page,<br>" + 1301 "corresponding to the use-case 'I want this little piece of information from http://yadda'.<br>" + 1302 "The web page is considered a heirarchical tree of nodes. Usually the root node is <html>,<br>" + 1303 "intermediate level nodes are <div> and <table> for example,<br>" + 1304 "and leaf nodes are things like text or <img>.<br>" + 1305 "Any node that isn't the root node has a 'parent' node.<br>" + 1306 "Leaf nodes, by definition, have no 'children'.<br>" + 1307 "A filter is a Java class that answers the simple question:<br>" + 1308 "<pre>Is this node acceptable? True or false.</pre><br>" + 1309 "Some filters know the answer just by looking at the node,<br>" + 1310 "while others must ask other filters, sometimes looking up or down the node heirarchy.<br>" + 1311 "<b>The FilterBuilder is a program for making other programs that use filters.</b><br>" + 1312 "By combining different types of filters, specific nodes can be isolated from the<br>" + 1313 "target web page.<br>" + 1314 "The results are usually passed on to another part of the users program<br>" + 1315 "that does something useful with them.<br>" + 1316 "The filters available include:<br>" + 1317 "<ul>" + 1318 "<li>AndFilter - The main 'combining' filter, answers <code>true</code> only if<br>" + 1319 "all it's subfilters (predicates) are <code>true</code>.</li>" + 1320 "<li>OrFilter - A 'combining' filter that answers <code>true</code> if<br>" + 1321 "any of it's subfilters (predicates) are <code>true</code>.</li>" + 1322 "<li>NotFilter - A 'reversing' filter that answers <code>true</code> if<br>" + 1323 "it's subfilter (predicate) is <code>false</code>.</li>" + 1324 "<li>StringFilter - A 'leaf' filter that answers <code>true</code> if<br>" + 1325 "the node is text and it contains a certain sequence of characters.<br>" + 1326 "It can be made case insensitive, but in this case a 'locale' must be<br>" + 1327 "supplied as a context for upper-case conversion.</li>" + 1328 "<li>RegexFilter - A 'leaf' filter that answers <code>true</code> if<br>" + 1329 "the node is text and it contains a certain pattern (regular expression).<br>" + 1330 "Regular expressions are descibed in the java.util.regex.Pattern class documentation.</li>" + 1331 "<li>TagNameFilter - A filter that answers <code>true</code> if<br>" + 1332 "the node is a tag and it has a certain name," + 1333 "i.e. <div> would match the name <code>DIV</code>.</li>" + 1334 "<li>NodeClassFilter - A filter that answers <code>true</code> if<br>" + 1335 "the node is a certain tag class. Not recommended, use TagNameFilter instead.</li>" + 1336 "<li>HasAttributeFilter - A filter that answers <code>true</code> if<br>" + 1337 "the node is a tag and it has a certain attribute,<br>" + 1338 "i.e. <script language=javascript> would match the attribute <code>LANGUAGE</code>.<br>" + 1339 "It can be further restricted to have a certain attribute value as well,<br>" + 1340 "i.e. 'javascript' in this example.</li>" + 1341 "<li>HasParentFilter - A filter that answers <code>true</code> if<br>" + 1342 "the node is a child of a node that is acceptable to a certain filter.<br>" + 1343 "This can be made recursive, which means the acceptable parent can be<br>" + 1344 "further up the heirarchy than just the immediate parent node.</li>" + 1345 "<li>HasChildFilter - A filter that answers <code>true</code> if<br>" + 1346 "the node is a parent of a node that is acceptable to a certain filter.<br>" + 1347 "This can be made recursive, which means the acceptable child can be<br>" + 1348 "further down the heirarchy than just the immediate children nodes.</li>" + 1349 "<li>HasSiblingFilter - A filter that answers <code>true</code> if<br>" + 1350 "the node is a sibling (they have a common parent) of a node that is<br>" + 1351 "acceptable to a certain filter.</li>" + 1352 "</ul>" + 1353 "</html>"; 1354 String close = "Close"; 1355 JOptionPane.showOptionDialog ( 1356 // not .showMessageDialog( 1357 mMainPanel, 1358 instructions, 1359 "FilterBuilder Instructons", 1360 // remove this: 1361 JOptionPane.DEFAULT_OPTION, 1362 JOptionPane.INFORMATION_MESSAGE, 1363 // and remove rest of these: 1364 null, 1365 new String[] { close }, 1366 close); 1367 } 1368 1369 /** 1370 * The action to take when "Tutorial" menu pressed. 1371 */ 1372 protected void tutorialAction () 1373 { 1374 String instructions = 1375 "<html>" + 1376 "To get the title text from a page:<br>" + 1377 "<ul><li>Choose 'New' from the File menu.</li>" + 1378 "<li>Choose 'AndFilter' from the Filter menu.</li>" + 1379 "<li>Select the And filter so it is highlighted.</li>" + 1380 "<li>Choose 'HasParent' from the Filter menu.</li>" + 1381 "<li>Toggle the 'Recursive' checkbox on in the HasParent filter.</li>" + 1382 "<li>Select the HasParent filter so it is highlighted.</li>" + 1383 "<li>Choose 'TagName' from the Filter menu.<br>" + 1384 "<i>Alternatively, you can drag the TagName filter (icon Hello-BOB)<br>" + 1385 "from the toolbar and drop inside the HasParent filter</i></li>" + 1386 "<li>Choose 'TITLE' from the TagName combo-box.</li>" + 1387 "<li>Select the And filter and choose 'Execute Filter' from the<br>" + 1388 "Operations menu to test it.</li>" + 1389 "<li>If there is unwanted non-text nodes in the result<br>" + 1390 "select the And filter and choose 'RegexFilter' from the Filter menu.</li>" + 1391 "<li>Test it again, as above.</li>" + 1392 "<li>Choose 'Save' from the File menu and enter a filename like GetTitle.java</li>" + 1393 "<li>Compile the java file and run it.</li></ul>" + 1394 "</html>"; 1395 String close = "Close"; 1396 JOptionPane.showOptionDialog ( 1397 // not .showMessageDialog( 1398 mMainPanel, 1399 instructions, 1400 "FilterBuilder Tutorial", 1401 // remove this: 1402 JOptionPane.DEFAULT_OPTION, 1403 JOptionPane.INFORMATION_MESSAGE, 1404 // and remove rest of these: 1405 null, 1406 new String[] { close }, 1407 close); 1408 } 1409 1410 /** 1411 * The action to take when "Hints" menu pressed. 1412 */ 1413 protected void hintsAction () 1414 { 1415 String instructions = 1416 "<html>" + 1417 "Hints:<br>" + 1418 "<ul><li>There is no undo yet, so save often.</li>" + 1419 "<li>Recursive HasParent and HasChild filters can be costly.</li>" + 1420 "<li>RegexFilter is more expensive than StringFilter.</li>" + 1421 "<li>The order of predicates in And and Or filters matters for performance,<br>" + 1422 "put cheap tests first.</li>" + 1423 "<li>The same node may show up more than once in the results,<br>" + 1424 "and at more than one nesting depth, depending on the filter used.</li>" + 1425 "<li>Typing in a tag name in the TagName filter is not recommended,<br>" + 1426 "since extraneous characters can be added. Use an item from the list instead.</li></ul>" + 1427 "</html>"; 1428 String close = "Close"; 1429 JOptionPane.showOptionDialog ( 1430 // not .showMessageDialog( 1431 mMainPanel, 1432 instructions, 1433 "FilterBuilder Hints", 1434 // remove this: 1435 JOptionPane.DEFAULT_OPTION, 1436 JOptionPane.INFORMATION_MESSAGE, 1437 // and remove rest of these: 1438 null, 1439 new String[] { close }, 1440 close); 1441 } 1442 1443 /** 1444 * The action to take when "About" menu or button pressed. 1445 */ 1446 protected void aboutAction () 1447 { 1448 String close = "Close"; 1449 JOptionPane.showOptionDialog ( 1450 // not .showMessageDialog( 1451 mMainPanel, 1452 "<html><center><font color=black>The HTML Parser <font color=blue><b>FilterBuilder</b></font><br><i>by Derrick Oswald</i> <b>DerrickOswald@users.sourceforge.net</b><br>http://htmlparser.org<br><br><font size=-2>Copyright © 2005</font></center></html>", 1453 "About FilterBuilder", 1454 // remove this: 1455 JOptionPane.DEFAULT_OPTION, 1456 JOptionPane.INFORMATION_MESSAGE, 1457 // and remove rest of these: 1458 null, 1459 new String[] { close }, 1460 close); 1461 } 1462 1463 /** 1464 * The action to take when "Expand" menu chosen. 1465 */ 1466 public void expandAction () 1467 { 1468 setExpanded (getSelection (), true, false); 1469 } 1470 1471 /** 1472 * The action to take when "Collapse" menu chosen. 1473 */ 1474 public void collapseAction () 1475 { 1476 setExpanded (getSelection (), false, false); 1477 } 1478 1479 /** 1480 * The action to take when "Expand All" menu chosen. 1481 */ 1482 public void expandAllAction () 1483 { 1484 setExpanded (getSelection (), true, true); 1485 } 1486 1487 /** 1488 * The action to take when "Collapse" menu chosen. 1489 */ 1490 public void collapseAllAction () 1491 { 1492 setExpanded (getSelection (), false, true); 1493 } 1494 1495 /** 1496 * Set up mouse listeners. 1497 * Sets <code>this</code> up to listen to each command 1498 * in the list as a MouseListener. 1499 * Recursively descends the tree adding to all contained elements also. 1500 * @param filters The container with commands in it. 1501 */ 1502 public void setupMouseListeners (Filter[] filters) 1503 { 1504 SubFilterList list; 1505 1506 for (int i = 0; i < filters.length; i++) 1507 { 1508 // set us up as a mouse listener on it 1509 ((Component)filters[i]).addMouseListener (this); 1510 ((Component)filters[i]).addMouseMotionListener (this); 1511 list = getEnclosed (filters[i]); 1512 if (null != list) 1513 setupMouseListeners (list.getFilters ()); 1514 } 1515 } 1516 1517 /** 1518 * Set up drop targets. 1519 * Recursively descends the filter tree and sets up 1520 * the filter lists as drop targets. 1521 * @param filters The container with filters in it. 1522 */ 1523 public void setupDropTargets (Filter[] filters) 1524 { 1525 SubFilterList list; 1526 Component[] components; 1527 1528 for (int i = 0; i < filters.length; i++) 1529 { 1530 list = getEnclosed (filters[i]); 1531 if (null != list) 1532 { 1533 components = list.getDropTargets (); 1534 for (int j = 0; j < components.length; j++) 1535 new DropTarget (components[j], this); 1536 setupDropTargets (list.getFilters ()); 1537 } 1538 } 1539 } 1540 1541 /** 1542 * Expand or collapse filters, possibly recursively. 1543 * @param filters The list of filters to expand or collapse. 1544 * @param expanded If <code>true</code> the filters are expanded, 1545 * otherwise they are collapsed. 1546 * @param recursive If <code>true</code> the filters are processed 1547 * recursively. 1548 */ 1549 public void setExpanded ( 1550 Filter[] filters, 1551 boolean expanded, 1552 boolean recursive) 1553 { 1554 SubFilterList list; 1555 1556 for (int i = 0; i < filters.length; i++) 1557 { 1558 if (recursive && (null != (list = getEnclosed (filters[i])))) 1559 setExpanded (list.getFilters (), expanded, recursive); 1560 filters[i].setExpanded (expanded); 1561 } 1562 } 1563 1564 /** 1565 * Retrieve the top level filters in the main window. 1566 * @return The top level filters. 1567 */ 1568 public Filter[] getFilters () 1569 { 1570 Component[] components; 1571 Filter[] ret; 1572 1573 components = mMainPanel.getComponents (); 1574 ret = new Filter[components.length]; 1575 System.arraycopy (components, 0, ret, 0, components.length); 1576 1577 return (ret); 1578 } 1579 1580 /** 1581 * Redo the layout. 1582 */ 1583 public void relayout () 1584 { 1585 mMainPanel.invalidate (); 1586 mMainScroller.invalidate (); 1587 mMainScroller.validate (); 1588 mMainScroller.repaint (); 1589 } 1590 1591 /** 1592 * Read a workspace from file. 1593 * The current contents are erased. 1594 * @param name The name of the file to open. 1595 */ 1596 public void open (String name) 1597 { 1598 LineNumberReader reader; 1599 String line; 1600 Filter[] filters; 1601 Point point; 1602 Dimension dimension; 1603 1604 try 1605 { 1606 reader = new LineNumberReader (new FileReader (name)); 1607 while (null != (line = reader.readLine ())) 1608 if (line.startsWith ("// [")) 1609 { 1610 line = line.substring (3); 1611 try 1612 { 1613 filters = Filter.reconstitute (line, new Parser (mURLField.getText ())); 1614 mMainPanel.removeAll (); 1615 point = new Point (); 1616 for (int i = 0; i < filters.length; i++) 1617 { 1618 dimension = filters[i].getPreferredSize (); 1619 mMainPanel.add (filters[i]); 1620 filters[i].setLocation (point); 1621 point.y += dimension.height; 1622 } 1623 setupMouseListeners (filters); 1624 setupDropTargets (filters); 1625 relayout (); 1626 } 1627 catch (ParserException pe) 1628 { 1629 pe.printStackTrace (); 1630 } 1631 break; 1632 } 1633 reader.close (); 1634 } 1635 catch (IOException ioe) 1636 { 1637 ioe.printStackTrace (); 1638 } 1639 } 1640 1641 /** 1642 * Exit back to the operating system. 1643 */ 1644 void exitApplication () 1645 { 1646 this.setVisible (false); // hide the Frame 1647 this.dispose (); // free the system resources 1648 System.exit (0); // close the application 1649 } 1650 1651 /** 1652 * Show a pop up context menu. 1653 * Shows a context sensitive popup menu at the location of the 1654 * mouse event. 1655 * @param event The mouse event that initiates the popup. 1656 */ 1657 public void showContextMenu (MouseEvent event) 1658 { 1659 JPopupMenu menu; 1660 JMenuItem item; 1661 1662 menu = new JPopupMenu (); 1663 menu.setName ("Popup"); 1664 1665 item = new JMenuItem ("Expand"); 1666 item.setActionCommand ("expandAction"); 1667 item.addActionListener (this); 1668 menu.add (item); 1669 1670 item = new JMenuItem ("Collapse"); 1671 item.setActionCommand ("collapseAction"); 1672 item.addActionListener (this); 1673 menu.add (item); 1674 1675 menu.addSeparator (); 1676 1677 item = new JMenuItem ("Expand All"); 1678 item.setActionCommand ("expandAllAction"); 1679 item.addActionListener (this); 1680 menu.add (item); 1681 1682 item = new JMenuItem ("CollapseAll"); 1683 item.setActionCommand ("collapseAllAction"); 1684 item.addActionListener (this); 1685 menu.add (item); 1686 1687 menu.addSeparator (); 1688 1689 item = new JMenuItem ("Cut"); 1690 item.setActionCommand ("cutAction"); 1691 item.addActionListener (this); 1692 menu.add (item); 1693 1694 item = new JMenuItem ("Copy"); 1695 item.setActionCommand ("copyAction"); 1696 item.addActionListener (this); 1697 menu.add (item); 1698 1699 item = new JMenuItem ("Paste"); 1700 item.setActionCommand ("pasteAction"); 1701 item.addActionListener (this); 1702 menu.add (item); 1703 1704 item = new JMenuItem ("Delete"); 1705 item.setActionCommand ("deleteAction"); 1706 item.addActionListener (this); 1707 menu.add (item); 1708 1709 menu.addSeparator (); 1710 1711 item = new JMenuItem ("Execute Filter"); 1712 item.setActionCommand ("executeAction"); 1713 item.addActionListener (this); 1714 menu.add (item); 1715 1716 menu.show (event.getComponent (), event.getX (), event.getY ()); 1717 } 1718 1719 // 1720 // selection manipulation 1721 // 1722 1723 /** 1724 * Add a filter to the current selection set. 1725 * @param filter The filter to add. 1726 */ 1727 protected void addSelection (Filter filter) 1728 { 1729 if (!selectionContains (filter)) 1730 mSelection.addElement (filter); 1731 filter.setSelected (true); 1732 mMoved = false; 1733 } 1734 1735 /** 1736 * Remove a filter from the current selection set. 1737 * @param filter The filter to remove. 1738 */ 1739 protected void removeSelection (Filter filter) 1740 { 1741 mSelection.removeElement (filter); // no harm if not contained 1742 filter.setSelected (false); 1743 } 1744 1745 /** 1746 * Select(highlight)/deselect the current selection set. 1747 * @param select If <code>true</code> turn on highlighting, 1748 * turn it off otherwise. 1749 */ 1750 protected void selectSelection (boolean select) 1751 { 1752 int count; 1753 Filter filter; 1754 1755 count = mSelection.size (); 1756 for (int i = 0; i < count; i++) 1757 { 1758 filter = (Filter)mSelection.elementAt (i); 1759 filter.setSelected (select); 1760 } 1761 } 1762 1763 /** 1764 * Clear (empty) the current selection set. 1765 */ 1766 protected void clearSelection () 1767 { 1768 selectSelection (false); 1769 mSelection.removeAllElements (); 1770 } 1771 1772 /** 1773 * Move the current selection set as a group. 1774 * @param translation The displacement to move them all by. 1775 */ 1776 protected void moveSelection (Point translation) 1777 { 1778 int count; 1779 Filter filter; 1780 Point point; 1781 1782 count = mSelection.size (); 1783 for (int i = 0; i < count; i++) 1784 { 1785 filter = (Filter)mSelection.elementAt (i); 1786 point = filter.getLocation (); 1787 point.translate (translation.x, translation.y); 1788 synchronized (filter.getTreeLock ()) 1789 { 1790 filter.setLocation (point.x, point.y); 1791 } 1792 } 1793 mMoved = true; 1794 } 1795 1796 /** 1797 * Check if the current selection set contains the given filter. 1798 * @param filter The filter to check. 1799 * @return <code>true</code> if the filter is a member, 1800 * <code>false</code> otherwise. 1801 */ 1802 protected boolean selectionContains (Filter filter) 1803 { 1804 return (mSelection.contains (filter)); 1805 } 1806 1807 /** 1808 * Return the last filter added to the selection set. 1809 * @return The last filter added or <code>null</code> if the current 1810 * selection set is empty. 1811 */ 1812 protected Filter lastSelected () 1813 { 1814 Filter ret; 1815 1816 ret = null; 1817 1818 if (0 < mSelection.size ()) 1819 ret = (Filter)mSelection.lastElement (); 1820 1821 return (ret); 1822 } 1823 1824 /** 1825 * Return the current selection set as an array. 1826 * @return The array of selected filters. 1827 */ 1828 protected Filter[] getSelection () 1829 { 1830 Filter[] ret; 1831 1832 ret = new Filter[mSelection.size ()]; 1833 mSelection.copyInto (ret); 1834 1835 return (ret); 1836 } 1837 1838 /** 1839 * Serialize the current selection set. 1840 * @return The serialized form of the set of filters. 1841 */ 1842 public String serializeSelection () 1843 { 1844 Filter[] filters; 1845 StringWriter writer; 1846 PrintWriter out; 1847 1848 filters = getSelection (); 1849 writer = new StringWriter (200); 1850 out = new PrintWriter (writer, false); 1851 try 1852 { 1853 out.println (Filter.deconstitute (filters)); 1854 } 1855 catch (IOException ioe) 1856 { 1857 ioe.printStackTrace (); 1858 } 1859 finally 1860 { 1861 out.close (); 1862 } 1863 1864 return (writer.getBuffer ().toString ()); 1865 } 1866 1867 /** 1868 * Delete the current selection set from the filters in the GUI. 1869 */ 1870 public void deleteSelection () 1871 { 1872 Filter[] filters; 1873 SubFilterList list; 1874 1875 filters = getSelection (); 1876 for (int i = 0; i < filters.length; i++) 1877 { 1878 list = getEnclosing (filters[i]); 1879 if (null != list) 1880 list.removeFilter (filters[i]); 1881 else 1882 mMainPanel.remove (filters[i]); 1883 } 1884 mSelection.clear (); 1885 } 1886 1887 /** 1888 * Check if there is more than one filter selected. 1889 * @return <code>true</code> if only one filter is selected, 1890 * <code>false</code> otherwise. 1891 */ 1892 public boolean isSingleSelection () 1893 { 1894 return (1 == mSelection.size()); 1895 } 1896 1897 // 1898 // MouseListener interface 1899 // 1900 1901 /** 1902 * Invoked when the mouse has been clicked on a component. 1903 * @param event The mouse clicked event. 1904 */ 1905 public void mouseClicked (MouseEvent event) 1906 { 1907 Object component; 1908 Filter filter; 1909 SubFilterList list; 1910 int modifiers; 1911 boolean contained; 1912 Filter[] filters; 1913 1914 component = event.getSource (); 1915 if (component instanceof Filter) 1916 { 1917 filter = (Filter)component; 1918 modifiers = event.getModifiers (); 1919 contained = selectionContains (filter); 1920 1921 if (0 != (modifiers & InputEvent.SHIFT_MASK)) 1922 { 1923 // add everything from last selected to this command 1924 list = getEnclosed (filter); 1925 if (null != list) 1926 filters = list.getFilters (); 1927 else 1928 filters = getFilters (); 1929 Filter last = lastSelected (); 1930 if (null == last) 1931 addSelection (filter); 1932 else 1933 { 1934 int current = -1; 1935 int recent = -1; 1936 for (int i = 0; i < filters.length; i++) 1937 { 1938 if (filters[i] == filter) 1939 current = i; 1940 if (filters[i] == last) 1941 recent = i; 1942 } 1943 if ((current != -1) && (recent != -1)) 1944 for (int i = Math.min (current, recent); 1945 i <= Math.max (current, recent); i++) 1946 addSelection (filters[i]); 1947 } 1948 } 1949 else if (0 != (modifiers & InputEvent.CTRL_MASK)) 1950 { 1951 // add just the new command 1952 if (contained) 1953 removeSelection (filter); 1954 else 1955 addSelection (filter); 1956 } 1957 else if (0 != (modifiers & InputEvent.BUTTON3_MASK)) 1958 { 1959 if (!selectionContains (filter)) 1960 { 1961 clearSelection (); 1962 addSelection (filter); 1963 } 1964 showContextMenu (event); 1965 } 1966 else 1967 { 1968 clearSelection (); 1969 addSelection (filter); 1970 } 1971 } 1972 else 1973 clearSelection (); 1974 } 1975 1976 /** 1977 * Invoked when a mouse button has been released on a component. 1978 * @param event The mouse released event. 1979 */ 1980 public void mouseReleased (MouseEvent event) 1981 { 1982 } 1983 1984 /** 1985 * Invoked when the mouse enters a component. 1986 * @param event The mouse entered event. 1987 */ 1988 public void mouseEntered (MouseEvent event) 1989 { 1990 } 1991 1992 /** 1993 * Invoked when the mouse exits a component. 1994 * @param event The mouse exited event. 1995 */ 1996 public void mouseExited (MouseEvent event) 1997 { 1998 } 1999 2000 /** 2001 * Invoked when a mouse button has been pressed on a component. 2002 * @param event The mouse pressed event. 2003 */ 2004 public void mousePressed (MouseEvent event) 2005 { 2006 Object component; 2007 Point newpoint; 2008 Point upperleft; 2009 2010 component = event.getSource (); 2011 if (component instanceof Filter) 2012 { 2013 // translate the point relative to the enclosing container 2014 newpoint = event.getPoint (); 2015 upperleft = ((Component)component).getLocation (); 2016 newpoint.translate (upperleft.x, upperleft.y); 2017 setBasePoint (newpoint); 2018 } 2019 else 2020 setBasePoint (null); 2021 } 2022 2023 // 2024 // MouseMotionListener interface 2025 // 2026 2027 /** 2028 * Mouse drag notification. 2029 * Invoked when a mouse button is pressed on a component and 2030 * then dragged. Mouse drag events will continue to be 2031 * delivered to the component where the first originated 2032 * until the mouse button is released (regardless of whether 2033 * the mouse position is within the bounds of the component). 2034 * @param event The mouse drag event. 2035 */ 2036 public synchronized void mouseDragged (MouseEvent event) 2037 { 2038 Object component; 2039 Filter filter; 2040 Point base; 2041 Point newpoint; 2042 Point upperleft; 2043 Point translation; 2044 2045 component = event.getSource (); 2046 if (component instanceof Filter) 2047 { 2048 filter = (Filter)component; 2049 if (selectionContains (filter)) // drag on a selected item 2050 { 2051 if (null == getEnclosing (filter)) // not contained 2052 try 2053 { 2054 base = getBasePoint (); 2055 if (null != base) 2056 { 2057 newpoint = event.getPoint (); 2058 // translate the point relative to the enclosing container 2059 upperleft = filter.getLocation (); 2060 newpoint.translate (upperleft.x, upperleft.y); 2061 // get the difference between this point and the old base 2062 translation = new Point ( 2063 newpoint.x - base.x, 2064 newpoint.y - base.y); 2065 // update the base point 2066 setBasePoint (newpoint); 2067 // apply this difference to the selection 2068 moveSelection (translation); 2069 } 2070 } 2071 catch (Exception e) 2072 { 2073 } 2074 } 2075 else 2076 mouseClicked (event); // a small slip shouldn't stop a click 2077 } 2078 } 2079 2080 /** 2081 * Mouse move notification. 2082 * Invoked when the mouse button has been moved on a component 2083 * (with no buttons no down). 2084 * @param event The mouse moved event. 2085 */ 2086 public void mouseMoved (MouseEvent event) 2087 { 2088 } 2089 2090 // 2091 // WindowListener interface 2092 // 2093 2094 /** 2095 * Invoked the first time a window is made visible. 2096 * <i>Not used.</i> 2097 * @param event The window event. 2098 */ 2099 public void windowOpened (WindowEvent event) {} 2100 2101 /** 2102 * Handles window closing event. 2103 * Performs function <code>exitApplication()</code>. 2104 * @param event The window event. 2105 */ 2106 public void windowClosing (WindowEvent event) 2107 { 2108 if (event.getSource () == this) 2109 exitApplication (); 2110 } 2111 2112 /** 2113 * Invoked when a window has been closed as the result 2114 * of calling dispose on the window. 2115 * <i>Not used.</i> 2116 * @param event The window event. 2117 */ 2118 public void windowClosed (WindowEvent event) {} 2119 2120 /** 2121 * Invoked when a window is changed from a normal to a 2122 * minimized state. For many platforms, a minimized window 2123 * is displayed as the icon specified in the window's 2124 * iconImage property. 2125 * <i>Not used.</i> 2126 * @param event The window event. 2127 */ 2128 public void windowIconified (WindowEvent event) {} 2129 2130 /** 2131 * Invoked when a window is changed from a minimized 2132 * to a normal state. 2133 * <i>Not used.</i> 2134 * @param event The window event. 2135 */ 2136 public void windowDeiconified (WindowEvent event) {} 2137 2138 /** 2139 * Invoked when the window is set to be the user's 2140 * active window, which means the window (or one of its 2141 * subcomponents) will receive keyboard events. 2142 * <i>Not used.</i> 2143 * @param event The window event. 2144 */ 2145 public void windowActivated (WindowEvent event) {} 2146 2147 /** 2148 * Invoked when a window is no longer the user's active 2149 * window, which means that keyboard events will no longer 2150 * be delivered to the window or its subcomponents. 2151 * <i>Not used.</i> 2152 * @param event The window event. 2153 */ 2154 public void windowDeactivated (WindowEvent event) {} 2155 2156 // 2157 // ActionListener interface 2158 // 2159 2160 /** 2161 * Handles menu and toolbar item choices. 2162 * @param event The action even that triggers this function. 2163 */ 2164 public void actionPerformed (ActionEvent event) 2165 { 2166 Object object; 2167 String action; 2168 2169 object = event.getSource(); 2170 // if (object instanceof JButton) 2171 // { 2172 // String url; 2173 // url = mURLField.getText (); 2174 // mURLField.selectAll (); 2175 // //setURL (url); 2176 // } 2177 if (object instanceof JButton) 2178 action = ((JButton)object).getActionCommand (); 2179 else if (object instanceof JMenuItem) 2180 action = ((JMenuItem)object).getActionCommand (); 2181 else 2182 action = null; 2183 2184 if (object instanceof Component) 2185 mCurrentComponent = (Component)object; 2186 2187 if (null != action) 2188 try 2189 { 2190 Method method = this.getClass ().getDeclaredMethod (action, new Class[0]); 2191 method.invoke (this, new Object[0]); 2192 } 2193 catch (NoSuchMethodException nsme) 2194 { 2195 System.out.println ("no " + action + " method found"); 2196 } 2197 catch (Exception e) 2198 { 2199 e.printStackTrace (); 2200 } 2201 } 2202 2203 // 2204 // ClipboardOwner interface 2205 // 2206 2207 /** 2208 * Notifies this object that it is no longer the owner 2209 * of the contents of the clipboard. 2210 * @param clipboard The clipboard that is no longer owned. 2211 * @param contents The contents which this owner had placed on the clipboard. 2212 */ 2213 public void lostOwnership (Clipboard clipboard, Transferable contents) 2214 { 2215 System.out.println ("lost clipboard ownership"); 2216 } 2217 2218 // 2219 // DragGestureListener interface 2220 // 2221 2222 /** 2223 * A DragGestureRecognizer has detected a platform-dependent drag initiating gesture. 2224 * It is notifying this listener in order for it to initiate the action for the user. 2225 * @param event The DragGestureEvent describing the gesture that has just occurred. 2226 */ 2227 public void dragGestureRecognized (DragGestureEvent event) 2228 { 2229 Component component; 2230 String cls; 2231 Filter filter; 2232 StringSelection text; 2233 2234 2235 component = event.getComponent (); 2236 try 2237 { 2238 cls = component.getName (); // (String)Filter.mWrappers.get (component.getName ()); 2239 if (null != cls) 2240 { 2241 filter = Filter.instantiate (cls); 2242 text = new StringSelection (Filter.deconstitute (new Filter[] { filter })); 2243 mDragSource.startDrag (event, DragSource.DefaultMoveDrop, text, this); 2244 } 2245 } 2246 catch (Exception e) 2247 { 2248 e.printStackTrace (); 2249 } 2250 } 2251 2252 // 2253 // DragSourceListener interface 2254 // 2255 2256 /** 2257 * This message goes to DragSourceListener, 2258 * informing it that the dragging has ended. 2259 * @param event Details about the drop event. 2260 */ 2261 public void dragDropEnd (DragSourceDropEvent event) 2262 { 2263 if (event.getDropSuccess ()) 2264 { 2265 // System.out.println ("added new class"); 2266 } 2267 } 2268 2269 /** 2270 * This message goes to DragSourceListener, 2271 * informing it that the dragging has entered the DropSite. 2272 * @param event Details about the drag event. 2273 */ 2274 public void dragEnter (DragSourceDragEvent event) 2275 { 2276 // System.out.println ("dragEnter"); 2277 } 2278 2279 /** 2280 * This message goes to DragSourceListener, informing it that the dragging 2281 * has exited the DropSite. 2282 * @param event Details about the drag event. 2283 */ 2284 public void dragExit (DragSourceEvent event) 2285 { 2286 // System.out.println( "dragExit"); 2287 } 2288 2289 /** 2290 * This message goes to DragSourceListener, informing it that the dragging is currently 2291 * ocurring over the DropSite. 2292 * @param event Details about the drag event. 2293 */ 2294 public void dragOver (DragSourceDragEvent event) 2295 { 2296 // System.out.println( "dragExit"); 2297 } 2298 2299 /** 2300 * This is invoked when the user changes the dropAction. 2301 * @param event Details about the drop action event. 2302 */ 2303 public void dropActionChanged (DragSourceDragEvent event) 2304 { 2305 // System.out.println( "dropActionChanged"); 2306 } 2307 2308 // 2309 // DropTargetListener interface 2310 // 2311 2312 /** 2313 * This is invoked when you are dragging over the DropSite. 2314 * @param event Details about the drag event. 2315 */ 2316 public void dragEnter (DropTargetDragEvent event) 2317 { 2318 // debug messages for diagnostics 2319 // event.acceptDrag (DnDConstants.ACTION_MOVE); 2320 // System.out.println ("dragEnter"); 2321 DropTargetContext context; 2322 Component component; 2323 SubFilterList list; 2324 2325 // find the enclosing filter 2326 context = event.getDropTargetContext (); 2327 component = context.getComponent (); 2328 while ( (null != component) 2329 && !(component instanceof SubFilterList) 2330 && !(component == mMainPanel)) 2331 component = component.getParent (); 2332 if (component instanceof SubFilterList) 2333 list = (SubFilterList)component; 2334 else 2335 list = null; 2336 // so either list is the enclosing list, 2337 // or list is null and the target component is the main panel 2338 2339 if (null != list) 2340 if (!list.canAccept ()) 2341 event.rejectDrag (); 2342 else 2343 list.setSelected (true); 2344 } 2345 2346 /** 2347 * Thi ss invoked when you are exit the DropSite without dropping. 2348 * @param event Details about the drag event. 2349 */ 2350 public void dragExit (DropTargetEvent event) 2351 { 2352 // debug messages for diagnostics 2353 // event.acceptDrag (DnDConstants.ACTION_MOVE); 2354 // System.out.println ("dragEnter"); 2355 DropTargetContext context; 2356 Component component; 2357 SubFilterList list; 2358 2359 // find the enclosing filter 2360 context = event.getDropTargetContext (); 2361 component = context.getComponent (); 2362 while ( (null != component) 2363 && !(component instanceof SubFilterList) 2364 && !(component == mMainPanel)) 2365 component = component.getParent (); 2366 if (component instanceof SubFilterList) 2367 list = (SubFilterList)component; 2368 else 2369 list = null; 2370 // so either list is the enclosing list, 2371 // or list is null and the target component is the main panel 2372 2373 if (null != list) 2374 list.setSelected (false); 2375 } 2376 2377 /** 2378 * This is invoked when a drag operation is going on. 2379 * @param event Details about the drag event. 2380 */ 2381 public void dragOver (DropTargetDragEvent event) 2382 { 2383 // System.out.println( "dragOver"); 2384 } 2385 2386 /** 2387 * This is invoked when a drop has occurred. 2388 * @param event The drop event. 2389 */ 2390 public void drop (DropTargetDropEvent event) 2391 { 2392 DropTargetContext context; 2393 Component component; 2394 SubFilterList list; 2395 String s; 2396 Point point; 2397 Filter[] filters; 2398 boolean accept; 2399 2400 // find the enclosing filter 2401 context = event.getDropTargetContext (); 2402 component = context.getComponent (); 2403 while ( (null != component) 2404 && !(component instanceof SubFilterList) 2405 && !(component == mMainPanel)) 2406 component = component.getParent (); 2407 if (component instanceof SubFilterList) 2408 list = (SubFilterList)component; 2409 else 2410 list = null; 2411 // so either list is the enclosing list, 2412 // or list is null and the target component is the main panel 2413 2414 try 2415 { 2416 accept = false; 2417 Transferable transferable = event.getTransferable(); 2418 2419 // we accept only Strings 2420 if (transferable.isDataFlavorSupported (DataFlavor.stringFlavor)) 2421 { 2422 accept = true; 2423 event.acceptDrop (DnDConstants.ACTION_MOVE); 2424 s = (String)transferable.getTransferData (DataFlavor.stringFlavor); 2425 point = event.getLocation (); 2426 try 2427 { 2428 // get the filter and add into the target 2429 filters = Filter.reconstitute (s, new Parser (mURLField.getText ())); 2430 if (0 < filters.length) 2431 insertFilters (filters, point, list); 2432 if (null != list) 2433 list.setSelected (false); 2434 } 2435 catch (Exception e) 2436 { 2437 e.printStackTrace (); 2438 } 2439 // signal the drop was successful 2440 context.dropComplete (accept); 2441 } 2442 else 2443 event.rejectDrop(); 2444 } 2445 catch (IOException exception) 2446 { 2447 exception.printStackTrace(); 2448 System.err.println( "Exception" + exception.getMessage()); 2449 event.rejectDrop(); 2450 } 2451 catch (UnsupportedFlavorException ufException) 2452 { 2453 ufException.printStackTrace(); 2454 System.err.println( "Exception" + ufException.getMessage()); 2455 event.rejectDrop(); 2456 } 2457 } 2458 2459 /** 2460 * This is invoked if the user modifies the current drop gesture. 2461 * @param event Details about the drop action change event. 2462 */ 2463 public void dropActionChanged (DropTargetDragEvent event) 2464 { 2465 // System.out.println( "dropActionChanged"); 2466 } 2467 2468 /** 2469 * The entry point for this application. 2470 * Creates a new FilterBuilder and makes it visible. 2471 * @param args [0] optional URL to operate on. 2472 */ 2473 public static void main (String args[]) 2474 { 2475 try 2476 { 2477 // set the Look and Feel to the the native system 2478 // try 2479 // { 2480 // javax.swing.UIManager.setLookAndFeel (javax.swing.UIManager.getSystemLookAndFeelClassName ()); 2481 // } 2482 // catch (Exception e) 2483 // { 2484 // } 2485 2486 // create a new instance of our application's frame, and make it visible 2487 FilterBuilder builder = new FilterBuilder (); 2488 if (0 != args.length) 2489 builder.mURLField.setText (args[0]); 2490 builder.setVisible (true); 2491 } 2492 catch (Throwable t) 2493 { 2494 t.printStackTrace (); 2495 // ensure the application exits with an error condition 2496 System.exit (1); 2497 } 2498 } 2499 2500 }