001    /*
002     * LAPIS lightweight structured text processing system
003     *
004     * Copyright (C) 1998-2002 Carnegie Mellon University,
005     * Copyright (C) 2003 Massachusetts Institute of Technology.
006     * All rights reserved.
007     *
008     * This library is free software; you can redistribute it
009     * and/or modify it under the terms of the GNU General
010     * Public License as published by the Free Software
011     * Foundation, version 2.
012     *
013     * LAPIS homepage: http://graphics.lcs.mit.edu/lapis/
014     */
015    
016    package lapis.swing;
017    
018    import lapis.*;
019    import lapis.tc.*;
020    import java.awt.event.*;
021    import java.io.*;
022    import javax.swing.*;
023    import lapisx.swing.*;
024    
025    public abstract class ToolAction extends AcceleratedAction {
026        public static lapisx.util.Debug debug = lapisx.util.Debug.QUIET; 
027    
028        Browser browser;
029        Tool tool;
030        BrowserArguments args;
031        boolean usesSelection;
032    
033        public ToolAction (Browser browser, Tool tool, String label, boolean usesSelection) {
034            super (label);
035            this.browser = browser;
036            this.tool = tool;
037            this.usesSelection = usesSelection;
038        }
039    
040        public class BrowserArguments extends Arguments {
041            String command;
042    
043            public BrowserArguments () {
044                super (browser.getInterpreter ());
045            }
046        }
047    
048        public abstract BrowserArguments makeArguments ();
049    
050        public NamedRegionSet getSelection () {
051            return browser.getSelection ();
052        }
053    
054        public String quote (TC pat) {
055            return pat != null
056                ? quote (pat.getExpression ())
057                : "selection";
058        }
059    
060        public String quote (String s) {
061            if (s == null)
062                return "selection";
063    
064            String t = browser.getInterpreter ().quote (s);
065            debug.println ("quoted '" + s + "' to get '" + t + "'");
066            return t;
067        }
068    
069    
070        public void actionPerformed (ActionEvent event) {
071            browser.stop ();
072    
073            if (usesSelection && getSelection ().isEmpty ()) {
074                browser.getToolkit ().beep ();
075                return;
076            }
077    
078            args = makeArguments ();
079            if (args == null)
080                return;
081    
082            // Set the interpreter's input document
083            browser.getInterpreter ().setVar (Interpreter.DOCUMENT_VAR, 
084                                              browser.getDocument ());
085    
086            browser.run (new RunnableWithExceptions () {
087                    public void run () throws Exception {
088                        final Document result = tool.invoke (args);
089                        if (result instanceof StatusWriter) {
090                            ((StatusWriter) result).close ();
091                        } else if (result != null) {
092                            if (args.command != null) {
093                                if (result.getProperty (SwingDocument.CommandProperty) == null)
094                                    result.putProperty (SwingDocument.CommandProperty, 
095                                                        args.command);
096                            }
097    
098                            SwingUtilities.invokeLater (new Runnable () {
099                                    public void run () {
100                                        if (args.command != null)
101                                            browser.setCommand (args.command, true);
102                                        browser.setDocument (result);
103                                        browser.getActivePane ().requestFocus ();
104                                    }
105                                });
106                        }
107                    }
108                });
109        }
110    
111        static class ToolboxAction extends ToolAction {
112            public ToolboxAction (Browser browser, Toolbox.Info info) {
113                super (browser, info.getTool (), info.getName (), false);
114    
115                String tooltip = info.getDescription ();
116                if (tooltip != null)
117                    putValue (SHORT_DESCRIPTION, tooltip);
118    
119                File iconFile = info.getIcon ();
120                if (iconFile != null)
121                    putValue (SMALL_ICON, new ImageIcon (iconFile.toString ()));
122            }
123            
124            public BrowserArguments makeArguments () {
125                return new BrowserArguments ();
126            }
127        }
128    
129    
130        static class ToolboxChange implements Toolbox.ToolBoxListener { 
131            Browser browser;
132    
133            public ToolboxChange (Browser browser) {
134                this.browser = browser;
135            }
136    
137            public void toolAdded(Toolbox toolBox, Toolbox.Info info){
138                debug.println("Calling " + info.getName() + " to toolbar.");
139                browser.addToToolBar(info);
140                
141            }
142            
143            public void toolChanged(Toolbox toolBox, Toolbox.Info info){
144                //      browser.removeFromToolBar(info);
145                //      browser.addToToolBar(info);
146                browser.changeInTool(info);
147                
148            }
149            public void toolRemoved(Toolbox toolBox, Toolbox.Info info){
150                debug.println("Calling " + info.getName() + " to toolbar.");
151                browser.removeFromTools(info);
152            }
153        }
154    
155    
156    
157        /**
158         * Action for Keep tool.
159         */
160        public static class Keep extends ToolAction {
161            public Keep (Browser browser) {
162                super (browser, new lapis.tools.Keep (), "&Keep", true);
163            }
164    
165            public BrowserArguments makeArguments () {
166                NamedRegionSet sel = getSelection ();
167                BrowserArguments args = (BrowserArguments) new BrowserArguments ()
168                    .add ("query", sel)
169                    .add ("outof", sel.getPattern ().getUniversePattern ())
170                    ;
171                args.command = "keep " + quote (sel.getPattern ());
172                return args;
173            }
174        }
175    
176    
177        /**
178         * Action for Sort tool.  Sorts selection
179         * to create a new document, and displays that.
180         */
181        public static class Sort extends ToolAction {
182            public Sort (Browser browser) {
183                super (browser, new lapis.tools.Sort (), "&Sort...", true);
184            }
185    
186            public BrowserArguments makeArguments () {
187                SortDialog dialog = new SortDialog ();
188                dialog.show ();
189                return dialog.args;
190            }
191    
192            class SortDialog extends OkCancelDialog {
193                ButtonGroup keyGroup;
194                JRadioButton useEntireRecord;  // use entire record as sort key
195                JRadioButton usePattern;       // use specified pattern as sort key
196                TCEditor keyPattern;
197            
198                JComboBox order;            // alphabetic, numeric, etc.        
199                BrowserArguments args;             // null until created by ok()
200            
201                public SortDialog () {
202                    super (browser, "Sort");
203                
204                    Layout layout = Layout.gridbag (getControlsPane ())
205                        .setAlignment (Layout.NORTHWEST)
206                        .setSize (Layout.FIXED_SIZE);
207    
208                    layout
209                        .add (new JLabel ("Sort Key: "))
210                        .add (useEntireRecord = new JRadioButton ("Full record"))
211                        .nextRow ()
212                        .nextColumn ()
213                        .add (usePattern = new JRadioButton ("Part of record matching: "))
214                        .nextRow ()
215                        .nextColumn ()
216                        .add (keyPattern = new TCEditor (true), Layout.ANY_SIZE)
217                        .nextRow ();
218    
219                    keyGroup = new ButtonGroup ();
220                    keyGroup.add (useEntireRecord);
221                    keyGroup.add (usePattern);
222                    useEntireRecord.setSelected (true);
223                    keyPattern.setEnabled (false);
224    
225                    keyPattern.addMouseListener (new MouseAdapter () {
226                            public void mousePressed (MouseEvent event) {
227                                usePattern.setSelected (true);
228                                keyPattern.setEnabled (true);
229                                keyPattern.requestFocus ();
230                            }
231                        });
232                    ActionListener enabler = new ActionListener () {
233                            public void actionPerformed (ActionEvent event) {
234                                boolean usingPattern = usePattern.isSelected ();
235                                keyPattern.setEnabled (usingPattern);
236                                if (usingPattern)
237                                    keyPattern.requestFocus ();
238                            }
239                        };
240                    useEntireRecord.addActionListener (enabler);
241                    usePattern.addActionListener (enabler);
242    
243                    String yourLanguage = 
244                        java.util.Locale.getDefault ().getDisplayLanguage ();
245                    if (yourLanguage.equals (""))
246                        yourLanguage = "Dictionary";
247                    layout
248                        .add (new JLabel ("Order: "))
249                        .add (order = new JComboBox (new String[] {
250                            yourLanguage + " (a b c ...)",
251                            "Reverse " + yourLanguage + " (z y x ...)", 
252                            "Numeric (1 2 3 ...)", 
253                            "Reverse Numeric (9 8 7 ...)",
254                            "Unicode (A B C ... a b c ...)", 
255                            "Reverse Unicode (z y x ... Z Y X ...)",
256                            "Random" }))
257                        .nextRow ();
258                    order.setEditable (false);
259    
260                    SortDialog.this.pack ();
261                }
262    
263                public void ok () {
264                    try {
265                        // Create arguments
266                        NamedRegionSet sel = getSelection ();
267                        args = (BrowserArguments)new BrowserArguments ()
268                            .add ("query", sel)
269                            ;
270                        args.command = "sort " + quote (sel.getPattern ());
271    
272                        if (usePattern.isSelected ()) {
273                            TC keys = PatternPane.makeTCFromTextComponent (keyPattern,
274                                                                       true);
275                            args.add ("by", keys);
276                            args.command += " -by " + quote (keyPattern.getText ());
277                        }
278    
279                        boolean reversed;
280                        String orderCode;
281                        args.addName ("order");
282                        switch (order.getSelectedIndex ()) {
283                        case 0:
284                            reversed = false;
285                            orderCode = "dictionary";
286                            break;
287                        case 1:
288                            reversed = true;
289                            orderCode = "dictionary";
290                            break;
291                        case 2:
292                            reversed = false;
293                            orderCode = "numeric";
294                            break;
295                        case 3:
296                            reversed = true;
297                            orderCode = "numeric";
298                            break;
299                        case 4:
300                            reversed = false;
301                            orderCode = "unicode";
302                            break;
303                        case 5:
304                            reversed = true;
305                            orderCode = "unicode";
306                            break;
307                        case 6:
308                            reversed = false;
309                            orderCode = "random";
310                            break;
311                        default:
312                            throw new RuntimeException ("illegal sort order: " + order.getSelectedIndex ());
313                        }
314    
315                        if (reversed)
316                            args.addValue ("reverse");
317                        args.addValue (orderCode);
318    
319                        if (! ("dictionary".equals (orderCode) && !reversed))
320                            args.command += " -order " + (reversed ? "reverse " : "") + orderCode;
321                    
322    
323                        super.ok ();
324                    } catch (TCParseException e) {
325                        FeedbackForm.showMessageDialog (browser, 
326                                                        e.getMessage (), 
327                                                        "Parse Error",
328                                                        JOptionPane.ERROR_MESSAGE);
329                        args = null;
330                    }
331                }
332            }
333        }
334    
335    
336        /**
337         * Action for Replace tool.
338         */
339        public static class Replace extends ToolAction {
340            public Replace (Browser browser) {
341                super (browser, new lapis.tools.Replace (), "&Replace...", true);
342            }
343    
344            public BrowserArguments makeArguments () {
345                ReplaceDialog dialog = new ReplaceDialog ();
346                dialog.show ();
347                return dialog.args;
348            }
349    
350            class ReplaceDialog extends OkCancelDialog {
351    
352                JTextArea template;
353                JCheckBox isTemplate;
354                BrowserArguments args;  // null until created by ok()
355            
356                public ReplaceDialog () {
357                    super (browser, "Replace");
358                
359                    Layout.gridbag (getControlsPane ())
360                        .setAlignment (Layout.WEST)
361                        .add (new JLabel ("Replace Each Selection With: "), Layout.FIXED_SIZE)
362                        .nextRow ()
363                        .add (template = new JTextArea (5, 40))
364                        .nextRow ()
365                        .add (isTemplate = 
366                              new JCheckBox ("Substitute curly braces", false))
367                        .nextRow ()
368                        ;
369                    ReplaceDialog.this.pack ();
370                }
371            
372                public void ok () {
373                    try {
374                        // Configure arguments
375                        NamedRegionSet sel = getSelection ();
376                        args = (BrowserArguments) new BrowserArguments ()
377                            .add ("query", sel)
378                            ;
379                        String tclCommand = "replace " + quote (sel.getPattern ());
380    
381                        try {
382                            String tmplt = template.getText ();
383                            args.add ("replace",
384                                      lapis.tools.Template.makeFromString (tmplt));
385                            tclCommand += " " + quote (tmplt);
386                        } catch (TCParseException e) {
387                            // Select the error, then re-throw the exception
388                            TCEditor.selectParseError (template, e);
389                            throw e;
390                        }
391    
392                        args.command = tclCommand;
393    
394                        super.ok ();
395                    } catch (TCParseException e) {
396                        FeedbackForm.showMessageDialog (browser, 
397                                                        e.getMessage (), 
398                                                        "Parse Error",
399                                                        JOptionPane.ERROR_MESSAGE);
400                        args = null;
401                    }
402                }
403            }
404        }
405    
406    
407    
408        /**
409         * Action for Delete tool (called "Omit" in UI).
410         */
411        public static class Omit extends ToolAction {
412            public Omit (Browser browser) {
413                super (browser, new lapis.tools.Delete (), "&Omit", true);
414            }
415    
416            public BrowserArguments makeArguments () {
417                NamedRegionSet sel = getSelection ();
418                BrowserArguments args = (BrowserArguments) new BrowserArguments ()
419                    .add ("query", sel)
420                    ;
421                args.command = "omit " + quote (sel.getPattern ());
422                return args;
423            }
424        }
425    
426    
427        /**
428         * Action for Extract tool.
429         */
430        public static class Extract extends ToolAction {
431            public Extract (Browser browser) {
432                super (browser, new lapis.tools.Extract (), "&Extract", true);
433            }
434    
435            public BrowserArguments makeArguments () {
436                NamedRegionSet sel = getSelection ();
437                BrowserArguments args =
438                    (BrowserArguments) new BrowserArguments ()
439                    .add ("query", sel)
440                    ;
441                args.command = "extract " + quote (sel.getPattern ());
442                return args;
443            }
444        }
445    
446    
447        /**
448         * Action for Calc tool.
449         */
450        public static class Calc extends ToolAction {
451            public Calc (Browser browser) {
452                super (browser, new lapis.tools.Calc (), "&Calc", true);
453            }
454    
455            public BrowserArguments makeArguments () {
456                NamedRegionSet sel = getSelection ();
457                BrowserArguments args = (BrowserArguments) new BrowserArguments ()
458                    .add ("query", sel)
459                    ;
460                args.command = "calc " + quote (sel.getPattern ());
461                return args;
462            }
463        }
464    
465    }
466