PageRenderTime 56ms CodeModel.GetById 39ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms


HTML | 294 lines | 272 code | 22 blank | 0 comment | 0 complexity | 8ebf5063dcc3e53663d7e2c25d86fd81 MD5 | raw file
  1<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Getting Input for a Macro</title><meta name="generator" content="DocBook XSL Stylesheets V1.73.2"><link rel="start" href="index.html" title="jEdit 4.3 User's Guide"><link rel="up" href="macro-tips.html" title="Chapter 15. Macro Tips and Techniques"><link rel="prev" href="macro-tips.html" title="Chapter 15. Macro Tips and Techniques"><link rel="next" href="startup-scripts.html" title="Startup Scripts"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Getting Input for a Macro</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="macro-tips.html">Prev</a> </td><th width="60%" align="center">Chapter 15. Macro Tips and Techniques</th><td width="20%" align="right"> <a accesskey="n" href="startup-scripts.html">Next</a></td></tr></table><hr></div><div class="sect1" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="macro-tips-input"></a>Getting Input for a Macro</h2></div></div></div><p>The dialog-based macro discussed in <a class="xref" href="dialog-macro.html" title="Chapter 14. A Dialog-Based Macro">Chapter 14, <i>A Dialog-Based Macro</i></a> reflects a conventional approach to obtaining
  2        input in a Java program. Nevertheless, it can be too lengthy or tedious
  3        for someone trying to write a macro quickly. Not every macro needs a
  4        user interface specified in such detail; some macros require only a
  5        single keystroke or no input at all. In this section we outline some
  6        other techniques for obtaining input that will help you write macros
  7        quickly.</p><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="macro-tips-input-single-line"></a>Getting a Single Line of Text</h3></div></div></div><p>As mentioned earlier in <a class="xref" href="helpful-methods.html" title="Helpful Methods in the Macros Class">the section called &#8220;Helpful Methods in the Macros Class&#8221;</a>,
  8            the method <code class="function">Macros.input()</code> offers a convenient
  9            way to obtain a single line of text input. Here is an example that
 10            inserts a pair of HTML markup tags specified by the user.</p><div class="informalexample"><pre class="programlisting">// Insert_Tag.bsh
 12void insertTag()
 14    caret = textArea.getCaretPosition();
 15    tag = Macros.input(view, &#8220;<span class="quote">Enter name of tag:</span>&#8221;);
 16    if( tag == null || tag.length() == 0) return;
 17    text = textArea.getSelectedText();
 18    if(text == null) text = &#8220;<span class="quote"></span>&#8221;;
 19    sb = new StringBuffer();
 20    sb.append(&#8220;<span class="quote">&lt;</span>&#8221;).append(tag).append(&#8220;<span class="quote">&gt;</span>&#8221;);
 21    sb.append(text);
 22    sb.append(&#8220;<span class="quote">&lt;/</span>&#8221;).append(tag).append(&#8220;<span class="quote">&gt;</span>&#8221;);
 23    textArea.setSelectedText(sb.toString());
 24    if(text.length() == 0)
 25        textArea.setCaretPosition(caret + tag.length() + 2);
 30// end Insert_Tag.bsh</pre></div><p>Here the call to <code class="function">Macros.input()</code> seeks the
 31            name of the markup tag. This method sets the message box title to a
 32            fixed string, &#8220;<span class="quote">Macro input</span>&#8221;, but the specific message
 33            <span class="guilabel"><strong>Enter name of tag</strong></span> provides all the information
 34            necessary. The return value <code class="varname">tag</code> must be tested to
 35            see if it is null. This would occur if the user presses the
 36            <span class="guilabel"><strong>Cancel</strong></span> button or closes the dialog window
 37            displayed by <code class="function">Macros.input()</code>.</p></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="macro-tips-input-multiple-data"></a>Getting Multiple Data Items</h3></div></div></div><p>If more than one item of input is needed, a succession of
 38            calls to <code class="function">Macros.input()</code> is a possible, but
 39            awkward approach, because it would not be possible to correct early
 40            input after the corresponding message box is dismissed. Where more
 41            is required, but a full dialog layout is either unnecessary or too
 42            much work, the Java method
 43            <code class="function">JOptionPane.showConfirmDialog()</code> is available.
 44            The version to use has the following prototype:</p><div class="itemizedlist"><ul type="disc"><li><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0"><tr><td><code class="funcdef">public static int
 45                            <b class="fsfunc">showConfirmDialog</b>(</code></td><td>Component
 46                             </td><td><var class="pdparam">parentComponent</var>, </td></tr><tr><td> </td><td>Object
 47                             </td><td><var class="pdparam">message</var>, </td></tr><tr><td> </td><td>String
 48                             </td><td><var class="pdparam">title</var>, </td></tr><tr><td> </td><td>int
 49                             </td><td><var class="pdparam">optionType</var>, </td></tr><tr><td> </td><td>int
 50                             </td><td><var class="pdparam">messageType</var><code>)</code>;</td></tr></table></div></li></ul></div><p>The usefulness of this method arises from the fact that the
 51            <code class="varname">message</code> parameter can be an object of any Java
 52            class (since all classes are derived from
 53            <code class="classname">Object</code>), or any array of objects. The
 54            following example shows how this feature can be used.</p><div class="informalexample"><pre class="programlisting">// excerpt from Write_File_Header.bsh
 56title = &#8220;<span class="quote">Write file header</span>&#8221;;
 58currentName = buffer.getName();
 60nameField = new JTextField(currentName);
 61authorField = new JTextField(&#8220;<span class="quote">Your name here</span>&#8221;);
 62descField = new JTextField(&#8220;<span class="quote"></span>&#8221;, 25);
 64namePanel = new JPanel(new GridLayout(1, 2));
 65nameLabel = new JLabel(&#8220;<span class="quote">Name of file:</span>&#8221;, SwingConstants.LEFT);
 66saveField = new JCheckBox(&#8220;<span class="quote">Save file when done</span>&#8221;,
 67    !buffer.isNewFile());
 72message = new Object[9];
 73message[0] = namePanel;
 74message[1] = nameField;
 75message[2] = Box.createVerticalStrut(10);
 76message[3] = &#8220;<span class="quote">Author's name:</span>&#8221;;
 77message[4] = authorField;
 78message[5] = Box.createVerticalStrut(10);
 79message[6] = &#8220;<span class="quote">Enter description:</span>&#8221;;
 80message[7] = descField;
 81message[8] = Box.createVerticalStrut(5);
 83if( JOptionPane.OK_OPTION !=
 84    JOptionPane.showConfirmDialog(view, message, title,
 85        JOptionPane.OK_CANCEL_OPTION,
 86        JOptionPane.QUESTION_MESSAGE))
 87    return null;
 89// *****remainder of macro script omitted*****
 91// end excerpt from Write_File_Header.bsh</pre></div><p>This macro takes several items of user input and produces a
 92            formatted file header at the beginning of the buffer. The full macro
 93            is included in the set of macros installed by jEdit. There are a
 94            number of input features of this excerpt worth noting.</p><div class="itemizedlist"><ul type="disc"><li><p>The macro uses a total of seven visible components.
 95                    Two of them are created behind the scenes by
 96                    <code class="function">showConfirmDialog()</code>, the rest are made
 97                    by the macro. To arrange them, the script creates an array
 98                    of <code class="classname">Object</code> objects and assigns
 99                    components to each location in the array. This translates to
100                    a fixed, top-to-bottom arrangement in the message box
101                    created by <code class="function">showConfirmDialog()</code>.</p></li><li><p>The macro uses <code class="classname">JTextField</code>
102                    objects to obtain most of the input data. The fields
103                    <code class="varname">nameField</code> and
104                    <code class="varname">authorField</code> are created with constructors
105                    that take the initial, default text to be displayed in the
106                    field as a parameter. When the message box is displayed, the
107                    default text will appear and can be altered or deleted by
108                    the user.</p></li><li><p>The text field <code class="varname">descField</code> uses an
109                    empty string for its initial value. The second parameter in
110                    its constructor sets the width of the text field component,
111                    expressed as the number of characters of
112                    &#8220;<span class="quote">average</span>&#8221; width. When
113                    <code class="function">showConfirmDialog()</code> prepares the layout
114                    of the message box, it sets the width wide enough to
115                    accommodate the designated with of
116                    <code class="varname">descField</code>. This technique produces a
117                    message box and input text fields that are wide enough for
118                    your data with one line of code.</p></li><li><p>The displayed message box includes a
119                    <code class="classname">JCheckBox</code> component that determines
120                    whether the buffer will be saved to disk immediately after
121                    the file header is written. To conserve space in the message
122                    box, we want to display the check box to the right of the
123                    label <span class="guilabel"><strong>Name of file:</strong></span>. To do that, we
124                    create a <code class="classname">JPanel</code> object and populate
125                    it with the label and the checkbox in a left-to-right
126                    <code class="classname">GridLayout</code>. The
127                    <code class="classname">JPanel</code> containing the two components
128                    is then added to the beginning of <code class="varname">message</code>
129                    array.</p></li><li><p>The two visible components created by
130                    <code class="function">showConfirmDialog()</code> appear at positions
131                    3 and 6 of the <code class="varname">message</code> array. Only the
132                    text is required; they are rendered as text labels.</p></li><li><p>There are three invisible components created by
133                    <code class="function">showConfirmDialog()</code>. Each of them
134                    involves a call to
135                    <code class="function">Box.createVerticalStrut()</code>. The
136                    <code class="classname">Box</code> class is a sophisticated layout
137                    class that gives the user great flexibility in sizing and
138                    positioning components. Here we use a
139                    <code class="function">static</code> method of the
140                    <code class="classname">Box</code> class that produces a vertical
141                    <em class="glossterm">strut</em>. This is a transparent
142                    component whose width expands to fill its parent component
143                    (in this case, the message box). The single parameter
144                    indicates the height of the strut in pixels. The last call
145                    to <code class="function">createVerticalStrut()</code> separates the
146                    description text field from the <span class="guilabel"><strong>OK</strong></span> and
147                    <span class="guilabel"><strong>Cancel</strong></span> buttons that are automatically
148                    added by <code class="function">showConfirmDialog()</code>.</p></li><li><p>Finally, the call to
149                    <code class="function">showConfirmDialog()</code> uses defined
150                    constants for the option type and the message type. The
151                    constants are the same as those used with the
152                    <code class="function">Macros.confirm()</code> method; see <a class="xref" href="helpful-methods.html" title="Helpful Methods in the Macros Class">the section called &#8220;Helpful Methods in the Macros Class&#8221;</a>. The option type signifies the
153                    use of <span class="guilabel"><strong>OK</strong></span> and
154                    <span class="guilabel"><strong>Cancel</strong></span> buttons. The
155                    <code class="constant">QUERY_MESSAGE</code> message type causes the
156                    message box to display a question mark icon.</p><p>The return value of the method is tested against the
157                    value <code class="constant">OK_OPTION</code>. If the return value is
158                    something else (because the <span class="guilabel"><strong>Cancel</strong></span>
159                    button was pressed or because the message box window was
160                    closed without a button press), a <code class="constant">null</code>
161                    value is returned to a calling function, signaling that the
162                    user canceled macro execution. If the return value is
163                    <code class="constant">OK_OPTION</code>, each of the input components
164                    can yield their contents for further processing by calls to
165                    <code class="function">JTextField.getText()</code> (or, in the case
166                    of the check box,
167                    <code class="function">JCheckBox.isSelected()</code>).</p></li></ul></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="tips-macro-input-combo"></a>Selecting Input From a List</h3></div></div></div><p>Another useful way to get user input for a macro is to use a
168            combo box containing a number of pre-set options. If this is the
169            only input required, one of the versions of
170            <code class="function">showInputDialog()</code> in the
171            <code class="classname">JOptionPane</code> class provides a shortcut. Here
172            is its prototype:</p><div class="itemizedlist"><ul type="disc"><li><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0"><tr><td><code class="funcdef">public static Object
173                            <b class="fsfunc">showInputDialog</b>(</code></td><td>Component
174                             </td><td><var class="pdparam">parentComponent</var>, </td></tr><tr><td> </td><td>Object
175                             </td><td><var class="pdparam">message</var>, </td></tr><tr><td> </td><td>String
176                             </td><td><var class="pdparam">title</var>, </td></tr><tr><td> </td><td>int
177                             </td><td><var class="pdparam">messageType</var>, </td></tr><tr><td> </td><td>Icon  </td><td><var class="pdparam">icon</var>, </td></tr><tr><td> </td><td>Object[]
178                             </td><td><var class="pdparam">selectionValues</var>, </td></tr><tr><td> </td><td>Object
179                             </td><td><var class="pdparam">initialSelectionValue</var><code>)</code>;</td></tr></table></div></li></ul></div><p>This method creates a message box containing a drop-down list
180            of the options specified in the method's parameters, along with
181            <span class="guilabel"><strong>OK</strong></span> and <span class="guilabel"><strong>Cancel</strong></span> buttons.
182            Compared to <code class="function">showConfirmDialog()</code>, this method
183            lacks an <code class="varname">optionType</code> parameter and has three
184            additional parameters: an <code class="varname">icon</code> to display in the
185            dialog (which can be set to <code class="constant">null</code>), an array of
186            <code class="varname">selectionValues</code> objects, and a reference to one
187            of the options as the <code class="varname">initialSelectionValue</code> to be
188            displayed. In addition, instead of returning an
189            <code class="classname">int</code> representing the user's action,
190            <code class="function">showInputDialog()</code> returns the
191            <code class="classname">Object</code> corresponding to the user's selection,
192            or <code class="constant">null</code> if the selection is canceled.</p><p>The following macro fragment illustrates the use of this
193            method.</p><div class="informalexample"><pre class="programlisting">// fragment illustrating use of showInputDialog()
194options = new Object[5];
195options[0] = "JLabel";
196options[1] = "JTextField";
197options[2] = "JCheckBox";
198options[3] = "HistoryTextField";
199options[4} = "-- other --";
201result = JOptionPane.showInputDialog(view,
202    "Choose component class",
203    "Select class for input component",
204    JOptionPane.QUESTION_MESSAGE,
205    null, options, options[0]);</pre></div><p>The return value <code class="varname">result</code> will contain either
206            the <code class="classname">String</code> object representing the selected
207            text item or <code class="constant">null</code> representing no selection.
208            Any further use of this fragment would have to test the value of
209            <code class="varname">result</code> and likely exit from the macro if the
210            value equaled <code class="constant">null</code>.</p><p>A set of options can be similarly placed in a
211            <code class="classname">JComboBox</code> component created as part of a
212            larger dialog or <code class="function">showMessageDialog()</code> layout.
213            Here are some code fragments showing this approach:</p><div class="informalexample"><pre class="programlisting">// fragments from Display_Abbreviations.bsh
214// import statements and other code omitted
216// from main routine, this method call returns an array
217// of Strings representing the names of abbreviation sets
219abbrevSets = getActiveSets();
223// from showAbbrevs() method
225combo = new JComboBox(abbrevSets);
226// set width to uniform size regardless of combobox contents
227Dimension dim = combo.getPreferredSize();
228dim.width = Math.max(dim.width, 120);
230combo.setSelectedItem(STARTING_SET); // defined as "global"
232// end fragments</pre></div></div><div class="sect2" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="macro-tips-single-char"></a>Using a Single Keypress as Input</h3></div></div></div><p>Some macros may choose to emulate the style of character-based
233            text editors such as <span class="application">emacs</span> or
234            <span class="application">vi</span>. They will require only a single
235            keypress as input that would be handled by the macro but not
236            displayed on the screen. If the keypress corresponds to a character
237            value, jEdit can pass that value as a parameter to a BeanShell
238            script.</p><p>The jEdit class <a class="ulink" href="../api/org/gjt/sp/jedit/gui/InputHandler.html" target="_top">InputHandler</a>
239            is an abstract class that that manages associations between keyboard
240            input and editing actions, along with the recording of macros.
241            Keyboard input in jEdit is normally managed by the derived class
242            <a class="ulink" href="../api/org/gjt/sp/jedit/gui/DefaultInputHandler.html" target="_top">DefaultInputHandler</a>.
243            One of the methods in the <a class="ulink" href="../api/org/gjt/sp/jedit/gui/InputHandler.html" target="_top">InputHandler</a>
244            class handles input from a single keypress:</p><div class="itemizedlist"><ul type="disc"><li><div class="funcsynopsis"><table border="0" summary="Function synopsis" cellspacing="0" cellpadding="0"><tr><td><code class="funcdef">public void
245                            <b class="fsfunc">readNextChar</b>(</code></td><td>String
246                             </td><td><var class="pdparam">prompt</var>, </td></tr><tr><td> </td><td>String
247                             </td><td><var class="pdparam">code</var><code>)</code>;</td></tr></table></div></li></ul></div><p>When this method is called, the contents of the
248            <code class="varname">prompt</code> parameter is shown in the view's status
249            bar. The method then waits for a key press, after which the contents
250            of the <code class="varname">code</code> parameter will be run as a BeanShell
251            script, with one important modification. Each time the string
252            <code class="varname">__char__</code> appears in the parameter script, it will
253            be substituted by the character pressed. The key press is
254            &#8220;<span class="quote">consumed</span>&#8221; by <code class="function">readNextChar()</code>. It
255            will not be displayed on the screen or otherwise processed by
256            jEdit.</p><p>Using <code class="function">readNextChar()</code> requires a macro
257            within the macro, formatted as a single, potentially lengthy string
258            literal. The following macro illustrates this technique. It selects
259            a line of text from the current caret position to the first
260            occurrence of the character next typed by the user. If the character
261            does not appear on the line, no new selection occurs and the display
262            remains unchanged.</p><div class="informalexample"><pre class="programlisting">// Next_Char.bsh
264script = new StringBuffer(512);
265script.append( "start = textArea.getCaretPosition();"         );
266script.append( "line = textArea.getCaretLine();"              );
267script.append( "end = textArea.getLineEndOffset(line) + 1;"   );
268script.append( "text = buffer.getText(start, end - start);"   );
269script.append( "match = text.indexOf(__char__, 1);"           );
270script.append( "if(match != -1) {"                            );
271script.append(   "if(__char__ != '\\n') ++match;"             );
272script.append(   ", start + match - 1);" );
273script.append( "}"                                            );
275view.getInputHandler().readNextChar("Enter a character",
276    script.toString());
278// end Next_Char.bsh</pre></div><p>Once again, here are a few comments on the macro's
279            design.</p><div class="itemizedlist"><ul type="disc"><li><p>A <code class="classname">StringBuffer</code> object is used
280                    for efficiency; it obviates multiple creation of
281                    fixed-length <code class="classname">String</code> objects. The
282                    parameter to the constructor of <code class="varname">script</code>
283                    specifies the initial size of the buffer that will receive
284                    the contents of the child script.</p></li><li><p>Besides the quoting of the script code, the formatting
285                    of the macro is entirely optional but (hopefully) makes it
286                    easier to read.</p></li><li><p>It is important that the child script be
287                    self-contained. It does not run in the same namespace as the
288                    &#8220;<span class="quote">parent</span>&#8221; macro
289                    <code class="filename">Next_Char.bsh</code> and therefore does not
290                    share variables, methods, or scripted objects defined in the
291                    parent macro.</p></li><li><p>Finally, access to the <a class="ulink" href="../api/org/gjt/sp/jedit/gui/InputHandler.html" target="_top">InputHandler</a>
292                    object used by jEdit is available by calling
293                    <code class="function">getInputHandler()</code> on the current
294                    view.</p></li></ul></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="macro-tips.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="macro-tips.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="startup-scripts.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter 15. Macro Tips and Techniques </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Startup Scripts</td></tr></table></div></body></html>