home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / jfc.bin / MacTextUI.java < prev    next >
Text File  |  1998-02-26  |  16KB  |  527 lines

  1. /*
  2.  * @(#)MacTextUI.java    1.7 98/02/02
  3.  *
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  *
  19.  */
  20.  
  21.  
  22. package com.sun.java.swing.plaf.mac;
  23.  
  24. import java.awt.*;
  25. import java.awt.event.*;
  26. import com.sun.java.swing.*;
  27. import com.sun.java.swing.text.*;
  28. import com.sun.java.swing.plaf.*;
  29. import com.sun.java.swing.border.Border;
  30.  
  31. /**
  32.  * <p>
  33.  * Warning: serialized objects of this class will not be compatible with
  34.  * future swing releases.  The current serialization support is appropriate
  35.  * for short term storage or RMI between Swing1.0 applications.  It will
  36.  * not be possible to load serialized Swing1.0 objects with future releases
  37.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  38.  * baseline for the serialized form of Swing objects.
  39.  *
  40.  * @version 1.7 02/02/98
  41.  * @author Symantec
  42.  */
  43. public abstract class MacTextUI extends DefaultTextUI {
  44.  
  45.     Window parentWindow = null;
  46.     MacTextAncestorListener anAncestorListener;
  47.     boolean activated = false;
  48.     
  49.     //set border and
  50.     //install Ancestor Listener
  51.     protected void installDefaults(JComponent c) 
  52.     {
  53.         JTextComponent editor = getComponent();
  54.         editor.setBorder(MacBorderFactory.getTextBorder());
  55.         
  56.         //set up listener so we know when addNotify and removeNotify are called
  57.         anAncestorListener = new MacTextAncestorListener();
  58.         editor.addAncestorListener(anAncestorListener);
  59.         
  60.         //load these here so I can switch foreground color if needed
  61.         String prefix = getPropertyPrefix();
  62.         
  63.         Color sbg = editor.getSelectionColor();
  64.         if ((sbg == null) || (sbg instanceof UIResource)) {
  65.             editor.setSelectionColor(UIManager.getColor(prefix + ".selectionBackground"));
  66.         }
  67.     
  68.         Color sfg = editor.getSelectedTextColor();
  69.         if ((sfg == null) || (sfg instanceof UIResource)) {
  70.             editor.setSelectedTextColor(UIManager.getColor(prefix + ".selectionForeground"));
  71.         }
  72.         //if both black, switch text color to white
  73. //        if(sbg.equals(Color.black) && (sfg.equals(Color.black)))
  74. //            editor.setSelectedTextColor(MacUtilities.GrayscaleAppearanceW);
  75.         
  76.         super.installDefaults(c);
  77.       }
  78.     
  79.     //remove Ancestor Listener
  80.     protected void uninstallDefaults(JComponent c) 
  81.     {
  82.         JTextComponent editor = getComponent();
  83.         editor.removeAncestorListener(anAncestorListener);
  84.         
  85.         super.uninstallDefaults(c);
  86.     }
  87.  
  88.     
  89.     public JTextComponent getComponentEditor()
  90.     {
  91.         return getComponent();
  92.     }
  93.     
  94.     /**
  95.     * return true if point in non-border area
  96.     *
  97.     * @param c the editor component
  98.     * @param x the horizontal coordinate
  99.     * @param y the vertical coordinate
  100.     */
  101.     public boolean contains(JComponent c, int x, int y) 
  102.     {
  103.         Rectangle viewRect = new Rectangle(c.getSize());
  104.         Insets i = c.getInsets();
  105.             
  106.         viewRect.x += i.left;
  107.         viewRect.y += i.top;
  108.         viewRect.width -= (i.right + viewRect.x);
  109.         viewRect.height -= (i.bottom + viewRect.y);
  110.         
  111.         return viewRect.contains(x, y);
  112.     }
  113.     
  114.     /**
  115.     * Override so that if opaque the edges are painted 
  116.     * in parent's background color.
  117.     * Interior is painted in component's background color 
  118.     * in paintBackground.
  119.     * @see paintBackground
  120.     *
  121.     * @param g the graphics context
  122.     * @param c the editor component
  123.     */
  124.      public void update(Graphics g, JComponent c) 
  125.      {
  126.      Rectangle viewRect = new Rectangle(c.getSize());
  127.      Insets i = c.getInsets();
  128.      
  129.      if (c.isOpaque())     {
  130.          //if there is an inset, draw the correct frame
  131.          if(i.left > 0) {
  132.          g.setColor(c.getParent().getBackground());
  133.          
  134.          int h = c.getHeight();
  135.          int w = c.getWidth();
  136.          //if not in focus, draw where focus border would be
  137.          if(!c.hasFocus()) {
  138.              
  139.              g.drawRect(0, 0, w - 1, h - 1);
  140.              g.drawRect(1, 1, w - 2, h - 2);
  141.          } else {//just draw corner pixels
  142.              g.drawLine(0, 0, 0, 0);
  143.              g.drawLine(0, h-1, 0, h-1);
  144.              g.drawLine(w-1, 0, w-1, 0);
  145.              g.drawLine(w-1, h-1, w-1, h-1);
  146.          }
  147.          }
  148.      }
  149.      //paint in background for interior
  150.      g.setColor(c.getBackground());
  151.         
  152.      viewRect.x += i.left;
  153.      viewRect.y += i.top;
  154.      viewRect.width -= (i.right + viewRect.x);
  155.      viewRect.height -= (i.bottom + viewRect.y);
  156.      g.fillRect(viewRect.x, viewRect.y, viewRect.width, viewRect.height);
  157.         
  158.      paint(g, c);
  159.      }
  160.      
  161.     /**
  162.      * Paint a background for the view.  This will only be
  163.      * called if isOpaque() on the associated component is
  164.      * true. It does check for the insets of the border.
  165.      *
  166.      * @param g the graphics context
  167.      */
  168.     protected void paintBackground(Graphics g) 
  169.     {
  170.         JTextComponent editor = getComponentEditor();
  171.         g.setColor(editor.getBackground());
  172.         Rectangle viewRect = new Rectangle(editor.getSize());
  173.         Insets i = editor.getInsets();
  174.         
  175.         viewRect.x += i.left;
  176.         viewRect.y += i.top;
  177.         viewRect.width -= (i.right + viewRect.x);
  178.         viewRect.height -= (i.bottom + viewRect.y);
  179.         
  180.         g.fillRect(viewRect.x, viewRect.y, viewRect.width, viewRect.height);
  181.     }
  182.  
  183.     
  184.     /**
  185.      * Load the given keymap with default settings
  186.      * appropriate for the UI being created.  This
  187.      * is called if a default keymap is being created
  188.      * because an existing one wasn't found.  Subclasses
  189.      * that reimplement this would generally want to 
  190.      * call the superclass implementation to make sure
  191.      * all of the appropriate bindings get loaded.
  192.      *
  193.      * This is implemented to load the set of keybindings
  194.      * appropriate for all text components in mac.
  195.      */
  196.      
  197.     protected void loadDefaultKeymap(Keymap map) {
  198.     JTextComponent.loadKeymap(map, defaultBindings, 
  199.                      getComponent().getActions());
  200.     }
  201.  
  202.     /**
  203.      * Allows one to fetch the name of the keymap that
  204.      * will be installed/used by default for this UI.
  205.      * This is implemented to generate a name based upon
  206.      * the getPropertyPrefix method, and will generally
  207.      * need not be redefined.
  208.      */
  209.     public String getKeymapName() {
  210.     return "Mac" + getPropertyPrefix();
  211.     }
  212.  
  213.     /**
  214.      * Creates the object to use for a caret.  By default an
  215.      * instance of MacTextUI.MacCaret is created.  This method
  216.      * can be redefined to provide something else that implements
  217.      * the Caret interface.
  218.      *
  219.      * @return the caret object
  220.      */
  221.     protected Caret createCaret() {
  222.     return new MacCaret();
  223.     }
  224.  
  225.     /**
  226.      * Creates the keymap to use for the text component, and installs
  227.      * any necessary bindings into it.  By default, the keymap is
  228.      * shared between all instances of the associated text component.
  229.      * It has the name defined by the getKeymapName method.
  230.      *
  231.      * @see #getKeymapName
  232.      * @see com.sun.java.swing.text.JTextComponent
  233.      */
  234.     protected Keymap createKeymap() {
  235.     String nm = getKeymapName();
  236.     Keymap map = JTextComponent.getKeymap(nm);
  237.     if (map == null) {
  238.         Keymap parent = JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP);
  239.         map = JTextComponent.addKeymap(nm, parent);
  240.         loadDefaultKeymap(map);
  241.     }
  242.     return map;
  243.     }
  244.     
  245.     public void setActivated(boolean activated)
  246.     {
  247.         this.activated = activated;
  248.     }
  249.     
  250.     public boolean isActivated()
  251.     {
  252.         return activated;
  253.     }
  254.  
  255.     /**
  256.      * The mac caret is rendered as an vertical line.
  257.      * <p>
  258.      * Warning: serialized objects of this class will not be compatible with
  259.      * future swing releases.  The current serialization support is appropriate
  260.      * for short term storage or RMI between Swing1.0 applications.  It will
  261.      * not be possible to load serialized Swing1.0 objects with future releases
  262.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  263.      * baseline for the serialized form of Swing objects.
  264.      */
  265.     public class MacCaret extends DefaultCaret implements UIResource {
  266.  
  267.         int preSelectionBlinkRate = -1;
  268.         
  269.         /**
  270.          * Damages the area surrounding the caret to cause
  271.          * it to be repainted.  If paint() is reimplemented,
  272.          * this method should also be reimplemented.
  273.          *
  274.          * @param r  the current location of the caret
  275.          * @see #paint
  276.          */
  277.             protected void damage(Rectangle r) {
  278.             if (r != null) {
  279.             Component c = getComponent();
  280.             c.repaint(r.x - 1, r.y, 
  281.                   r.width + 2, r.height);
  282.             }
  283.         }
  284.     
  285.         /**
  286.          * Renders the caret as a vertical line.  If this is reimplemented
  287.          * the damage method should also be reimplemented as it assumes the
  288.          * shape of the caret is a vertical line.
  289.          *
  290.          * @param g the graphics context
  291.          * @see #damage
  292.          */
  293.         public void paint(Graphics g) 
  294.         {
  295.             JTextComponent c = getComponent();    
  296.             
  297.             //if there is a selection, don't blink
  298.             if(c.getSelectedText() != null)
  299.             {
  300.                 if(preSelectionBlinkRate < 0)
  301.                 {
  302.                     preSelectionBlinkRate = getBlinkRate();
  303.                     setBlinkRate(0);
  304.                 }
  305.                 return;
  306.             }
  307.             else //restore old blink rate and go on
  308.             {
  309.                 if(preSelectionBlinkRate > 0)
  310.                 {
  311.                     setBlinkRate(preSelectionBlinkRate);
  312.                     setVisible(true);
  313.                     preSelectionBlinkRate = -1;
  314.                 }
  315.             }
  316.             
  317.             if(isVisible()) 
  318.             {
  319.                 try 
  320.                 {    
  321.                     Color fg = isActivated() ? c.getCaretColor() : 
  322.                                 c.getDisabledTextColor();
  323.                     Color bg = c.getBackground();
  324.                     if (fg.equals(bg))
  325.                         g.setXORMode(bg);    // Make sure caret is visible when the background color equals caret color
  326.                     
  327.                     TextUI mapper = c.getUI();
  328.                     int dot = getDot();
  329.                     Rectangle r = mapper.modelToView(dot);
  330.                     int x0 = r.x;
  331.                     int y0 = r.y + 1;
  332.                     int y1 = r.y + r.height - 2;
  333.                     
  334.                     g.setColor(fg);
  335.                     g.drawLine(x0, y0, x0, y1);
  336.                         
  337.                     //enclosing window needs to be active for us to care
  338.                     if((isActivated()) && (c.hasFocus() == false))
  339.                     {
  340.                         setVisible(false);
  341.                     }
  342.                     
  343.                     g.setPaintMode();    // reset back to normal mode
  344.                 } 
  345.                 catch (BadLocationException e) 
  346.                 {
  347.                     // can't render I guess
  348.                     //System.err.println("Can't render caret");
  349.                 }
  350.             }
  351.         }
  352.  
  353.         /**
  354.          * Turns the caret on as a result of getting
  355.          * focus.  The mac caret is visible when component has focus 
  356.          * or when window is deactivated when component has focus
  357.          * but quits flashing when window is deactivated.
  358.          * Repaint entire component to paint focus rectangle
  359.          */
  360.                 public void focusGained(FocusEvent e) {
  361.             Caret caret = getComponent().getCaret();
  362.             if (lastBlinkRate >= 0) {
  363.             caret.setBlinkRate(lastBlinkRate);
  364.             }
  365.             caret.setVisible(true);
  366.             
  367.             getComponent().repaint();
  368.         }
  369.     
  370.          /**
  371.          * Turns the caret off as a result of losing 
  372.          * focus.  The mac caret is only visible
  373.          * when the component has focus, even if window is deactivated.  The
  374.          * current blink rate is stashed so it can be
  375.          * restored later, and the rate is set to 0.
  376.          * The caret itself takes care of it's change
  377.          * in appearance.
  378.          * Repaint entire component to unpaint focus rectangle
  379.          */
  380.                 public void focusLost(FocusEvent e) {
  381.             Caret caret = getComponent().getCaret();
  382.             lastBlinkRate = caret.getBlinkRate();
  383.             caret.setBlinkRate(0);
  384.             caret.setDot(caret.getDot());
  385.             if(isActivated())
  386.             {
  387.                 caret.setVisible(false);
  388.             }
  389.             else
  390.             {
  391.                 caret.setVisible(true);
  392.             }
  393.             getComponent().getParent().repaint();
  394.         }
  395.     
  396.         int lastBlinkRate = -1;
  397.         final int IBeamOverhang = 2;
  398.     }
  399.  
  400.     
  401.     class MacTextAncestorListener implements com.sun.java.swing.event.AncestorListener
  402.     {
  403.         TextWindowAdapter aTextWindowAdapter;
  404.         
  405.         /**
  406.          * Called when the source or one of its ancestors is made visible
  407.          * either by setVisible(true) being called or by its being
  408.          * added to the component hierarchy.  The method is only called
  409.          * if the source has actually become visible.  For this to be true
  410.          * all its parents must be visible and it must be in a hierarchy
  411.          * rooted at a Window
  412.          */
  413.         public void ancestorAdded(com.sun.java.swing.event.AncestorEvent event)
  414.         {
  415.             Component parent = null;
  416.             JTextComponent c = getComponentEditor();
  417.             int hHeight = 0, vWidth = 0;
  418.             
  419.             Object object = event.getSource();
  420.             if(object == c )
  421.                  parent = c.getParent();
  422.             
  423.                 while((parent != null) && (!(parent instanceof Window)))
  424.                     parent = parent.getParent();
  425.                     
  426.                 
  427.             if(parent != null)
  428.             {
  429.                 parentWindow = (Window)parent;
  430.                 
  431.                 aTextWindowAdapter = new TextWindowAdapter();
  432.                 parentWindow.addWindowListener(aTextWindowAdapter);
  433.             }
  434.         }
  435.     
  436.         /**
  437.          * Called when the source or one of its ancestors is made invisible
  438.          * either by setVisible(false) being called or by its being
  439.          * remove from the component hierarchy.  The method is only called
  440.          * if the source has actually become invisible.  For this to be true
  441.          * at least one of its parents must by invisible or it is not in
  442.          * a hierarchy rooted at a Window
  443.          */
  444.         public void ancestorRemoved(com.sun.java.swing.event.AncestorEvent event)
  445.         {
  446.             if(parentWindow != null)
  447.                 parentWindow.removeWindowListener(aTextWindowAdapter);
  448.         }
  449.     
  450.         /**
  451.          * Called when either the source or one of its ancestors is moved.
  452.          */
  453.         public void ancestorMoved(com.sun.java.swing.event.AncestorEvent event)
  454.         {
  455.         }
  456.     }
  457.     
  458.     class TextWindowAdapter extends java.awt.event.WindowAdapter
  459.     {
  460.         public void windowDeactivated(java.awt.event.WindowEvent event)
  461.         {
  462.             Object object = event.getSource();
  463.             if (object == parentWindow)
  464.                 ParentWindow_WindowDeactivated(event);
  465.         }
  466.  
  467.         public void windowActivated(java.awt.event.WindowEvent event)
  468.         {
  469.             Object object = event.getSource();
  470.             if (object == parentWindow)
  471.                 ParentWindow_WindowActivated(event);
  472.         }
  473.     }
  474.  
  475.     void ParentWindow_WindowActivated(java.awt.event.WindowEvent event)
  476.     {
  477.         setActivated(true);
  478.         
  479.         //if it was active before, turn it on again
  480.         if(getComponent().getCaret().isVisible())
  481.         {
  482.             getComponent().requestFocus();
  483.         }
  484.     }
  485.  
  486.     void ParentWindow_WindowDeactivated(java.awt.event.WindowEvent event)
  487.     {
  488.         setActivated(false);
  489.     }
  490.     
  491.     
  492.  
  493.     /**
  494.      * Default bindings all keymaps implementing the Mac feel.
  495.      */
  496.     static final JTextComponent.KeyBinding[] defaultBindings = {
  497.     new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 
  498.                                     InputEvent.CTRL_MASK),
  499.                          DefaultEditorKit.copyAction),
  500.     new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, 
  501.                                     InputEvent.SHIFT_MASK),
  502.                          DefaultEditorKit.pasteAction),
  503.     new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 
  504.                                     InputEvent.SHIFT_MASK),
  505.                          DefaultEditorKit.cutAction),
  506.     new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 
  507.                                     InputEvent.SHIFT_MASK),
  508.                          DefaultEditorKit.selectionBackwardAction),
  509.     new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 
  510.                                     InputEvent.SHIFT_MASK),
  511.                          DefaultEditorKit.selectionForwardAction),
  512.     new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_F, 
  513.                                     InputEvent.CTRL_MASK),
  514.                          DefaultEditorKit.forwardAction),
  515.     new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_B, 
  516.                                     InputEvent.CTRL_MASK),
  517.                          DefaultEditorKit.backwardAction),
  518.     new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_D, 
  519.                                     InputEvent.CTRL_MASK),
  520.                          DefaultEditorKit.deleteNextCharAction),
  521.     };
  522.     
  523.     
  524.  
  525.  
  526. }
  527.