1   /*
2    * Editor.java
3    *
4    * Copyright (c) 2000-2001, The University of Sheffield.
5    *
6    * This file is part of GATE (see http://gate.ac.uk/), and is free
7    * software, licenced under the GNU Library General Public License,
8    * Version 2, June1991.
9    *
10   * A copy of this licence is included in the distribution in the file
11   * licence.html, and is also available at http://gate.ac.uk/gate/licence.html.
12   *
13   * Valentin Tablan, October 2000
14   *
15   * $Id: Editor.java,v 1.9 2001/11/18 15:16:24 valyt Exp $
16   */
17  package guk;
18  
19  import java.awt.*;
20  import java.awt.event.*;
21  import javax.swing.*;
22  import javax.swing.text.*;
23  import javax.swing.event.*;
24  import javax.swing.undo.*;
25  import java.beans.*;
26  import java.io.*;
27  import java.util.Locale;
28  import java.util.*;
29  
30  import guk.im.GateIM;
31  import guk.im.GateIMDescriptor;
32  
33  /**
34   * A simple text editor included here to demonstrate the capabilities of the GUK
35   * package.
36   *
37   * @author             <a href="http://www.gate.ac.uk/people/">The Gate Team</a>
38   * @version            1.0
39   */
40  public class Editor extends JFrame {
41    JPanel contentPane;
42    JMenuBar jMenuBar1 = new JMenuBar();
43    JMenu jMenuFile = new JMenu();
44    JMenu jMenuEdit = new JMenu();
45    JMenu jMenuHelp = new JMenu();
46    JMenu jMenuIM = null;
47    JMenuItem jMenuHelpAbout = new JMenuItem();
48    JToolBar jToolBar = new JToolBar();
49    JTextPane textPane = new JTextPane();
50    JMenu jMenuOptions = new JMenu();
51    JComboBox fontsComboBox;
52    JComboBox sizeComboBox;
53    JCheckBoxMenuItem jCheckBoxMenuItemKeyboardMap = new JCheckBoxMenuItem();
54    Action openAction, saveAction, saveAsAction, closeAction,
55           exitAction, undoAction, redoAction, cutAction, copyAction,
56           pasteAction, attributesChangedAction;
57    /**
58     * The current open file
59     */
60    File file = null;
61    /**
62     * The file chooser used in all operations requiring the user to select a file
63     */
64    JFileChooser filer = new JFileChooser();
65    /**
66     * The main frame
67     */
68    JFrame frame;
69    UndoManager undoManager = new UndoManager();
70    /**
71     * has the current document changed since the last save?
72     */
73    boolean docChanged = false;
74  
75    /**
76     * Construct the frame
77     */
78    public Editor() {
79      frame = this;
80      enableEvents(AWTEvent.WINDOW_EVENT_MASK);
81      try {
82        jbInit();
83      }
84      catch(Exception e) {
85        e.printStackTrace();
86      }
87      frame.validate();
88      Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
89      Dimension frameSize = getSize();
90      if (frameSize.height > screenSize.height) {
91        frameSize.height = screenSize.height;
92      }
93      if (frameSize.width > screenSize.width) {
94        frameSize.width = screenSize.width;
95      }
96      setLocation((screenSize.width - frameSize.width) / 2,
97                (screenSize.height - frameSize.height) / 2);
98      setVisible(true);
99    }// public Editor()
100 
101   /**
102    * Component initialization
103    */
104   private void jbInit() throws Exception {
105     java.util.List installedLocales = new ArrayList();
106     try{
107       //if this fails guk is not present
108       Class.forName("guk.im.GateIMDescriptor");
109       //add the Gate input methods
110       installedLocales.addAll(Arrays.asList(new guk.im.GateIMDescriptor().
111                                             getAvailableLocales()));
112     }catch(Exception e){
113       //something happened; most probably guk not present.
114       //just drop it, is not vital.
115     }
116     try{
117       //add the MPI IMs
118       //if this fails mpi IM is not present
119       Class.forName("mpi.alt.java.awt.im.spi.lookup.LookupDescriptor");
120 
121       installedLocales.addAll(Arrays.asList(
122             new mpi.alt.java.awt.im.spi.lookup.LookupDescriptor().
123             getAvailableLocales()));
124     }catch(Exception e){
125       //something happened; most probably MPI not present.
126       //just drop it, is not vital.
127     }
128     Collections.sort(installedLocales, new Comparator(){
129       public int compare(Object o1, Object o2){
130         return ((Locale)o1).getDisplayName().compareTo(((Locale)o2).getDisplayName());
131       }
132     });
133     JMenuItem item;
134     if(!installedLocales.isEmpty()) {
135       jMenuIM = new JMenu("Input methods");
136       ButtonGroup bg = new ButtonGroup();
137       Iterator localIter = installedLocales.iterator();
138       while(localIter.hasNext()){
139         Locale aLocale = (Locale)localIter.next();
140         item = new LocaleSelectorMenuItem(aLocale, frame);
141         jMenuIM.add(item);
142         bg.add(item);
143       }
144     }// if
145 
146     undoManager.setLimit(1000);
147     //OPEN ACTION
148     openAction = new AbstractAction("Open", new ImageIcon(
149             guk.Editor.class.getResource("img/openFile.gif"))){
150       public void actionPerformed(ActionEvent e){
151         int res = JOptionPane.OK_OPTION;
152         if(docChanged){
153           res = JOptionPane.showConfirmDialog(
154                 frame,
155                 "Close unsaved file " +
156                 (file== null?"Untitled":file.getName()) + "?",
157                 "Gate",
158                 JOptionPane.OK_CANCEL_OPTION,
159                 JOptionPane.WARNING_MESSAGE);
160         }
161         if(res == JOptionPane.OK_OPTION){
162           filer.setMultiSelectionEnabled(false);
163           filer.setDialogTitle("Select file to open...");
164           filer.setSelectedFile(null);
165           filer.setFileFilter(filer.getAcceptAllFileFilter());
166           int res1 = filer.showOpenDialog(frame);
167           if(res1 == filer.APPROVE_OPTION){
168             //we have the file, what's the encoding?
169             Object[] encodings = { "UTF-8", "UTF-16BE", "UTF-16LE", "UTF-16",
170                                    "ISO-8859-1", "US-ASCII" };
171             Object encoding = JOptionPane.showInputDialog(
172                       frame,
173                       "Please select the encoding for the chosen file",
174                       "Gate",
175                       JOptionPane.INFORMATION_MESSAGE,
176                       null,
177                       encodings,
178                       encodings[0]
179                       );
180             if(encoding == null) return;
181             file = filer.getSelectedFile();
182             try {
183               InputStreamReader reader = new InputStreamReader(
184                 new BufferedInputStream(new FileInputStream(file)),
185                 (String)encoding);
186               textPane.selectAll();
187               textPane.replaceSelection("");
188               textPane.read(reader, null);
189               reader.close();
190             } catch(FileNotFoundException fnfe) {
191               JOptionPane.showMessageDialog(frame,
192                                             "Cannot find the file specified!",
193                                             "Gate",
194                                             JOptionPane.ERROR_MESSAGE);
195               file = null;
196               docChanged = false;
197               updateTitle();
198             } catch(UnsupportedEncodingException usee) {
199               JOptionPane.showMessageDialog(frame,
200                                             "Unsupported encoding!\n" +
201                                             "Please choose another.",
202                                             "Gate",
203                                             JOptionPane.ERROR_MESSAGE);
204               file = null;
205               docChanged = false;
206               updateTitle();
207             } catch(IOException ioe) {
208               JOptionPane.showMessageDialog(
209                                   frame,
210                                   "Input/Output error! (wrong encoding?)\n" +
211                                   "Please try again.",
212                                   "Gate",
213                                   JOptionPane.ERROR_MESSAGE);
214               file = null;
215               docChanged = false;
216               updateTitle();
217             }
218             docChanged = false;
219             updateTitle();
220           }
221         }
222       }// actionPerformed(ActionEvent e)
223     };
224     openAction.putValue(Action.SHORT_DESCRIPTION, "Open file...");
225 
226 
227     //SAVE ACTION
228     saveAction = new AbstractAction("Save", new ImageIcon(
229             guk.Editor.class.getResource("img/saveFile.gif"))) {
230       public void actionPerformed(ActionEvent e){
231         if(docChanged){
232           if(file == null) saveAsAction.actionPerformed(null);
233           else {
234             //get the encoding
235             Object[] encodings = { "UTF-8", "UTF-16BE", "UTF-16LE", "UTF-16",
236                                    "ISO-8859-1", "US-ASCII" };
237             Object encoding = JOptionPane.showInputDialog(
238                       frame,
239                       "Please select the encoding for the chosen file",
240                       "Gate",
241                       JOptionPane.INFORMATION_MESSAGE,
242                       null,
243                       encodings,
244                       encodings[0]
245                       );
246             if(encoding == null) return;
247             try {
248               OutputStreamWriter writer = new OutputStreamWriter(
249                   new FileOutputStream(file), (String)encoding);
250               writer.write(textPane.getText());
251               writer.flush();
252               writer.close();
253               docChanged = false;
254               updateTitle();
255             } catch(UnsupportedEncodingException usee) {
256               JOptionPane.showMessageDialog(frame,
257                                             "Unsupported encoding!\n" +
258                                             "Please choose another.",
259                                             "Gate",
260                                             JOptionPane.ERROR_MESSAGE);
261               docChanged = true;
262               updateTitle();
263             } catch(IOException ioe) {
264               JOptionPane.showMessageDialog(frame,
265                                             "Input/Output error!\n" +
266                                             "Please try again.",
267                                             "Gate",
268                                             JOptionPane.ERROR_MESSAGE);
269               docChanged = true;
270               updateTitle();
271             }
272           }// else
273         }// if
274       }// actionPerformed(ActionEvent e)
275     };
276     saveAction.putValue(Action.SHORT_DESCRIPTION, "Save...");
277 
278     //SAVE AS ACTION
279     saveAsAction = new AbstractAction("Save as...", new ImageIcon(
280             guk.Editor.class.getResource("img/saveFile.gif"))){
281       public void actionPerformed(ActionEvent e) {
282           filer.setMultiSelectionEnabled(false);
283           filer.setDialogTitle("Select file to save to...");
284           filer.setSelectedFile(null);
285           filer.setFileFilter(filer.getAcceptAllFileFilter());
286           int res = filer.showSaveDialog(frame);
287           if(res == filer.APPROVE_OPTION){
288             File newFile = filer.getSelectedFile();
289             if(newFile == null) return;
290             int res1 = JOptionPane.OK_OPTION;
291             if(newFile.exists()){
292               res1 = JOptionPane.showConfirmDialog(
293                       frame,
294                       "Overwrite existing file " + newFile.getName() + "?",
295                       "Gate",
296                       JOptionPane.OK_CANCEL_OPTION,
297                       JOptionPane.WARNING_MESSAGE);
298             }
299             if(res1 == JOptionPane.OK_OPTION){
300               file = newFile;
301               docChanged = true;
302               saveAction.actionPerformed(null);
303             }
304           }
305       }// actionPerformed(ActionEvent e)
306     };
307     saveAsAction.putValue(Action.SHORT_DESCRIPTION, "Save as...");
308 
309     //CLOSE ACTION
310     closeAction = new AbstractAction("Close", new ImageIcon(
311             guk.Editor.class.getResource("img/closeFile.gif"))){
312       public void actionPerformed(ActionEvent e){
313         int res = JOptionPane.OK_OPTION;
314         if(docChanged){
315           res = JOptionPane.showConfirmDialog(
316                 frame,
317                 "Close unsaved file " +
318                 (file== null?"Untitled":file.getName()) + "?",
319                 "Gate",
320                 JOptionPane.OK_CANCEL_OPTION,
321                 JOptionPane.WARNING_MESSAGE);
322         }
323         if(res == JOptionPane.OK_OPTION){
324           textPane.selectAll();
325           textPane.replaceSelection("");
326           docChanged = false;
327           file = null;
328           updateTitle();
329         }
330       }// actionPerformed(ActionEvent e)
331     };
332     closeAction.putValue(Action.SHORT_DESCRIPTION, "Close...");
333 
334 
335     //EXIT ACTION
336     exitAction = new AbstractAction("Exit", new ImageIcon(
337             guk.Editor.class.getResource("img/exit.gif"))){
338       public void actionPerformed(ActionEvent e){
339         int res = JOptionPane.OK_OPTION;
340         if(docChanged){
341           res = JOptionPane.showConfirmDialog(
342                 frame,
343                 "Close unsaved file " +
344                 (file== null?"Untitled":file.getName()) + "?",
345                 "Gate",
346                 JOptionPane.OK_CANCEL_OPTION,
347                 JOptionPane.WARNING_MESSAGE);
348         }
349         if(res == JOptionPane.OK_OPTION){
350           frame.setVisible(false);
351           frame.dispose();
352         }
353       }// actionPerformed(ActionEvent e)
354     };
355     exitAction.putValue(Action.SHORT_DESCRIPTION, "Exit...");
356 
357     //UNDO ACTION
358     undoAction = new AbstractAction("Undo", new ImageIcon(
359             guk.Editor.class.getResource("img/undo.gif"))){
360       public void actionPerformed(ActionEvent e){
361         if(undoManager.canUndo()) undoManager.undo();
362       }
363     };
364      undoAction.setEnabled(undoManager.canUndo());
365      undoAction.putValue(Action.SHORT_DESCRIPTION, "Undo...");
366 
367     //REDO ACTION
368     redoAction = new AbstractAction("Redo", new ImageIcon(
369             guk.Editor.class.getResource("img/redo.gif"))){
370       public void actionPerformed(ActionEvent e){
371         if(undoManager.canRedo()) undoManager.redo();
372       }
373     };
374     redoAction.setEnabled(undoManager.canRedo());
375     redoAction.putValue(Action.SHORT_DESCRIPTION, "Redo...");
376 
377     //COPY ACTION
378     copyAction = new AbstractAction("Copy", new ImageIcon(
379             guk.Editor.class.getResource("img/copy.gif"))){
380       public void actionPerformed(ActionEvent e){
381         textPane.copy();
382       }
383     };
384     copyAction.putValue(Action.SHORT_DESCRIPTION, "Copy...");
385 
386     //CUT ACTION
387     cutAction = new AbstractAction("Cut", new ImageIcon(
388             guk.Editor.class.getResource("img/cut.gif"))){
389       public void actionPerformed(ActionEvent e){
390         textPane.cut();
391       }
392     };
393     cutAction.putValue(Action.SHORT_DESCRIPTION, "Cut...");
394 
395     //PASTE ACTION
396     pasteAction = new AbstractAction("Paste", new ImageIcon(
397             guk.Editor.class.getResource("img/paste.gif"))){
398       public void actionPerformed(ActionEvent e){
399         textPane.paste();
400       }
401     };
402     pasteAction.putValue(Action.SHORT_DESCRIPTION, "Paste...");
403 
404     //attributesChangedAction
405     attributesChangedAction = new AbstractAction() {
406       public void actionPerformed(ActionEvent e) {
407         int start = textPane.getSelectionStart();
408         int end = textPane.getSelectionEnd();
409         //change the selection
410         MutableAttributeSet as = textPane.getInputAttributes();
411         StyleConstants.setFontFamily(as,
412                                     (String)fontsComboBox.getSelectedItem());
413         StyleConstants.setFontSize(as,
414                                    Integer.parseInt(
415                                    (String)sizeComboBox.getSelectedItem()));
416         textPane.setCharacterAttributes(as, false);
417         //restore selection
418         textPane.setCaretPosition(start);
419         textPane.moveCaretPosition(end);
420       }// actionPerformed(ActionEvent e)
421     };
422 
423     textPane.addPropertyChangeListener("document", new PropertyChangeListener(){
424       public void propertyChange(PropertyChangeEvent evt){
425         undoAction.setEnabled(undoManager.canUndo());
426         redoAction.setEnabled(undoManager.canRedo());
427         //add the document listener
428         textPane.getDocument().addDocumentListener(new DocumentListener(){
429           public void insertUpdate(DocumentEvent e){
430             changeOccured();
431           }
432           public void removeUpdate(DocumentEvent e){
433             changeOccured();
434           }
435           public void changedUpdate(DocumentEvent e){
436             changeOccured();
437           }
438           protected void changeOccured(){
439             undoAction.setEnabled(undoManager.canUndo());
440             undoAction.putValue(Action.SHORT_DESCRIPTION,
441                                 undoManager.getUndoPresentationName());
442             redoAction.setEnabled(undoManager.canRedo());
443             redoAction.putValue(Action.SHORT_DESCRIPTION,
444                                 undoManager.getRedoPresentationName());
445             if(docChanged) return;
446             else{
447               docChanged = true;
448               updateTitle();
449             }
450           }// changeOccured()
451         });
452         //add the document UNDO listener
453         undoManager.discardAllEdits();
454         textPane.getDocument().addUndoableEditListener(undoManager);
455       }// propertyChange(PropertyChangeEvent evt)
456     });
457 
458     fontsComboBox = new JComboBox(
459                         GraphicsEnvironment.getLocalGraphicsEnvironment().
460                         getAvailableFontFamilyNames()
461                         );
462     fontsComboBox.setEditable(false);
463     fontsComboBox.addActionListener(new ActionListener(){
464       public void actionPerformed(ActionEvent e){
465         attributesChangedAction.actionPerformed(null);
466       }// actionPerformed(ActionEvent e)
467     });
468 
469 
470     sizeComboBox = new JComboBox(new Object[]{"6", "8", "10", "12", "14", "16",
471                                               "18", "20", "22", "24", "26"});
472     sizeComboBox.setEditable(true);
473     sizeComboBox.addActionListener(new ActionListener(){
474       public void actionPerformed(ActionEvent e){
475         try {
476           Integer.parseInt((String)sizeComboBox.getSelectedItem());
477           //fire the action
478           attributesChangedAction.actionPerformed(null);
479         } catch(NumberFormatException nfe){
480           //invalid input, go to default
481           sizeComboBox.setSelectedIndex(3);
482         }
483       }//actionPerformed(ActionEvent e)
484     });
485 
486     //initialisation for the fonts and size combos
487     fontsComboBox.setSelectedItem(StyleConstants.getFontFamily(
488                                   textPane.getInputAttributes()));
489     sizeComboBox.setSelectedItem(String.valueOf(StyleConstants.getFontSize(
490                                   textPane.getInputAttributes())));
491     //keep them updated
492     textPane.addCaretListener(new CaretListener(){
493       public void caretUpdate(CaretEvent e) {
494         if(e.getDot() == e.getMark()){
495           fontsComboBox.setSelectedItem(StyleConstants.getFontFamily(
496                                         textPane.getCharacterAttributes()));
497           sizeComboBox.setSelectedItem(String.valueOf(StyleConstants.getFontSize(
498                                         textPane.getCharacterAttributes())));
499         }
500       }//caretUpdate(CaretEvent e)
501     });
502 
503     fontsComboBox.setMaximumSize(new Dimension(150,25));
504     //fontsComboBox.setMinimumSize(new Dimension(150,25));
505     fontsComboBox.setPreferredSize(new Dimension(150,25));
506     //fontsComboBox.setSize(new Dimension(150,25));
507     sizeComboBox.setMaximumSize(new Dimension(50,25));
508     //sizeComboBox.setMinimumSize(new Dimension(30,25));
509     sizeComboBox.setPreferredSize(new Dimension(50,25));
510     //sizeComboBox.setSize(new Dimension(30,25));
511     sizeComboBox.enableInputMethods(false);
512     //setIconImage(Toolkit.getDefaultToolkit().createImage(EditorFrame.class.getResource("[Your Icon]")));
513     contentPane = (JPanel) this.getContentPane();
514     contentPane.setLayout(new BorderLayout());
515     this.setSize(new Dimension(800, 600));
516     updateTitle();
517     jMenuFile.setText("File");
518     jMenuEdit.setText("Edit");
519     jMenuHelp.setText("Help");
520     jMenuHelpAbout.setText("About");
521     jMenuHelpAbout.addActionListener(new ActionListener()  {
522       public void actionPerformed(ActionEvent e) {
523         jMenuHelpAbout_actionPerformed(e);
524       }
525     });
526     jMenuOptions.setText("Options");
527     jCheckBoxMenuItemKeyboardMap.setText("Keyboard Map");
528     jCheckBoxMenuItemKeyboardMap.setSelected(false);
529     jCheckBoxMenuItemKeyboardMap.setMnemonic('0');
530     jCheckBoxMenuItemKeyboardMap.addActionListener(new ActionListener()  {
531       public void actionPerformed(ActionEvent e) {
532         jCheckBoxMenuItemKeyboardMap_stateChanged(e);
533       }
534     });
535     jToolBar.add(openAction);
536     jToolBar.add(saveAction);
537     jToolBar.add(closeAction);
538     jToolBar.addSeparator();
539     jToolBar.add(undoAction);
540     jToolBar.add(redoAction);
541     jToolBar.addSeparator();
542     jToolBar.add(cutAction);
543     jToolBar.add(copyAction);
544     jToolBar.add(pasteAction);
545     jToolBar.addSeparator();
546     jToolBar.add(fontsComboBox);
547     jToolBar.addSeparator();
548     jToolBar.add(sizeComboBox);
549 
550     jToolBar.add(Box.createHorizontalGlue());
551 
552     jMenuFile.add(openAction);
553     jMenuFile.add(saveAction);
554     jMenuFile.add(saveAsAction);
555     jMenuFile.add(closeAction);
556     jMenuFile.addSeparator();
557     jMenuFile.add(exitAction);
558 
559     jMenuEdit.add(cutAction);
560     jMenuEdit.add(copyAction);
561     jMenuEdit.add(pasteAction);
562     jMenuEdit.addSeparator();
563     jMenuEdit.add(undoAction);
564     jMenuEdit.add(redoAction);
565 
566     jMenuOptions.add(jCheckBoxMenuItemKeyboardMap);
567     if(jMenuIM != null) jMenuOptions.add(jMenuIM);
568 
569     jMenuHelp.add(jMenuHelpAbout);
570 
571     jMenuBar1.add(jMenuFile);
572     jMenuBar1.add(jMenuEdit);
573     jMenuBar1.add(jMenuOptions);
574     jMenuBar1.add(jMenuHelp);
575 
576 //    textPane.setEditorKit(new UnicodeStyledEditorKit(GUK.getFontSet()));
577     textPane.setEditorKit(new StyledEditorKit());
578     textPane.setFont(new Font("Arial Unicode MS", Font.PLAIN, 14));
579     this.setJMenuBar(jMenuBar1);
580     contentPane.add(jToolBar, BorderLayout.NORTH);
581     contentPane.add(new JScrollPane(textPane), BorderLayout.CENTER);
582   }// jbInit()
583 
584   protected void updateTitle(){
585     String title = "Gate Unicode Editor - ";
586     if(file != null) title += file.getName();
587     else title += "Untitled";
588     if(docChanged) title += "*";
589     frame.setTitle(title);
590   }// updateTitle()
591 
592   /**
593    * Main method
594    */
595   public static void main(String[] args) {
596     try {
597       UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
598     }
599     catch(Exception e) {
600       e.printStackTrace();
601     }
602     /*
603     Object[] ffs = java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
604     for(int i = 0; i < ffs.length; i++) System.out.println(ffs[i]);
605     */
606     new Editor();
607   }// main
608 
609   /**
610    * Help | About action performed
611    */
612   public void jMenuHelpAbout_actionPerformed(ActionEvent e) {
613     Editor_AboutBox dlg = new Editor_AboutBox(this);
614     Dimension dlgSize = dlg.getPreferredSize();
615     Dimension frmSize = getSize();
616     Point loc = getLocation();
617     dlg.setLocation((frmSize.width - dlgSize.width) / 2 + loc.x,
618                     (frmSize.height - dlgSize.height) / 2 + loc.y);
619     dlg.setModal(true);
620     dlg.show();
621   }// jMenuHelpAbout_actionPerformed(ActionEvent e)
622 
623   /**
624    * Overridden so we can exit when window is closed
625    */
626   protected void processWindowEvent(WindowEvent e) {
627     if (e.getID() == WindowEvent.WINDOW_CLOSING) {
628       exitAction.actionPerformed(null);
629     } else {
630       super.processWindowEvent(e);
631     }
632   }// processWindowEvent(WindowEvent e)
633 
634   void jCheckBoxMenuItemKeyboardMap_stateChanged(ActionEvent e) {
635     Object imObject = getInputContext().getInputMethodControlObject();
636     if(imObject != null && imObject instanceof GateIM){
637       ((GateIM)imObject).setMapVisible(jCheckBoxMenuItemKeyboardMap.getState());
638     }else jCheckBoxMenuItemKeyboardMap.setState(false);
639   }// void jCheckBoxMenuItemKeyboardMap_stateChanged(ActionEvent e)
640 }// class Editor extends JFrame
641 
642 class LocaleSelectorMenuItem extends JRadioButtonMenuItem {
643   public LocaleSelectorMenuItem(Locale locale, Frame pframe){
644     super(locale.getDisplayName());
645     this.frame = pframe;
646     me = this;
647     myLocale = locale;
648     this.addActionListener(new ActionListener()  {
649       public void actionPerformed(ActionEvent e) {
650         me.setSelected(frame.getInputContext().selectInputMethod(myLocale));
651       }
652     });
653   }// LocaleSelectorMenuItem(Locale locale, Frame pframe)
654   Locale myLocale;
655   JRadioButtonMenuItem me;
656   Frame frame;
657 }// class LocaleSelectorMenuItem extends JRadioButtonMenuItem