source: tmcsimulator/trunk/src/spikes/TextComponentDemo.java @ 416

Revision 416, 14.7 KB checked in by jdalbey, 7 years ago (diff)

Create new ExportAction?.java for Sim Mgr and a new client, CADlogDisplay that outputs to console the current CAD log every 10 seconds.

Line 
1
2package spikes;
3
4
5import java.awt.*;
6import java.awt.event.*;
7import java.util.HashMap;
8import java.util.logging.Level;
9import java.util.logging.Logger;
10
11import javax.swing.*;
12import javax.swing.text.*;
13import javax.swing.event.*;
14import javax.swing.undo.*;
15
16public class TextComponentDemo extends JFrame {
17    JTextPane textPane;
18    AbstractDocument doc;
19    static final int MAX_CHARACTERS = 300;
20    JTextArea changeLog;
21    String newline = "\n";
22    HashMap<Object, Action> actions;
23
24    //undo helpers
25    protected UndoAction undoAction;
26    protected RedoAction redoAction;
27    protected UndoManager undo = new UndoManager();
28    private ClearAction saveAction = new ClearAction();
29
30    public TextComponentDemo() {
31        super("TextComponentDemo");
32
33        //Create the text pane and configure it.
34        textPane = new JTextPane();
35        textPane.setCaretPosition(0);
36        textPane.setMargin(new Insets(5,5,5,5));
37        StyledDocument styledDoc = textPane.getStyledDocument();
38        if (styledDoc instanceof AbstractDocument) {
39            doc = (AbstractDocument)styledDoc;
40            doc.setDocumentFilter(new DocumentSizeFilter(MAX_CHARACTERS));
41        } else {
42            System.err.println("Text pane's document isn't an AbstractDocument!");
43            System.exit(-1);
44        }
45        JScrollPane scrollPane = new JScrollPane(textPane);
46        scrollPane.setPreferredSize(new Dimension(200, 200));
47
48        //Create the text area for the status log and configure it.
49        changeLog = new JTextArea(5, 30);
50        changeLog.setEditable(false);
51        JScrollPane scrollPaneForLog = new JScrollPane(changeLog);
52
53        //Create a split pane for the change log and the text area.
54        JSplitPane splitPane = new JSplitPane(
55                                       JSplitPane.VERTICAL_SPLIT,
56                                       scrollPane, scrollPaneForLog);
57        splitPane.setOneTouchExpandable(true);
58
59        //Create the status area.
60        JPanel statusPane = new JPanel(new GridLayout(1, 1));
61        CaretListenerLabel caretListenerLabel =
62                new CaretListenerLabel("Caret Status");
63        statusPane.add(caretListenerLabel);
64
65        //Add the components.
66        getContentPane().add(splitPane, BorderLayout.CENTER);
67        getContentPane().add(statusPane, BorderLayout.PAGE_END);
68
69        //Set up the menu bar.
70        actions=createActionTable(textPane);
71        JMenu editMenu = createEditMenu();
72        JMenu styleMenu = createStyleMenu();
73        JMenuBar mb = new JMenuBar();
74        mb.add(editMenu);
75        mb.add(styleMenu);
76        setJMenuBar(mb);
77
78        //Add some key bindings.
79        addBindings();
80
81        //Put the initial text into the text pane.
82        initDocument();
83        textPane.setCaretPosition(0);
84
85        //Start watching for undoable edits and caret changes.
86        doc.addUndoableEditListener(new MyUndoableEditListener());
87        textPane.addCaretListener(caretListenerLabel);
88        doc.addDocumentListener(new MyDocumentListener());
89    }
90
91    //This listens for and reports caret movements.
92    protected class CaretListenerLabel extends JLabel
93                                       implements CaretListener {
94        public CaretListenerLabel(String label) {
95            super(label);
96        }
97
98        //Might not be invoked from the event dispatch thread.
99        public void caretUpdate(CaretEvent e) {
100            displaySelectionInfo(e.getDot(), e.getMark());
101        }
102
103        //This method can be invoked from any thread.  It
104        //invokes the setText and modelToView methods, which
105        //must run on the event dispatch thread. We use
106        //invokeLater to schedule the code for execution
107        //on the event dispatch thread.
108        protected void displaySelectionInfo(final int dot,
109                                            final int mark) {
110            SwingUtilities.invokeLater(new Runnable() {
111                public void run() {
112                    if (dot == mark) {  // no selection
113                        try {
114                            Rectangle caretCoords = textPane.modelToView(dot);
115                            //Convert it to view coordinates.
116                            setText("caret: text position: " + dot
117                                    + ", view location = ["
118                                    + caretCoords.x + ", "
119                                    + caretCoords.y + "]"
120                                    + newline);
121                        } catch (BadLocationException ble) {
122                            setText("caret: text position: " + dot + newline);
123                        }
124                    } else if (dot < mark) {
125                        setText("selection from: " + dot
126                                + " to " + mark + newline);
127                    } else {
128                        setText("selection from: " + mark
129                                + " to " + dot + newline);
130                    }
131                }
132            });
133        }
134    }
135
136    //This one listens for edits that can be undone.
137    protected class MyUndoableEditListener
138                    implements UndoableEditListener {
139        public void undoableEditHappened(UndoableEditEvent e) {
140            //Remember the edit and update the menus.
141            undo.addEdit(e.getEdit());
142            undoAction.updateUndoState();
143            redoAction.updateRedoState();
144        }
145    }
146
147    //And this one listens for any changes to the document.
148    protected class MyDocumentListener
149                    implements DocumentListener {
150        public void insertUpdate(DocumentEvent e) {
151            displayEditInfo(e);
152        }
153        public void removeUpdate(DocumentEvent e) {
154            displayEditInfo(e);
155        }
156        public void changedUpdate(DocumentEvent e) {
157            displayEditInfo(e);
158        }
159        private void displayEditInfo(DocumentEvent e) {
160            Document document = e.getDocument();
161            int changeLength = e.getLength();
162            changeLog.append(e.getType().toString() + ": " +
163                changeLength + " character" +
164                ((changeLength == 1) ? ". " : "s. ") +
165                " Text length = " + document.getLength() +
166                "." + newline);
167        }
168    }
169
170    //Add a couple of emacs key bindings for navigation.
171    protected void addBindings() {
172        InputMap inputMap = textPane.getInputMap();
173        ActionMap actionMap = textPane.getActionMap();
174        //Ctrl-b to go backward one character
175        KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_B, Event.CTRL_MASK);
176        //inputMap.put(key, DefaultEditorKit.backwardAction);
177        inputMap.put(key, "myAction");
178        actionMap.put("myAction", saveAction);
179       
180        //Ctrl-f to go forward one character
181        key = KeyStroke.getKeyStroke(KeyEvent.VK_F, Event.CTRL_MASK);
182        inputMap.put(key, DefaultEditorKit.forwardAction);
183
184        //Ctrl-p to go up one line
185        key = KeyStroke.getKeyStroke(KeyEvent.VK_P, Event.CTRL_MASK);
186        inputMap.put(key, DefaultEditorKit.upAction);
187
188        //Ctrl-n to go down one line
189        key = KeyStroke.getKeyStroke(KeyEvent.VK_N, Event.CTRL_MASK);
190        inputMap.put(key, DefaultEditorKit.downAction);
191    }
192
193    //Create the edit menu.
194    protected JMenu createEditMenu() {
195        JMenu menu = new JMenu("Edit");
196
197        //Undo and redo are actions of our own creation.
198        undoAction = new UndoAction();
199        menu.add(undoAction);
200
201        redoAction = new RedoAction();
202        menu.add(redoAction);
203
204        menu.addSeparator();
205
206        //These actions come from the default editor kit.
207        //Get the ones we want and stick them in the menu.
208        menu.add(getActionByName(DefaultEditorKit.cutAction));
209        menu.add(getActionByName(DefaultEditorKit.copyAction));
210        menu.add(getActionByName(DefaultEditorKit.pasteAction));
211
212        menu.addSeparator();
213
214        menu.add(getActionByName(DefaultEditorKit.selectAllAction));
215        return menu;
216    }
217
218    //Create the style menu.
219    protected JMenu createStyleMenu() {
220        JMenu menu = new JMenu("Style");
221
222        Action action = new StyledEditorKit.BoldAction();
223        action.putValue(Action.NAME, "Bold");
224        menu.add(action);
225
226        action = new StyledEditorKit.ItalicAction();
227        action.putValue(Action.NAME, "Italic");
228        menu.add(action);
229
230        action = new StyledEditorKit.UnderlineAction();
231        action.putValue(Action.NAME, "Underline");
232        menu.add(action);
233
234        menu.addSeparator();
235
236        menu.add(new StyledEditorKit.FontSizeAction("12", 12));
237        menu.add(new StyledEditorKit.FontSizeAction("14", 14));
238        menu.add(new StyledEditorKit.FontSizeAction("18", 18));
239
240        menu.addSeparator();
241
242        menu.add(new StyledEditorKit.FontFamilyAction("Serif",
243                                                      "Serif"));
244        menu.add(new StyledEditorKit.FontFamilyAction("SansSerif",
245                                                      "SansSerif"));
246
247        menu.addSeparator();
248
249        menu.add(new StyledEditorKit.ForegroundAction("Red",
250                                                      Color.red));
251        menu.add(new StyledEditorKit.ForegroundAction("Green",
252                                                      Color.green));
253        menu.add(new StyledEditorKit.ForegroundAction("Blue",
254                                                      Color.blue));
255        menu.add(new StyledEditorKit.ForegroundAction("Black",
256                                                      Color.black));
257
258        return menu;
259    }
260
261    protected void initDocument() {
262        String initString[] =
263                { "Use the mouse to place the caret.",
264                  "Use the edit menu to cut, copy, paste, and select text.",
265                  "Also to undo and redo changes.",
266                  "Use the style menu to change the style of the text.",
267                  "Use the arrow keys on the keyboard or these emacs key bindings to move the caret:",
268                  "Ctrl-f, Ctrl-b, Ctrl-n, Ctrl-p." };
269
270        SimpleAttributeSet[] attrs = initAttributes(initString.length);
271
272        try {
273            for (int i = 0; i < initString.length; i ++) {
274                doc.insertString(doc.getLength(), initString[i] + newline,
275                        attrs[i]);
276            }
277        } catch (BadLocationException ble) {
278            System.err.println("Couldn't insert initial text.");
279        }
280    }
281
282    protected SimpleAttributeSet[] initAttributes(int length) {
283        //Hard-code some attributes.
284        SimpleAttributeSet[] attrs = new SimpleAttributeSet[length];
285
286        attrs[0] = new SimpleAttributeSet();
287        StyleConstants.setFontFamily(attrs[0], "SansSerif");
288        StyleConstants.setFontSize(attrs[0], 16);
289
290        attrs[1] = new SimpleAttributeSet(attrs[0]);
291        StyleConstants.setBold(attrs[1], true);
292
293        attrs[2] = new SimpleAttributeSet(attrs[0]);
294        StyleConstants.setItalic(attrs[2], true);
295
296        attrs[3] = new SimpleAttributeSet(attrs[0]);
297        StyleConstants.setFontSize(attrs[3], 20);
298
299        attrs[4] = new SimpleAttributeSet(attrs[0]);
300        StyleConstants.setFontSize(attrs[4], 12);
301
302        attrs[5] = new SimpleAttributeSet(attrs[0]);
303        StyleConstants.setForeground(attrs[5], Color.red);
304
305        return attrs;
306    }
307
308    //The following two methods allow us to find an
309    //action provided by the editor kit by its name.
310    private HashMap<Object, Action> createActionTable(JTextComponent textComponent) {
311        HashMap<Object, Action> actions = new HashMap<Object, Action>();
312        Action[] actionsArray = textComponent.getActions();
313        for (int i = 0; i < actionsArray.length; i++) {
314            Action a = actionsArray[i];
315            actions.put(a.getValue(Action.NAME), a);
316        }
317        return actions;
318    }
319
320    private Action getActionByName(String name) {
321        return actions.get(name);
322    }
323
324    class ClearAction extends AbstractAction
325    {
326        public void actionPerformed(ActionEvent evt) 
327        {
328            JTextPane src = (JTextPane) evt.getSource();
329            StyledDocument doc = src.getStyledDocument();
330            int length = doc.getLength();
331            try {
332                doc.remove(0,length);
333            } catch (BadLocationException ex) {
334                Logger.getLogger(TextComponentDemo.class.getName()).log(Level.SEVERE, null, ex);
335            }
336        }
337    }
338
339    class UndoAction extends AbstractAction {
340        public UndoAction() {
341            super("Undo");
342            setEnabled(false);
343        }
344
345        public void actionPerformed(ActionEvent e) {
346            try {
347                undo.undo();
348            } catch (CannotUndoException ex) {
349                System.out.println("Unable to undo: " + ex);
350                ex.printStackTrace();
351            }
352            updateUndoState();
353            redoAction.updateRedoState();
354        }
355
356        protected void updateUndoState() {
357            if (undo.canUndo()) {
358                setEnabled(true);
359                putValue(Action.NAME, undo.getUndoPresentationName());
360            } else {
361                setEnabled(false);
362                putValue(Action.NAME, "Undo");
363            }
364        }
365    }
366
367    class RedoAction extends AbstractAction {
368        public RedoAction() {
369            super("Redo");
370            setEnabled(false);
371        }
372
373        public void actionPerformed(ActionEvent e) {
374            try {
375                undo.redo();
376            } catch (CannotRedoException ex) {
377                System.out.println("Unable to redo: " + ex);
378                ex.printStackTrace();
379            }
380            updateRedoState();
381            undoAction.updateUndoState();
382        }
383
384        protected void updateRedoState() {
385            if (undo.canRedo()) {
386                setEnabled(true);
387                putValue(Action.NAME, undo.getRedoPresentationName());
388            } else {
389                setEnabled(false);
390                putValue(Action.NAME, "Redo");
391            }
392        }
393    }
394
395    /**
396     * Create the GUI and show it.  For thread safety,
397     * this method should be invoked from the
398     * event dispatch thread.
399     */
400    private static void createAndShowGUI() {
401        //Create and set up the window.
402        final TextComponentDemo frame = new TextComponentDemo();
403        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
404
405        //Display the window.
406        frame.pack();
407        frame.setVisible(true);
408    }
409
410    //The standard main method.
411    public static void main(String[] args) {
412        //Schedule a job for the event dispatch thread:
413        //creating and showing this application's GUI.
414        SwingUtilities.invokeLater(new Runnable() {
415            public void run() {
416                //Turn off metal's use of bold fonts
417                UIManager.put("swing.boldMetal", Boolean.FALSE);
418                createAndShowGUI();
419            }
420        });
421    }
422}
Note: See TracBrowser for help on using the repository browser.