Änderung 1: Einbinden der CIS-Klassen
Änderung 2: Einfügen eines neuen Menüpunkts
CIS
Änderung 3: Aktion, die beim Aufruf des
Menüpunkts ausgeführt wird
/* * LAPIS lightweight structured text processing system * Copyright (C) 1998,1999 Carnegie Mellon University * * This library is free software; you can redistribute it * and/or modify it under the terms of the GNU Library * General Public License as published by the Free Software * Foundation, version 2. * * LAPIS homepage: http://www.cs.cmu.edu/~rcm/lapis/ */ package lapis.swing; import lapis.*; import lapis.tc.*; import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; import java.net.*; import java.beans.*; import java.awt.datatransfer.*; import javax.swing.*; import javax.swing.text.*; import javax.swing.event.*; import javax.swing.tree.*; import javax.swing.undo.*; import rcm.awt.Constrain; import rcm.awt.PopupDialog; import rcm.swing.*; import rcm.net.URLUtil; import rcm.progress.*; import rcm.util.Str; import rcm.util.Thr; import rcm.util.Debug; import lapis.Parser; // MED: Klasse hinzugefügt: import lapis.cis.*; public class Browser extends JFrame implements Tool { //////////////////// //////////////////// Constants //////////////////// /** * Number of Documents stored in browser history. Note that the * browser history stores not only the URL but the content and named * region sets too, so this may occupy significant memory. */ public static final int MAX_DOCUMENT_HISTORY = 100; /** * Number of patterns stored in pattern history. Patterns are stored * simply as strings. */ public static final int MAX_PATTERN_HISTORY = 100; /** * Priority of background thread (for evaluating commands, downloading * URLs, and parsing). Ranges from 1 to 10. */ public static final int BACKGROUND_PRIORITY = 4; // /** // * Proportion of browser pane devoted to displaying standard output // * when a program's stdout and stderr must be shown. Ranges from 0 to 1. // */ // public static final double STDOUT_PROPORTION = 0.5; /** * Background color of active browser pane. */ public static final Color ACTIVE_PANE_COLOR = Color.orange; //////////////////// //////////////////// Browser UI //////////////////// JMenuBar menubar; JToolBar toolbar; JMenu toolMenu; JComboBox location; // Document location (URL or filename) + document history JComboBox view; // Content type (text, HTML, Java, etc.) TCEditor pattern; // TC pattern to highlight UndoManager undoPattern; // undo manager for pattern LabelTree tree; // Labeling tree JLabel patternMatchCount; // displays # of matches BrowserPane outputPane; // Text/HTML display BrowserPane errorPane; // Standard error display JLabel outputLabel; JLabel errorLabel; JScrollPane browserScrollPane, errorScrollPane; JScrollPane patternScrollPane, treeScrollPane; // Panels containing outputPane, errorPane, pattern, and tree. JPanel outputPanel; JPanel errorPanel; JPanel patternPanel; JPanel treePanel; // Splitters tiling the browser window with outputPanel, // errorPanel, and treePanel. JSplitPane errorSplitter; // splitter containing outputPane and errorPane JSplitPane treeSplitter; // splitter containing pattern and tree JSplitPane midSplitter; // splitter containing errorSplitter and treeSplitter SwingProgressBar progressBar; // Progress bar JLabel statusBar; // Status bar JButton feedbackButton; // Feedback button TCFileEditor tcEditor; // Pattern editor (null until requested by user) TCLFileEditor tclEditor; // Script editor (null until requested by user) lapis.trees.RegionSetDisplay regionSetDisplay; // Debugging window (==null until requested by user) //////////////////// //////////////////// Browser state //////////////////// BrowserPane activePane; // either outputPane or errorPane, whichever // has been given focus by user SwingDocument.Factory factory; // DocumentFactory (includes Tcl interpreter state) //////////////////// //////////////////// Highlighted search result //////////////////// RegionSet highlightedRegions; // Currently highlighted region set, or null if none RegionSet highlightedFlatRegions; // Flat version of highlightedRegions, or null if none String highlightedPattern; // TC pattern of highlighted region set, or null if none String highlightedName; // Label of highlighted region set, or null if not a simple named region set boolean isSearching = false; // true if Next Match has been invoked // on the current highlighted region set int shiftDragMark = -1; // the anchor for the current mouse selection Region clickedRegion = null; // the region right-clicked on //////////////////// //////////////////// Constructors //////////////////// public Browser () { super ("Lapis"); // Set look-and-feel // Windows: "com.sun.java.swing.plaf.windows.WindowsLookAndFeel" // Motif: "com.sun.java.swing.plaf.motif.MotifLookAndFeel" // Default: null String lookAndFeel = Main.config.getProperty ("look-and-feel"); if (lookAndFeel != null) { try { javax.swing.UIManager.setLookAndFeel(lookAndFeel); } catch (Exception e) { Debug.report (e); } } //System.err.println ("Creating Browser"); // Handle window-close operation setDefaultCloseOperation (DISPOSE_ON_CLOSE); addWindowListener (new WindowAdapter () { public void windowClosed (WindowEvent evt) { saveConfiguration (); lapis.Main.browserDisposed (); } }); Layout mainLayout = Layout.vertical ((JComponent)getContentPane ()); // Create the menubar menubar = new JMenuBar (); JMenuItem item; JMenu fileMenu = new AcceleratedMenu ("&File"); fileMenu.add (newBrowserAction); fileMenu.add (openAction); fileMenu.add (saveAction); fileMenu.add (closeAction); fileMenu.add (exitAction); menubar.add (fileMenu); JMenu editMenu = new AcceleratedMenu ("&Edit"); editMenu.add (undoAction); editMenu.add (cutAction); editMenu.add (copyAction); editMenu.add (pasteAction); editMenu.add (selectAllAction); editMenu.addSeparator (); editMenu.add (nextMatchAction); //editMenu.add (previousMatchAction); menubar.add (editMenu); JMenu goMenu = new AcceleratedMenu ("&Go"); goMenu.add (backAction); goMenu.add (forwardAction); goMenu.add (reloadAction); goMenu.add (stopAction); menubar.add (goMenu); JMenu parserMenu = new AcceleratedMenu ("&Patterns"); parserMenu.add (editorAction); parserMenu.add (parserAction); parserMenu.addSeparator (); parserMenu.add (nameAction); parserMenu.add (nameAsAction); parserMenu.add (unnameAction); parserMenu.addSeparator (); parserMenu.add (deleteLabelAction); menubar.add (parserMenu); JMenu scriptMenu = new AcceleratedMenu ("&Scripts"); scriptMenu.add (scriptEditorAction); scriptMenu.add (demonstrateAction); scriptMenu.add (historyScriptAction); menubar.add (scriptMenu); JMenu toolMenu = new AcceleratedMenu ("&Tools"); toolMenu.add (keepAction); toolMenu.add (deleteAction); toolMenu.add (sortAction); toolMenu.add (replaceAction); toolMenu.add (extractAction); toolMenu.add (sumAction); toolMenu.add (averageAction); menubar.add (toolMenu); // MED: Hier Menüleiste eingefügt JMenu cisMenu = new AcceleratedMenu("&CIS"); cisMenu.add(focCrawlAction); menubar.add(cisMenu); JMenu helpMenu = new AcceleratedMenu ("&Help"); helpMenu.add (feedbackAction); menubar.add (helpMenu); JMenu debugMenu = new AcceleratedMenu ("&Debug"); debugMenu.add (documentPropertiesAction); debugMenu.add (regionSetDisplayAction); debugMenu.add (highlightOptionAction); helpMenu.add (debugMenu); setJMenuBar (menubar); // Create the toolbar toolbar = new JToolBar (JToolBar.HORIZONTAL); toolbar.setFloatable (false); toolbar.add (backAction); toolbar.add (forwardAction); toolbar.add (reloadAction); toolbar.add (stopAction); // toolbar.addSeparator (); // toolbar.add (keepAction); // toolbar.add (deleteAction); // toolbar.add (sortAction); // toolbar.add (replaceAction); // toolbar.add (extractAction); // toolbar.add (sumAction); // toolbar.add (averageAction); // toolbar.add (dictionaryAction); // toolbar.add (googleAction); // toolbar.add (amazonAction); // toolbar.addSeparator (); // toolbar.add (editorAction); // toolbar.add (demonstrateAction); mainLayout.add (toolbar, Layout.FIXED_HEIGHT); // Create the Location/View As controls location = new JComboBox (new History (MAX_DOCUMENT_HISTORY)); location.setEditable (true); location.setEditor (new BrowserComboBoxEditor ()); location.getEditor ().addActionListener (locationAction); location.addActionListener (historyAction); view = new JComboBox (); view.addItem (new ViewType ("Text", "text/plain")); view.addItem (new ViewType ("HTML", "text/html")); view.addActionListener (changeViewAction); mainLayout.add (Layout.gridbag () .setContainerInsets (1, 1, 1, 1) .add (new JLabel ("Command: "), Layout.FIXED_WIDTH) .add (location) .add (new JLabel (" View As: "), Layout.FIXED_WIDTH) .add (view, Layout.FIXED_WIDTH) .done (), Layout.FIXED_HEIGHT); // Create the browser pane and its decorations outputPane = new BrowserPane (this); outputPane.addCaretListener (caretListener); outputPane.addHyperlinkListener (hyperlinkListener); outputPane.addMouseListener (rightClickListener); outputPane.addMouseListener (shiftClickListener); outputPane.addMouseMotionListener (shiftDragListener); outputPane.addFocusListener (paneFocusListener); browserScrollPane = new JScrollPane (outputPane); browserScrollPane.setVerticalScrollBarPolicy (JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); browserScrollPane.setMinimumSize (new Dimension (0, 0)); outputPanel = (JPanel) Layout.border () .add (outputLabel = new JLabel ("Output: "), Layout.NORTH) .add (browserScrollPane, Layout.CENTER) .done (); outputPanel.setPreferredSize (getSavedDimension ("outputPane", new Dimension (600, 400))); outputPane .getKeymap () .addActionForKeyStroke (KeyStroke.getKeyStroke ('C', KeyEvent.CTRL_MASK), copyKeystrokeAction); // Create the error pane and its decorations errorPane = new BrowserPane (this); errorPane.addCaretListener (caretListener); errorPane.addHyperlinkListener (hyperlinkListener); errorPane.addMouseListener (rightClickListener); errorPane.addMouseListener (shiftClickListener); errorPane.addMouseMotionListener (shiftDragListener); errorPane.addFocusListener (paneFocusListener); errorScrollPane = new JScrollPane (errorPane); errorScrollPane.setVerticalScrollBarPolicy (JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); errorScrollPane.setMinimumSize (new Dimension (0, 0)); errorPanel = (JPanel) Layout.border () .add (errorLabel = new JLabel ("Errors: "), Layout.NORTH) .add (errorScrollPane, Layout.CENTER) .done (); errorPanel.setPreferredSize (getSavedDimension ("errorPane", new Dimension (600, 80))); // Create the pattern box pattern = new TCEditor (); undoPattern = new UndoManager (); pattern.getDocument ().addUndoableEditListener (new UndoableEditListener () { public void undoableEditHappened (UndoableEditEvent e) { undoPattern.addEdit (e.getEdit ()); } }); patternScrollPane = new JScrollPane (pattern); patternScrollPane.setMinimumSize (new Dimension (0, 0)); JLabel patternLabel = new JLabel ("Pattern: "); int buttonHeight = patternLabel.getPreferredSize ().height; patternPanel = (JPanel) Layout.vertical () .setAlignment (Layout.WEST) .setContainerInsets (5, 5, 5, 5) .add (Layout.horizontal () .setAlignment (Layout.SOUTH) .add (patternLabel) .addGlue () .add (makeTinyButton ("Go", findAction, buttonHeight)) .add (makeTinyButton ("Clear", removeAllHighlightsAction, buttonHeight)) .done (), Layout.FIXED_HEIGHT) .add (patternScrollPane) .add (patternMatchCount = new JLabel ("0 matches highlighted")) .done (); patternPanel.setMinimumSize (new Dimension (0, 0)); patternPanel.setPreferredSize (getSavedDimension ("patternPane", new Dimension (200, 150))); patternPanel.registerKeyboardAction (findAction, KeyStroke.getKeyStroke (KeyEvent.VK_ENTER, KeyEvent.CTRL_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW); patternPanel.registerKeyboardAction (removeAllHighlightsAction, KeyStroke.getKeyStroke (KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); // Create the label tree and its decorations tree = new LabelTree (); tree.addMouseListener (treeMouseListener); tree.addTreeExpansionListener (new TreeExpansionListener () { public void treeExpanded(TreeExpansionEvent event) { if (logExpansions) Log.println ("expanded " + event.getPath ()); } public void treeCollapsed(TreeExpansionEvent event) { if (logExpansions) Log.println ("collapsed " + event.getPath ()); } }); treeScrollPane = new JScrollPane (tree); treeScrollPane.setMinimumSize (new Dimension (0, 0)); treePanel = (JPanel) Layout.vertical () .setAlignment (Layout.WEST) .setContainerInsets (5, 5, 5, 5) .add (Layout.horizontal () .setAlignment (Layout.SOUTH) .add (new JLabel ("Names:")) .addGlue () .add (makeTinyButton ("Name...", labelAction, buttonHeight)) .done (), Layout.FIXED_HEIGHT) .add (treeScrollPane) .done (); treePanel.setMinimumSize (new Dimension (0, 0)); treePanel.setPreferredSize (getSavedDimension ("treePane", new Dimension (200, 400))); treePanel.registerKeyboardAction (labelAction, KeyStroke.getKeyStroke ('M', KeyEvent.CTRL_MASK), JComponent.WHEN_IN_FOCUSED_WINDOW); // Create the splitters separating output, error, pattern, // and tree errorSplitter = new JSplitPane (JSplitPane.VERTICAL_SPLIT, outputPanel, errorPanel); errorSplitter.setOneTouchExpandable (true); treeSplitter = new JSplitPane (JSplitPane.VERTICAL_SPLIT, patternPanel, treePanel); treeSplitter.setOneTouchExpandable (true); midSplitter = new JSplitPane (JSplitPane.HORIZONTAL_SPLIT, errorSplitter, treeSplitter); midSplitter.setOneTouchExpandable (true); mainLayout.add (midSplitter); // Create the status panel progressBar = new BrowserProgressBar (); statusBar = new JLabel (""); feedbackButton = new JButton ("Feedback"); feedbackButton.addActionListener (feedbackAction); mainLayout.add (Layout.horizontal () .setContainerInsets (1, 1, 1, 1) .add (progressBar, Layout.FIXED_SIZE) .add (statusBar, new Insets (0, 3, 0, 0)) .addGlue () .add (feedbackButton, Layout.FIXED_WIDTH) .done (), Layout.FIXED_HEIGHT); //System.err.println ("Packing window"); pack (); // Activate output pane activatePane (outputPane, false); // Create document factory and Tcl interpreter (needs to be // after pack() call for some reason) factory = new SwingDocument.Factory (); factory.getProgressGenerator ().addProgressListener (progressBar); // factory.getProgressGenerator ().addProgressListener (new StreamProgressBar (System.err)); // Register browse tool registerBrowserTools (); // Register self with default Toolbox, so that when user creates // new tools we can add them to our menus //System.err.println ("Loading toolbox"); Toolbox.getDefaultToolbox ().addBrowser (this); lapis.Main.browserCreated (); //System.err.println ("Done creating Browser"); } public void show () { super.show (); Point p = getSavedPoint ("location", null); if (p != null) setLocation (p); else PopupDialog.centerWindow (this, null); } void saveDimension (String name, Dimension d) { Main.config.put (name, d.width + "x" + d.height); } Dimension getSavedDimension (String name, Dimension defaultDim) { String s = Main.config.getProperty (name); try { return new Dimension (Integer.parseInt (Str.before (s, "x")), Integer.parseInt (Str.after (s, "x"))); } catch (Exception e) { return defaultDim; } } void savePoint (String name, Point pt) { Main.config.put (name, pt.x + "," + pt.y); } Point getSavedPoint (String name, Point defaultPt) { String s = Main.config.getProperty (name); try { return new Point (Integer.parseInt (Str.before (s, ",")), Integer.parseInt (Str.after (s, ","))); } catch (Exception e) { return defaultPt; } } void saveConfiguration () { savePoint ("location", getLocation ()); saveDimension ("outputPane", outputPanel.getSize ()); saveDimension ("errorPane", errorPanel.getSize ()); saveDimension ("patternPane", patternPanel.getSize ()); saveDimension ("namesPane", treePanel.getSize ()); Main.config.put ("errorSplitter", String.valueOf (getErrorSplitterLocations () [0])); Main.config.save (); Log.close (); } JButton makeTinyButton (String label, Action action, int height) { JButton button = new JButton (label); Font oldFont = button.getFont (); Font font = new Font (oldFont.getName (), oldFont.getStyle (), oldFont.getSize () - 2); button.setFont (font); Dimension d = new Dimension (button.getPreferredSize ().width, height); button.setPreferredSize (d); button.setMaximumSize (d); button.addActionListener (action); String tooltip = (String) action.getValue (Action.SHORT_DESCRIPTION); if (tooltip != null) button.setToolTipText (tooltip); return button; } class BrowserProgressBar extends SwingProgressBar { public BrowserProgressBar () { setStringPainted (false); Dimension size = BrowserProgressBar.this.getMinimumSize (); if (size.width < 100) setMinimumSize (new Dimension (100, size.height)); } public void setString (String label) { if (label != null) setStatus (label + "..."); } public void doneProgress (ProgressEvent event) { clearStatus (); } } /* * Text field of Location and Find combo boxes. Overrides JComboBox's standard * text field so that losing focus doesn't automatically send an Action event; * only pressing Enter does. */ static class BrowserComboBoxEditor extends javax.swing.plaf.basic.BasicComboBoxEditor { public BrowserComboBoxEditor () { super (); // make fonts big for demo purposes // Font f = editor.getFont (); // if (f != null) // editor.setFont (new Font (f.getName (), Font.BOLD, 14)); } public void focusGained(FocusEvent e) { selectAll (); } public void focusLost(FocusEvent e) { JTextField f = (JTextField)getEditorComponent (); Caret caret = f.getCaret (); caret.setDot (caret.getDot ()); } } void registerBrowserTools () { Interpreter interp = factory.getInterpreter (); interp.registerTool ("view", new Tool () { public lapis.Document invoke (Arguments args) throws Exception { args.setUsage ( "Usage: View [options] <file/URL> ...\n" + " <file/URL> Document(s) to print\n" + "\n" + "Options include:\n" + " -help Display this message\n" ); while (args.hasMoreElements ()) { String name = args.nextName (); args.consume (name); } Enumeration inputs = args.getInputs (); lapis.Document doc = null; while (inputs.hasMoreElements ()) { doc = (lapis.Document)inputs.nextElement (); setDocument (doc); } return doc; } }); interp.registerTool ("print", new Tool () { public lapis.Document invoke (Arguments args) throws Exception { args.setUsage ( "Usage: Print [options] <file/URL> ...\n" + " <file/URL> Document(s) to print\n" + "\n" + "Options include:\n" + " -help Display this message\n" ); while (args.hasMoreElements ()) { String name = args.nextName (); args.consume (name); } Enumeration inputs = args.getInputs (); lapis.Document doc = null; while (inputs.hasMoreElements ()) { doc = (lapis.Document)inputs.nextElement (); setDocument (doc); String title = (String)doc.getProperty ("title"); if (title == null) title = doc.toString (); BasicProgressGenerator gen = args.getFactory ().getProgressGenerator (); gen.fireStartProgress ("Printing " + title + "...", 10); for (int i = 0; i < 10; ++i) { gen.fireProgress (i); Thread.sleep (100); } gen.fireDoneProgress (); } return doc; } }); } //////////////////// //////////////////// Closing the browser //////////////////// public Action closeAction = new AcceleratedAction ("&Close", 'W', KeyEvent.CTRL_MASK) { public void actionPerformed (ActionEvent evt) { dispose (); } }; public Action exitAction = new AcceleratedAction ("E&xit", 'Q', KeyEvent.CTRL_MASK) { public void actionPerformed (ActionEvent evt) { if (lapis.Main.getRunningBrowsers () == 1 || JOptionPane.showConfirmDialog(Browser.this, "Close all windows and exit Lapis?", "Exit Lapis?", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { saveConfiguration (); System.exit (0); } } }; //////////////////// //////////////////// Debugging //////////////////// Action documentPropertiesAction = new AcceleratedAction ("&Document Info") { public void actionPerformed (ActionEvent evt) { SwingDocument doc = getDocument (); if (doc == null) { getToolkit ().beep (); return; } JDialog dlg = new JDialog (Browser.this, "Document Info - " + doc.toString (), false); Container contentPane = dlg.getContentPane (); Layout.border (contentPane) .add (new DocumentProperties (doc), Layout.CENTER); dlg.pack (); dlg.show (); PopupDialog.centerWindow (dlg, null); } }; Action regionSetDisplayAction = new AcceleratedAction ("&Region Set") { public void actionPerformed (ActionEvent evt) { if (regionSetDisplay == null) { regionSetDisplay = lapis.trees.RegionSetDisplay.makeInFrame (); regionSetDisplay.setLocation (getSize ().width, 0); regionSetDisplay.setDocument (getDocument ()); regionSetDisplay.setRegions (getRegions ()); } regionSetDisplay.setVisible (true); } }; Action highlightOptionAction = new AcceleratedAction ("&Highlight Options") { public void actionPerformed (ActionEvent evt) { ((RegionHighlighter) activePane.getHighlighter ()) .showOptionDialog (Browser.this); } }; //////////////////// //////////////////// Help & feedback //////////////////// Action feedbackAction = new AcceleratedAction ("&Feedback and Bug Reports") { public void actionPerformed (ActionEvent evt) { FeedbackForm.showFeedbackForm (Browser.this); } }; //////////////////// //////////////////// Status bar and stop button //////////////////// public void setStatus (String message) { if (statusBar != null) statusBar.setText (message); } public void clearStatus () { setStatus (" "); progressBar.setValue (0); } int hourglassCount; // reference count on setHourglass(true) public void setHourglass (boolean enabled) { if (enabled) ++hourglassCount; else if (--hourglassCount > 0) return; // somebody still wants the hourglass showing else hourglassCount = 0; // Change the stop button stopAction.putValue (Action.SMALL_ICON, enabled ? stopIcon : graystopIcon); } public void clearHourglass () { hourglassCount = 0; setHourglass (false); } //////////////////// //////////////////// Evaluating Tcl commands //////////////////// /** * Evaluate a Tcl script (in the background). * @param script Tcl code to evaluate (may be multiple lines) */ public void eval (final String script) { this.eval (script, true); } public void eval (final String script, final boolean annotateResult) { stop (); Log.println ("eval " + script); setStatus ("Evaluating command..."); runStoppableActivity (new RunnableWithExceptions () { public void run () throws Exception { Interpreter interp = factory.getInterpreter (); // Evaluate the script and get its output lapis.Document output = (lapis.Document) interp.eval (script, getDocument ()); Thr.check (); if (annotateResult) // Attach script to its output output.putProperty (SwingDocument.CommandProperty, toOneLine (script)); // Display output setDocument (output); } }); } // Convert a possibly multi-line Tcl script to a single line. private static String toOneLine (String script) { return Str.replace (script.trim (), "\n", " ; "); } //////////////////// //////////////////// Getting browser state //////////////////// /** * Get the current document. */ public SwingDocument getDocument () { return (SwingDocument)activePane.getDocument (); } /** * Get the browser's document factory. */ public DocumentFactory getFactory () { return factory; } /** * Get command that generated browser contents. * @returns command (actually a URL, filename, or command), * or null if browser is showing nothing. */ public String getCommand () { SwingDocument doc = getDocument (); return (doc != null) ? (String)doc.getProperty (SwingDocument.CommandProperty) : null; } /** * Get browser history. */ public History getHistory () { return (History)location.getModel (); } //////////////////// //////////////////// Visiting new pages in browser //////////////////// /** * Change the current document to a Document object. */ public void setDocument (lapis.Document newdoc) { // Convert to a SwingDocument if necessary final SwingDocument doc = convertToSwingDocument (newdoc); Log.println ("show " + doc); // Prepare to change current document loadingDocument (doc); // Load output document setStatus ("Loading " + doc + "..."); // runStoppableActivity (new RunnableWithExceptions () { // public void run () { outputPane.setDocument (doc); // Done changing document loadedDocument (doc); clearStatus (); setStatus ("Document loaded."); // } // }); // Load error document (if any) final lapis.Document error = (lapis.Document) doc.getProperty (SwingDocument.ErrorProperty); if (error != null) { // runStoppableActivity (new RunnableWithExceptions () { // public void run () { errorPane.setDocument (convertToSwingDocument (error)); // } // }); } } private SwingDocument convertToSwingDocument (lapis.Document doc) { if (doc instanceof SwingDocument) return (SwingDocument)doc; SwingDocument sdoc = (SwingDocument) factory.make (doc); factory.getInterpreter ().setVar (Interpreter.DOCUMENT_VAR, sdoc); return sdoc; } /** * Called when a document is about to be loaded. The document has not * necessarily * been fully downloaded yet, so its content is unavailable, but its * URL and content type are available. Default behavior adds * the document to the browsing history and puts its URL in the Location * text box and its content type in the View drop-down list. */ protected void loadingDocument (SwingDocument doc) { Thr.check (); // Put new doc in the history, if necessary try { blockHistoryAction = true; History history = getHistory (); if (!history.contains (doc)) history.put (doc); } finally { blockHistoryAction = false; } // Update location box location.getEditor ().setItem (doc); location.getEditor ().selectAll (); // Update content-type updateContentType (doc); // Update title bar (no TitleProperty available yet, but URLProperty // is) updateTitle (doc); // Clear the highlighted region set setRegions (null, null); // Update debugging display if (regionSetDisplay != null) regionSetDisplay.setDocument (doc); // Activate browser pane activatePane (outputPane, doc.getProperty (SwingDocument.ErrorProperty) != null); } /** * Called after the current document has been fully loaded. */ protected void loadedDocument (SwingDocument doc) { Thr.check (); // Update title bar -- TitleProperty (if any) is available now // since document is loaded. updateTitle (doc); // Update label tree updateLabels (); } private void updateTitle (SwingDocument doc) { String title = (String) doc.getProperty (SwingDocument.TitleProperty); if (title == null) title = doc.toString (); setTitle ((title != null) ? "Lapis - " + title : "Lapis"); } //////////////////// //////////////////// Switching between browser and error pane //////////////////// private FocusListener paneFocusListener = new FocusAdapter () { public void focusGained (FocusEvent event) { selectPane ((BrowserPane)event.getSource ()); } }; private void selectPane (BrowserPane pane) { if (pane == activePane) return; Log.println ("select " + ((pane == outputPane) ? "output" : "error")); // Clear the old pane's highlighting setRegions (null, null); // Activate the new pane activatePane (pane, errorShowing); // Update the UI to match new pane updateContentType (getDocument ()); updateLabels (); } boolean errorShowing = true; Color inactivePaneColor; private void activatePane (BrowserPane pane, boolean showErrorPane) { if (inactivePaneColor == null) { // first time a pane has been activated. // save the default background color to // use for inactive panes inactivePaneColor = outputPanel.getBackground (); } // show or hide error panel, adjusting error splitter accordingly int[] locations = getErrorSplitterLocations (); outputLabel.setVisible (showErrorPane); errorPanel.setVisible (showErrorPane); errorSplitter.setDividerLocation (locations[showErrorPane ? 0 : 1]); errorSplitter.setLastDividerLocation (locations[0]); // Set the panel's background color (affecting only the // panel's label) to indicate which panel is activated outputPanel.setBackground ((pane == outputPane) ? ACTIVE_PANE_COLOR : inactivePaneColor); errorPanel.setBackground ((pane == errorPane) ? ACTIVE_PANE_COLOR : inactivePaneColor); activePane = pane; errorShowing = showErrorPane; } int[] getErrorSplitterLocations () { int bottom = errorSplitter.getHeight () - errorSplitter.getInsets ().bottom - errorSplitter.getDividerSize (); int middle = errorSplitter.getDividerLocation (); if (Math.abs (middle - bottom) < 15) middle = errorSplitter.getLastDividerLocation(); if (Math.abs (middle - bottom) < 15) { String loc = Main.config.getProperty ("errorSplitter"); if (loc != null) middle = Integer.parseInt (loc); } errorSplitter.setLastDividerLocation (middle); //System.err.println ("middle = " + middle + ", bottom = " + bottom); return new int[] { middle, bottom }; } //////////////////// //////////////////// Invoking URLs (by typing, from history, or by hyperlink) //////////////////// /** * Action invoked when user edits the URL in the Location box and leaves * the URL box (by pressing Enter or clicking somewhere else). */ public Action locationAction = new AbstractAction () { public void actionPerformed (ActionEvent evt) { Object item = location.getEditor ().getItem (); //System.err.println ("Goto " + item); if (item instanceof String) eval (item.toString ()); location.getEditor ().selectAll (); } }; /** * Action invoked when user selects a document from the history drop-down list. */ public Action historyAction = new AbstractAction () { public void actionPerformed (ActionEvent evt) { if (blockHistoryAction) return; SwingDocument doc = (SwingDocument)location.getSelectedItem (); if (doc == null) return; setDocument (doc); } }; boolean blockHistoryAction = false; /** * Listener invoked when user clicks on a hyperlink in an HTML document. */ public HyperlinkListener hyperlinkListener = new HyperlinkListener () { public void hyperlinkUpdate(HyperlinkEvent e) { HyperlinkEvent.EventType type = e.getEventType(); URL url = e.getURL (); if (url == null) return; if (url.toString ().startsWith ("file://localhost/")) url = URLUtil.FileToURL (new File (url.toString ().substring (16))); if (type == HyperlinkEvent.EventType.ACTIVATED) { eval (url.toString ()); } else if (type == HyperlinkEvent.EventType.ENTERED) { // FIX: ENTERED and EXITED events aren't sent by current Swing setStatus (url.toString ()); ((Component)e.getSource ()) .setCursor (Cursor.getPredefinedCursor (Cursor.HAND_CURSOR)); } else if (type == HyperlinkEvent.EventType.EXITED) { setStatus (" "); ((Component)e.getSource ()) .setCursor (Cursor.getDefaultCursor ()); } } }; /** * Action invoked by Back command. Move back to previous document in history. */ public Action backAction = new AcceleratedAction ("&Back", new ImageIcon (System.getProperty ("lapis.dir", ".") + "/images/back.gif"), KeyEvent.VK_LEFT, KeyEvent.ALT_MASK, "Go back to previous page in history") { public void actionPerformed (ActionEvent evt) { History history = getHistory (); SwingDocument doc = (SwingDocument)history.back (); if (doc == null) getToolkit().beep (); else { stop (); setDocument (doc); } } }; /** * Action invoked by Forward command. Moves forward to next document in history. */ public Action forwardAction = new AcceleratedAction ("&Forward", new ImageIcon (System.getProperty ("lapis.dir", ".") + "/images/fwd.gif"), KeyEvent.VK_RIGHT, KeyEvent.ALT_MASK, "Go forward to next page in history") { public void actionPerformed (ActionEvent evt) { History history = getHistory (); SwingDocument doc = (SwingDocument)history.forward (); if (doc == null) getToolkit().beep (); else { stop (); setDocument (doc); } } }; /** * Action invoked by Reload command. Reloads and reparses the current * page. */ public Action reloadAction = new AcceleratedAction ("&Reload", new ImageIcon (System.getProperty ("lapis.dir", ".") + "/images/reload.gif"), 'R', KeyEvent.CTRL_MASK, "Reload the current page") { public void actionPerformed (ActionEvent evt) { String command = getCommand (); if (command != null) eval (command.toString ()); } }; //////////////////// //////////////////// Running and stopping background activities //////////////////// Vector backgroundThreads = new Vector (); public synchronized void runStoppableActivity (RunnableWithExceptions r) { new BackgroundThread (r) .start (); } private interface RunnableWithExceptions { public void run () throws Exception; } private class BackgroundThread extends Thread { RunnableWithExceptions r; public BackgroundThread (RunnableWithExceptions r) { this.r = r; setPriority (BACKGROUND_PRIORITY); backgroundThreads.addElement (this); } public void run () { try { setHourglass (true); r.run (); setHourglass (false); } catch (final Exception e) { SwingUtilities.invokeLater (new Runnable () { public void run () { FeedbackForm.showExceptionDialog (Browser.this, e); clearHourglass (); clearStatus (); } }); } } } /** * Action invoked by Stop command. Stops downloading or parsing. */ ImageIcon stopIcon = new ImageIcon (System.getProperty ("lapis.dir", ".") + "/images/stop.gif"); ImageIcon graystopIcon = new ImageIcon (System.getProperty ("lapis.dir", ".") + "/images/gray-stop.gif"); public Action stopAction = new AcceleratedAction ("&Stop", graystopIcon, "Stop the current page load") { public void actionPerformed (ActionEvent evt) { stop (); SwingUtilities.invokeLater (new Runnable () { public void run () { setStatus ("Stopped."); } }); } }; public synchronized void stop () { // Interrupt all background threads, forcing I/O operations to throw // errors and Thr.check() to throw ThreadDeath for (Enumeration e = backgroundThreads.elements (); e.hasMoreElements (); ) ((Thread)e.nextElement ()).interrupt (); backgroundThreads.removeAllElements (); // Reset progress UI clearHourglass (); clearStatus (); } //////////////////// //////////////////// File operations (open and save) //////////////////// /** * Action invoked when user selects File/New Browser. * Creates a new Browser window. */ public Action newBrowserAction = new AcceleratedAction ("&New Browser", 'N', KeyEvent.CTRL_MASK) { public void actionPerformed (ActionEvent evt) { Browser b = new Browser (); // Copy history to new browser window History h = new History (getHistory ()); b.location.setModel (h); Object d = h.get (); if (d != null) b.setDocument ((SwingDocument)d); // Show new browser window offset 50,50 from this window b.show (); Point p = getLocation (); p.translate (50, 50); b.setLocation (p); } }; /** * Action invoked when user selects File/Open. * Pops up a file-open dialog to open a file into the browser. */ public Action openAction = new AcceleratedAction ("&Open...", 'O', KeyEvent.CTRL_MASK) { public void actionPerformed (ActionEvent evt) { FileChooser chooser = new FileChooser (); if (chooser.showOpenDialog (Browser.this) == JFileChooser.APPROVE_OPTION) eval (chooser.getSelectedFile ().toString ()); } }; /** * Action invoked when user selects File/Save. * Pops up a save-as dialog box, then saves the browser contents. */ public Action saveAction = new AcceleratedAction ("&Save As...", 'S', KeyEvent.CTRL_MASK) { public void actionPerformed (ActionEvent evt) { FileChooser chooser = new FileChooser (); File filename = getFile (); if (filename != null) chooser.setSelectedFile (filename); if (chooser.showSaveDialog (Browser.this) != JFileChooser.APPROVE_OPTION) return; File f = chooser.getSelectedFile (); if (f.exists ()) switch (JOptionPane.showConfirmDialog (Browser.this, f + " already exists. Overwrite?\n", "Overwrite?", JOptionPane.YES_NO_CANCEL_OPTION)) { case JOptionPane.YES_OPTION: break; case JOptionPane.NO_OPTION: // Pop up dialog box again actionPerformed (evt); return; case JOptionPane.CANCEL_OPTION: return; } save (f); } }; /** * Save browser contents to a local file. * @param f Local file to save */ public void save (File f) { try { PrintWriter out = new PrintWriter (new FileWriter (f)); out.print (getDocument ().getContentText ()); out.close (); } catch (Exception e) { FeedbackForm.showExceptionDialog (Browser.this, e); } } /** * Get local filename corresponding to browser contents. * @returns local filename, or null if browser is showing nothing or * a remote page. */ public File getFile () { SwingDocument doc = getDocument (); if (doc == null) return null; URL url = (URL)doc.getProperty (SwingDocument.URLProperty); if (url == null) return null; try { return URLUtil.URLToFile (url); } catch (MalformedURLException e) { return null; } } //////////////////// //////////////////// edit operations (cut, copy, paste, etc) //////////////////// public Action cutAction = new KeystrokeAction ("Cu&t", 'X', KeyEvent.CTRL_MASK); public Action copyAction = new KeystrokeAction ("&Copy", 'C', KeyEvent.CTRL_MASK); public Action pasteAction = new KeystrokeAction ("&Paste", 'V', KeyEvent.CTRL_MASK); public Action selectAllAction = new KeystrokeAction ("Select &All", 'A', KeyEvent.CTRL_MASK); class KeystrokeAction extends AcceleratedAction { public KeystrokeAction (String name, int keycode, int modifiers) { super (name, keycode, modifiers); } public void actionPerformed (ActionEvent event) { Keymap keymap = outputPane.getKeymap (); if (keymap == null) { Toolkit.getDefaultToolkit ().beep (); return; } KeyStroke keystroke = (KeyStroke) getValue (ACCELERATOR); Action action = keymap.getAction (keystroke); if (action == null) { Toolkit.getDefaultToolkit ().beep (); return; } action.actionPerformed (event); } } /** * Action invoked by Undo command. Undoes one editing action. */ public Action undoAction = new AcceleratedAction ("&Undo", 'Z', KeyEvent.CTRL_MASK, new javax.swing.text.TextAction ("Undo") { public void actionPerformed (ActionEvent evt) { if (getTextComponent (evt) == pattern) { try { undoPattern.undo (); } catch (CannotUndoException e) { getToolkit ().beep (); } } } }); /** * Override copy action (for ALL JTextComponents) to mark * which JTextComponent generated the clipboard contents. */ public Action copyKeystrokeAction = new DefaultEditorKit.CopyAction () { public void actionPerformed(ActionEvent event) { JTextComponent target = getTextComponent(event); if (! (target instanceof BrowserPane)) { super.actionPerformed (event); return; } Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); BrowserPane br = (BrowserPane) target; javax.swing.text.Document doc = (javax.swing.text.Document)target.getDocument(); RegionHighlighter h = (RegionHighlighter) br.getHighlighter (); RegionSet s = h.getRegions (); if (s != null) { if (doc instanceof CookedDocument) s = s.convert (((CookedDocument)doc).getCoordinateMap ()); s = s.meld (); RegionEnumeration re = s.regions (); StringBuffer result = new StringBuffer (); for (Interval r = (Interval) re.first (); r != null; r = (Interval) re.next ()) { try { result.append (doc.getText(r.start, r.end - r.start)); } catch (BadLocationException e) { } } StringSelection contents = new StringSelection (result.toString ()); clipboard.setContents(contents, contents); } } }; //////////////////// //////////////////// Changing the view (text, html, etc.) //////////////////// static class ViewType { public String uiName; // name for UI purposes (e.g. "Text") public String contentType; // content type (e.g. "text/plain") public ViewType (String uiName, String contentType) { this.uiName = uiName; this.contentType = contentType; } public String toString () { return uiName; } } private void updateContentType (SwingDocument doc) { try { blockContentTypeAction = true; setViewContentType (view, (String) doc.getProperty (SwingDocument.MIMEProperty)); } finally { blockContentTypeAction = false; } } /** * Action invoked when user selects a different view from the drop-down list. */ boolean blockContentTypeAction = false; public Action changeViewAction = new AbstractAction () { public void actionPerformed (ActionEvent evt) { if (blockContentTypeAction) return; ViewType vt = (ViewType) view.getSelectedItem (); if (vt == null) return; changeContentType (vt.contentType); } }; public void changeContentType (String contentType) { SwingDocument doc = getDocument (); if (doc == null) return; // Check whether content type is actually changing String oldContentType = (String) doc.getProperty (SwingDocument.MIMEProperty); if (contentType.equals (oldContentType)) return; // Re-create document with desired content type SwingDocument olddoc = doc; doc.putProperty (SwingDocument.MIMEProperty, contentType); doc = (SwingDocument) factory.make (olddoc); olddoc.putProperty (SwingDocument.MIMEProperty, contentType); // Replace document in history. // Use block flag to block its action listener // from firing, thereby avoiding multiple calls to setDocument(). try { blockHistoryAction = true; (getHistory ()).replace (doc); } finally { blockHistoryAction = false; } // Hang on the highlighting RegionSet highlight = getRegions (); String highlightName = getRegionSetName (); // Set the converted document setDocument (doc); // Set the background appropriate to this content type new lapis.parsers.BackgroundParser () .parse (doc); // Restore the original highlighting setRegions (highlightName, highlight); } /* * Set the view drop-down list to match a loaded document's content type. */ static void setViewContentType (JComboBox view, String contentType) { int selection = 0; // use Text as default if we can't find contentType try { ComboBoxModel model = view.getModel (); int n = model.getSize (); for (int i = 0; i < n; ++i) { ViewType vt = (ViewType)model.getElementAt (i); if (vt.contentType.equals (contentType)) { selection = i; break; } } } catch (NullPointerException e) { } view.setSelectedIndex (selection); } //////////////////// //////////////////// Parsing the current document //////////////////// /** * Parse the current document (in the background) using * a specified parser. */ public void parse (final Parser parser) { runStoppableActivity (new RunnableWithExceptions () { public void run () { SwingDocument doc = getDocument (); if (doc == null) return; parser.parse (doc); updateLabels (); } }); } //////////////////// //////////////////// Searching for patterns //////////////////// /** * Action invoked when user types something in the Find text box and presses Enter, * or selects a pattern from the pattern history drop-down. * Searches for the text constraint pattern and highlights the matching regions. */ public Action findAction = new AcceleratedAction ("Go", KeyEvent.VK_ENTER, KeyEvent.CTRL_MASK, "Highlight all matches to the pattern [Ctrl-Enter]") { // keep this action from firing recursively public boolean blockFindAction = false; public void actionPerformed (ActionEvent evt) { try { // finally if (blockFindAction) return; blockFindAction = true; // // get pattern expression // ComboBoxEditor ed = pattern.getEditor (); // String expr = ed.getItem ().toString (); // if (expr.length () == 0) // return; // // add it to pattern history // History history = (History) pattern.getModel (); // if (!history.contains (expr)) // history.add (expr); Log.println ("find pattern:\n" + pattern.getText ().trim ()); // compile pattern into a TC structure final TC system = makeTCFromTextComponent (pattern); // evaluate pattern in background runStoppableActivity (new RunnableWithExceptions () { public void run () { SwingDocument doc = getDocument (); if (doc == null) return; final TCParseException warnings = new TCParseException (); RegionSet result = system.evaluate (doc, warnings); updateLabels (); String canonicalLabel = null; String label = system.getLabel (); if (label != null) { Labeling labels = doc.getLabeling (); try { canonicalLabel = labels.lookup (label); } catch (Labeling.LookupException e) { } } setRegions (canonicalLabel, result); if (!warnings.isEmpty ()) SwingUtilities.invokeLater (new Runnable () { public void run () { FeedbackForm.showMessageDialog (Browser.this, warnings.getMessage (), "Warning", JOptionPane.ERROR_MESSAGE); } }); } }); } catch (TCParseException e) { Log.println ("parse errors: " + e.getMessage ()); FeedbackForm.showMessageDialog (Browser.this, e.errors ().nextElement ().toString (), "Parse Error", JOptionPane.ERROR_MESSAGE); } finally { blockFindAction = false; pattern.requestFocus (); } } }; /** * Action invoked when user selects an earlier pattern from the Find drop-down list. */ // public ItemListener findHistoryListener = new ItemListener () { // public void itemStateChanged(ItemEvent e) { // Object item = pattern.getSelectedItem (); // if (item == null) // item = ""; // pattern.getEditor ().setItem (item); // } // }; public static TC makeTCFromTextComponent (JTextComponent textbox) throws TCParseException { String text = textbox.getText (); try { return new TC (text); } catch (TCParseException e) { // Select the error, then re-throw the exception selectParseError (textbox, e); e.setStringContext (text); throw e; } } public static void selectParseError (JTextComponent textbox, TCParseException e) { int len = textbox.getText ().length (); int start = Math.max (0, Math.min (len, e.getStart ())); int end = Math.max (0, Math.min (len, e.getEnd ())); textbox.select (start, end); if (start == end) { // insert a marker to make error position visible textbox.replaceSelection ("???"); textbox.select (start, end+3); } textbox.requestFocus (); } /** * Append a name to the pattern box (usually because it was selected from * a popup menu or the label tree). */ /* protected void putNameInPattern (Label name) { ComboBoxEditor editor = pattern.getEditor (); String item = (String)editor.getItem (); if (item.length () != 0) item += ' '; item += name; editor.setItem (item); } */ /** * Action invoked when user clicks on Name... button. * Pops up a dialog to assign a label to current highlight. */ public Action labelAction = new AcceleratedAction ("Name...", 'M', KeyEvent.CTRL_MASK, "Give a name to the current highlight [Ctrl-M]") { public void actionPerformed (ActionEvent evt) { String name = promptForName (highlightedName); if (name == null) return; Log.println ("named " + name); Labeling labels = getDocument ().getLabeling (); boolean nameExists = labels.contains (name); labels.put (name, getRegions ()); if (!nameExists) updateLabels (); setRegions (name, null); } }; /** * Action invoked when user clicks on Remove Highlight on context menu. * Unhighlights the region under the cursor. */ public Action removeHighlightAction = new AcceleratedAction ("Remove Highlight") { public void actionPerformed (ActionEvent evt) { if (clickedRegion == null) return; Log.println ("unhighlight " + clickedRegion); setRegions (null, highlightedRegions.copy () .delete (clickedRegion)); } }; /** * Action invoked when user clicks on Clear button. * Clears the highlight. */ public Action removeAllHighlightsAction = new AcceleratedAction ("Remove All Highlights", KeyEvent.VK_ESCAPE, 0, "Clear all highlights and clear the Pattern box [Esc]") { public void actionPerformed (ActionEvent evt) { Log.println ("clear"); setRegions (null, null); pattern.requestFocus (); } }; /** * Action invoked when user clicks on TC Editor button. * Pops up a new TCFileEditor window. */ public Action editorAction = new AcceleratedAction ("Pattern &Editor") { public void actionPerformed (ActionEvent evt) { showTCFileEditor (); } }; public void showTCFileEditor () { if (tcEditor == null) { tcEditor = new TCFileEditor (Browser.this); tcEditor.show (); PopupDialog.centerWindow (tcEditor, Browser.this); } else tcEditor.show (); } /** * Action invoked when user selects Structure/Run Parser menu command. * Pops up a dialog box for parser name. */ public Action parserAction = new AcceleratedAction ("&Run Parser...") { public void actionPerformed (ActionEvent evt) { ParserDialog dialog = new ParserDialog (Browser.this); dialog.show (); Parser parser = dialog.getParser (); if (parser == null) return; parse (parser); } }; class ParserDialog extends OkCancelDialog { JTextField name; JButton browseButton; private Parser parser; // created by OK button; null if dialog canceled public ParserDialog (Frame owner) { super (owner, "Run Parser"); Layout.gridbag (getControlsPane ()) .setAlignment (Layout.NORTHWEST) .add (new JLabel ("Parser (filename, URL or Java class): "), Layout.FIXED_SIZE) .nextRow () .add (name = new JTextField ()) .add (browseButton = new JButton ("Browse..."), Layout.FIXED_SIZE); name.addActionListener (new ActionListener () { public void actionPerformed (ActionEvent event) { ok (); } }); browseButton.addActionListener (new ActionListener () { public void actionPerformed (ActionEvent event) { FileChooser chooser = new FileChooser (); if (chooser.showOpenDialog (ParserDialog.this) == JFileChooser.APPROVE_OPTION) name.setText (chooser.getSelectedFile ().toString ()); } }); pack (); } public void ok () { try { parser = ParserGroup.loadParser (name.getText ()); } catch (Exception e) { FeedbackForm.showExceptionDialog (Browser.this, e); } super.ok (); } public Parser getParser () { return parser; } } //////////////////// //////////////////// Refreshing the label tree //////////////////// boolean logExpansions = true; protected void updateLabels () { try { logExpansions = false; tree.setLabeling (getDocument ().getLabeling ()); } finally { logExpansions = true; } } //////////////////// //////////////////// The highlighted region set //////////////////// /** * Set the highlighted region set with its name. If name is null, * assumes region set is anonymous. If r is null, looks up name * in document's labeling. If both name and r are null, uses * EMPTY_SET. */ public void setRegions (String name, RegionSet r) { if (r == null) { if (name != null) { Labeling labels = getDocument ().getLabeling (); // Lookup name r = labels.get (name); // Display (abbreviated) name in pattern box pattern.setText (labels.getShortestName (name).toString ()); } else { pattern.setText (""); } } highlightedRegions = r; highlightedName = name; changedRegions (); } /** * Called when the highlighted region set changes. */ protected void changedRegions () { // Record the pattern used to generate the highlighted regions highlightedPattern = (highlightedRegions != null) ? pattern.getText () : null; // Highlight the region set name (if any) in the label tree try { logExpansions = false; tree.setSelectedLabel (highlightedName); } finally { logExpansions = true; } // Flatten the region set highlightedFlatRegions = (highlightedRegions != null) ? highlightedRegions.flatten () : null; // Highlight the matches in the browser pane activePane.setRegions (highlightedRegions); // Reset search resetFind (); // Display number of matches in status bar int n = (highlightedRegions != null) ? highlightedRegions.getSize () : 0; if (((RegionHighlighter)activePane.getHighlighter ()).getFeedback () != null) ++n; patternMatchCount.setText ( n + " match" + ((n == 1) ? "" : "es") + " highlighted"); // Update debugging display if (regionSetDisplay != null) regionSetDisplay.setRegions (highlightedRegions); // // Scroll to first match // if (highlightedFlatRegions != null) { // Region firstMatch = highlightedFlatRegions.regions ().first (); // if (firstMatch != null) // activePane.scrollRegionToVisible (firstMatch); // } } /** * Get the highlighted region set. */ public RegionSet getRegions () { return highlightedRegions; } /** * Get the label of the highlighted region set (or null if not labeled). */ public String getRegionSetName () { return highlightedName; } /** * Step to next match in highlighted region set. Starts from current selection * or cursor position. */ public Action nextMatchAction = new AcceleratedAction ("&Next Match", KeyEvent.VK_F3, 0) { public void actionPerformed (ActionEvent event) { findNext (true); } }; public void resetFind () { isSearching = false; } public void findNext (boolean beepIfNone) { if (highlightedRegions == null) { if (beepIfNone) getToolkit().beep (); return; } // Find start point of search. Interval selection = null; // Document position to start searching from. if (isSearching) // Next Match has been invoked since the highlighted // region set last changed. // Start after current selection. selection = activePane.getSelectedRegion (); else isSearching = true; if (selection == null) selection = new Interval (0, 0); // Find first highlighted region after selection Region r = highlightedFlatRegions.regions ((Region)selection.after ()).first (); if (r == null){ if (beepIfNone) getToolkit().beep (); } else { // Select it activePane.selectRegion (r); activePane.requestFocus (); } } /** * Step to previous match in highlighted region set. Looks backward from current * selection or cursor position. */ public Action previousMatchAction = new AcceleratedAction ("&Previous Match", KeyEvent.VK_F3, KeyEvent.SHIFT_MASK) { public void actionPerformed (ActionEvent event) { // Fix: can't support this until we can enumerate backwards getToolkit().beep (); } }; //////////////////// //////////////////// Naming regions manually //////////////////// /** * Action invoked by Label command. Adds selected region to current region set. */ public Action nameAction = new AcceleratedAction ("&Label", 'L', KeyEvent.CTRL_MASK) { public void actionPerformed (ActionEvent evt) { Interval r = activePane.getSelectedRegion (); if (r.start == r.end) return; // ignore 0-length selections if (highlightedName != null) nameRegion (highlightedName, r); else nameAsAction.actionPerformed (evt); } }; /** * Action invoked by Label As command. Pops up a dialog to give * selection region an arbitrary name. */ public Action nameAsAction = new AcceleratedAction ("Label &As...") { public void actionPerformed (ActionEvent evt) { Interval r = activePane.getSelectedRegion (); if (r.start == r.end) return; // ignore 0-length selections String name = promptForName (highlightedName); activePane.selectRegion (r); if (name != null) nameRegion (name, r); } }; /** * Action invoked by Unlabel command. * Removes selected region from current region set. */ public Action unnameAction = new AcceleratedAction ("&Unlabel", 'U', KeyEvent.CTRL_MASK) { public void actionPerformed (ActionEvent evt) { Interval r = activePane.getSelectedRegion (); if (r.start == r.end) return; // ignore 0-length selections if (highlightedName != null) unnameRegion (highlightedName, r); } }; /** * Action invoked by Delete Label command. Deletes selected label * from labeling. */ public Action deleteLabelAction = new AcceleratedAction ("&Delete Label", 'D', KeyEvent.CTRL_MASK) { public void actionPerformed (ActionEvent evt) { if (highlightedName != null) { Labeling labels = getDocument ().getLabeling (); labels.remove (highlightedName); setRegions (null, null); updateLabels (); } } }; void nameRegion (String name, Region r) { Labeling labels = getDocument ().getLabeling (); boolean nameExists = labels.contains (name); labels.add (name, r); setRegions (name, null); if (!nameExists) updateLabels (); } void unnameRegion (String name, Region r) { Labeling labels = getDocument ().getLabeling (); RegionSet s = labels.get (name); // delete all regions inside r (including fuzz) Region inR = (Region)r.in (); labels.get (SwingDocument.BACKGROUND).fuzzifyBoundingBox (inR); s = s.delete (inR); // trim all regions overlapping r (not including fuzz) s = s.trim (r); labels.put (name, s); setRegions (name, null); } String promptForName (String defaultName) { String answer = (String) JOptionPane.showInputDialog (null, "Name for current highlight: ", "Name Highlight", JOptionPane.PLAIN_MESSAGE, null, null, ""); if (answer == null) return null; answer = answer.trim (); if (answer.length() == 0) return null; return answer; // try { // return getDocument ().getLabeling ().lookup (answer); // } catch (Labeling.LabelNotFoundException e) { // return answer; // } catch (Labeling.LabelAmbiguousException e) { // return (String) // JOptionPane.showInputDialog (null, // "Several labels match that name.\n" // + "Please select the one you want.", // "Choose Label", // JOptionPane.PLAIN_MESSAGE, // null, // e.getChoices (), // null); // } } //////////////////// //////////////////// Selecting named region sets //////////////////// /** * Action invoked when user clicks on the tree display. * Clears the selection if the mouse isn't pointing at a name. */ public MouseListener treeMouseListener = new MouseAdapter () { public void mousePressed (MouseEvent e) { tree.expandNodeAtLocation (e.getX(), e.getY()); String label = tree.getLabelAtLocation (e.getX(), e.getY()); if (label != null) { Log.println ("find name " + label); setRegions (label, null); } } // public void mouseClicked (MouseEvent e) { // TreePath path = tree.getPathForLocation(e.getX(), e.getY()); // if(path != null && e.getClickCount() == 2) // putNameInPattern ((Label)path.getPathComponent (path.getPathCount ()-1)); // } }; /** * Listener invoked when user shift-clicks on the browser pane. * Adds a region to the highlighted region set. */ MouseListener shiftClickListener = new MouseAdapter () { public void mousePressed (MouseEvent evt) { if (SwingUtilities.isLeftMouseButton (evt)) { RegionHighlighter highlighter = (RegionHighlighter) activePane.getHighlighter (); Point pt = new Point (evt.getX (), evt.getY ()); RegionHighlighter.Handle h = highlighter.handleAtPoint (pt); if (h != null) { Region r = h.getRegion (); // prepare to move handle of highlighted region Interval i = (Interval) r.crispen (); shiftDragMark = h.isStart () ? i.end : i.start; highlighter.setFeedback (i); setRegions (null, highlightedRegions.copy () .delete (r)); Log.println ("adjust handle of " + r); } else { // prepare to add new region to highlight. // start dragging it out Interval r = activePane.convertPointToRegion (pt); shiftDragMark = r.start; highlighter.setFeedback (r); setRegions (highlightedName, highlightedRegions); } } } public void mouseReleased (MouseEvent evt) { if (shiftDragMark != -1) { RegionHighlighter highlighter = (RegionHighlighter) activePane.getHighlighter (); Interval r = highlighter.getFeedback (); highlighter.setFeedback (null); if (r != null && r.start != r.end) { Log.println ("highlight " + r); if (highlightedRegions == null) setRegions (null, r); else { setRegions (null, highlightedRegions.copy () .insert (r)); } } shiftDragMark = -1; } } }; MouseMotionListener shiftDragListener = new MouseMotionAdapter () { public void mouseDragged (MouseEvent evt) { if (shiftDragMark != -1) { Point pt = new Point (evt.getX (), evt.getY ()); Interval r = activePane.convertPointToRegion (pt); Interval s = new Interval (Math.min (shiftDragMark, r.start), Math.max (shiftDragMark, r.start)); ((RegionHighlighter) activePane.getHighlighter ()) .setFeedback (s); } } }; /** * Action invoked when user right-clicks on the browser pane. * Pops up a menu showing region set names that coincide with * the current selection. */ MouseListener rightClickListener = new MouseAdapter () { public void mousePressed (MouseEvent evt) { if (SwingUtilities.isRightMouseButton (evt)) showPopupMenu ((Component)evt.getSource (), evt.getX (), evt.getY ()); } }; protected void showPopupMenu (Component source, int x, int y) { JPopupMenu menu = new JPopupMenu (); // menu.add (nameAction); // menu.add (nameAsAction); // menu.add (unnameAction); // menu.addSeparator (); // menu.add (possibleTextConstraints (activePane.getSelectedRegion ())); // menu.addSeparator (); // menu.add (copyAction); clickedRegion = activePane.regionAtPoint (new Point (x, y)); removeHighlightAction.setEnabled (clickedRegion != null); menu.add (removeHighlightAction); menu.add (removeAllHighlightsAction); menu.show (source, x, y); } JMenu possibleTextConstraints (Region selection) { Labeling labels = getDocument ().getLabeling (); // Look for any region containing the selection. Region filter = (Region)selection.contains (); // Fuzzify filter. labels.get (SwingDocument.BACKGROUND).fuzzifyBoundingBox (filter); // Scan all the names in the label tree looking for region sets // that intersect filter. Vector userNames = new Vector (); Region any = (Region)labels.get (SwingDocument.ANY); for (Enumeration e = labels.names (); e.hasMoreElements (); ) { String name = e.nextElement ().toString (); Region r = firstMatchingRegion (name, filter); if (r != null && !r.equals (any) && !name.startsWith (SwingDocument.SYSTEM)) userNames.addElement (new NameItem (name, r)); } // FIX: put back sorting rules for (top-level names first, // then leaf names, then generalizations) // Create a popup menu with the names on it and show it JMenu menu = new JMenu ("Text Constraints"); addItems (menu, userNames); return menu; } void addItems (JMenu menu, Vector names) { for (Enumeration e = names.elements (); e.hasMoreElements (); ) { Object o = e.nextElement (); if (o instanceof JSeparator) menu.addSeparator (); else menu.add ((JMenuItem) o); } } Region firstMatchingRegion (String name, Region r) { Labeling labels = getDocument ().getLabeling (); RegionSet s = labels.get (name); if (s == null) return null; RegionEnumeration e = s.regions (r); Region m = e.first (); if (m == null || m.equals (labels.get (lapis.Document.ANY))) return null; // don't return useless names return m; } class NameItem extends JMenuItem { String name; Region region; public NameItem (String name, Region region) { super (name.toString ()); this.name = name; this.region = region; } /** * When a menu item is selected, highlight the corresponding region * set in the document (and set the selection to the corresponding region * that includes it). */ public void menuSelectionChanged(boolean isIncluded) { super.menuSelectionChanged (isIncluded); if (isIncluded) { setRegions (null, region); } else { setRegions (null, null); } } public void fireActionPerformed (ActionEvent evt) { super.fireActionPerformed (evt); //putNameInPattern (name); setRegions (name, null); } } /** * Handle change in user's selection. Sets the named region SELECTION to the current * selection. */ public CaretListener caretListener = new CaretListener () { public void caretUpdate(CaretEvent e) { SwingDocument doc = getDocument (); if (doc == null) return; Region sel = activePane.getSelectedRegion (); //System.err.println ("selection changed to " + sel); doc.getLabeling ().put (SwingDocument.SELECTION, sel); } }; //////////////////// //////////////////// Scripting //////////////////// /** * Action invoked when user clicks on Script Editor menu item. * Pops up a new TCLFileEditor window. */ public Action scriptEditorAction = new AcceleratedAction ("Script Editor") { public void actionPerformed (ActionEvent evt) { showTclEditor (); } }; public void showTclEditor () { if (tclEditor == null) { tclEditor = new TCLFileEditor (Browser.this); tclEditor.show (); PopupDialog.centerWindow (tclEditor, this); } else tclEditor.show (); } /** * Action invoked by Demonstrate command. */ public Action demonstrateAction = new AcceleratedAction ("&Demonstrate", 'D', KeyEvent.CTRL_MASK) { public void actionPerformed (ActionEvent evt) { Demonstrator d = new Demonstrator (Browser.this); d.show (); Point p = getLocation (); p.translate (50, 50); d.setLocation (p); } }; /** * Action invoked by History to Script command. */ public Action historyScriptAction = new AcceleratedAction ("Convert &History to Script", 'H', KeyEvent.CTRL_MASK) { public void actionPerformed (ActionEvent evt) { popupScriptEditor (convertHistoryToScript ()); } }; public String convertHistoryToScript () { History history = getHistory (); String script = ""; for (Enumeration e = history.elements (); e.hasMoreElements (); ) script += e.nextElement () + "\n"; return script; } public void popupScriptEditor (String contents) { showTclEditor (); if (tclEditor.okToClear ()) { tclEditor.setText (contents); tclEditor.setFilename (null); } } //////////////////// //////////////////// Text-processing tools //////////////////// public void addTool (Tool tool) { String description = Toolbox.getToolDescription (tool); String name; if (description.endsWith (".tcl")) // description is a filename; use the basename (deleting // directory and .tcl extension) name = URLUtil.getBasename (URLUtil.HrefToURL (description)); else { // description is a Java class name; use the base name // (deleting the package) int lastPeriod = description.lastIndexOf ('.'); if (lastPeriod > -1) name = description.substring (lastPeriod+1); else name = description; } Action action = new LoadedToolAction (tool, name); toolMenu.add (action); toolbar.add (action); factory.getInterpreter ().registerTool (name, tool); } class BrowserArguments extends Arguments { String command; public BrowserArguments () { super (Browser.this.factory); } } abstract class ToolAction extends AcceleratedAction { Tool tool; BrowserArguments args; boolean usesHighlight; public ToolAction (Tool tool, String label, boolean usesHighlight) { super (label); this.tool = tool; this.usesHighlight = usesHighlight; } public abstract BrowserArguments makeArguments (); public void actionPerformed (ActionEvent event) { stop (); if (usesHighlight && getRegions () == null) { getToolkit ().beep (); return; } args = makeArguments (); if (args == null) return; runStoppableActivity (new RunnableWithExceptions () { public void run () throws Exception { lapis.Document result = tool.invoke (args); if (! (result instanceof StatusWriter)) { if (args.command != null) result.putProperty (SwingDocument.CommandProperty, args.command); setDocument (result); } } }); } } class LoadedToolAction extends ToolAction { public LoadedToolAction (Tool tool, String name) { super (tool, name, false); } public BrowserArguments makeArguments () { BrowserArguments args = (BrowserArguments) new BrowserArguments () .add ("doc", getDocument ()); args.command = getValue (NAME).toString (); return args; } } public static String tclQuote (String s) { if (Str.indexOfAnyChar (s, " \r\n{}\"\'\\") == -1) return s; // no special characters else return "{" + s + "}"; } /** * Action invoked by Keep command. Keeps highlighted regions * to create a new document. */ public Action keepAction = new ToolAction (new lapis.tools.Keep (), "&Keep", true) { public BrowserArguments makeArguments () { BrowserArguments args = (BrowserArguments) new BrowserArguments () .add ("query", highlightedRegions) .add ("outof", (highlightedPattern != null) ? (Object)TC.make (highlightedPattern).getObjectPattern () : (Object)highlightedRegions) .add ("doc", getDocument ()) ; args.command = "keep " + tclQuote (highlightedPattern); return args; } }; /** * Action invoked by Delete command. Deletes out highlighted regions * to create a new document. */ public Action deleteAction = new ToolAction (new lapis.tools.Delete (), "&Delete", true) { public BrowserArguments makeArguments () { BrowserArguments args = (BrowserArguments) new BrowserArguments () .add ("query", highlightedRegions) .add ("doc", getDocument ()) ; args.command = "delete " + tclQuote (highlightedPattern); return args; } }; /** * Action invoked by Sort command. Sorts highlighted regions * to create a new document, and displays that. */ public Action sortAction = new ToolAction (new lapis.tools.Sort (), "&Sort", true) { public BrowserArguments makeArguments () { SortDialog dialog = new SortDialog (); dialog.show (); return dialog.args; } }; class SortDialog extends OkCancelDialog { ButtonGroup keyGroup; JRadioButton useEntireRecord; // use entire record as sort key JRadioButton usePattern; // use specified pattern as sort key JTextField keyPattern; JComboBox order; // alphabetic, numeric, etc. JComboBox direction; // ascending or descending BrowserArguments args; // null until created by ok() public SortDialog () { super (Browser.this, "Sort"); Layout layout = Layout.gridbag (getControlsPane ()) .setAlignment (Layout.NORTHWEST); layout .add (new JLabel ("Sort Key: "), Layout.FIXED_SIZE) .add (useEntireRecord = new JRadioButton ("Full record")) .nextRow () .nextColumn () .add (usePattern = new JRadioButton ("Part of record matching: ")) .nextRow () .nextColumn () .add (keyPattern = new JTextField ()) .nextRow (); keyGroup = new ButtonGroup (); keyGroup.add (useEntireRecord); keyGroup.add (usePattern); useEntireRecord.setSelected (true); String yourLanguage = java.util.Locale.getDefault ().getDisplayLanguage (); if (yourLanguage.equals ("")) yourLanguage = "Dictionary"; layout .add (new JLabel ("Order: "), Layout.FIXED_SIZE) .add (order = new JComboBox (new String[] { yourLanguage, "Numeric", "ASCII", "Random" }), Layout.FIXED_SIZE) .nextRow (); order.setEditable (false); layout .add (new JLabel ("Direction: "), Layout.FIXED_SIZE) .add (direction = new JComboBox (new String[] { "Increasing", "Decreasing" }), Layout.FIXED_SIZE) .nextRow (); direction.setEditable (false); pack (); } public void ok () { try { // Create arguments args = (BrowserArguments)new BrowserArguments () .add ("query", highlightedRegions) .add ("doc", getDocument ()) ; String tclCommand = "sort " + tclQuote (highlightedPattern); if (usePattern.isSelected ()) { TC keys = Browser.makeTCFromTextComponent (keyPattern); args.add ("by", keys); tclCommand += " -by " + tclQuote (keyPattern.getText ()); } boolean reverse = (direction.getSelectedIndex () == 1); switch (order.getSelectedIndex ()) { case 0: // natural args.addName ("order"); if (reverse) args.addValue ("reverse"); args.addValue ("dictionary"); tclCommand += " -order " + (reverse ? "reverse " : "") + "dictionary"; break; case 1: // numeric args.addName ("order"); if (reverse) args.addValue ("reverse"); args.addValue ("numeric"); tclCommand += " -order " + (reverse ? "reverse " : "") + "numeric"; break; case 2: // ASCII args.addName ("order"); if (reverse) args.addValue ("reverse"); args.addValue ("ascii"); tclCommand += " -order " + (reverse ? "reverse " : "") + "ascii"; break; case 3: // RANDOM args.addName ("order"); args.addValue ("random"); tclCommand += " -order random"; break; } args.command = tclCommand; super.ok (); } catch (TCParseException e) { FeedbackForm.showMessageDialog (Browser.this, e.getMessage (), "Parse Error", JOptionPane.ERROR_MESSAGE); args = null; } } } /** * Action invoked by Replace command. Replaces regions * to create a new document, and displays that. */ public Action replaceAction = new ToolAction (new lapis.tools.Replace (), "&Replace", true) { public BrowserArguments makeArguments () { ReplaceDialog dialog = new ReplaceDialog (); dialog.show (); return dialog.args; } }; class ReplaceDialog extends OkCancelDialog { JTextArea template; BrowserArguments args; // null until created by ok() public ReplaceDialog () { super (Browser.this, "Replace"); Layout.gridbag (getControlsPane ()) .setAlignment (Layout.WEST) .add (new JLabel ("Replace With: "), Layout.FIXED_SIZE) .nextRow () .add (template = new JTextArea (5, 40)); pack (); } public void ok () { try { // Configure arguments args = (BrowserArguments) new BrowserArguments () .add ("query", highlightedRegions) .add ("doc", getDocument ()) ; String tclCommand = "replace " + tclQuote (highlightedPattern); try { String tmplt = template.getText (); args.add ("replace", lapis.tools.Template.makeFromString (tmplt)); tclCommand += " " + tclQuote (tmplt); } catch (TCParseException e) { // Select the error, then re-throw the exception selectParseError (template, e); throw e; } args.command = tclCommand; super.ok (); } catch (TCParseException e) { FeedbackForm.showMessageDialog (Browser.this, e.getMessage (), "Parse Error", JOptionPane.ERROR_MESSAGE); args = null; } } } /** * Action invoked by Extract command. Extracts regions * to create a new document, and displays that. */ public Action extractAction = new ToolAction (new lapis.tools.Extract (), "&Extract", true) { public BrowserArguments makeArguments () { ExtractDialog dialog = new ExtractDialog (); dialog.show (); return dialog.args; } }; class ExtractDialog extends OkCancelDialog { JTextArea template; JComboBox view; // HTML or text BrowserArguments args; // null until created by ok() public ExtractDialog () { super (Browser.this, "Extract"); Layout.gridbag (getControlsPane ()) .setAlignment (Layout.WEST) .add (new JLabel ("View As: "), Layout.FIXED_SIZE) .add (view = new JComboBox (), Layout.FIXED_SIZE); view.addItem (new ViewType ("Text", "text/plain")); view.addItem (new ViewType ("HTML", "text/html")); setViewContentType (view, ((ViewType)Browser.this.view.getSelectedItem ()).contentType); pack (); } public void ok () { // try { ViewType vt = (ViewType)view.getSelectedItem (); // Configure arguments args = (BrowserArguments) new BrowserArguments () .add ("query", highlightedRegions) .add ("doc", getDocument ()) .add ("as", vt.contentType) ; args.command = "extract " + tclQuote (highlightedPattern) + " -as " + vt.uiName; if ("text/plain".equals (vt.contentType)) { args.add ("endswith", "\n"); args.command += " -endswith \\n"; } else { args.add ("endswith", "<br>"); args.command += " -endswith <br>"; } // try { // tool.template = lapis.tools.Template.makeFromString (template.getText (), warningListener); // } catch (TCParseException e) { // // Select the error, then re-throw the exception // selectParseError (template, e); // throw e; // } super.ok (); // } catch (TCParseException e) { // FeedbackForm.showMessageDialog (Browser.this, // e.getMessage (), // "Parse Error", // JOptionPane.ERROR_MESSAGE); // tool = null; // } } } /** * Action invoked by Sum command. Sums the highlighted regions and displays * the answer in the status bar. */ public Action sumAction = new ToolAction (new lapis.tools.Calc (), "Su&m", true) { public BrowserArguments makeArguments () { StatusWriter out = new StatusWriter (Browser.this); out.print ("Sum is "); return (BrowserArguments) new BrowserArguments () .add ("query", highlightedRegions) .add ("doc", getDocument ()) .add ("output", out) .add ("function", new lapis.tools.Calc.Sum ()) ; } }; /** * Action invoked by Average command. Averages the highlighted regions and displays * the answer in the status bar. */ public Action averageAction = new ToolAction (new lapis.tools.Calc (), "&Average", true) { public BrowserArguments makeArguments () { StatusWriter out = new StatusWriter (Browser.this); out.print ("Average is "); return (BrowserArguments) new BrowserArguments () .add ("query", highlightedRegions) .add ("doc", getDocument ()) .add ("output", out) .add ("function", new lapis.tools.Calc.Average ()) ; } }; //////////////////// //////////////////// MED: New Menu item for CIS enhancements //////////////////// /** * Action invoked when user selects CIS/Focused Crawl command. * Pops up a dialog box for keyword and URL files */ public Action focCrawlAction = new AcceleratedAction ("&Focused Crawl", 'F', KeyEvent.CTRL_MASK) { public void actionPerformed (ActionEvent evt) { FocCrawlDialog dialog = new FocCrawlDialog(Browser.this); dialog.show (); } }; //////////////////// //////////////////// Tool interface for Browser itself //////////////////// public Browser make () { return new Browser (); } public lapis.Document invoke (Arguments args) throws Exception { boolean startNewBrowser = false; Vector commands = new Vector (); args.setUsage ( "Usage: Browser [options] [file/URL]\n" + " file/URL Go to file/URL\n" + "\n" + "Options:\n" + " -new Create a new browser\n" + " -help Display this message\n" ); while (args.hasMoreElements ()) { String name = args.nextName (); if ("new".equals (name)) startNewBrowser = true; else if ("log".equals (name)) Log.open (args.nextString ()); else if (name == null) commands.addElement (args.nextString ()); else args.consume (name); } Browser b = (startNewBrowser && isShowing ()) ? make () : this; b.show (); b.toFront (); Enumeration cmds = commands.elements (); if (cmds.hasMoreElements ()) { String s = cmds.nextElement ().toString (); if (s.trim ().length () > 0) b.eval (s); while (cmds.hasMoreElements ()) { Point p = b.getLocation (); b = new Browser (); b.show (); p.translate (50, 50); b.setLocation (p); s = cmds.nextElement ().toString (); if (s.trim ().length () > 0) b.eval (s); } } return null; } }