OSDN Git Service

2004-11-30 Thomas Fitzsimmons <fitzsim@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / javax / swing / plaf / basic / BasicTextUI.java
1 /* BasicTextUI.java
2    Copyright (C) 2002, 2003, 2004  Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package javax.swing.plaf.basic;
40
41 import java.awt.Container;
42 import java.awt.Dimension;
43 import java.awt.Graphics;
44 import java.awt.Insets;
45 import java.awt.Point;
46 import java.awt.Rectangle;
47 import java.awt.Shape;
48 import java.awt.event.FocusEvent;
49 import java.awt.event.FocusListener;
50 import java.beans.PropertyChangeEvent;
51 import java.beans.PropertyChangeListener;
52
53 import javax.swing.Action;
54 import javax.swing.ActionMap;
55 import javax.swing.InputMap;
56 import javax.swing.JComponent;
57 import javax.swing.SwingUtilities;
58 import javax.swing.UIDefaults;
59 import javax.swing.UIManager;
60 import javax.swing.plaf.TextUI;
61 import javax.swing.plaf.UIResource;
62 import javax.swing.text.BadLocationException;
63 import javax.swing.text.Caret;
64 import javax.swing.text.DefaultCaret;
65 import javax.swing.text.DefaultEditorKit;
66 import javax.swing.text.DefaultHighlighter;
67 import javax.swing.text.Document;
68 import javax.swing.text.EditorKit;
69 import javax.swing.text.Element;
70 import javax.swing.text.Highlighter;
71 import javax.swing.text.JTextComponent;
72 import javax.swing.text.Keymap;
73 import javax.swing.text.PlainView;
74 import javax.swing.text.Position;
75 import javax.swing.text.View;
76 import javax.swing.text.ViewFactory;
77
78
79 public abstract class BasicTextUI extends TextUI
80   implements ViewFactory
81 {
82   public static class BasicCaret extends DefaultCaret
83     implements UIResource
84   {
85     public BasicCaret()
86     {
87     }
88   }
89
90   public static class BasicHighlighter extends DefaultHighlighter
91     implements UIResource
92   {
93     public BasicHighlighter()
94     {
95     }
96   }
97
98   private class RootView extends View
99   {
100     private View view;
101     
102     public RootView()
103     {
104       super(null);
105     }
106
107     public ViewFactory getViewFactory()
108     {
109       // FIXME: Handle EditorKit somehow.
110       return BasicTextUI.this;
111     }
112
113     public void setView(View v)
114       {
115           if (view != null)
116         view.setParent(null);
117       
118       if (v != null)
119         v.setParent(null);
120
121       view = v;
122     }
123
124     public Container getContainer()
125               {
126       return textComponent;
127     }
128
129     public float getPreferredSpan(int axis)
130     {
131       if (view != null)
132         return view.getPreferredSpan(axis);
133
134       return Integer.MAX_VALUE;
135               }
136
137     public void paint(Graphics g, Shape s)
138     {
139       if (view != null)
140         view.paint(g, s);
141     }
142
143     protected Rectangle modelToView(int position, Shape a, Position.Bias bias)
144       throws BadLocationException
145     {
146       return ((PlainView) view).modelToView(position, a, bias).getBounds();
147     }
148   }
149
150   class UpdateHandler implements PropertyChangeListener
151   {
152     public void propertyChange(PropertyChangeEvent event)
153     {
154       if (event.getPropertyName().equals("document"))
155         {
156           // Document changed.
157           modelChanged();
158         }
159     }
160   }
161   
162   static EditorKit kit = new DefaultEditorKit();
163
164   RootView rootView = new RootView();
165   JTextComponent textComponent;
166   UpdateHandler updateHandler = new UpdateHandler();
167
168   public BasicTextUI()
169   {
170   }
171
172   protected Caret createCaret()
173   {
174     return new BasicCaret();
175   }
176
177   protected Highlighter createHighlighter()
178   {
179     return new BasicHighlighter();
180   }
181   
182   protected final JTextComponent getComponent()
183   {
184     return textComponent;
185   }
186
187   public void installUI(final JComponent c)
188   {
189     super.installUI(c);
190     c.setOpaque(true);
191
192     textComponent = (JTextComponent) c;
193
194     Document doc = textComponent.getDocument();
195     if (doc == null)
196       {
197         doc = getEditorKit(textComponent).createDefaultDocument();
198         textComponent.setDocument(doc);
199       }
200     
201     textComponent.addPropertyChangeListener(updateHandler);
202     modelChanged();
203     
204     installDefaults();
205     installListeners();
206     installKeyboardActions();
207   }
208
209   protected void installDefaults()
210   {
211     Caret caret = textComponent.getCaret();
212     if (caret == null)
213       {
214         caret = createCaret();
215         textComponent.setCaret(caret);
216       }
217
218     Highlighter highlighter = textComponent.getHighlighter();
219     if (highlighter == null)
220       textComponent.setHighlighter(createHighlighter());
221
222     String prefix = getPropertyPrefix();
223     UIDefaults defaults = UIManager.getLookAndFeelDefaults();
224     textComponent.setBackground(defaults.getColor(prefix + ".background"));
225     textComponent.setForeground(defaults.getColor(prefix + ".foreground"));
226     textComponent.setMargin(defaults.getInsets(prefix + ".margin"));
227     textComponent.setBorder(defaults.getBorder(prefix + ".border"));
228     textComponent.setFont(defaults.getFont(prefix + ".font"));
229
230     caret.setBlinkRate(defaults.getInt(prefix + ".caretBlinkRate"));
231   }
232
233   private FocusListener focuslistener = new FocusListener() {
234       public void focusGained(FocusEvent e) 
235       {
236         textComponent.repaint();
237       }
238       public void focusLost(FocusEvent e)
239       {
240         textComponent.repaint();
241       }
242     };
243
244   protected void installListeners()
245   {
246     textComponent.addFocusListener(focuslistener);
247   }
248
249   protected String getKeymapName()
250   {
251     return "BasicTextUI";
252   }
253
254   protected Keymap createKeymap()
255   {
256     String prefix = getPropertyPrefix();
257     UIDefaults defaults = UIManager.getLookAndFeelDefaults();
258     JTextComponent.KeyBinding[] bindings = 
259       (JTextComponent.KeyBinding[]) defaults.get(prefix + ".keyBindings");
260     Keymap km = JTextComponent.addKeymap(getKeymapName(), 
261                                          JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP));    
262     JTextComponent.loadKeymap(km, bindings, textComponent.getActions());
263     return km;    
264   }
265
266   protected void installKeyboardActions()
267   {    
268     // load any bindings for the older Keymap interface
269     Keymap km = JTextComponent.getKeymap(getKeymapName());
270     if (km == null)
271       km = createKeymap();
272     textComponent.setKeymap(km);
273
274     // load any bindings for the newer InputMap / ActionMap interface
275     SwingUtilities.replaceUIInputMap(textComponent, 
276                                      JComponent.WHEN_FOCUSED,
277                                      getInputMap(JComponent.WHEN_FOCUSED));
278     SwingUtilities.replaceUIActionMap(textComponent, getActionMap());
279   }
280
281   InputMap getInputMap(int condition)
282   {
283     String prefix = getPropertyPrefix();
284     UIDefaults defaults = UIManager.getLookAndFeelDefaults();
285     switch (condition)
286       {
287       case JComponent.WHEN_IN_FOCUSED_WINDOW:
288         // FIXME: is this the right string? nobody seems to use it.
289         return (InputMap) defaults.get(prefix + ".windowInputMap"); 
290       case JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT:
291         return (InputMap) defaults.get(prefix + ".ancestorInputMap");
292       default:
293       case JComponent.WHEN_FOCUSED:
294         return (InputMap) defaults.get(prefix + ".focusInputMap");
295       }
296   }
297
298   ActionMap getActionMap()
299   {
300     String prefix = getPropertyPrefix();
301     UIDefaults defaults = UIManager.getLookAndFeelDefaults();    
302     ActionMap am = (ActionMap) defaults.get(prefix + ".actionMap");
303     if (am == null)
304       {
305         am = createActionMap();
306         defaults.put(prefix + ".actionMap", am);
307       }
308     return am;
309   }
310
311   ActionMap createActionMap()
312   {
313     Action[] actions = textComponent.getActions();
314     ActionMap am = new ActionMap();
315     for (int i = 0; i < actions.length; ++i)
316       {
317         String name = (String) actions[i].getValue(Action.NAME);
318         if (name != null)
319           am.put(name, actions[i]);
320       }
321     return am;
322   }
323   
324   public void uninstallUI(final JComponent component)
325   {
326     super.uninstallUI(component);
327     rootView.setView(null);
328
329     textComponent.removePropertyChangeListener(updateHandler);
330     textComponent = null;
331
332     uninstallDefaults();
333     uninstallListeners();
334     uninstallKeyboardActions();
335   }
336
337   protected void uninstallDefaults()
338   {
339     // Do nothing here.
340   }
341
342   protected void uninstallListeners()
343   {
344     textComponent.removeFocusListener(focuslistener);
345   }
346
347   protected void uninstallKeyboardActions()
348   {
349     // Do nothing here.
350   }
351   
352   protected abstract String getPropertyPrefix();
353
354   public Dimension getPreferredSize(JComponent c)
355   {
356     View v = getRootView(textComponent);
357
358     float w = v.getPreferredSpan(View.X_AXIS);
359     float h = v.getPreferredSpan(View.Y_AXIS);
360
361     return new Dimension((int) w, (int) h);
362   }
363
364   public final void paint(Graphics g, JComponent c)
365   {
366     paintSafely(g);
367   }
368
369   protected void paintSafely(Graphics g)
370   {
371     Caret caret = textComponent.getCaret();
372     Highlighter highlighter = textComponent.getHighlighter();
373     
374     if (textComponent.isOpaque())
375       paintBackground(g);
376     
377     if (highlighter != null
378         && textComponent.getSelectionStart() != textComponent.getSelectionEnd())
379       highlighter.paint(g);
380
381     rootView.paint(g, getVisibleEditorRect());
382
383     if (caret != null && textComponent.hasFocus())
384       caret.paint(g);
385   }
386
387   protected void paintBackground(Graphics g)
388   {
389     g.setColor(textComponent.getBackground());
390     g.fillRect(0, 0, textComponent.getWidth(), textComponent.getHeight());
391   }
392
393   public void damageRange(JTextComponent t, int p0, int p1)
394   {
395     damageRange(t, p0, p1, null, null);
396   }
397
398   public void damageRange(JTextComponent t, int p0, int p1,
399                           Position.Bias firstBias, Position.Bias secondBias)
400   {
401   }
402
403   public EditorKit getEditorKit(JTextComponent t)
404   {
405     return kit;
406   }
407
408   public int getNextVisualPositionFrom(JTextComponent t, int pos,
409                                        Position.Bias b, int direction,
410                                        Position.Bias[] biasRet)
411     throws BadLocationException
412   {
413     return 0;
414   }
415
416   public View getRootView(JTextComponent t)
417   {
418     return rootView;
419   }
420
421   public Rectangle modelToView(JTextComponent t, int pos)
422     throws BadLocationException
423   {
424     return modelToView(t, pos, Position.Bias.Forward);
425   }
426
427   public Rectangle modelToView(JTextComponent t, int pos, Position.Bias bias)
428     throws BadLocationException
429   {
430     return rootView.modelToView(pos, getVisibleEditorRect(), bias).getBounds();
431   }
432
433   public int viewToModel(JTextComponent t, Point pt)
434   {
435     return viewToModel(t, pt, null);
436   }
437
438   public int viewToModel(JTextComponent t, Point pt, Position.Bias[] biasReturn)
439   {
440     return 0;
441   }
442
443   public View create(Element elem)
444   {
445     // subclasses have to implement this to get this functionality
446     return null;
447   }
448
449   public View create(Element elem, int p0, int p1)
450   {
451     // subclasses have to implement this to get this functionality
452     return null;
453   }
454   
455   protected Rectangle getVisibleEditorRect()
456   {
457     int width = textComponent.getWidth();
458     int height = textComponent.getHeight();
459
460     if (width <= 0 || height <= 0)
461       return null;
462         
463     Insets insets = textComponent.getInsets();
464     return new Rectangle(insets.left, insets.top,
465                          width - insets.left + insets.right,
466                          height - insets.top + insets.bottom);
467   }
468
469   protected final void setView(View view)
470   {
471     rootView.setView(view);
472     view.setParent(rootView);
473   }
474
475   protected void modelChanged()
476   {
477     if (textComponent == null || rootView == null) 
478       return;
479     ViewFactory factory = rootView.getViewFactory();
480     if (factory == null) 
481       return;
482     Document doc = textComponent.getDocument();
483     if (doc == null)
484       return;
485     Element elem = doc.getDefaultRootElement();
486     if (elem == null)
487       return;
488     setView(factory.create(elem));
489   }
490 }