Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: jplot/SimpleEditor.java


1   /*
2    * SimpleEditor  -- Originally developped for use by JPlot and JChess,
3    *                  this class has evolved to a quite useful but still
4    *                  simple data- and text editor.
5    * 
6    * Copyright (C) 2001 Jan van der Lee
7    *
8    * This program is free software; you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License
10   * as published by the Free Software Foundation; either version 2
11   * of the License, or (at your option) any later version.
12   *
13   * This program is distributed in the hope that it will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   * GNU General Public License for more details.
17   * 
18   * You should have received a copy of the GNU General Public License
19   * along with this program; if not, write to the Free Software
20   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
21   * 02111-1307, USA.
22   *
23   * Send bugs, suggestions or queries to <jplot@cig.ensmp.fr>
24   * The latest releases are found at 
25   * http://www.cig.ensmp.fr/~vanderlee/jplot.html
26   *
27   * Initally developed for use by the Centre d'Informatique Geologique 
28   * Ecole des Mines de Paris, Fontainebleau, France.
29   */
30  
31  package jplot;
32  
33  import javax.swing.*;
34  import javax.swing.border.*;
35  import javax.swing.text.*;
36  import javax.swing.filechooser.*;
37  
38  import java.io.*;
39  import java.util.*;
40  import java.awt.*;
41  import java.awt.event.*;
42  import java.awt.print.*;
43  import java.net.*;
44  
45  /** 
46   * The class shows a frame which enables to look at and eventually edit
47   * a file, any type of file. Build in a JPanel, so someone can reuse
48   * the editor in another class.
49   */
50  public class SimpleEditor extends JPanel {
51  
52    private JEditorPane textArea;
53    private File file;
54    private JFrame frame;
55    private String text;
56    private JComboBox fonts,sizes;
57    private int size, style;
58    private Font currentFont = new Font("Monospaced",Font.PLAIN,12);
59    private Color currentColor = Color.black;
60    private SmallToggleButton b_bold, b_italic;  
61    private JScrollPane scrollpane;
62    private boolean textChanged;
63    private JPanel thisPanel;
64    private JPanel parent; 
65    private FindPanel findPanel;
66    private boolean isEditable;
67  
68    private Dimension panelSize;
69  
70    private final DefaultHighlighter.DefaultHighlightPainter g;
71    //final JobAttributes theJobAttribs = new JobAttributes();
72    //final PageAttributes thePageAttribs = new PageAttributes();
73    
74    /**
75     * Principal constructor,
76     * builds the panel which includes the report as text.
77     * @param parent parent
78     * @param title title of the editor
79     * @param idEditable true if the editor is actually editable
80     * @param width width in pixels of the panel
81     * @param height height in pixels of the panel
82     */
83    public SimpleEditor(JPanel parent, String title, boolean isEditable,
84            int width, int height) {
85      setLayout(new BorderLayout());
86      setBorder(new EtchedBorder());
87      size = 12;
88      style = Font.PLAIN;
89      thisPanel = this;
90      this.parent = parent;
91      this.isEditable = isEditable;
92      panelSize = new Dimension(width,height);
93  
94      JPanel mainPanel = new JPanel(new BorderLayout());
95      EmptyBorder eb = new EmptyBorder(2,2,2,2);
96      BevelBorder bb = new BevelBorder(BevelBorder.LOWERED);
97      mainPanel.setBorder(new CompoundBorder(eb,bb));
98  
99      textArea = new JEditorPane();
100     textArea.setEditable(isEditable);
101     textArea.setFont(currentFont);
102     scrollpane = new JScrollPane(textArea);
103     mainPanel.add(scrollpane,BorderLayout.CENTER);
104 
105     JToolBar toolbar = new JToolBar();
106     ImageIcon icon = getImageIcon(parent,"exit.jpg");
107     Action action = new AbstractAction("Close",icon) {
108       public void actionPerformed(ActionEvent e) {
109   frame.dispose();
110       }
111     };
112     addButton(toolbar,action,"Close this panel");
113 
114     icon = getImageIcon(parent,"Save24.gif");
115     action = new AbstractAction("Save",icon) {
116       public void actionPerformed(ActionEvent e) {
117   save();
118       }
119     };
120     addButton(toolbar,action,"Save the current file");
121 
122     icon = getImageIcon(parent,"Print24.gif");
123     action = new AbstractAction("Print",icon) {
124   public void actionPerformed(ActionEvent e) {
125     printText();
126   }
127       };
128     addButton(toolbar,action,"Print the current content");
129     toolbar.addSeparator();
130       
131     icon = getImageIcon(parent,"Refresh24.gif");
132     action = new AbstractAction("Reload",icon) {
133       public void actionPerformed(ActionEvent e) {
134   refresh(file);
135       }
136     };
137     addButton(toolbar,action,"Reload the current file");
138 
139     icon = getImageIcon(parent,"Find24.gif");
140     action = new AbstractAction("Find",icon) {
141       public void actionPerformed(ActionEvent e) {
142   find();
143       }
144     };
145     addButton(toolbar,action,"Find a piece of text in this file");
146 
147     toolbar.addSeparator();
148     fonts = new JComboBox(JPlot.fontNames);
149     fonts.setMaximumSize(fonts.getPreferredSize());
150     fonts.setEditable(true);
151     fonts.setSelectedItem("Monospaced");
152     fonts.addActionListener(new ActionListener() {
153       public void actionPerformed(ActionEvent e) {
154   setSelectedFont();
155       }
156     });
157     toolbar.add(fonts);
158 
159     toolbar.addSeparator();
160     sizes = new JComboBox(new String[] {"7","8","9","10","11","12","14","16","18","20","22","26","32"});
161     sizes.setMaximumSize(sizes.getPreferredSize());
162     sizes.setEditable(true);
163     sizes.setSelectedItem("12");
164     sizes.addActionListener(new ActionListener() {
165       public void actionPerformed(ActionEvent e) {
166   int fontSize = 0;
167   try {
168     fontSize = Integer.parseInt(sizes.getSelectedItem().toString());
169   } 
170   catch (NumberFormatException ex) {return;}
171   size = fontSize;
172   setSelectedFont();
173       }
174     });
175     toolbar.add(sizes);
176 
177     toolbar.addSeparator();
178     icon = getImageIcon(parent,"Bold16.gif");
179     b_bold = new SmallToggleButton(false,icon,icon,"Bold font");
180     b_bold.addActionListener(new ActionListener() {
181       public void actionPerformed(ActionEvent e) {
182   setSelectedFont();
183       }
184     });
185     toolbar.add(b_bold);
186     b_bold.resetBorder();
187     icon = getImageIcon(parent,"Italic16.gif");
188     b_italic = new SmallToggleButton(false,icon,icon,"Italic font");
189     b_italic.addActionListener(new ActionListener() {
190       public void actionPerformed(ActionEvent e) {
191   setSelectedFont();
192       }
193     });
194     toolbar.add(b_italic);
195     b_italic.resetBorder();
196     mainPanel.add(toolbar,BorderLayout.NORTH);
197 
198     add(makeMenuBar(),BorderLayout.NORTH);
199     add(mainPanel,BorderLayout.CENTER);
200 
201     textChanged = false;
202     textArea.setSelectionColor(new Color(248,248,215));
203     g = new DefaultHighlighter.DefaultHighlightPainter(new Color(248,248,215));
204     
205     frame = new JFrame(title);
206     frame.getContentPane().add(this);
207     frame.pack();
208   }
209 
210   /**
211    * Constructor, builds a simple editor/viewer with default dimensions.
212    * @param parent parent
213    * @param title title of the editor
214    * @param idEditable true if the editor is actually editable
215    */
216   public SimpleEditor(JPanel parent, String title, boolean isEditable) {
217     this(parent,title,isEditable,640,550);
218   }
219 
220   /**
221    * Add a button of type SmallButton to the toolbar.
222    * Done here to bypass a bug in jdk 1.4 which resets the
223    * border of a button to some default value when added to the
224    * toolbar.
225    */
226   private void addButton(JToolBar toolbar, Action action, String tip) {
227     SmallButton sb = new SmallButton(action,tip);
228     toolbar.add(sb);
229     sb.resetBorder();    // needed to bypass a bug (since jdk1.4)
230   }
231 
232   /*
233    * Returns an image which is found in a valid image URL. The basis
234    * of the url is where this class is created.
235    * @param parent the parent class
236    * @param name name of the image
237    * @return an image or icon */
238   private ImageIcon getImageIcon(JPanel parent, String name) {
239     ImageIcon im=null;
240     try {
241       URL imageURL = parent.getClass().getResource("/images/" + name);
242       Toolkit tk = Toolkit.getDefaultToolkit();
243       im = new ImageIcon(tk.createImage(imageURL));
244     }
245     catch(Exception e) {
246       Utils.oops(frame,"Impossible to load the TextEditor's icon '" + 
247      name + "'.\nSomething's wrong with the installation.");
248     }
249     return im;
250   }
251 
252   /**
253    * Builds the menubar.
254    *
255    * @return an instance of a JMenuBar class
256    */
257   JMenuBar makeMenuBar() {
258     JMenuItem mi;
259     JMenuBar menuBar = new JMenuBar();
260 
261     // make the file-menu:
262     JMenu fm = (JMenu) menuBar.add(new JMenu("File"));
263     fm.setMnemonic('F');
264     ImageIcon icon = getImageIcon(parent,"Open16.gif");
265     mi = (JMenuItem) fm.add(new JMenuItem("Open...",icon));
266     mi.setMnemonic('O');
267     mi.addActionListener(new ActionListener() {
268       public void actionPerformed(ActionEvent e) {
269   openFile();
270       }
271     });
272     icon = getImageIcon(parent,"Save16.gif");
273     mi = (JMenuItem) fm.add(new JMenuItem("Save...",icon));
274     mi.setMnemonic('S');
275     mi.addActionListener(new ActionListener() {
276       public void actionPerformed(ActionEvent e) {
277   save();
278       }
279     });
280     icon = getImageIcon(parent,"SaveAs16.gif");
281     mi = (JMenuItem) fm.add(new JMenuItem("Save as...",icon));
282     mi.setMnemonic('A');
283     mi.addActionListener(new ActionListener() {
284       public void actionPerformed(ActionEvent e) {
285   saveAs();
286       }
287     });
288     fm.addSeparator();
289     icon = getImageIcon(parent,"Print16.gif");
290     mi = (JMenuItem) fm.add(new JMenuItem("Print",icon));
291     mi.setMnemonic('P');
292     mi.addActionListener(new ActionListener() {
293       public void actionPerformed(ActionEvent e) {
294   printText();
295       }
296     });
297 
298     fm.addSeparator();
299     mi = (JMenuItem) fm.add(new JMenuItem("Quit"));
300     mi.setMnemonic('Q');
301     mi.addActionListener(new ActionListener() {
302       public void actionPerformed(ActionEvent e) {
303   dispose();
304       }
305     });
306 
307     // make the edit-menu:
308     //--------------------
309     JMenu edit = (JMenu) menuBar.add(new JMenu("Edit"));
310     edit.setMnemonic('E');
311     icon = getImageIcon(parent,"Refresh16.gif");
312     mi = (JMenuItem) edit.add(new JMenuItem("Reload",icon));
313     mi.setMnemonic('R');
314     mi.addActionListener(new ActionListener() {
315       public void actionPerformed(ActionEvent e) {
316   refresh(file);
317       }
318     });
319     icon = getImageIcon(parent,"Find16.gif");
320     mi = (JMenuItem) edit.add(new JMenuItem("Find",icon));
321     mi.setMnemonic('F');
322     mi.addActionListener(new ActionListener() {
323       public void actionPerformed(ActionEvent e) {
324   find();
325       }
326     });
327     return menuBar;
328   }  
329 
330   /*
331    * Repaints the text area with the currently selected font.
332    */
333   private void setSelectedFont() {
334     if (b_bold.isSelected()) {
335       if (b_italic.isSelected()) {
336   style = Font.BOLD | Font.ITALIC;
337       }
338       else style = Font.BOLD;
339     }
340     else if (b_italic.isSelected()) style = Font.ITALIC;
341     else style = Font.PLAIN;
342     currentFont = new Font((String)fonts.getSelectedItem(),style,size);
343     textArea.setFont(currentFont);
344     textArea.repaint();
345   }
346 
347   /*
348    * Converts the content of the file to a string.
349    */
350   private void fileToString() {
351     StringBuffer sb = new StringBuffer();
352     if (file.exists() && file.canRead()) {
353       try {
354   BufferedReader in = new BufferedReader(new FileReader(file));
355   String s;    
356   while ((s=in.readLine()) != null) {
357     sb.append(s).append("\n");
358   }
359       }
360       catch (IOException e) {}
361     }
362     text = sb.toString().trim();
363   }
364 
365   /**
366    * Clears the current canvas
367    */
368   public void clear() {
369     try {
370       Document d = textArea.getDocument();
371       d.remove(0,d.getLength());
372     }
373     catch (BadLocationException e) {}
374   }
375 
376   /**
377    * Refreshes the text, updates with the content of
378    * the current outputfile.
379    * @param f file containing the report
380    */
381   public void refresh(File f) {
382     //setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
383     file = f;
384     fileToString();
385     refresh(text);
386     //setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
387   }
388   
389   /**
390    * Refreshes the text, updates with the content of
391    * the current viewer/editor.
392    * @param text text to display
393    */
394   public void refresh(String s) {
395     if (s.startsWith("<!DOC") || s.startsWith("<!doc") ||
396   s.startsWith("<html>") || s.startsWith("<HTML>")) {
397       textArea.setContentType("text/html");
398     }
399     else textArea.setContentType("text/plain");
400     textArea.setText(s);
401     if (isEditable) textArea.setCaretPosition(0);
402     textArea.revalidate();
403   }
404 
405   /**
406    * Saves the text after an edit to the current file.
407    */
408   public void save() {
409     if (file == null) return;
410     try {
411       PrintWriter pw = new PrintWriter(new FileWriter(file));
412       pw.println(textArea.getText());
413       pw.close();
414     }
415     catch (IOException e) {
416       Utils.bummer(frame,"Impossible to write to " + file.toString());
417     }    
418   }
419 
420   /**
421    * Saves the text after an edit to a new file.
422    */
423   public void saveAs() {
424     JFileChooser chooser = new JFileChooser(new File("."));
425     javax.swing.filechooser.FileFilter ff = new DataFileFilter();
426     chooser.addChoosableFileFilter(ff);
427     chooser.setFileFilter(ff);
428     if (chooser.showDialog(thisPanel,"Save As") == 0) {
429       file = chooser.getSelectedFile();
430       if (file.exists()) {
431   int res = JOptionPane.showConfirmDialog(thisPanel,
432             "The file exists: do you want to overwrite this file?","",JOptionPane.YES_NO_OPTION);
433   if (res == JOptionPane.NO_OPTION) return;
434       }
435       save();
436     }
437   }
438 
439   private class DataFileFilter extends javax.swing.filechooser.FileFilter {
440     public boolean accept(File pathname) {
441       return pathname.isDirectory() || 
442   pathname.getName().endsWith(".res") ||
443   pathname.getName().endsWith(".dat");
444     }
445     public String getDescription() {
446       return "data files (*.res, *.dat)";
447     }
448   }
449 
450   /**
451    * Saves the text after an edit to a new file.
452    */
453   public void openFile() {
454     JFileChooser chooser = new JFileChooser(new File("."));
455     javax.swing.filechooser.FileFilter ff = new DataFileFilter();
456     chooser.addChoosableFileFilter(ff);
457     chooser.setFileFilter(ff);
458     if (chooser.showOpenDialog(thisPanel) == 0) {
459       if (textChanged) {
460   int result = JOptionPane.showConfirmDialog(thisPanel,"The file has been changed, shouldn't we save it first?");
461   if (result == JOptionPane.CANCEL_OPTION) return;
462   else if (result == JOptionPane.YES_OPTION) save();
463       }
464       refresh(chooser.getSelectedFile());
465     }
466   }
467 
468   /**
469    * Disposes the frame. Prefer hide(), but then, show doesn't
470    * work with my current jdk (it pops the frame up iconified).
471    */
472   public void dispose() {
473     clear();
474     //frame.hide();
475     frame.dispose();
476   }
477 
478   /*
479    * Print a file. The problem is that this thing only works for 
480    * a file, not for a text...
481    */
482   private void printText() {
483     setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
484     Thread t = new Thread() {
485   public void run() {
486     PrinterJob job = PrinterJob.getPrinterJob();
487     if (job != null) {
488       PageFormat pf = new PageFormat();
489       PrintTextPainter ptp = new PrintTextPainter(text);
490       ptp.setFont(currentFont);
491       ptp.setForeground(currentColor);
492       job.setPrintable(ptp,pf);
493       job.setCopies(1);
494       if (job.printDialog()) {
495         try {job.print();}
496         catch (Exception e) {
497     System.out.println("Oops, error while printing...");
498         }
499       }
500     }
501   }
502       };
503     t.start();
504     setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
505   }
506 
507   /*
508    * Print a file. The problem is that this thing only works for 
509    * a file, not for a text...
510    */
511   private void printFile() {
512     setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
513     Thread t = new Thread() {
514   public void run() {
515     PrinterJob job = PrinterJob.getPrinterJob();
516     if (job != null) {
517       PageFormat pf = new PageFormat();
518       //PageFormat pf = job.pageDialog(job.defaultPage());
519       //Paper paper = new Paper();
520       //paper.setSize(597,844);   // should be an A4
521       //pf.setPaper(paper);
522       PrintFilePainter pfp = new PrintFilePainter(file.toString());
523       pfp.setFont(currentFont);
524       pfp.setForeground(currentColor);
525       job.setPrintable(pfp,pf);
526       job.setCopies(1);
527       if (job.printDialog()) {
528         try {job.print();}
529         catch (Exception e) {}
530       }
531     }
532   }
533       };
534     t.start();
535     setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
536   }
537 
538   /**
539    * @return the preferred size of this panel.
540    */
541   public Dimension getPreferredSize() {
542     return panelSize;
543   }
544 
545   /**
546    * Pops up a frame with the report printed in it.
547    * @param x x-position of the upper-left corner of the frame.
548    * @param y y-position of the upper-left corner of the frame.
549    * @param f file containing the report
550    */
551   public void show(int x, int y, File f) {
552     refresh(f);
553     frame.setLocation(x,y);
554     frame.setState(Frame.NORMAL);
555     frame.show();
556   }
557 
558   /**
559    * Pops up a frame with the report printed in it.
560    * @param x x-position of the upper-left corner of the frame.
561    * @param y y-position of the upper-left corner of the frame.
562    * @param t string with text to display
563    */
564   public void show(int x, int y, String t) {
565     refresh(t);
566     frame.setLocation(x,y);
567     frame.setState(Frame.NORMAL);
568     frame.show();
569   }
570 
571   /*
572    * Pops up a find dialog.
573    */
574   private void find() {
575     if (findPanel == null) findPanel = new FindPanel();
576     findPanel.show(frame,100,100);
577   }
578 
579   /*
580    * Panel with all the widgets needed to find a string.
581    * Builds a dialog which pops up, containing this panel.
582    */
583   class FindPanel extends GriddedPanel {
584 
585     private JDialog dialog;
586     private JTextField textField;
587     private int startIndex=0;
588     private int findIndex;
589     private final Dimension preferredSize = new Dimension(260,80);
590 
591     public FindPanel() {
592       JLabel label = new JLabel("Search:");
593       label.setBorder(new EmptyBorder(new Insets(5,5,5,5)));
594       addComponent(label,1,1);
595       textField = new JTextField();
596       textField.setColumns(15);
597       addFilledComponent(textField,1,2);
598     }
599 
600     /**
601      * @return the preferred size of this panel.
602      */
603     public Dimension getPreferredSize() {
604       return preferredSize;
605     }
606 
607 
608     /*
609      * Finds a string in the text. Scrolls to that position and
610      * assures that the string is visible. Wouldn't it be nice
611      * if the string was high-lighted as well...
612      * @param word piece of text which is searched for
613      * @return true if the word was found
614      */
615     private boolean find(String word) {
616       findIndex = -1;
617       int wordLen = word.length();
618       int N = text.length() - wordLen;
619       for(int i=startIndex; i<N; i++) {
620   String s = text.substring(i,i+wordLen);
621   if (s.equals(word)) {
622     findIndex = i;
623     try {
624       textArea.getHighlighter().removeAllHighlights();
625       textArea.getHighlighter().addHighlight(i,i+wordLen,g);
626     }
627     catch(BadLocationException e) {}
628     break;
629   }
630       }
631       return (findIndex > -1)? true : false;
632     }
633 
634     /*
635      * Performs the actual search. Asks to rewind the file
636      * if it hits the bottom without finding the string.
637      */
638     private void findAction() {
639       int i=0;
640       if (!textField.getText().equals("")) {
641   startIndex = textArea.getCaretPosition();
642   boolean tryFind = true;
643   while (tryFind) {
644     if (!find(textField.getText())) {
645       int result = JOptionPane.showConfirmDialog(frame,"Reaching the end of the text,\nrestart the scan from the top?","Search failed",JOptionPane.OK_CANCEL_OPTION,JOptionPane.INFORMATION_MESSAGE);
646       if (result == JOptionPane.CANCEL_OPTION) tryFind = false;
647       else startIndex = 0;
648     }
649     else tryFind = false;
650     if (i++ > 0) break;
651   }
652   if (findIndex != -1) {
653     //System.out.println("Found '" + textField.getText() + "' at position " + findIndex);
654     textArea.setCaretPosition(++findIndex);
655   }
656       }
657     }
658 
659     /**
660      * Pops up a modal frame including the panel. 
661      * @param parent parent frame
662      * @param x x-position of the dialog
663      * @param y y-position of the dialog
664      */
665     public void show(Frame parent, int x, int y) {
666       if (dialog == null) {
667   JPanel panel = new JPanel(new BorderLayout());
668   dialog = new JDialog(parent,"Find",true);
669   dialog.addWindowListener(new WindowAdapter() {
670       public void windowClosing(WindowEvent e) {
671         textArea.getHighlighter().removeAllHighlights();
672         dialog.dispose();
673       }
674     });
675   JPanel p = new JPanel(new FlowLayout());
676   p.setBorder(BorderFactory.createEtchedBorder());
677   JButton b = new JButton("Find");
678   b.addActionListener(new ActionListener() {
679       public void actionPerformed(ActionEvent e) {
680         findAction();
681       }
682     });
683   p.add(b);
684   b = new JButton("Quit");
685   b.addActionListener(new ActionListener() {
686       public void actionPerformed(ActionEvent e) {
687         textArea.getHighlighter().removeAllHighlights();
688         dialog.dispose();
689       }
690     });
691   p.add(b);
692   panel.add(this,BorderLayout.CENTER);
693   panel.add(p,BorderLayout.SOUTH);
694   dialog.getContentPane().add(panel);
695   dialog.setLocation(x,y);
696   dialog.pack();
697       }
698       
699       dialog.show();  // blocks until user brings dialog down.
700     } 
701   }
702 }