/*
 * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package com.sun.java.swing.plaf.windows;

import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import javax.swing.plaf.*;
import javax.swing.plaf.basic.BasicTextFieldUI;
import javax.swing.text.*;
import javax.swing.*;
import javax.swing.plaf.UIResource;
import sun.swing.DefaultLookup;



/**
 * Provides the Windows look and feel for a text field.  This
 * is basically the following customizations to the default
 * look-and-feel.
 * <ul>
 * <li>The border is beveled (using the standard control color).
 * <li>The background is white by default.
 * <li>The highlight color is a dark color, blue by default.
 * <li>The foreground color is high contrast in the selected
 *  area, white by default.  The unselected foreground is black.
 * <li>The cursor blinks at about 1/2 second intervals.
 * <li>The entire value is selected when focus is gained.
 * <li>Shift-left-arrow and shift-right-arrow extend selection
 * <li>Cntrl-left-arrow and cntrl-right-arrow act like home and
 *   end respectively.
 * </ul>
 * <p>
 * <strong>Warning:</strong>
 * Serialized objects of this class will not be compatible with
 * future Swing releases.  The current serialization support is appropriate
 * for short term storage or RMI between applications running the same
 * version of Swing.  A future release of Swing will provide support for
 * long term persistence.
 *
 * @author  Timothy Prinzing
 */
public class WindowsTextFieldUI extends BasicTextFieldUI
{
    /**
     * Creates a UI for a JTextField.
     *
     * @param c the text field
     * @return the UI
     */
    public static ComponentUI createUI(JComponent c) {
        return new WindowsTextFieldUI();
    }

    /**
     * Paints a background for the view.  This will only be
     * called if isOpaque() on the associated component is
     * true.  The default is to paint the background color
     * of the component.
     *
     * @param g the graphics context
     */
    protected void paintBackground(Graphics g) {
        super.paintBackground(g);
    }

    /**
     * Creates the caret for a field.
     *
     * @return the caret
     */
    protected Caret createCaret() {
        return new WindowsFieldCaret();
    }

    /**
     * WindowsFieldCaret has different scrolling behavior than
     * DefaultCaret.
     */
    static class WindowsFieldCaret extends DefaultCaret implements UIResource {

        public WindowsFieldCaret() {
            super();
        }

        /**
         * Adjusts the visibility of the caret according to
         * the windows feel which seems to be to move the
         * caret out into the field by about a quarter of
         * a field length if not visible.
         */
        protected void adjustVisibility(Rectangle r) {
            SwingUtilities.invokeLater(new SafeScroller(r));
        }

        /**
         * Gets the painter for the Highlighter.
         *
         * @return the painter
         */
        protected Highlighter.HighlightPainter getSelectionPainter() {
            return WindowsTextUI.WindowsPainter;
        }


        private class SafeScroller implements Runnable {
            SafeScroller(Rectangle r) {
                this.r = r;
            }

            public void run() {
                JTextField field = (JTextField) getComponent();
                if (field != null) {
                    TextUI ui = field.getUI();
                    int dot = getDot();
                    // PENDING: We need to expose the bias in DefaultCaret.
                    Position.Bias bias = Position.Bias.Forward;
                    Rectangle startRect = null;
                    try {
                        startRect = ui.modelToView(field, dot, bias);
                    } catch (BadLocationException ble) {}

                    Insets i = field.getInsets();
                    BoundedRangeModel vis = field.getHorizontalVisibility();
                    int x = r.x + vis.getValue() - i.left;
                    int quarterSpan = vis.getExtent() / 4;
                    if (r.x < i.left) {
                        vis.setValue(x - quarterSpan);
                    } else if (r.x + r.width > i.left + vis.getExtent()) {
                        vis.setValue(x - (3 * quarterSpan));
                    }
                    // If we scroll, our visual location will have changed,
                    // but we won't have updated our internal location as
                    // the model hasn't changed. This checks for the change,
                    // and if necessary, resets the internal location.
                    if (startRect != null) {
                        try {
                            Rectangle endRect;
                            endRect = ui.modelToView(field, dot, bias);
                            if (endRect != null && !endRect.equals(startRect)){
                                damage(endRect);
                            }
                        } catch (BadLocationException ble) {}
                    }
                }
            }

            private Rectangle r;
        }
    }

}
