1 /* 2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.java.swing.plaf.windows; 27 28 import java.awt.Color; 29 import java.awt.Graphics; 30 import java.awt.Rectangle; 31 import java.awt.Shape; 32 import javax.swing.plaf.basic.*; 33 import javax.swing.*; 34 import javax.swing.plaf.TextUI; 35 import javax.swing.plaf.UIResource; 36 import javax.swing.text.*; 37 38 /** 39 * Windows text rendering. 40 * <p> 41 * <strong>Warning:</strong> 42 * Serialized objects of this class will not be compatible with 43 * future Swing releases. The current serialization support is appropriate 44 * for short term storage or RMI between applications running the same 45 * version of Swing. A future release of Swing will provide support for 46 * long term persistence. 47 */ 48 public abstract class WindowsTextUI extends BasicTextUI { 49 /** 50 * Creates the object to use for a caret. By default an 51 * instance of WindowsCaret is created. This method 52 * can be redefined to provide something else that implements 53 * the InputPosition interface or a subclass of DefaultCaret. 54 * 55 * @return the caret object 56 */ 57 protected Caret createCaret() { 58 return new WindowsCaret(); 59 } 60 61 /* public */ 62 static LayeredHighlighter.LayerPainter WindowsPainter = new WindowsHighlightPainter(null); 63 64 /* public */ 65 @SuppressWarnings("serial") // Superclass is not serializable across versions 66 static class WindowsCaret extends DefaultCaret 67 implements UIResource { 68 /** 69 * Gets the painter for the Highlighter. 70 * 71 * @return the painter 72 */ 73 protected Highlighter.HighlightPainter getSelectionPainter() { 74 return WindowsTextUI.WindowsPainter; 75 } 76 } 77 78 /* public */ 79 static class WindowsHighlightPainter extends 80 DefaultHighlighter.DefaultHighlightPainter { 81 WindowsHighlightPainter(Color c) { 82 super(c); 83 } 84 85 // --- HighlightPainter methods --------------------------------------- 86 87 /** 88 * Paints a highlight. 89 * 90 * @param g the graphics context 91 * @param offs0 the starting model offset >= 0 92 * @param offs1 the ending model offset >= offs1 93 * @param bounds the bounding box for the highlight 94 * @param c the editor 95 */ 96 public void paint(Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c) { 97 Rectangle alloc = bounds.getBounds(); 98 try { 99 // --- determine locations --- 100 TextUI mapper = c.getUI(); 101 Rectangle p0 = mapper.modelToView(c, offs0); 102 Rectangle p1 = mapper.modelToView(c, offs1); 103 104 // --- render --- 105 Color color = getColor(); 106 107 if (color == null) { 108 g.setColor(c.getSelectionColor()); 109 } 110 else { 111 g.setColor(color); 112 } 113 boolean firstIsDot = false; 114 boolean secondIsDot = false; 115 if (c.isEditable()) { 116 int dot = c.getCaretPosition(); 117 firstIsDot = (offs0 == dot); 118 secondIsDot = (offs1 == dot); 119 } 120 if (p0.y == p1.y) { 121 // same line, render a rectangle 122 Rectangle r = p0.union(p1); 123 if (r.width > 0) { 124 if (firstIsDot) { 125 r.x++; 126 r.width--; 127 } 128 else if (secondIsDot) { 129 r.width--; 130 } 131 } 132 g.fillRect(r.x, r.y, r.width, r.height); 133 } else { 134 // different lines 135 int p0ToMarginWidth = alloc.x + alloc.width - p0.x; 136 if (firstIsDot && p0ToMarginWidth > 0) { 137 p0.x++; 138 p0ToMarginWidth--; 139 } 140 g.fillRect(p0.x, p0.y, p0ToMarginWidth, p0.height); 141 if ((p0.y + p0.height) != p1.y) { 142 g.fillRect(alloc.x, p0.y + p0.height, alloc.width, 143 p1.y - (p0.y + p0.height)); 144 } 145 if (secondIsDot && p1.x > alloc.x) { 146 p1.x--; 147 } 148 g.fillRect(alloc.x, p1.y, (p1.x - alloc.x), p1.height); 149 } 150 } catch (BadLocationException e) { 151 // can't render 152 } 153 } 154 155 // --- LayerPainter methods ---------------------------- 156 /** 157 * Paints a portion of a highlight. 158 * 159 * @param g the graphics context 160 * @param offs0 the starting model offset >= 0 161 * @param offs1 the ending model offset >= offs1 162 * @param bounds the bounding box of the view, which is not 163 * necessarily the region to paint. 164 * @param c the editor 165 * @param view View painting for 166 * @return region drawing occurred in 167 */ 168 public Shape paintLayer(Graphics g, int offs0, int offs1, 169 Shape bounds, JTextComponent c, View view) { 170 Color color = getColor(); 171 172 if (color == null) { 173 g.setColor(c.getSelectionColor()); 174 } 175 else { 176 g.setColor(color); 177 } 178 boolean firstIsDot = false; 179 boolean secondIsDot = false; 180 if (c.isEditable()) { 181 int dot = c.getCaretPosition(); 182 firstIsDot = (offs0 == dot); 183 secondIsDot = (offs1 == dot); 184 } 185 if (offs0 == view.getStartOffset() && 186 offs1 == view.getEndOffset()) { 187 // Contained in view, can just use bounds. 188 Rectangle alloc; 189 if (bounds instanceof Rectangle) { 190 alloc = (Rectangle)bounds; 191 } 192 else { 193 alloc = bounds.getBounds(); 194 } 195 if (firstIsDot && alloc.width > 0) { 196 g.fillRect(alloc.x + 1, alloc.y, alloc.width - 1, 197 alloc.height); 198 } 199 else if (secondIsDot && alloc.width > 0) { 200 g.fillRect(alloc.x, alloc.y, alloc.width - 1, 201 alloc.height); 202 } 203 else { 204 g.fillRect(alloc.x, alloc.y, alloc.width, alloc.height); 205 } 206 return alloc; 207 } 208 else { 209 // Should only render part of View. 210 try { 211 // --- determine locations --- 212 Shape shape = view.modelToView(offs0, Position.Bias.Forward, 213 offs1,Position.Bias.Backward, 214 bounds); 215 Rectangle r = (shape instanceof Rectangle) ? 216 (Rectangle)shape : shape.getBounds(); 217 if (firstIsDot && r.width > 0) { 218 g.fillRect(r.x + 1, r.y, r.width - 1, r.height); 219 } 220 else if (secondIsDot && r.width > 0) { 221 g.fillRect(r.x, r.y, r.width - 1, r.height); 222 } 223 else { 224 g.fillRect(r.x, r.y, r.width, r.height); 225 } 226 return r; 227 } catch (BadLocationException e) { 228 // can't render 229 } 230 } 231 // Only if exception 232 return null; 233 } 234 235 } 236 237 }