KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > salsa > richtext > RichTextBox


1 /*
2 ** Salsa - Swing Add-On Suite
3 ** Copyright (c) 2001, 2002, 2003 by Gerald Bauer
4 **
5 ** This program is free software.
6 **
7 ** You may redistribute it and/or modify it under the terms of the GNU
8 ** General Public License as published by the Free Software Foundation.
9 ** Version 2 of the license should be included with this distribution in
10 ** the file LICENSE, as well as License.html. If the license is not
11 ** included with this distribution, you may find a copy at the FSF web
12 ** site at 'www.gnu.org' or 'www.fsf.org', or you may write to the
13 ** Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139 USA.
14 **
15 ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
16 ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
17 ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
18 ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
19 ** REDISTRIBUTION OF THIS SOFTWARE.
20 **
21 */

22 package salsa.richtext;
23
24 import java.util.*;
25 import java.awt.*;
26 import java.awt.event.*;
27 import java.io.*;
28 import java.net.*;
29 import javax.swing.*;
30 import javax.swing.event.*;
31 import javax.swing.text.*;
32 import javax.swing.text.html.*;
33 import javax.swing.undo.*;
34
35 import houston.*;
36 import houston.swing.*;
37
38 import salsa.menu.*;
39 import salsa.font.*;
40 import salsa.util.*;
41 import salsa.html.*;
42
43 class HtmlStyle
44 {
45    HTML.Tag _tag;
46    String JavaDoc _name;
47
48
49    public HtmlStyle( HTML.Tag tag, String JavaDoc name )
50    {
51       _tag = tag;
52       _name = name;
53    }
54
55
56    public HTML.Tag getTag()
57    {
58       return _tag;
59    }
60
61
62    public String JavaDoc getName()
63    {
64       return _name;
65    }
66
67
68    public String JavaDoc toString()
69    {
70       return getName() + " <" + getTag() + ">";
71    }
72 }
73
74 abstract class SimpleAction extends AbstractAction
75 {
76
77
78    public SimpleAction( String JavaDoc name )
79    {
80       super( name );
81    }
82
83
84    public abstract void execute();
85
86
87    public void actionPerformed( ActionEvent ev )
88    {
89       execute();
90    }
91 }
92
93 public class RichTextBox extends JPanel
94        implements ChangeListener
95 {
96
97
98    static Logger T = Logger.getLogger( RichTextBox.class );
99
100    public final static String JavaDoc APP_TITLE = "Rich Text Box";
101
102    JFrame _frame;
103
104
105    public JFrame getFrame()
106    {
107       return _frame;
108    }
109
110
111    JTextPane _editor;
112
113
114    public JTextPane getEditor()
115    {
116       return _editor;
117    }
118
119
120    CustomHTMLEditorKit _kit;
121    MutableHTMLDocument _doc;
122    StyleSheet _styleSheet;
123
124    JTextArea _source;
125    JScrollPane _sourceTab;
126    JTabbedPane _tab;
127
128    JComboBox _fontNamesCombo;
129    JComboBox _fontSizesCombo;
130    JComboBox _stylesCombo;
131
132    String JavaDoc _fontNames[];
133    String JavaDoc _fontSizes[];
134
135    public static HtmlStyle[] STYLES =
136          {
137          new HtmlStyle( HTML.Tag.P, "Paragraph" ),
138          new HtmlStyle( HTML.Tag.H1, "Heading 1" ),
139          new HtmlStyle( HTML.Tag.H2, "Heading 2" ),
140          new HtmlStyle( HTML.Tag.H3, "Heading 3" ),
141          new HtmlStyle( HTML.Tag.H4, "Heading 4" ),
142          new HtmlStyle( HTML.Tag.H5, "Heading 5" ),
143          new HtmlStyle( HTML.Tag.H6, "Heading 6" ),
144          new HtmlStyle( HTML.Tag.ADDRESS, "Address" ),
145          new HtmlStyle( HTML.Tag.PRE, "Preformat" )
146          };
147
148    FontChooser _fontChooser;
149
150    JToggleButton _boldButton;
151    JToggleButton _italicButton;
152    JToggleButton _underlineButton;
153
154    ColorMenu _foregroundMenu;
155
156    Action _cmdCut;
157    Action _cmdCopy;
158    Action _cmdPaste;
159    Action _cmdUndo;
160    Action _cmdRedo;
161
162    Action _cmdOpen;
163    Action _cmdSaveAs;
164    Action _cmdSave;
165    Action _cmdNew;
166    Action _cmdInsertImage;
167    Action _cmdInsertHyperlink;
168    Action _cmdFont;
169    Action _cmdFind;
170    Action _cmdReplace;
171
172    UndoManager _undoManager = new UndoManager();
173
174    boolean _skipUpdate = false;
175
176    String JavaDoc _fontName = "";
177    int _fontSize = 0;
178
179    int _xStart = -1;
180    // selection start
181
int _xEnd = -1;
182    // selection finish
183

184    FindDialog _findDialog;
185    JFileChooser _chooser;
186    File _file;
187
188    boolean _isDirty = false;
189    // unsaved file changes?
190

191    WebAddressDialog _addressDialog;
192
193
194    public JFileChooser getFileChooser()
195    {
196       return _chooser;
197    }
198
199
200    public File getFile()
201    {
202       return _file;
203    }
204
205
206    public void newFile()
207    {
208       _doc = ( MutableHTMLDocument ) _kit.createDocument();
209       _styleSheet = _doc.getStyleSheet();
210       _editor.setDocument( _doc );
211
212       syncStyleAttributes( 0 );
213
214       _doc.addUndoableEditListener( new Undoer() );
215       _doc.addDocumentListener( new UpdateListener() );
216       _isDirty = false;
217
218       setFile( null );
219    }
220
221
222    public void openFile()
223    {
224       if( !canCloseDocument() )
225          return;
226
227       if( _chooser.showOpenDialog( getFrame() ) != JFileChooser.APPROVE_OPTION )
228          return;
229
230       File file = _chooser.getSelectedFile();
231
232       // todo: issue a warning
233
if( file == null || !file.isFile() )
234          return;
235
236       openFileWorker( file );
237    }
238
239
240    public void openFileWorker( File file )
241    {
242       Reader r = null;
243       try
244       {
245          setCursor( Cursor.getPredefinedCursor( Cursor.WAIT_CURSOR ) );
246
247          r = new InputStreamReader( new FileInputStream( file ) );
248          _doc = ( MutableHTMLDocument ) _kit.createDocument();
249          _styleSheet = _doc.getStyleSheet();
250          _kit.read( r, _doc, 0 );
251          _editor.setDocument( _doc );
252
253          _editor.setCaretPosition( 1 );
254          syncStyleAttributes( 1 );
255
256          _doc.addUndoableEditListener( new Undoer() );
257          _doc.addDocumentListener( new UpdateListener() );
258          _isDirty = false;
259
260          setFile( file );
261          Status.info( "file '" + file.getName() + "' successfully opened" );
262       }
263       catch( BadLocationException bex )
264       {
265          Status.error( "*** failed to open file '" + file.getName() + "': " + bex.toString() );
266       }
267       catch( IOException ioex )
268       {
269          Status.error( "*** failed to open file '" + file.getName() + "': " + ioex.toString() );
270       }
271       finally
272       {
273          if( r != null )
274             try
275             {
276                r.close();
277             }
278             catch( IOException ioex )
279             {}
280
281          setCursor( Cursor.getPredefinedCursor( Cursor.DEFAULT_CURSOR ) );
282       }
283    }
284
285
286    public boolean saveFile()
287    {
288       return saveFileWorker( false );
289    }
290
291
292    public boolean saveFileAs()
293    {
294       return saveFileWorker( true );
295    }
296
297
298    private boolean saveFileWorker( boolean saveAs )
299    {
300       // returns successfull --> true
301
// or failed --> false
302

303       if( !saveAs && !_isDirty )
304          return true;
305
306       if( saveAs || _file == null )
307       {
308          if( _chooser.showSaveDialog( getFrame() ) != JFileChooser.APPROVE_OPTION )
309             return false;
310
311          File file = _chooser.getSelectedFile();
312
313          if( file == null || !file.isFile() )
314             return false;
315
316          setFile( file );
317       }
318
319       Writer w = null;
320       try
321       {
322          setCursor( Cursor.getPredefinedCursor( Cursor.WAIT_CURSOR ) );
323
324          w = new OutputStreamWriter( new FileOutputStream( _file ) );
325
326          _kit.write( w, _doc, 0, _doc.getLength() );
327          _isDirty = false;
328
329          Status.info( "file '" + _file.getName() + "' successfully saved" );
330          return true;
331       }
332       catch( BadLocationException bex )
333       {
334          Status.error( "*** failed to save file '" + _file.getName() + "': " + bex.toString() );
335          return false;
336       }
337       catch( IOException ioex )
338       {
339          Status.error( "*** failed to save file '" + _file.getName() + "': " + ioex.toString() );
340          return false;
341       }
342       finally
343       {
344          if( w != null )
345             try
346             {
347                w.close();
348             }
349             catch( IOException ioex )
350             {}
351
352          setCursor( Cursor.getPredefinedCursor( Cursor.DEFAULT_CURSOR ) );
353       }
354    }
355
356
357    public void setFile( File file )
358    {
359       _file = file;
360
361       // change title
362

363       getFrame().setTitle( getDocumentName() + " - " + APP_TITLE );
364    }
365
366
367    public String JavaDoc getDocumentName()
368    {
369       String JavaDoc name;
370
371       if( _file == null )
372          name = "Untitled";
373       else
374       {
375          name = _file.getName();
376
377          // add document's directory path to title
378
if( _file.getParentFile() != null )
379             name += " (" + _file.getParentFile().getAbsolutePath() + ")";
380       }
381
382       return name;
383    }
384
385
386    public RichTextBox( JFrame frame )
387    {
388       _frame = frame;
389
390       _source = new JTextArea();
391       _source.setFont( FontUtils.getMonospacedFont( 12 ) );
392
393       createEditor();
394
395       _chooser = new JFileChooser();
396       // todo: use prefs to store/retrieve file chooser dir
397
_chooser.setCurrentDirectory( new File( "." ) );
398
399       _addressDialog = new WebAddressDialog( getFrame(), APP_TITLE, _chooser );
400
401       _tab = new JTabbedPane( JTabbedPane.BOTTOM );
402       _tab.add( new JScrollPane( _editor ), "Normal" );
403       _tab.add( _sourceTab = new JScrollPane( _source ), "Source" );
404
405       _tab.addChangeListener( this );
406
407       setLayout( new BorderLayout() );
408       add( _tab, BorderLayout.CENTER );
409
410       GraphicsEnvironment genv = GraphicsEnvironment.getLocalGraphicsEnvironment();
411       _fontNames = genv.getAvailableFontFamilyNames();
412
413       _fontSizes = new String JavaDoc[]{"8", "9", "10", "11", "12",
414             "14", "16", "18", "20", "22", "24", "26", "28", "36", "48", "72"};
415
416       _fontChooser = new FontChooser( getFrame(), _fontNames, _fontSizes );
417
418       createActions();
419
420       // get toolbars
421
JToolBar mainToolBar = createMainToolBar();
422       JToolBar styleToolBar = createStyleToolBar();
423
424       JPanel toolBarPanel = new JPanel( new BorderLayout() );
425       toolBarPanel.add( mainToolBar, BorderLayout.NORTH );
426       toolBarPanel.add( styleToolBar, BorderLayout.SOUTH );
427
428       JMenuBar menuBar = createMenuBar();
429
430       JPanel topPanel = new JPanel( new BorderLayout() );
431       topPanel.add( menuBar, BorderLayout.NORTH );
432       topPanel.add( toolBarPanel, BorderLayout.SOUTH );
433
434       add( topPanel, BorderLayout.NORTH );
435
436       _editor.addCaretListener(
437          new CaretListener()
438          {
439             public void caretUpdate( CaretEvent ev )
440             {
441                syncStyleAttributes( ev.getDot() );
442             }
443          } );
444
445       // start off with an empty file
446
newFile();
447    }
448
449
450    private void createEditor()
451    {
452       _editor = new JTextPane();
453       _kit = new CustomHTMLEditorKit();
454       _editor.setEditorKit( _kit );
455       _doc = ( MutableHTMLDocument ) _kit.createDocument();
456       _styleSheet = _doc.getStyleSheet();
457       _editor.setDocument( _doc );
458
459       _doc.addDocumentListener( new UpdateListener() );
460       _isDirty = false;
461
462       // save and restore text selection
463
_editor.addFocusListener(
464          new FocusListener()
465          {
466             public void focusGained( FocusEvent ev )
467             {
468                int len = _editor.getDocument().getLength();
469
470                if( _xStart >= 0 && _xEnd >= 0 && _xStart < len && _xEnd < len )
471                {
472                   if( _editor.getCaretPosition() == _xStart )
473                   {
474                      _editor.setCaretPosition( _xEnd );
475                      _editor.moveCaretPosition( _xStart );
476                   }
477                   else
478                      _editor.select( _xStart, _xEnd );
479                }
480             }
481
482
483             public void focusLost( FocusEvent ev )
484             {
485                _xStart = _editor.getSelectionStart();
486                _xEnd = _editor.getSelectionEnd();
487             }
488          } );
489    }
490
491
492    private JMenuBar createMenuBar()
493    {
494       // create dynamic menus
495

496       _foregroundMenu = new ColorMenu( "Text Color" );
497       _foregroundMenu.setColor( _editor.getForeground() );
498       _foregroundMenu.setMnemonic( 'C' );
499       _foregroundMenu.addActionListener(
500          new ActionListener()
501          {
502             public void actionPerformed( ActionEvent ev )
503             {
504                MutableAttributeSet attr = new SimpleAttributeSet();
505                StyleConstants.setForeground( attr, _foregroundMenu.getColor() );
506                setStyleAttributes( attr );
507             }
508          } );
509
510       _foregroundMenu.addMenuListener(
511          new MenuListener()
512          {
513             public void menuSelected( MenuEvent ev )
514             {
515                int pos = _editor.getCaretPosition();
516                AttributeSet attr = _doc.getCharacterElement( pos ).getAttributes();
517                Color color = StyleConstants.getForeground( attr );
518                _foregroundMenu.setColor( color );
519             }
520
521
522             public void menuDeselected( MenuEvent ev ) { }
523
524
525             public void menuCanceled( MenuEvent ev ) { }
526          } );
527
528       JMenuBar menuBar = new JMenuBar();
529
530       JMenu fileMenu = new JMenu( "File" );
531       fileMenu.setMnemonic( 'F' );
532
533       JMenuItem mi = new JMenuItem( "New" );
534       mi.setMnemonic( 'N' );
535       mi.addActionListener( _cmdNew );
536       fileMenu.add( mi );
537
538       mi = new JMenuItem( "Open..." );
539       mi.setMnemonic( 'O' );
540       mi.addActionListener( _cmdOpen );
541       fileMenu.add( mi );
542
543       mi = new JMenuItem( "Save" );
544       mi.setMnemonic( 'S' );
545       mi.addActionListener( _cmdSave );
546       fileMenu.add( mi );
547
548       mi = new JMenuItem( "Save As..." );
549       mi.setMnemonic( 'A' );
550       mi.addActionListener( _cmdSaveAs );
551       fileMenu.add( mi );
552
553       fileMenu.addSeparator();
554
555       mi = new JMenuItem( "Page Layout..." );
556       mi.setMnemonic( 'Y' );
557       fileMenu.add( mi );
558
559       mi = new JMenuItem( "Print..." );
560       mi.setMnemonic( 'P' );
561       fileMenu.add( mi );
562
563       JMenu editMenu = new JMenu( "Edit" );
564       editMenu.setMnemonic( 'E' );
565
566       mi = new JMenuItem( "Undo" );
567       mi.setMnemonic( 'U' );
568       mi.addActionListener( _cmdUndo );
569       editMenu.add( mi );
570
571       mi = new JMenuItem( "Redo" );
572       mi.setMnemonic( 'R' );
573       mi.addActionListener( _cmdRedo );
574       editMenu.add( mi );
575
576       editMenu.addSeparator();
577
578       mi = new JMenuItem( "Cut" );
579       mi.setMnemonic( 'T' );
580       mi.addActionListener( _cmdCut );
581       editMenu.add( mi );
582
583       mi = new JMenuItem( "Copy" );
584       mi.setMnemonic( 'C' );
585       mi.addActionListener( _cmdCopy );
586       editMenu.add( mi );
587
588       mi = new JMenuItem( "Paste" );
589       mi.setMnemonic( 'P' );
590       mi.addActionListener( _cmdPaste );
591       editMenu.add( mi );
592
593       mi = new JMenuItem( "Delete" );
594       mi.setMnemonic( 'D' );
595       editMenu.add( mi );
596
597       editMenu.addSeparator();
598
599       mi = new JMenuItem( "Select All" );
600       mi.setMnemonic( 'S' );
601       editMenu.add( mi );
602
603       editMenu.addSeparator();
604
605       mi = new JMenuItem( "Find..." );
606       mi.setMnemonic( 'F' );
607       mi.addActionListener( _cmdFind );
608       editMenu.add( mi );
609
610       mi = new JMenuItem( "Replace..." );
611       mi.setMnemonic( 'R' );
612       mi.addActionListener( _cmdReplace );
613       editMenu.add( mi );
614
615       JMenu insertMenu = new JMenu( "Insert" );
616       insertMenu.setMnemonic( 'I' );
617
618       mi = new JMenuItem( "Hyperlink..." );
619       mi.setMnemonic( 'L' );
620       mi.addActionListener( _cmdInsertHyperlink );
621       insertMenu.add( mi );
622
623       mi = new JMenuItem( "Image..." );
624       mi.setMnemonic( 'I' );
625       mi.addActionListener( _cmdInsertImage );
626       insertMenu.add( mi );
627
628       JMenu formatMenu = new JMenu( "Format" );
629       formatMenu.setMnemonic( 'F' );
630
631       mi = new JMenuItem( "Font..." );
632       mi.setMnemonic( 'F' );
633       mi.addActionListener( _cmdFont );
634       formatMenu.add( mi );
635
636       formatMenu.add( _foregroundMenu );
637
638       menuBar.add( fileMenu );
639       menuBar.add( editMenu );
640       menuBar.add( insertMenu );
641       menuBar.add( formatMenu );
642
643       return menuBar;
644    }
645
646
647    private JToolBar createMainToolBar()
648    {
649       JToolBar toolBar = new JToolBar();
650       toolBar.setFloatable( false );
651
652       JButton bt = new JButton( "New" );
653       bt.addActionListener( _cmdNew );
654       bt.setToolTipText( "New File" );
655       toolBar.add( bt );
656
657       bt = new JButton( "Open" );
658       bt.addActionListener( _cmdOpen );
659       bt.setToolTipText( "Open File" );
660       toolBar.add( bt );
661
662       bt = new JButton( "Save" );
663       bt.addActionListener( _cmdSave );
664       bt.setToolTipText( "Save File" );
665       toolBar.add( bt );
666
667       toolBar.addSeparator();
668
669       bt = new JButton( "Cut" );
670       bt.addActionListener( _cmdCut );
671       bt.setToolTipText( "Cut Selection To Clipboard" );
672       toolBar.add( bt );
673
674       bt = new JButton( "Copy" );
675       bt.addActionListener( _cmdCopy );
676       bt.setToolTipText( "Copy Selection To Clipboard" );
677       toolBar.add( bt );
678
679       bt = new JButton( "Paste" );
680       bt.addActionListener( _cmdPaste );
681       bt.setToolTipText( "Paste From Clipboard" );
682       toolBar.add( bt );
683
684       return toolBar;
685    }
686
687
688    private JToolBar createStyleToolBar()
689    {
690       JToolBar toolBar = new JToolBar();
691       toolBar.setFloatable( false );
692
693       _stylesCombo = new JComboBox( STYLES );
694       _stylesCombo.setMaximumSize( new Dimension( 150, 23 ) );
695       _stylesCombo.setRequestFocusEnabled( false );
696       _stylesCombo.addActionListener(
697          new ActionListener()
698          {
699             public void actionPerformed( ActionEvent e )
700             {
701                HtmlStyle style = ( HtmlStyle ) _stylesCombo.getSelectedItem();
702                if( style == null )
703                   return;
704
705                MutableAttributeSet attr = new SimpleAttributeSet();
706                attr.addAttribute( StyleConstants.NameAttribute, style.getTag() );
707                setStyleAttributes( attr, true );
708                _editor.grabFocus();
709             }
710          } );
711
712       _fontNamesCombo = new JComboBox( _fontNames );
713       _fontNamesCombo.setMaximumSize( new Dimension( 200, 23 ) );
714
715       _fontNamesCombo.addActionListener(
716          new ActionListener()
717          {
718             public void actionPerformed( ActionEvent ev )
719             {
720                _fontName = _fontNamesCombo.getSelectedItem().toString();
721                MutableAttributeSet attr = new SimpleAttributeSet();
722                StyleConstants.setFontFamily( attr, _fontName );
723                setStyleAttributes( attr );
724                _editor.grabFocus();
725             }
726          } );
727
728       _fontSizesCombo = new JComboBox( _fontSizes );
729       _fontSizesCombo.setMaximumSize( new Dimension( 50, 23 ) );
730       _fontSizesCombo.setEditable( true );
731
732       _fontSizesCombo.addActionListener(
733          new ActionListener()
734          {
735             public void actionPerformed( ActionEvent ev )
736             {
737                int fontSize = 0;
738                try
739                {
740                   fontSize = Integer.parseInt( _fontSizesCombo.getSelectedItem().toString() );
741                }
742                catch( NumberFormatException JavaDoc nex )
743                {
744                   Status.error( "*** selected font size is not a number: " + nex.toString() );
745                   return;
746                }
747
748                _fontSize = fontSize;
749                MutableAttributeSet attr = new SimpleAttributeSet();
750                StyleConstants.setFontSize( attr, fontSize );
751                setStyleAttributes( attr );
752                _editor.grabFocus();
753             }
754          } );
755
756       _boldButton = new JToggleButton( "Bold" );
757       _boldButton.addActionListener(
758          new ActionListener()
759          {
760             public void actionPerformed( ActionEvent ev )
761             {
762                MutableAttributeSet attr = new SimpleAttributeSet();
763                StyleConstants.setBold( attr, _boldButton.isSelected() );
764                setStyleAttributes( attr );
765                _editor.grabFocus();
766             }
767          } );
768
769       _italicButton = new JToggleButton( "Italic" );
770       _italicButton.addActionListener(
771          new ActionListener()
772          {
773             public void actionPerformed( ActionEvent ev )
774             {
775                MutableAttributeSet attr = new SimpleAttributeSet();
776                StyleConstants.setItalic( attr, _italicButton.isSelected() );
777                setStyleAttributes( attr );
778                _editor.grabFocus();
779             }
780          } );
781
782       _underlineButton = new JToggleButton( "Underline" );
783       _underlineButton.addActionListener(
784          new ActionListener()
785          {
786             public void actionPerformed( ActionEvent ev )
787             {
788                MutableAttributeSet attr = new SimpleAttributeSet();
789                StyleConstants.setUnderline( attr, _underlineButton.isSelected() );
790                setStyleAttributes( attr );
791                _editor.grabFocus();
792             }
793          } );
794
795       toolBar.add( _stylesCombo );
796       toolBar.addSeparator();
797       toolBar.add( _boldButton );
798       toolBar.add( _italicButton );
799       toolBar.add( _underlineButton );
800       toolBar.addSeparator();
801       toolBar.add( _fontNamesCombo );
802       toolBar.add( _fontSizesCombo );
803       toolBar.addSeparator();
804       toolBar.add( new JButton( "Left" ) );
805       toolBar.add( new JButton( "Center" ) );
806       toolBar.add( new JButton( "Right" ) );
807       toolBar.add( new JButton( "Justify" ) );
808
809       return toolBar;
810    }
811
812
813    private void createActions()
814    {
815       _cmdOpen =
816          new SimpleAction( "Open..." )
817          {
818             public void execute()
819             {
820                openFile();
821             }
822          };
823
824       _cmdSaveAs =
825          new SimpleAction( "Save As..." )
826          {
827             public void execute()
828             {
829                saveFileAs();
830             }
831          };
832
833       _cmdSave =
834          new SimpleAction( "Save" )
835          {
836             public void execute()
837             {
838                saveFile();
839             }
840          };
841
842       _cmdNew =
843          new SimpleAction( "New" )
844          {
845             public void execute()
846             {
847                if( !canCloseDocument() )
848                   return;
849
850                newFile();
851             }
852          };
853
854       _cmdCut =
855          new SimpleAction( "Cut" )
856          {
857             public void execute()
858             {
859                getEditor().cut();
860             }
861          };
862
863       _cmdCopy =
864          new SimpleAction( "Copy" )
865          {
866             public void execute()
867             {
868                getEditor().copy();
869             }
870          };
871
872       _cmdPaste =
873          new SimpleAction( "Paste" )
874          {
875             public void execute()
876             {
877                getEditor().paste();
878             }
879          };
880
881       _cmdUndo =
882          new SimpleAction( "Undo" )
883          {
884             public void execute()
885             {
886                onUndo();
887             }
888          };
889
890       _cmdRedo =
891          new SimpleAction( "Redo" )
892          {
893             public void execute()
894             {
895                onRedo();
896             }
897          };
898
899       _cmdInsertImage =
900          new SimpleAction( "Image..." )
901          {
902             public void execute()
903             {
904                if( _addressDialog.showDialog(
905                      "Please enter the image's web address (URL):", "" ) != JOptionPane.OK_OPTION )
906                   return;
907
908                String JavaDoc url = _addressDialog.getAddress();
909
910                try
911                {
912                   ImageIcon icon = new ImageIcon( new URL( url ) );
913
914                   int w = icon.getIconWidth();
915                   int h = icon.getIconHeight();
916
917                   if( w <= 0 || h <= 0 )
918                   {
919                      Status.error( "*** failed to read image using URL " + url );
920                      return;
921                   }
922
923                   MutableAttributeSet attr = new SimpleAttributeSet();
924                   attr.addAttribute( StyleConstants.NameAttribute, HTML.Tag.IMG );
925                   attr.addAttribute( HTML.Attribute.SRC, url );
926                   attr.addAttribute( HTML.Attribute.HEIGHT, Integer.toString( h ) );
927                   attr.addAttribute( HTML.Attribute.WIDTH, Integer.toString( w ) );
928
929                   int p = _editor.getCaretPosition();
930                   _doc.insertString( p, " ", attr );
931                }
932                catch( Exception JavaDoc ex )
933                {
934                   Status.error( "*** failed to insert image: " + ex.toString() );
935                }
936             }
937          };
938
939       _cmdInsertHyperlink =
940          new SimpleAction( "Hyperlink..." )
941          {
942             public void execute()
943             {
944                String JavaDoc oldHref = null;
945                int p = _editor.getCaretPosition();
946                AttributeSet attr = _doc.getCharacterElement( p ).getAttributes();
947                AttributeSet anchor = ( AttributeSet ) attr.getAttribute( HTML.Tag.A );
948                if( anchor != null )
949                   oldHref = ( String JavaDoc ) anchor.getAttribute( HTML.Attribute.HREF );
950
951                if( _addressDialog.showDialog(
952                      "Please enter the hyperlink's web address (URL):", oldHref ) != JOptionPane.OK_OPTION )
953                   return;
954
955                String JavaDoc newHref = _addressDialog.getAddress();
956
957                SimpleAttributeSet attr2 = new SimpleAttributeSet();
958                attr2.addAttribute( StyleConstants.NameAttribute, HTML.Tag.A );
959                attr2.addAttribute( HTML.Attribute.HREF, newHref );
960                setStyleAttributes( attr2, true );
961                _editor.grabFocus();
962             }
963          };
964
965       _cmdFont =
966          new SimpleAction( "Font..." )
967          {
968             public void execute()
969             {
970                AttributeSet attr = _doc.getCharacterElement(
971                      _editor.getCaretPosition() ).getAttributes();
972                _fontChooser.setAttributes( attr );
973
974                WindowUtils.centerOnWindow( getFrame(), _fontChooser );
975                _fontChooser.show();
976
977                if( _fontChooser.getOption() == JOptionPane.OK_OPTION )
978                {
979                   setStyleAttributes( _fontChooser.getAttributes() );
980                   syncStyleAttributes( _editor.getCaretPosition() );
981                }
982             }
983          };
984
985       _cmdFind =
986          new SimpleAction( "Find..." )
987          {
988             public void execute()
989             {
990                if( _findDialog == null )
991                   _findDialog = new FindDialog( getFrame(), 0 );
992                else
993                   _findDialog.setSelectedTabIndex( 0 );
994
995                WindowUtils.centerOnWindow( getFrame(), _findDialog );
996                _findDialog.show();
997             }
998          };
999
1000      _cmdReplace =
1001         new SimpleAction( "Replace..." )
1002         {
1003            public void execute()
1004            {
1005               if( _findDialog == null )
1006                  _findDialog = new FindDialog( getFrame(), 1 );
1007               else
1008                  _findDialog.setSelectedTabIndex( 1 );
1009
1010               WindowUtils.centerOnWindow( getFrame(), _findDialog );
1011               _findDialog.show();
1012            }
1013         };
1014   }
1015
1016
1017   private void onUndo()
1018   {
1019      try
1020      {
1021         _undoManager.undo();
1022      }
1023      catch( CannotUndoException cex )
1024      {
1025         Status.error( "*** unable to undo: " + cex.toString() );
1026      }
1027      updateUndoMenus();
1028   }
1029
1030
1031   private void onRedo()
1032   {
1033      try
1034      {
1035         _undoManager.redo();
1036      }
1037      catch( CannotRedoException cex )
1038      {
1039         Status.error( "*** undable to redo: " + cex.toString() );
1040      }
1041      updateUndoMenus();
1042   }
1043
1044
1045   private void updateUndoMenus()
1046   {
1047      if( _undoManager.canUndo() )
1048      {
1049         _cmdUndo.setEnabled( true );
1050         _cmdUndo.putValue( Action.NAME, _undoManager.getUndoPresentationName() );
1051      }
1052      else
1053      {
1054         _cmdUndo.setEnabled( false );
1055         _cmdUndo.putValue( Action.NAME, "Undo" );
1056      }
1057
1058      if( _undoManager.canRedo() )
1059      {
1060         _cmdRedo.setEnabled( true );
1061         _cmdRedo.putValue( Action.NAME, _undoManager.getRedoPresentationName() );
1062      }
1063      else
1064      {
1065         _cmdRedo.setEnabled( false );
1066         _cmdRedo.putValue( Action.NAME, "Redo" );
1067      }
1068   }
1069
1070
1071   class Undoer implements UndoableEditListener
1072   {
1073      public Undoer()
1074      {
1075         _undoManager.die();
1076         updateUndoMenus();
1077      }
1078
1079
1080      public void undoableEditHappened( UndoableEditEvent ev )
1081      {
1082         _undoManager.addEdit( ev.getEdit() );
1083         updateUndoMenus();
1084      }
1085   }
1086
1087
1088   private void syncStyleAttributes( int pos )
1089   {
1090      _skipUpdate = true;
1091
1092      Element ep = _doc.getParagraphElement( pos );
1093      HTML.Tag attrName = ( HTML.Tag ) ep.getAttributes().getAttribute( StyleConstants.NameAttribute );
1094      int index = -1;
1095      if( attrName != null )
1096      {
1097         for( int i = 0; i < STYLES.length; i++ )
1098         {
1099            if( STYLES[i].getTag().equals( attrName ) )
1100            {
1101               index = i;
1102               break;
1103            }
1104         }
1105      }
1106      _stylesCombo.setSelectedIndex( index );
1107
1108      AttributeSet attr = _doc.getCharacterElement( pos ).getAttributes();
1109      String JavaDoc fontName = StyleConstants.getFontFamily( attr );
1110      if( !_fontName.equals( fontName ) )
1111      {
1112         _fontName = fontName;
1113         _fontNamesCombo.setSelectedItem( _fontName );
1114      }
1115
1116      int fontSize = StyleConstants.getFontSize( attr );
1117      if( _fontSize != fontSize )
1118      {
1119         _fontSize = fontSize;
1120         _fontSizesCombo.setSelectedItem( "" + _fontSize );
1121      }
1122
1123      boolean isBold = StyleConstants.isBold( attr );
1124      if( isBold != _boldButton.isSelected() )
1125         _boldButton.setSelected( isBold );
1126
1127      boolean isItalic = StyleConstants.isItalic( attr );
1128      if( isItalic != _italicButton.isSelected() )
1129         _italicButton.setSelected( isItalic );
1130
1131      boolean isUnderline = StyleConstants.isUnderline( attr );
1132      if( isUnderline != _underlineButton.isSelected() )
1133         _underlineButton.setSelected( isUnderline );
1134
1135      Style style = _doc.getLogicalStyle( pos );
1136      if( style != null )
1137      {
1138         String JavaDoc styleName = style.getName();
1139         _stylesCombo.setSelectedItem( styleName );
1140      }
1141      else
1142      {
1143         // todo: select to no-style
1144
}
1145
1146      _skipUpdate = false;
1147   }
1148
1149
1150   private void setStyleAttributes( AttributeSet attr )
1151   {
1152      setStyleAttributes( attr, false );
1153   }
1154
1155
1156   private void setStyleAttributes( AttributeSet attr, boolean setParagraphAttributes )
1157   {
1158      // only set style attributes for user selections (not for syncing)
1159
if( _skipUpdate )
1160         return;
1161
1162      int xStart = _editor.getSelectionStart();
1163      int xEnd = _editor.getSelectionEnd();
1164
1165      if( !_editor.hasFocus() )
1166      {
1167         xStart = _xStart;
1168         xEnd = _xEnd;
1169      }
1170
1171      if( setParagraphAttributes )
1172         _doc.setParagraphAttributes( xStart, xEnd - xStart, attr, false );
1173      else if( xStart != xEnd )
1174         _doc.setCharacterAttributes( xStart, xEnd - xStart, attr, false );
1175      else
1176         // if selection is empty, use style attributes for text yet to be entered
1177
_kit.getInputAttributes().addAttributes( attr );
1178   }
1179
1180
1181   boolean canCloseDocument()
1182   {
1183      if( !_isDirty )
1184         return true;
1185
1186      int result = JOptionPane.showConfirmDialog( this,
1187            "Save changes to " + getDocumentName() + " before closing?", APP_TITLE,
1188            JOptionPane.YES_NO_CANCEL_OPTION,
1189            JOptionPane.INFORMATION_MESSAGE );
1190
1191      switch ( result )
1192      {
1193         case JOptionPane.YES_OPTION:
1194            if( !saveFile() )
1195               // document successfully saved?
1196
return false;
1197            else
1198               return true;
1199         case JOptionPane.NO_OPTION:
1200            return true;
1201         case JOptionPane.CANCEL_OPTION:
1202         default:
1203            return false;
1204      }
1205   }
1206
1207
1208   class UpdateListener implements DocumentListener
1209   {
1210      public void insertUpdate( DocumentEvent ev )
1211      {
1212         _isDirty = true;
1213      }
1214
1215
1216      public void removeUpdate( DocumentEvent ev )
1217      {
1218         _isDirty = true;
1219      }
1220
1221
1222      public void changedUpdate( DocumentEvent ev )
1223      {
1224         _isDirty = true;
1225      }
1226   }
1227
1228
1229   Component _prevSelectedTab;
1230   Component _selectedTab;
1231
1232
1233   public void stateChanged( ChangeEvent ev )
1234   {
1235      T.debug( "tab changed - user clicked on tab" );
1236
1237      // todo: reset tab selections in onOpen and onNew
1238

1239      _prevSelectedTab = _selectedTab;
1240      _selectedTab = _tab.getSelectedComponent();
1241
1242      if( _prevSelectedTab == _sourceTab )
1243      {
1244         // todo: add isDirty() check for source editor
1245

1246         try
1247         {
1248            StringReader reader = new StringReader( _source.getText() );
1249
1250            _doc = ( MutableHTMLDocument ) _kit.createDocument();
1251            _styleSheet = _doc.getStyleSheet();
1252            _kit.read( reader, _doc, 0 );
1253            reader.close();
1254
1255            _editor.setDocument( _doc );
1256            _editor.revalidate();
1257            _editor.repaint();
1258
1259            _isDirty = true;
1260         }
1261         catch( Exception JavaDoc ex )
1262         {
1263            Status.error( "*** failed to update HTML document using HTML source: " + ex.toString() );
1264         }
1265      }
1266      else if( _selectedTab == _sourceTab )
1267      {
1268         try
1269         {
1270            _source.setText( "" );
1271
1272            StringWriter writer = new StringWriter();
1273            _kit.write( writer, _doc, 0, _doc.getLength() );
1274            writer.close();
1275
1276            _source.setText( writer.toString() );
1277         }
1278         catch( Exception JavaDoc ex )
1279         {
1280            Status.error( "*** failed to get HTML source: " + ex.toString() );
1281         }
1282      }
1283   }
1284}
1285
Popular Tags