comparison dwt/custom/StyledText.d @ 41:6337764516f1

Sync dwt/custom with dwt-linux (took copy of complete folder)
author Frank Benoit <benoit@tionex.de>
date Tue, 07 Oct 2008 16:29:55 +0200
parents db5a898b2119
children 07399639c0c8
comparison
equal deleted inserted replaced
40:fbe68c33eeee 41:6337764516f1
1 /******************************************************************************* 1 /*******************************************************************************
2 * Copyright (c) 2000, 2007 IBM Corporation and others. 2 * Copyright (c) 2000, 2008 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials 3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0 4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at 5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html 6 * http://www.eclipse.org/legal/epl-v10.html
7 * 7 *
8 * Contributors: 8 * Contributors:
9 * IBM Corporation - initial API and implementation 9 * IBM Corporation - initial API and implementation
10 * Port to the D programming language:
11 * Frank Benoit <benoit@tionex.de>
10 *******************************************************************************/ 12 *******************************************************************************/
11 module dwt.custom; 13 module dwt.custom.StyledText;
12 14
13 15
14 import java.util.*; 16 import dwt.DWT;
17 import dwt.DWTError;
18 import dwt.DWTException;
19 import dwt.accessibility.ACC;
20 import dwt.accessibility.Accessible;
21 import dwt.accessibility.AccessibleAdapter;
22 import dwt.accessibility.AccessibleControlAdapter;
23 import dwt.accessibility.AccessibleControlEvent;
24 import dwt.accessibility.AccessibleEvent;
25 import dwt.accessibility.AccessibleTextAdapter;
26 import dwt.accessibility.AccessibleTextEvent;
27 import dwt.dnd.Clipboard;
28 import dwt.dnd.DND;
29 import dwt.dnd.RTFTransfer;
30 import dwt.dnd.TextTransfer;
31 import dwt.dnd.Transfer;
32 import dwt.events.ModifyListener;
33 import dwt.events.SelectionEvent;
34 import dwt.events.SelectionListener;
35 import dwt.events.VerifyListener;
36 import dwt.graphics.Color;
37 import dwt.graphics.Cursor;
38 import dwt.graphics.Font;
39 import dwt.graphics.FontData;
40 import dwt.graphics.FontMetrics;
41 import dwt.graphics.GC;
42 import dwt.graphics.GlyphMetrics;
43 import dwt.graphics.Image;
44 import dwt.graphics.Device;
45 import dwt.graphics.Point;
46 import dwt.graphics.Rectangle;
47 import dwt.graphics.Resource;
48 import dwt.graphics.TextLayout;
49 import dwt.internal.BidiUtil;
50 import dwt.internal.Compatibility;
51 import dwt.printing.Printer;
52 import dwt.printing.PrinterData;
53 import dwt.widgets.Canvas;
54 import dwt.widgets.Caret;
55 import dwt.widgets.Composite;
56 import dwt.widgets.Control;
57 import dwt.widgets.Display;
58 import dwt.widgets.Event;
59 import dwt.widgets.IME;
60 import dwt.widgets.Label;
61 import dwt.widgets.Listener;
62 import dwt.widgets.ScrollBar;
63 import dwt.widgets.TypedListener;
64 import dwt.custom.StyledTextContent;
65 import dwt.custom.TextChangeListener;
66 import dwt.custom.StyledTextRenderer;
67 import dwt.custom.StyledTextPrintOptions;
68 import dwt.custom.ExtendedModifyListener;
69 import dwt.custom.BidiSegmentListener;
70 import dwt.custom.LineBackgroundListener;
71 import dwt.custom.LineStyleListener;
72 import dwt.custom.PaintObjectListener;
73 import dwt.custom.VerifyKeyListener;
74 import dwt.custom.MovementListener;
75 import dwt.custom.Bullet;
76 import dwt.custom.StyledTextEvent;
77 import dwt.custom.StyleRange;
78 import dwt.custom.TextChangedEvent;
79 import dwt.custom.TextChangingEvent;
80 import dwt.custom.DefaultContent;
81 import dwt.custom.StyledTextDropTargetEffect;
82 import dwt.custom.StyledTextListener;
83 import dwt.custom.ST;
84 import dwt.dwthelper.Runnable;
15 85
16 import dwt.*; 86 static import tango.text.Text;
17 import dwt.accessibility.*; 87 static import tango.text.Util;
18 import dwt.dnd.*; 88 static import tango.io.model.IFile;
19 import dwt.events.*; 89 static import tango.text.convert.Utf;
20 import dwt.graphics.*; 90 import tango.util.Convert;
21 import dwt.internal.*; 91 import dwt.dwthelper.utils;
22 import dwt.printing.*;
23 import dwt.widgets.*;
24 92
25 /** 93 alias tango.text.Text.Text!(char) StringBuffer;
26 * A StyledText is an editable user interface object that displays lines 94
27 * of text. The following style attributes can be defined for the text: 95 /**
96 * A StyledText is an editable user interface object that displays lines
97 * of text. The following style attributes can be defined for the text:
28 * <ul> 98 * <ul>
29 * <li>foreground color 99 * <li>foreground color
30 * <li>background color 100 * <li>background color
31 * <li>font style (bold, italic, bold-italic, regular) 101 * <li>font style (bold, italic, bold-italic, regular)
32 * <li>underline 102 * <li>underline
33 * <li>strikeout 103 * <li>strikeout
34 * </ul> 104 * </ul>
35 * <p> 105 * <p>
36 * In addition to text style attributes, the background color of a line may 106 * In addition to text style attributes, the background color of a line may
37 * be specified. 107 * be specified.
38 * </p><p> 108 * </p><p>
39 * There are two ways to use this widget when specifying text style information. 109 * There are two ways to use this widget when specifying text style information.
40 * You may use the API that is defined for StyledText or you may define your own 110 * You may use the API that is defined for StyledText or you may define your own
41 * LineStyleListener. If you define your own listener, you will be responsible 111 * LineStyleListener. If you define your own listener, you will be responsible
42 * for maintaining the text style information for the widget. IMPORTANT: You may 112 * for maintaining the text style information for the widget. IMPORTANT: You may
43 * not define your own listener and use the StyledText API. The following 113 * not define your own listener and use the StyledText API. The following
44 * StyledText API is not supported if you have defined a LineStyleListener: 114 * StyledText API is not supported if you have defined a LineStyleListener:
45 * <ul> 115 * <ul>
46 * <li>getStyleRangeAtOffset(int) 116 * <li>getStyleRangeAtOffset(int)
47 * <li>getStyleRanges() 117 * <li>getStyleRanges()
49 * <li>setStyleRange(StyleRange) 119 * <li>setStyleRange(StyleRange)
50 * <li>setStyleRanges(StyleRange[]) 120 * <li>setStyleRanges(StyleRange[])
51 * </ul> 121 * </ul>
52 * </p><p> 122 * </p><p>
53 * There are two ways to use this widget when specifying line background colors. 123 * There are two ways to use this widget when specifying line background colors.
54 * You may use the API that is defined for StyledText or you may define your own 124 * You may use the API that is defined for StyledText or you may define your own
55 * LineBackgroundListener. If you define your own listener, you will be responsible 125 * LineBackgroundListener. If you define your own listener, you will be responsible
56 * for maintaining the line background color information for the widget. 126 * for maintaining the line background color information for the widget.
57 * IMPORTANT: You may not define your own listener and use the StyledText API. 127 * IMPORTANT: You may not define your own listener and use the StyledText API.
58 * The following StyledText API is not supported if you have defined a 128 * The following StyledText API is not supported if you have defined a
59 * LineBackgroundListener: 129 * LineBackgroundListener:
60 * <ul> 130 * <ul>
61 * <li>getLineBackground(int) 131 * <li>getLineBackground(int)
62 * <li>setLineBackground(int,int,Color) 132 * <li>setLineBackground(int,int,Color)
63 * </ul> 133 * </ul>
64 * </p><p> 134 * </p><p>
65 * The content implementation for this widget may also be user-defined. To do so, 135 * The content implementation for this widget may also be user-defined. To do so,
66 * you must implement the StyledTextContent interface and use the StyledText API 136 * you must implement the StyledTextContent interface and use the StyledText API
67 * setContent(StyledTextContent) to initialize the widget. 137 * setContent(StyledTextContent) to initialize the widget.
68 * </p><p> 138 * </p><p>
69 * <dl> 139 * <dl>
70 * <dt><b>Styles:</b><dd>FULL_SELECTION, MULTI, READ_ONLY, SINGLE, WRAP 140 * <dt><b>Styles:</b><dd>FULL_SELECTION, MULTI, READ_ONLY, SINGLE, WRAP
71 * <dt><b>Events:</b><dd>ExtendedModify, LineGetBackground, LineGetSegments, LineGetStyle, Modify, Selection, Verify, VerifyKey 141 * <dt><b>Events:</b><dd>ExtendedModify, LineGetBackground, LineGetSegments, LineGetStyle, Modify, Selection, Verify, VerifyKey
72 * </dl> 142 * </dl>
73 * </p><p> 143 * </p><p>
74 * IMPORTANT: This class is <em>not</em> intended to be subclassed. 144 * IMPORTANT: This class is <em>not</em> intended to be subclassed.
75 * </p> 145 * </p>
146 *
147 * @see <a href="http://www.eclipse.org/swt/snippets/#styledtext">StyledText snippets</a>
148 * @see <a href="http://www.eclipse.org/swt/examples.php">DWT Examples: CustomControlExample, TextEditor</a>
149 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
76 */ 150 */
77 public class StyledText : Canvas { 151 public class StyledText : Canvas {
78 static final char TAB = '\t'; 152 alias Canvas.computeSize computeSize;
79 static final String PlatformLineDelimiter = System.getProperty("line.separator"); 153
80 static final int BIDI_CARET_WIDTH = 3; 154 static const char TAB = '\t';
81 static final int DEFAULT_WIDTH = 64; 155 static const String PlatformLineDelimiter = tango.io.model.IFile.FileConst.NewlineString;
82 static final int DEFAULT_HEIGHT = 64; 156 static const int BIDI_CARET_WIDTH = 3;
83 static final int V_SCROLL_RATE = 50; 157 static const int DEFAULT_WIDTH = 64;
84 static final int H_SCROLL_RATE = 10; 158 static const int DEFAULT_HEIGHT = 64;
85 159 static const int V_SCROLL_RATE = 50;
86 static final int ExtendedModify = 3000; 160 static const int H_SCROLL_RATE = 10;
87 static final int LineGetBackground = 3001; 161
88 static final int LineGetStyle = 3002; 162 static const int ExtendedModify = 3000;
89 static final int TextChanging = 3003; 163 static const int LineGetBackground = 3001;
90 static final int TextSet = 3004; 164 static const int LineGetStyle = 3002;
91 static final int VerifyKey = 3005; 165 static const int TextChanging = 3003;
92 static final int TextChanged = 3006; 166 static const int TextSet = 3004;
93 static final int LineGetSegments = 3007; 167 static const int VerifyKey = 3005;
94 static final int PaintObject = 3008; 168 static const int TextChanged = 3006;
95 static final int WordNext = 3009; 169 static const int LineGetSegments = 3007;
96 static final int WordPrevious = 3010; 170 static const int PaintObject = 3008;
97 171 static const int WordNext = 3009;
98 static final int PREVIOUS_OFFSET_TRAILING = 0; 172 static const int WordPrevious = 3010;
99 static final int OFFSET_LEADING = 1; 173
100 174 static const int PREVIOUS_OFFSET_TRAILING = 0;
175 static const int OFFSET_LEADING = 1;
176
101 Color selectionBackground; // selection background color 177 Color selectionBackground; // selection background color
102 Color selectionForeground; // selection foreground color 178 Color selectionForeground; // selection foreground color
103 StyledTextContent content; // native content (default or user specified) 179 StyledTextContent content; // native content (default or user specified)
104 StyledTextRenderer renderer; 180 StyledTextRenderer renderer;
105 Listener listener; 181 Listener listener;
116 int rightMargin; 192 int rightMargin;
117 int bottomMargin; 193 int bottomMargin;
118 int columnX; // keep track of the horizontal caret position when changing lines/pages. Fixes bug 5935 194 int columnX; // keep track of the horizontal caret position when changing lines/pages. Fixes bug 5935
119 int caretOffset = 0; 195 int caretOffset = 0;
120 int caretAlignment; 196 int caretAlignment;
121 Point selection = new Point(0, 0); // x and y are start and end caret offsets of selection 197 Point selection; // x and y are start and end caret offsets of selection
122 Point clipboardSelection; // x and y are start and end caret offsets of previous selection 198 Point clipboardSelection; // x and y are start and end caret offsets of previous selection
123 int selectionAnchor; // position of selection anchor. 0 based offset from beginning of text 199 int selectionAnchor; // position of selection anchor. 0 based offset from beginning of text
124 Point doubleClickSelection; // selection after last mouse double click 200 Point doubleClickSelection; // selection after last mouse double click
125 bool editable = true; 201 bool editable = true;
126 bool wordWrap = false; 202 bool wordWrap = false;
127 bool doubleClickEnabled = true; // see getDoubleClickEnabled 203 bool doubleClickEnabled = true; // see getDoubleClickEnabled
128 bool overwrite = false; // insert/overwrite edit mode 204 bool overwrite = false; // insert/overwrite edit mode
129 int textLimit = -1; // limits the number of characters the user can type in the widget. Unlimited by default. 205 int textLimit = -1; // limits the number of characters the user can type in the widget. Unlimited by default.
130 Hashtable keyActionMap = new Hashtable(); 206 int[int] keyActionMap;
131 Color background = null; // workaround for bug 4791 207 Color background = null; // workaround for bug 4791
132 Color foreground = null; // 208 Color foreground = null; //
133 Clipboard clipboard; 209 Clipboard clipboard;
134 int clickCount; 210 int clickCount;
135 int autoScrollDirection = DWT.NULL; // the direction of autoscrolling (up, down, right, left) 211 int autoScrollDirection = DWT.NULL; // the direction of autoscrolling (up, down, right, left)
136 int autoScrollDistance = 0; 212 int autoScrollDistance = 0;
137 int lastTextChangeStart; // cache data of the 213 int lastTextChangeStart; // cache data of the
138 int lastTextChangeNewLineCount; // last text changing 214 int lastTextChangeNewLineCount; // last text changing
139 int lastTextChangeNewCharCount; // event for use in the 215 int lastTextChangeNewCharCount; // event for use in the
140 int lastTextChangeReplaceLineCount; // text changed handler 216 int lastTextChangeReplaceLineCount; // text changed handler
141 int lastTextChangeReplaceCharCount; 217 int lastTextChangeReplaceCharCount;
142 int lastLineBottom; // the bottom pixel of the last line been replaced 218 int lastLineBottom; // the bottom pixel of the last line been replaced
143 bool isMirrored; 219 bool isMirrored_;
144 bool bidiColoring = false; // apply the BIDI algorithm on text segments of the same color 220 bool bidiColoring = false; // apply the BIDI algorithm on text segments of the same color
145 Image leftCaretBitmap = null; 221 Image leftCaretBitmap = null;
146 Image rightCaretBitmap = null; 222 Image rightCaretBitmap = null;
147 int caretDirection = DWT.NULL; 223 int caretDirection = DWT.NULL;
148 int caretWidth = 0; 224 int caretWidth = 0;
149 Caret defaultCaret = null; 225 Caret defaultCaret = null;
150 bool updateCaretDirection = true; 226 bool updateCaretDirection = true;
151 bool fixedLineHeight; 227 bool fixedLineHeight;
152 bool dragDetect = true; 228 bool dragDetect_ = true;
153 IME ime; 229 IME ime;
154 230
155 int alignment; 231 int alignment;
156 bool justify; 232 bool justify;
157 int indent; 233 int indent;
158 int lineSpacing; 234 int lineSpacing;
159 235
160 final static bool IS_CARBON, IS_GTK, IS_MOTIF; 236 const static bool IS_CARBON, IS_GTK, IS_MOTIF;
161 static { 237 static this(){
162 String platform = DWT.getPlatform(); 238 String platform = DWT.getPlatform();
163 IS_CARBON = "carbon".opEquals(platform); 239 IS_CARBON = ("carbon" == platform);
164 IS_GTK = "gtk".opEquals(platform); 240 IS_GTK = ("gtk" == platform);
165 IS_MOTIF = "motif".opEquals(platform); 241 IS_MOTIF = ("motif" == platform);
166 } 242 }
167 243
168 /** 244 /**
169 * The Printing class : printing of a range of text. 245 * The Printing class : printing of a range of text.
170 * An instance of <code>Printing</code> is returned in the 246 * An instance of <code>Printing</code> is returned in the
171 * StyledText#print(Printer) API. The run() method may be 247 * StyledText#print(Printer) API. The run() method may be
172 * invoked from any thread. 248 * invoked from any thread.
173 */ 249 */
174 static class Printing : Runnable { 250 static class Printing : Runnable {
175 final static int LEFT = 0; // left aligned header/footer segment 251 const static int LEFT = 0; // left aligned header/footer segment
176 final static int CENTER = 1; // centered header/footer segment 252 const static int CENTER = 1; // centered header/footer segment
177 final static int RIGHT = 2; // right aligned header/footer segment 253 const static int RIGHT = 2; // right aligned header/footer segment
178 254
179 Printer printer; 255 Printer printer;
180 StyledTextRenderer printerRenderer; 256 StyledTextRenderer printerRenderer;
181 StyledTextPrintOptions printOptions; 257 StyledTextPrintOptions printOptions;
182 Rectangle clientArea; 258 Rectangle clientArea;
183 FontData fontData; 259 FontData fontData;
184 Font printerFont; 260 Font printerFont;
185 Hashtable resources; 261 Resource[Resource] resources;
186 int tabLength; 262 int tabLength;
187 GC gc; // printer GC 263 GC gc; // printer GC
188 int pageWidth; // width of a printer page in pixels 264 int pageWidth; // width of a printer page in pixels
189 int startPage; // first page to print 265 int startPage; // first page to print
190 int endPage; // last page to print 266 int endPage; // last page to print
191 int startLine; // first (wrapped) line to print 267 int startLine; // first (wrapped) line to print
192 int endLine; // last (wrapped) line to print 268 int endLine; // last (wrapped) line to print
193 bool singleLine; // widget single line mode 269 bool singleLine; // widget single line mode
194 Point selection = null; // selected text 270 Point selection = null; // selected text
195 bool mirrored; // indicates the printing gc should be mirrored 271 bool mirrored; // indicates the printing gc should be mirrored
196 int lineSpacing; 272 int lineSpacing;
197 int printMargin; 273 int printMargin;
198 274
199 /** 275 /**
200 * Creates an instance of <code>Printing</code>. 276 * Creates an instance of <code>Printing</code>.
201 * Copies the widget content and rendering data that needs 277 * Copies the widget content and rendering data that needs
202 * to be requested from listeners. 278 * to be requested from listeners.
203 * </p> 279 * </p>
204 * @param parent StyledText widget to print. 280 * @param parent StyledText widget to print.
205 * @param printer printer device to print on. 281 * @param printer printer device to print on.
206 * @param printOptions print options 282 * @param printOptions print options
207 */ 283 */
208 this(StyledText styledText, Printer printer, StyledTextPrintOptions printOptions) { 284 this(StyledText styledText, Printer printer, StyledTextPrintOptions printOptions) {
209 this.printer = printer; 285 this.printer = printer;
210 this.printOptions = printOptions; 286 this.printOptions = printOptions;
211 this.mirrored = (styledText.getStyle() & DWT.MIRRORED) !is 0; 287 this.mirrored = (styledText.getStyle() & DWT.MIRRORED) !is 0;
212 singleLine = styledText.isSingleLine(); 288 singleLine = styledText.isSingleLine();
213 startPage = 1; 289 startPage = 1;
214 endPage = Integer.MAX_VALUE; 290 endPage = int.max;
215 PrinterData data = printer.getPrinterData(); 291 PrinterData data = printer.getPrinterData();
216 if (data.scope is PrinterData.PAGE_RANGE) { 292 if (data.scope_ is PrinterData.PAGE_RANGE) {
217 startPage = data.startPage; 293 startPage = data.startPage;
218 endPage = data.endPage; 294 endPage = data.endPage;
219 if (endPage < startPage) { 295 if (endPage < startPage) {
220 int temp = endPage; 296 int temp = endPage;
221 endPage = startPage; 297 endPage = startPage;
222 startPage = temp; 298 startPage = temp;
223 } 299 }
224 } else if (data.scope is PrinterData.SELECTION) { 300 } else if (data.scope_ is PrinterData.SELECTION) {
225 selection = styledText.getSelectionRange(); 301 selection = styledText.getSelectionRange();
226 } 302 }
227 printerRenderer = new StyledTextRenderer(printer, null); 303 printerRenderer = new StyledTextRenderer(printer, null);
228 printerRenderer.setContent(copyContent(styledText.getContent())); 304 printerRenderer.setContent(copyContent(styledText.getContent()));
229 cacheLineData(styledText); 305 cacheLineData(styledText);
230 } 306 }
231 /** 307 /**
232 * Caches all line data that needs to be requested from a listener. 308 * Caches all line data that needs to be requested from a listener.
233 * </p> 309 * </p>
234 * @param printerContent <code>StyledTextContent</code> to request 310 * @param printerContent <code>StyledTextContent</code> to request
235 * line data for. 311 * line data for.
236 */ 312 */
237 void cacheLineData(StyledText styledText) { 313 void cacheLineData(StyledText styledText) {
238 StyledTextRenderer renderer = styledText.renderer; 314 StyledTextRenderer renderer = styledText.renderer;
239 renderer.copyInto(printerRenderer); 315 renderer.copyInto(printerRenderer);
250 printerRenderer.setLineBackground(i, 1, event.lineBackground); 326 printerRenderer.setLineBackground(i, 1, event.lineBackground);
251 } 327 }
252 if (styledText.isBidi()) { 328 if (styledText.isBidi()) {
253 int[] segments = styledText.getBidiSegments(lineOffset, line); 329 int[] segments = styledText.getBidiSegments(lineOffset, line);
254 printerRenderer.setLineSegments(i, 1, segments); 330 printerRenderer.setLineSegments(i, 1, segments);
255 } 331 }
256 event = styledText.getLineStyleData(lineOffset, line); 332 event = styledText.getLineStyleData(lineOffset, line);
257 if (event !is null) { 333 if (event !is null) {
258 printerRenderer.setLineIndent(i, 1, event.indent); 334 printerRenderer.setLineIndent(i, 1, event.indent);
259 printerRenderer.setLineAlignment(i, 1, event.alignment); 335 printerRenderer.setLineAlignment(i, 1, event.alignment);
260 printerRenderer.setLineJustify(i, 1, event.justify); 336 printerRenderer.setLineJustify(i, 1, event.justify);
266 } 342 }
267 } 343 }
268 } 344 }
269 Point screenDPI = styledText.getDisplay().getDPI(); 345 Point screenDPI = styledText.getDisplay().getDPI();
270 Point printerDPI = printer.getDPI(); 346 Point printerDPI = printer.getDPI();
271 resources = new Hashtable (); 347 resources = null;
272 for (int i = 0; i < lineCount; i++) { 348 for (int i = 0; i < lineCount; i++) {
273 Color color = printerRenderer.getLineBackground(i, null); 349 Color color = printerRenderer.getLineBackground(i, null);
274 if (color !is null) { 350 if (color !is null) {
275 if (printOptions.printLineBackground) { 351 if (printOptions.printLineBackground) {
276 Color printerColor = cast(Color)resources.get(color); 352 Color printerColor;
277 if (printerColor is null) { 353 if ( auto p = color in resources ) {
354 printerColor = cast(Color)*p;
355 }
356 else {
278 printerColor = new Color (printer, color.getRGB()); 357 printerColor = new Color (printer, color.getRGB());
279 resources.put(color, printerColor); 358 resources[color]=printerColor;
280 } 359 }
281 printerRenderer.setLineBackground(i, 1, printerColor); 360 printerRenderer.setLineBackground(i, 1, printerColor);
282 } else { 361 } else {
283 printerRenderer.setLineBackground(i, 1, null); 362 printerRenderer.setLineBackground(i, 1, null);
284 } 363 }
291 StyleRange[] styles = printerRenderer.styles; 370 StyleRange[] styles = printerRenderer.styles;
292 for (int i = 0; i < printerRenderer.styleCount; i++) { 371 for (int i = 0; i < printerRenderer.styleCount; i++) {
293 StyleRange style = styles[i]; 372 StyleRange style = styles[i];
294 Font font = style.font; 373 Font font = style.font;
295 if (style.font !is null) { 374 if (style.font !is null) {
296 Font printerFont = cast(Font)resources.get(font); 375 Font printerFont;
297 if (printerFont is null) { 376 if ( auto p = font in resources ) {
377 printerFont = cast(Font)*p;
378 }
379 else {
298 printerFont = new Font (printer, font.getFontData()); 380 printerFont = new Font (printer, font.getFontData());
299 resources.put(font, printerFont); 381 resources[font]= printerFont;
300 } 382 }
301 style.font = printerFont; 383 style.font = printerFont;
302 } 384 }
303 Color color = style.foreground; 385 Color color = style.foreground;
304 if (color !is null) { 386 if (color !is null) {
305 Color printerColor = cast(Color)resources.get(color);
306 if (printOptions.printTextForeground) { 387 if (printOptions.printTextForeground) {
307 if (printerColor is null) { 388 Color printerColor;
389 if ( auto p = color in resources ) {
390 printerColor = cast(Color)*p;
391 }
392 else {
308 printerColor = new Color (printer, color.getRGB()); 393 printerColor = new Color (printer, color.getRGB());
309 resources.put(color, printerColor); 394 resources[color]=printerColor;
310 } 395 }
311 style.foreground = printerColor; 396 style.foreground = printerColor;
312 } else { 397 } else {
313 style.foreground = null; 398 style.foreground = null;
314 } 399 }
315 } 400 }
316 color = style.background; 401 color = style.background;
317 if (color !is null) { 402 if (color !is null) {
318 Color printerColor = cast(Color)resources.get(color);
319 if (printOptions.printTextBackground) { 403 if (printOptions.printTextBackground) {
320 if (printerColor is null) { 404 Color printerColor;
405 if ( auto p = color in resources ) {
406 printerColor = cast(Color)*p;
407 }
408 else {
321 printerColor = new Color (printer, color.getRGB()); 409 printerColor = new Color (printer, color.getRGB());
322 resources.put(color, printerColor); 410 resources[color]=printerColor;
323 } 411 }
324 style.background = printerColor; 412 style.background = printerColor;
325 } else { 413 } else {
326 style.background = null; 414 style.background = null;
327 } 415 }
368 void dispose() { 456 void dispose() {
369 if (gc !is null) { 457 if (gc !is null) {
370 gc.dispose(); 458 gc.dispose();
371 gc = null; 459 gc = null;
372 } 460 }
373 if (resources !is null) { 461 foreach( resource; resources.values ){
374 Enumeration enumeration = resources.elements(); 462 resource.dispose();
375 while (enumeration.hasMoreElements()) { 463 }
376 Resource resource = cast(Resource) enumeration.nextElement(); 464 resources = null;
377 resource.dispose();
378 }
379 resources = null;
380 }
381 if (printerFont !is null) { 465 if (printerFont !is null) {
382 printerFont.dispose(); 466 printerFont.dispose();
383 printerFont = null; 467 printerFont = null;
384 } 468 }
385 if (printerRenderer !is null) { 469 if (printerRenderer !is null) {
388 } 472 }
389 } 473 }
390 void init_() { 474 void init_() {
391 Rectangle trim = printer.computeTrim(0, 0, 0, 0); 475 Rectangle trim = printer.computeTrim(0, 0, 0, 0);
392 Point dpi = printer.getDPI(); 476 Point dpi = printer.getDPI();
393 477
394 printerFont = new Font(printer, fontData.getName(), fontData.getHeight(), DWT.NORMAL); 478 printerFont = new Font( cast(Device)printer, fontData.getName(), fontData.getHeight(), DWT.NORMAL);
395 clientArea = printer.getClientArea(); 479 clientArea = printer.getClientArea();
396 pageWidth = clientArea.width; 480 pageWidth = clientArea.width;
397 // one inch margin around text 481 // one inch margin around text
398 clientArea.x = dpi.x + trim.x; 482 clientArea.x = dpi.x + trim.x;
399 clientArea.y = dpi.y + trim.y; 483 clientArea.y = dpi.y + trim.y;
400 clientArea.width -= (clientArea.x + trim.width); 484 clientArea.width -= (clientArea.x + trim.width);
401 clientArea.height -= (clientArea.y + trim.height); 485 clientArea.height -= (clientArea.y + trim.height);
402 486
403 int style = mirrored ? DWT.RIGHT_TO_LEFT : DWT.LEFT_TO_RIGHT; 487 int style = mirrored ? DWT.RIGHT_TO_LEFT : DWT.LEFT_TO_RIGHT;
404 gc = new GC(printer, style); 488 gc = new GC(printer, style);
405 gc.setFont(printerFont); 489 gc.setFont(printerFont);
406 printerRenderer.setFont(printerFont, tabLength); 490 printerRenderer.setFont(printerFont, tabLength);
410 clientArea.height -= lineHeight * 2; 494 clientArea.height -= lineHeight * 2;
411 } 495 }
412 if (printOptions.footer !is null) { 496 if (printOptions.footer !is null) {
413 clientArea.height -= lineHeight * 2; 497 clientArea.height -= lineHeight * 2;
414 } 498 }
415 499
416 // TODO not wrapped 500 // TODO not wrapped
417 StyledTextContent content = printerRenderer.content; 501 StyledTextContent content = printerRenderer.content;
418 startLine = 0; 502 startLine = 0;
419 endLine = singleLine ? 0 : content.getLineCount() - 1; 503 endLine = singleLine ? 0 : content.getLineCount() - 1;
420 PrinterData data = printer.getPrinterData(); 504 PrinterData data = printer.getPrinterData();
421 if (data.scope is PrinterData.PAGE_RANGE) { 505 if (data.scope_ is PrinterData.PAGE_RANGE) {
422 int pageSize = clientArea.height / lineHeight;//WRONG 506 int pageSize = clientArea.height / lineHeight;//WRONG
423 startLine = (startPage - 1) * pageSize; 507 startLine = (startPage - 1) * pageSize;
424 } else if (data.scope is PrinterData.SELECTION) { 508 } else if (data.scope_ is PrinterData.SELECTION) {
425 startLine = content.getLineAtOffset(selection.x); 509 startLine = content.getLineAtOffset(selection.x);
426 if (selection.y > 0) { 510 if (selection.y > 0) {
427 endLine = content.getLineAtOffset(selection.x + selection.y - 1); 511 endLine = content.getLineAtOffset(selection.x + selection.y - 1);
428 } else { 512 } else {
429 endLine = startLine - 1; 513 endLine = startLine - 1;
475 printer.startPage(); 559 printer.startPage();
476 printDecoration(page, true, printLayout); 560 printDecoration(page, true, printLayout);
477 } 561 }
478 TextLayout layout = printerRenderer.getTextLayout(i, orientation, width, lineSpacing); 562 TextLayout layout = printerRenderer.getTextLayout(i, orientation, width, lineSpacing);
479 Color lineBackground = printerRenderer.getLineBackground(i, background); 563 Color lineBackground = printerRenderer.getLineBackground(i, background);
480 int paragraphBottom = paintY + layout.getBounds().height; 564 int paragraphBottom = paintY + layout.getBounds().height;
481 if (paragraphBottom <= pageBottom) { 565 if (paragraphBottom <= pageBottom) {
482 //normal case, the whole paragraph fits in the current page 566 //normal case, the whole paragraph fits in the current page
483 printLine(paintX, paintY, gc, foreground, lineBackground, layout, printLayout, i); 567 printLine(paintX, paintY, gc, foreground, lineBackground, layout, printLayout, i);
484 paintY = paragraphBottom; 568 paintY = paragraphBottom;
485 } else { 569 } else {
505 int height = paragraphBottom - paintY; 589 int height = paragraphBottom - paintY;
506 gc.setClipping(clientArea.x, paintY, clientArea.width, height); 590 gc.setClipping(clientArea.x, paintY, clientArea.width, height);
507 printLine(paintX, paintY, gc, foreground, lineBackground, layout, printLayout, i); 591 printLine(paintX, paintY, gc, foreground, lineBackground, layout, printLayout, i);
508 gc.setClipping(cast(Rectangle)null); 592 gc.setClipping(cast(Rectangle)null);
509 printDecoration(page, false, printLayout); 593 printDecoration(page, false, printLayout);
510 printer.endPage(); 594 printer.endPage();
511 page++; 595 page++;
512 if (page <= endPage) { 596 if (page <= endPage) {
513 printer.startPage(); 597 printer.startPage();
514 printDecoration(page, true, printLayout); 598 printDecoration(page, true, printLayout);
515 paintY = clientArea.y - height; 599 paintY = clientArea.y - height;
530 } 614 }
531 if (printLayout !is null) printLayout.dispose(); 615 if (printLayout !is null) printLayout.dispose();
532 } 616 }
533 /** 617 /**
534 * Print header or footer decorations. 618 * Print header or footer decorations.
535 * 619 *
536 * @param page page number to print, if specified in the StyledTextPrintOptions header or footer. 620 * @param page page number to print, if specified in the StyledTextPrintOptions header or footer.
537 * @param header true = print the header, false = print the footer 621 * @param header true = print the header, false = print the footer
538 */ 622 */
539 void printDecoration(int page, bool header, TextLayout layout) { 623 void printDecoration(int page, bool header, TextLayout layout) {
540 String text = header ? printOptions.header : printOptions.footer; 624 String text = header ? printOptions.header : printOptions.footer;
541 if (text is null) return; 625 if (text is null) return;
542 int lastSegmentIndex = 0; 626 int lastSegmentIndex = 0;
543 for (int i = 0; i < 3; i++) { 627 for (int i = 0; i < 3; i++) {
544 int segmentIndex = text.indexOf(StyledTextPrintOptions.SEPARATOR, lastSegmentIndex); 628 int segmentIndex = text.indexOf( StyledTextPrintOptions.SEPARATOR, lastSegmentIndex);
545 String segment; 629 String segment;
546 if (segmentIndex is -1) { 630 if (segmentIndex is -1 ) {
547 segment = text.substring(lastSegmentIndex); 631 segment = text.substring(lastSegmentIndex);
548 printDecorationSegment(segment, i, page, header, layout); 632 printDecorationSegment(segment, i, page, header, layout);
549 break; 633 break;
550 } else { 634 } else {
551 segment = text.substring(lastSegmentIndex, segmentIndex); 635 segment = text.substring(lastSegmentIndex, segmentIndex);
552 printDecorationSegment(segment, i, page, header, layout); 636 printDecorationSegment(segment, i, page, header, layout);
553 lastSegmentIndex = segmentIndex + StyledTextPrintOptions.SEPARATOR.length(); 637 lastSegmentIndex = segmentIndex + StyledTextPrintOptions.SEPARATOR.length;
554 } 638 }
555 } 639 }
556 } 640 }
557 /** 641 /**
558 * Print one segment of a header or footer decoration. 642 * Print one segment of a header or footer decoration.
559 * Headers and footers have three different segments. 643 * Headers and footers have three different segments.
560 * One each for left aligned, centered, and right aligned text. 644 * One each for left aligned, centered, and right aligned text.
561 * 645 *
562 * @param segment decoration segment to print 646 * @param segment decoration segment to print
563 * @param alignment alignment of the segment. 0=left, 1=center, 2=right 647 * @param alignment alignment of the segment. 0=left, 1=center, 2=right
564 * @param page page number to print, if specified in the decoration segment. 648 * @param page page number to print, if specified in the decoration segment.
565 * @param header true = print the header, false = print the footer 649 * @param header true = print the header, false = print the footer
566 */ 650 */
567 void printDecorationSegment(String segment, int alignment, int page, bool header, TextLayout layout) { 651 void printDecorationSegment(String segment, int alignment, int page, bool header, TextLayout layout) {
568 int pageIndex = segment.indexOf(StyledTextPrintOptions.PAGE_TAG); 652 int pageIndex = segment.indexOf(StyledTextPrintOptions.PAGE_TAG);
569 if (pageIndex !is -1) { 653 if (pageIndex !is -1 ) {
570 int pageTagLength = StyledTextPrintOptions.PAGE_TAG.length(); 654 int pageTagLength = StyledTextPrintOptions.PAGE_TAG.length;
571 StringBuffer buffer = new StringBuffer(segment.substring (0, pageIndex)); 655 StringBuffer buffer = new StringBuffer(segment.substring (0, pageIndex));
572 buffer.append (page); 656 buffer.append (page);
573 buffer.append (segment.substring(pageIndex + pageTagLength)); 657 buffer.append (segment.substring(pageIndex + pageTagLength));
574 segment = buffer.toString(); 658 segment = buffer.toString().dup;
575 } 659 }
576 if (segment.length() > 0) { 660 if (segment.length > 0) {
577 layout.setText(segment); 661 layout.setText(segment);
578 int segmentWidth = layout.getBounds().width; 662 int segmentWidth = layout.getBounds().width;
579 int segmentHeight = printerRenderer.getLineHeight(); 663 int segmentHeight = printerRenderer.getLineHeight();
580 int drawX = 0, drawY; 664 int drawX = 0, drawY;
581 if (alignment is LEFT) { 665 if (alignment is LEFT) {
596 void printLine(int x, int y, GC gc, Color foreground, Color background, TextLayout layout, TextLayout printLayout, int index) { 680 void printLine(int x, int y, GC gc, Color foreground, Color background, TextLayout layout, TextLayout printLayout, int index) {
597 if (background !is null) { 681 if (background !is null) {
598 Rectangle rect = layout.getBounds(); 682 Rectangle rect = layout.getBounds();
599 gc.setBackground(background); 683 gc.setBackground(background);
600 gc.fillRectangle(x, y, rect.width, rect.height); 684 gc.fillRectangle(x, y, rect.width, rect.height);
601 685
602 // int lineCount = layout.getLineCount(); 686 // int lineCount = layout.getLineCount();
603 // for (int i = 0; i < lineCount; i++) { 687 // for (int i = 0; i < lineCount; i++) {
604 // Rectangle rect = layout.getLineBounds(i); 688 // Rectangle rect = layout.getLineBounds(i);
605 // rect.x += paintX; 689 // rect.x += paintX;
606 // rect.y += paintY + layout.getSpacing(); 690 // rect.y += paintY + layout.getSpacing();
618 printLayout.setText(lineLabels[index]); 702 printLayout.setText(lineLabels[index]);
619 } else { 703 } else {
620 printLayout.setText(""); 704 printLayout.setText("");
621 } 705 }
622 } else { 706 } else {
623 printLayout.setText(String.valueOf(index)); 707 printLayout.setText(to!(String)(index));
624 } 708 }
625 int paintX = x - printMargin - printLayout.getBounds().width; 709 int paintX = x - printMargin - printLayout.getBounds().width;
626 printLayout.draw(gc, paintX, y); 710 printLayout.draw(gc, paintX, y);
627 printLayout.setAscent(-1); 711 printLayout.setAscent(-1);
628 printLayout.setDescent(-1); 712 printLayout.setDescent(-1);
637 String jobName = printOptions.jobName; 721 String jobName = printOptions.jobName;
638 if (jobName is null) { 722 if (jobName is null) {
639 jobName = "Printing"; 723 jobName = "Printing";
640 } 724 }
641 if (printer.startJob(jobName)) { 725 if (printer.startJob(jobName)) {
642 init(); 726 init_();
643 print(); 727 print();
644 dispose(); 728 dispose();
645 printer.endJob(); 729 printer.endJob();
646 } 730 }
647 } 731 }
648 } 732 }
649 /** 733 /**
650 * The <code>RTFWriter</code> class is used to write widget content as 734 * The <code>RTFWriter</code> class is used to write widget content as
651 * rich text. The implementation complies with the RTF specification 735 * rich text. The implementation complies with the RTF specification
652 * version 1.5. 736 * version 1.5.
653 * <p> 737 * <p>
654 * toString() is guaranteed to return a valid RTF String only after 738 * toString() is guaranteed to return a valid RTF string only after
655 * close() has been called. 739 * close() has been called.
656 * </p><p> 740 * </p><p>
657 * Whole and partial lines and line breaks can be written. Lines will be 741 * Whole and partial lines and line breaks can be written. Lines will be
658 * formatted using the styles queried from the LineStyleListener, if 742 * formatted using the styles queried from the LineStyleListener, if
659 * set, or those set directly in the widget. All styles are applied to 743 * set, or those set directly in the widget. All styles are applied to
660 * the RTF stream like they are rendered by the widget. In addition, the 744 * the RTF stream like they are rendered by the widget. In addition, the
661 * widget font name and size is used for the whole text. 745 * widget font name and size is used for the whole text.
662 * </p> 746 * </p>
663 */ 747 */
664 class RTFWriter : TextWriter { 748 class RTFWriter : TextWriter {
665 static final int DEFAULT_FOREGROUND = 0; 749
666 static final int DEFAULT_BACKGROUND = 1; 750 alias TextWriter.write write;
667 Vector colorTable, fontTable; 751
752 static const int DEFAULT_FOREGROUND = 0;
753 static const int DEFAULT_BACKGROUND = 1;
754 Color[] colorTable;
755 Font[] fontTable;
668 bool WriteUnicode; 756 bool WriteUnicode;
669 757
670 /** 758 /**
671 * Creates a RTF writer that writes content starting at offset "start" 759 * Creates a RTF writer that writes content starting at offset "start"
672 * in the document. <code>start</code> and <code>length</code>can be set to specify partial 760 * in the document. <code>start</code> and <code>length</code>can be set to specify partial
673 * lines. 761 * lines.
674 * 762 *
675 * @param start start offset of content to write, 0 based from 763 * @param start start offset of content to write, 0 based from
676 * beginning of document 764 * beginning of document
677 * @param length length of content to write 765 * @param length length of content to write
678 */ 766 */
679 public this(int start, int length) { 767 public this(int start, int length) {
680 super(start, length); 768 super(start, length);
681 colorTable = new Vector(); 769 colorTable ~= getForeground();
682 fontTable = new Vector(); 770 colorTable ~= getBackground();
683 colorTable.addElement(getForeground()); 771 fontTable ~= getFont();
684 colorTable.addElement(getBackground());
685 fontTable.addElement(getFont());
686 setUnicode(); 772 setUnicode();
687 } 773 }
688 /** 774 /**
689 * Closes the RTF writer. Once closed no more content can be written. 775 * Closes the RTF writer. Once closed no more content can be written.
690 * <b>NOTE:</b> <code>toString()</code> does not return a valid RTF String until 776 * <b>NOTE:</b> <code>toString()</code> does not return a valid RTF string until
691 * <code>close()</code> has been called. 777 * <code>close()</code> has been called.
692 */ 778 */
693 public void close() { 779 public override void close() {
694 if (!isClosed()) { 780 if (!isClosed()) {
695 writeHeader(); 781 writeHeader();
696 write("\n}}\0"); 782 write("\n}}\0");
697 super.close(); 783 super.close();
698 } 784 }
699 } 785 }
700 /** 786 /**
701 * Returns the index of the specified color in the RTF color table. 787 * Returns the index of the specified color in the RTF color table.
702 * 788 *
703 * @param color the color 789 * @param color the color
704 * @param defaultIndex return value if color is null 790 * @param defaultIndex return value if color is null
705 * @return the index of the specified color in the RTF color table 791 * @return the index of the specified color in the RTF color table
706 * or "defaultIndex" if "color" is null. 792 * or "defaultIndex" if "color" is null.
707 */ 793 */
708 int getColorIndex(Color color, int defaultIndex) { 794 int getColorIndex(Color color, int defaultIndex) {
709 if (color is null) return defaultIndex; 795 if (color is null) return defaultIndex;
710 int index = colorTable.indexOf(color); 796 int index = -1;
797 foreach( i, col; colorTable ){
798 if( col == color ){
799 index = i;
800 break;
801 }
802 }
711 if (index is -1) { 803 if (index is -1) {
712 index = colorTable.size(); 804 index = colorTable.length;
713 colorTable.addElement(color); 805 colorTable ~= color;
714 } 806 }
715 return index; 807 return index;
716 } 808 }
717 /** 809 /**
718 * Returns the index of the specified color in the RTF color table. 810 * Returns the index of the specified color in the RTF color table.
721 * @param defaultIndex return value if color is null 813 * @param defaultIndex return value if color is null
722 * @return the index of the specified color in the RTF color table 814 * @return the index of the specified color in the RTF color table
723 * or "defaultIndex" if "color" is null. 815 * or "defaultIndex" if "color" is null.
724 */ 816 */
725 int getFontIndex(Font font) { 817 int getFontIndex(Font font) {
726 int index = fontTable.indexOf(font); 818 int index = -1;
819 foreach( i, f; colorTable ){
820 if( f == font ){
821 index = i;
822 break;
823 }
824 }
727 if (index is -1) { 825 if (index is -1) {
728 index = fontTable.size(); 826 index = fontTable.length;
729 fontTable.addElement(font); 827 fontTable ~= font;
730 } 828 }
731 return index; 829 return index;
732 } 830 }
733 /** 831 /**
734 * Determines if Unicode RTF should be written. 832 * Determines if Unicode RTF should be written.
735 * Don't write Unicode RTF on Windows 95/98/ME or NT. 833 * Don't write Unicode RTF on Windows 95/98/ME or NT.
736 */ 834 */
737 void setUnicode() { 835 void setUnicode() {
738 final String Win95 = "windows 95"; 836 // const String Win95 = "windows 95";
739 final String Win98 = "windows 98"; 837 // const String Win98 = "windows 98";
740 final String WinME = "windows me"; 838 // const String WinME = "windows me";
741 final String WinNT = "windows nt"; 839 // const String WinNT = "windows nt";
742 String osName = System.getProperty("os.name").toLowerCase(); 840 // String osName = System.getProperty("os.name").toLowerCase();
743 String osVersion = System.getProperty("os.version"); 841 // String osVersion = System.getProperty("os.version");
744 int majorVersion = 0; 842 // int majorVersion = 0;
745 843 //
746 if (osName.startsWith(WinNT) && osVersion !is null) { 844 // if (osName.startsWith(WinNT) && osVersion !is null) {
747 int majorIndex = osVersion.indexOf('.'); 845 // int majorIndex = osVersion.indexOf('.');
748 if (majorIndex !is -1) { 846 // if (majorIndex !is -1) {
749 osVersion = osVersion.substring(0, majorIndex); 847 // osVersion = osVersion.substring(0, majorIndex);
750 try { 848 // try {
751 majorVersion = Integer.parseInt(osVersion); 849 // majorVersion = Integer.parseInt(osVersion);
752 } catch (NumberFormatException exception) { 850 // } catch (NumberFormatException exception) {
753 // ignore exception. version number remains unknown. 851 // // ignore exception. version number remains unknown.
754 // will write without Unicode 852 // // will write without Unicode
755 } 853 // }
756 } 854 // }
757 } 855 // }
758 WriteUnicode = !osName.startsWith(Win95) && 856 // WriteUnicode = !osName.startsWith(Win95) &&
759 !osName.startsWith(Win98) && 857 // !osName.startsWith(Win98) &&
760 !osName.startsWith(WinME) && 858 // !osName.startsWith(WinME) &&
761 (!osName.startsWith(WinNT) || majorVersion > 4); 859 // (!osName.startsWith(WinNT) || majorVersion > 4);
860 WriteUnicode = true; // we are on linux-gtk
762 } 861 }
763 /** 862 /**
764 * Appends the specified segment of "String" to the RTF data. 863 * Appends the specified segment of "string" to the RTF data.
765 * Copy from <code>start</code> up to, but excluding, <code>end</code>. 864 * Copy from <code>start</code> up to, but excluding, <code>end</code>.
766 * 865 *
767 * @param String String to copy a segment from. Must not contain 866 * @param string string to copy a segment from. Must not contain
768 * line breaks. Line breaks should be written using writeLineDelimiter() 867 * line breaks. Line breaks should be written using writeLineDelimiter()
769 * @param start start offset of segment. 0 based. 868 * @param start start offset of segment. 0 based.
770 * @param end end offset of segment 869 * @param end end offset of segment
771 */ 870 */
772 void write(String String, int start, int end) { 871 void write(String string, int start, int end) {
773 for (int index = start; index < end; index++) { 872 start = 0;
774 char ch = String.charAt(index); 873 end = string.length;
874 int incr = 1;
875 for (int index = start; index < end; index+=incr) {
876 dchar ch = firstCodePoint( string[index .. $], incr );
775 if (ch > 0xFF && WriteUnicode) { 877 if (ch > 0xFF && WriteUnicode) {
776 // write the sub String from the last escaped character 878 // write the sub string from the last escaped character
777 // to the current one. Fixes bug 21698. 879 // to the current one. Fixes bug 21698.
778 if (index > start) { 880 if (index > start) {
779 write(String.substring(start, index)); 881 write( string[start .. index ] );
780 } 882 }
781 write("\\u"); 883 write("\\u");
782 write(Integer.toString(cast(short) ch)); 884 write( to!(String)( cast(short)ch ));
783 write(' '); // control word delimiter 885 write(' '); // control word delimiter
784 start = index + 1; 886 start = index + incr;
785 } else if (ch is '}' || ch is '{' || ch is '\\') { 887 } else if (ch is '}' || ch is '{' || ch is '\\') {
786 // write the sub String from the last escaped character 888 // write the sub string from the last escaped character
787 // to the current one. Fixes bug 21698. 889 // to the current one. Fixes bug 21698.
788 if (index > start) { 890 if (index > start) {
789 write(String.substring(start, index)); 891 write(string[start .. index]);
790 } 892 }
791 write('\\'); 893 write('\\');
792 write(ch); 894 write(cast(char)ch); // ok because one of {}\
793 start = index + 1; 895 start = index + 1;
794 } 896 }
795 } 897 }
796 // write from the last escaped character to the end. 898 // write from the last escaped character to the end.
797 // Fixes bug 21698. 899 // Fixes bug 21698.
798 if (start < end) { 900 if (start < end) {
799 write(String.substring(start, end)); 901 write(string[ start .. end]);
800 } 902 }
801 } 903 }
802 /** 904 /**
803 * Writes the RTF header including font table and color table. 905 * Writes the RTF header including font table and color table.
804 */ 906 */
805 void writeHeader() { 907 void writeHeader() {
806 StringBuffer header = new StringBuffer(); 908 StringBuffer header = new StringBuffer();
807 FontData fontData = getFont().getFontData()[0]; 909 FontData fontData = getFont().getFontData()[0];
808 header.append("{\\rtf1\\ansi"); 910 header.append("{\\rtf1\\ansi");
809 // specify code page, necessary for copy to work in bidi 911 // specify code page, necessary for copy to work in bidi
810 // systems that don't support Unicode RTF. 912 // systems that don't support Unicode RTF.
811 String cpg = System.getProperty("file.encoding").toLowerCase(); 913 // PORTING_TODO: String cpg = System.getProperty("file.encoding").toLowerCase();
914 String cpg = "UTF16";
915 /+
812 if (cpg.startsWith("cp") || cpg.startsWith("ms")) { 916 if (cpg.startsWith("cp") || cpg.startsWith("ms")) {
813 cpg = cpg.substring(2, cpg.length()); 917 cpg = cpg.substring(2, cpg.length());
814 header.append("\\ansicpg"); 918 header.append("\\ansicpg");
815 header.append(cpg); 919 header.append(cpg);
816 } 920 }
921 +/
817 header.append("\\uc0\\deff0{\\fonttbl{\\f0\\fnil "); 922 header.append("\\uc0\\deff0{\\fonttbl{\\f0\\fnil ");
818 header.append(fontData.getName()); 923 header.append(fontData.getName());
819 header.append(";"); 924 header.append(";");
820 for (int i = 1; i < fontTable.size(); i++) { 925 for (int i = 1; i < fontTable.length; i++) {
821 header.append("\\f"); 926 header.append("\\f");
822 header.append(i); 927 header.append(i);
823 header.append(" "); 928 header.append(" ");
824 FontData fd = (cast(Font)fontTable.elementAt(i)).getFontData()[0]; 929 FontData fd = (cast(Font)fontTable[i]).getFontData()[0];
825 header.append(fd.getName()); 930 header.append(fd.getName());
826 header.append(";"); 931 header.append(";");
827 } 932 }
828 header.append("}}\n{\\colortbl"); 933 header.append("}}\n{\\colortbl");
829 for (int i = 0; i < colorTable.size(); i++) { 934 for (int i = 0; i < colorTable.length; i++) {
830 Color color = cast(Color) colorTable.elementAt(i); 935 Color color = cast(Color) colorTable[i];
831 header.append("\\red"); 936 header.append("\\red");
832 header.append(color.getRed()); 937 header.append(color.getRed());
833 header.append("\\green"); 938 header.append("\\green");
834 header.append(color.getGreen()); 939 header.append(color.getGreen());
835 header.append("\\blue"); 940 header.append("\\blue");
836 header.append(color.getBlue()); 941 header.append(color.getBlue());
837 header.append(";"); 942 header.append(";");
838 } 943 }
839 // some RTF readers ignore the deff0 font tag. Explicitly 944 // some RTF readers ignore the deff0 font tag. Explicitly
840 // set the font for the whole document to work around this. 945 // set the font for the whole document to work around this.
841 header.append("}\n{\\f0\\fs"); 946 header.append("}\n{\\f0\\fs");
842 // font size is specified in half points 947 // font size is specified in half points
843 header.append(fontData.getHeight() * 2); 948 header.append(fontData.getHeight() * 2);
844 header.append(" "); 949 header.append(" ");
845 write(header.toString(), 0); 950 write(header.toString(), 0);
846 } 951 }
847 /** 952 /**
848 * Appends the specified line text to the RTF data. Lines will be formatted 953 * Appends the specified line text to the RTF data. Lines will be formatted
849 * using the styles queried from the LineStyleListener, if set, or those set 954 * using the styles queried from the LineStyleListener, if set, or those set
850 * directly in the widget. 955 * directly in the widget.
851 * 956 *
852 * @param line line text to write as RTF. Must not contain line breaks 957 * @param line line text to write as RTF. Must not contain line breaks
853 * Line breaks should be written using writeLineDelimiter() 958 * Line breaks should be written using writeLineDelimiter()
854 * @param lineOffset offset of the line. 0 based from the start of the 959 * @param lineOffset offset of the line. 0 based from the start of the
855 * widget document. Any text occurring before the start offset or after the 960 * widget document. Any text occurring before the start offset or after the
856 * end offset specified during object creation is ignored. 961 * end offset specified during object creation is ignored.
857 * @exception DWTException <ul> 962 * @exception DWTException <ul>
858 * <li>ERROR_IO when the writer is closed.</li> 963 * <li>ERROR_IO when the writer is closed.</li>
859 * </ul> 964 * </ul>
860 */ 965 */
861 public void writeLine(String line, int lineOffset) { 966 public override void writeLine(String line, int lineOffset) {
862 if (isClosed()) { 967 if (isClosed()) {
863 DWT.error(DWT.ERROR_IO); 968 DWT.error(DWT.ERROR_IO);
864 } 969 }
865 int lineIndex = content.getLineAtOffset(lineOffset); 970 int lineIndex = content.getLineAtOffset(lineOffset);
866 int lineAlignment, lineIndent; 971 int lineAlignment, lineIndent;
874 lineJustify = event.justify; 979 lineJustify = event.justify;
875 ranges = event.ranges; 980 ranges = event.ranges;
876 styles = event.styles; 981 styles = event.styles;
877 } else { 982 } else {
878 lineAlignment = renderer.getLineAlignment(lineIndex, alignment); 983 lineAlignment = renderer.getLineAlignment(lineIndex, alignment);
879 lineIndent = renderer.getLineIndent(lineIndex, indent); 984 lineIndent = renderer.getLineIndent(lineIndex, indent);
880 lineJustify = renderer.getLineJustify(lineIndex, justify); 985 lineJustify = renderer.getLineJustify(lineIndex, justify);
881 ranges = renderer.getRanges(lineOffset, line.length()); 986 ranges = renderer.getRanges(lineOffset, line.length);
882 styles = renderer.getStyleRanges(lineOffset, line.length(), false); 987 styles = renderer.getStyleRanges(lineOffset, line.length, false);
883 } 988 }
884 if (styles is null) styles = new StyleRange[0]; 989 if (styles is null) styles = new StyleRange[0];
885 Color lineBackground = renderer.getLineBackground(lineIndex, null); 990 Color lineBackground = renderer.getLineBackground(lineIndex, null);
886 event = getLineBackgroundData(lineOffset, line); 991 event = getLineBackgroundData(lineOffset, line);
887 if (event !is null && event.lineBackground !is null) lineBackground = event.lineBackground; 992 if (event !is null && event.lineBackground !is null) lineBackground = event.lineBackground;
888 writeStyledLine(line, lineOffset, ranges, styles, lineBackground, lineIndent, lineAlignment, lineJustify); 993 writeStyledLine(line, lineOffset, ranges, styles, lineBackground, lineIndent, lineAlignment, lineJustify);
889 } 994 }
893 * @param lineDelimiter line delimiter to write as RTF. 998 * @param lineDelimiter line delimiter to write as RTF.
894 * @exception DWTException <ul> 999 * @exception DWTException <ul>
895 * <li>ERROR_IO when the writer is closed.</li> 1000 * <li>ERROR_IO when the writer is closed.</li>
896 * </ul> 1001 * </ul>
897 */ 1002 */
898 public void writeLineDelimiter(String lineDelimiter) { 1003 public override void writeLineDelimiter(String lineDelimiter) {
899 if (isClosed()) { 1004 if (isClosed()) {
900 DWT.error(DWT.ERROR_IO); 1005 DWT.error(DWT.ERROR_IO);
901 } 1006 }
902 write(lineDelimiter, 0, lineDelimiter.length()); 1007 write(lineDelimiter, 0, lineDelimiter.length);
903 write("\\par "); 1008 write("\\par ");
904 } 1009 }
905 /** 1010 /**
906 * Appends the specified line text to the RTF data. 1011 * Appends the specified line text to the RTF data.
907 * <p> 1012 * <p>
911 * Background colors are written using the \highlight tag (vs. the \cb tag). 1016 * Background colors are written using the \highlight tag (vs. the \cb tag).
912 * </p> 1017 * </p>
913 * 1018 *
914 * @param line line text to write as RTF. Must not contain line breaks 1019 * @param line line text to write as RTF. Must not contain line breaks
915 * Line breaks should be written using writeLineDelimiter() 1020 * Line breaks should be written using writeLineDelimiter()
916 * @param lineOffset offset of the line. 0 based from the start of the 1021 * @param lineOffset offset of the line. 0 based from the start of the
917 * widget document. Any text occurring before the start offset or after the 1022 * widget document. Any text occurring before the start offset or after the
918 * end offset specified during object creation is ignored. 1023 * end offset specified during object creation is ignored.
919 * @param styles styles to use for formatting. Must not be null. 1024 * @param styles styles to use for formatting. Must not be null.
920 * @param lineBackground line background color to use for formatting. 1025 * @param lineBackground line background color to use for formatting.
921 * May be null. 1026 * May be null.
922 */ 1027 */
923 void writeStyledLine(String line, int lineOffset, int ranges[], StyleRange[] styles, Color lineBackground, int indent, int alignment, bool justify) { 1028 void writeStyledLine(String line, int lineOffset, int ranges[], StyleRange[] styles, Color lineBackground, int indent, int alignment, bool justify) {
924 int lineLength = line.length(); 1029 int lineLength = line.length;
925 int startOffset = getStart(); 1030 int startOffset = getStart();
926 int writeOffset = startOffset - lineOffset; 1031 int writeOffset = startOffset - lineOffset;
927 if (writeOffset >= lineLength) return; 1032 if (writeOffset >= lineLength) return;
928 int lineIndex = Math.max(0, writeOffset); 1033 int lineIndex = Math.max(0, writeOffset);
929 1034
930 write("\\fi"); 1035 write("\\fi");
931 write(indent); 1036 write(indent);
932 switch (alignment) { 1037 switch (alignment) {
933 case DWT.LEFT: write("\\ql"); break; 1038 case DWT.LEFT: write("\\ql"); break;
934 case DWT.CENTER: write("\\qc"); break; 1039 case DWT.CENTER: write("\\qc"); break;
935 case DWT.RIGHT: write("\\qr"); break; 1040 case DWT.RIGHT: write("\\qr"); break;
1041 default:
936 } 1042 }
937 if (justify) write("\\qj"); 1043 if (justify) write("\\qj");
938 write(" "); 1044 write(" ");
939 1045
940 if (lineBackground !is null) { 1046 if (lineBackground !is null) {
941 write("{\\highlight"); 1047 write("{\\highlight");
942 write(getColorIndex(lineBackground, DEFAULT_BACKGROUND)); 1048 write(getColorIndex(lineBackground, DEFAULT_BACKGROUND));
943 write(" "); 1049 write(" ");
944 } 1050 }
945 int endOffset = startOffset + super.getCharCount(); 1051 int endOffset = startOffset + super.getCharCount();
946 int lineEndOffset = Math.min(lineLength, endOffset - lineOffset); 1052 int lineEndOffset = Math.min(lineLength, endOffset - lineOffset);
947 for (int i = 0; i < styles.length; i++) { 1053 for (int i = 0; i < styles.length; i++) {
948 StyleRange style = styles[i]; 1054 StyleRange style = styles[i];
963 break; 1069 break;
964 } 1070 }
965 // write any unstyled text 1071 // write any unstyled text
966 if (lineIndex < start) { 1072 if (lineIndex < start) {
967 // copy to start of style 1073 // copy to start of style
968 // style starting beyond end of write range or end of line 1074 // style starting beyond end of write range or end of line
969 // is guarded against above. 1075 // is guarded against above.
970 write(line, lineIndex, start); 1076 write(line, lineIndex, start);
971 lineIndex = start; 1077 lineIndex = start;
972 } 1078 }
973 // write styled text 1079 // write styled text
986 FontData fontData = font.getFontData()[0]; 1092 FontData fontData = font.getFontData()[0];
987 write("\\fs"); 1093 write("\\fs");
988 write(fontData.getHeight() * 2); 1094 write(fontData.getHeight() * 2);
989 } else { 1095 } else {
990 if ((style.fontStyle & DWT.BOLD) !is 0) { 1096 if ((style.fontStyle & DWT.BOLD) !is 0) {
991 write("\\b"); 1097 write("\\b");
992 } 1098 }
993 if ((style.fontStyle & DWT.ITALIC) !is 0) { 1099 if ((style.fontStyle & DWT.ITALIC) !is 0) {
994 write("\\i"); 1100 write("\\i");
995 } 1101 }
996 } 1102 }
997 if (style.underline) { 1103 if (style.underline) {
998 write("\\ul"); 1104 write("\\ul");
999 } 1105 }
1000 if (style.strikeout) { 1106 if (style.strikeout) {
1001 write("\\strike"); 1107 write("\\strike");
1002 } 1108 }
1003 write(" "); 1109 write(" ");
1004 // copy to end of style or end of write range or end of line 1110 // copy to end of style or end of write range or end of line
1005 int copyEnd = Math.min(end, lineEndOffset); 1111 int copyEnd = Math.min(end, lineEndOffset);
1006 // guard against invalid styles and let style processing continue 1112 // guard against invalid styles and let style processing continue
1007 copyEnd = Math.max(copyEnd, lineIndex); 1113 copyEnd = Math.max(copyEnd, lineIndex);
1008 write(line, lineIndex, copyEnd); 1114 write(line, lineIndex, copyEnd);
1009 if (font is null) { 1115 if (font is null) {
1010 if ((style.fontStyle & DWT.BOLD) !is 0) { 1116 if ((style.fontStyle & DWT.BOLD) !is 0) {
1011 write("\\b0"); 1117 write("\\b0");
1012 } 1118 }
1013 if ((style.fontStyle & DWT.ITALIC) !is 0) { 1119 if ((style.fontStyle & DWT.ITALIC) !is 0) {
1014 write("\\i0"); 1120 write("\\i0");
1015 } 1121 }
1016 } 1122 }
1017 if (style.underline) { 1123 if (style.underline) {
1018 write("\\ul0"); 1124 write("\\ul0");
1019 } 1125 }
1030 if (lineBackground !is null) write("}"); 1136 if (lineBackground !is null) write("}");
1031 } 1137 }
1032 } 1138 }
1033 /** 1139 /**
1034 * The <code>TextWriter</code> class is used to write widget content to 1140 * The <code>TextWriter</code> class is used to write widget content to
1035 * a String. Whole and partial lines and line breaks can be written. To write 1141 * a string. Whole and partial lines and line breaks can be written. To write
1036 * partial lines, specify the start and length of the desired segment 1142 * partial lines, specify the start and length of the desired segment
1037 * during object creation. 1143 * during object creation.
1038 * <p> 1144 * <p>
1039 * </b>NOTE:</b> <code>toString()</code> is guaranteed to return a valid String only after close() 1145 * </b>NOTE:</b> <code>toString()</code> is guaranteed to return a valid string only after close()
1040 * has been called. 1146 * has been called.
1041 * </p> 1147 * </p>
1042 */ 1148 */
1043 class TextWriter { 1149 class TextWriter {
1044 private StringBuffer buffer; 1150 private StringBuffer buffer;
1045 private int startOffset; // offset of first character that will be written 1151 private int startOffset; // offset of first character that will be written
1046 private int endOffset; // offset of last character that will be written. 1152 private int endOffset; // offset of last character that will be written.
1047 // 0 based from the beginning of the widget text. 1153 // 0 based from the beginning of the widget text.
1048 private bool isClosed = false; 1154 private bool isClosed_ = false;
1049 1155
1050 /** 1156 /**
1051 * Creates a writer that writes content starting at offset "start" 1157 * Creates a writer that writes content starting at offset "start"
1052 * in the document. <code>start</code> and <code>length</code> can be set to specify partial lines. 1158 * in the document. <code>start</code> and <code>length</code> can be set to specify partial lines.
1053 * 1159 *
1054 * @param start start offset of content to write, 0 based from beginning of document 1160 * @param start start offset of content to write, 0 based from beginning of document
1059 startOffset = start; 1165 startOffset = start;
1060 endOffset = start + length; 1166 endOffset = start + length;
1061 } 1167 }
1062 /** 1168 /**
1063 * Closes the writer. Once closed no more content can be written. 1169 * Closes the writer. Once closed no more content can be written.
1064 * <b>NOTE:</b> <code>toString()</code> is not guaranteed to return a valid String unless 1170 * <b>NOTE:</b> <code>toString()</code> is not guaranteed to return a valid string unless
1065 * the writer is closed. 1171 * the writer is closed.
1066 */ 1172 */
1067 public void close() { 1173 public void close() {
1068 if (!isClosed) { 1174 if (!isClosed_) {
1069 isClosed = true; 1175 isClosed_ = true;
1070 } 1176 }
1071 } 1177 }
1072 /** 1178 /**
1073 * Returns the number of characters to write. 1179 * Returns the number of characters to write.
1074 * @return the integer number of characters to write 1180 * @return the integer number of characters to write
1075 */ 1181 */
1076 public int getCharCount() { 1182 public int getCharCount() {
1077 return endOffset - startOffset; 1183 return endOffset - startOffset;
1078 } 1184 }
1079 /** 1185 /**
1080 * Returns the offset where writing starts. 0 based from the start of 1186 * Returns the offset where writing starts. 0 based from the start of
1081 * the widget text. Used to write partial lines. 1187 * the widget text. Used to write partial lines.
1082 * @return the integer offset where writing starts 1188 * @return the integer offset where writing starts
1083 */ 1189 */
1084 public int getStart() { 1190 public int getStart() {
1085 return startOffset; 1191 return startOffset;
1087 /** 1193 /**
1088 * Returns whether the writer is closed. 1194 * Returns whether the writer is closed.
1089 * @return a bool specifying whether or not the writer is closed 1195 * @return a bool specifying whether or not the writer is closed
1090 */ 1196 */
1091 public bool isClosed() { 1197 public bool isClosed() {
1092 return isClosed; 1198 return isClosed_;
1093 } 1199 }
1094 /** 1200 /**
1095 * Returns the String. <code>close()</code> must be called before <code>toString()</code> 1201 * Returns the string. <code>close()</code> must be called before <code>toString()</code>
1096 * is guaranteed to return a valid String. 1202 * is guaranteed to return a valid string.
1097 * 1203 *
1098 * @return the String 1204 * @return the string
1099 */ 1205 */
1100 public String toString() { 1206 public override String toString() {
1101 return buffer.toString(); 1207 return buffer.toString();
1102 } 1208 }
1103 /** 1209 /**
1104 * Appends the given String to the data. 1210 * Appends the given string to the data.
1105 */ 1211 */
1106 void write(String String) { 1212 void write(String string) {
1107 buffer.append(String); 1213 buffer.append(string);
1108 } 1214 }
1109 /** 1215 /**
1110 * Inserts the given String to the data at the specified offset. 1216 * Inserts the given string to the data at the specified offset.
1111 * <p> 1217 * <p>
1112 * Do nothing if "offset" is < 0 or > getCharCount() 1218 * Do nothing if "offset" is < 0 or > getCharCount()
1113 * </p> 1219 * </p>
1114 * 1220 *
1115 * @param String text to insert 1221 * @param string text to insert
1116 * @param offset offset in the existing data to insert "String" at. 1222 * @param offset offset in the existing data to insert "string" at.
1117 */ 1223 */
1118 void write(String String, int offset) { 1224 void write(String string, int offset) {
1119 if (offset < 0 || offset > buffer.length()) { 1225 if (offset < 0 || offset > buffer.length()) {
1120 return; 1226 return;
1121 } 1227 }
1122 buffer.insert(offset, String); 1228 buffer.select( offset );
1229 buffer.prepend( string );
1123 } 1230 }
1124 /** 1231 /**
1125 * Appends the given int to the data. 1232 * Appends the given int to the data.
1126 */ 1233 */
1127 void write(int i) { 1234 void write(int i) {
1136 /** 1243 /**
1137 * Appends the specified line text to the data. 1244 * Appends the specified line text to the data.
1138 * 1245 *
1139 * @param line line text to write. Must not contain line breaks 1246 * @param line line text to write. Must not contain line breaks
1140 * Line breaks should be written using writeLineDelimiter() 1247 * Line breaks should be written using writeLineDelimiter()
1141 * @param lineOffset offset of the line. 0 based from the start of the 1248 * @param lineOffset offset of the line. 0 based from the start of the
1142 * widget document. Any text occurring before the start offset or after the 1249 * widget document. Any text occurring before the start offset or after the
1143 * end offset specified during object creation is ignored. 1250 * end offset specified during object creation is ignored.
1144 * @exception DWTException <ul> 1251 * @exception DWTException <ul>
1145 * <li>ERROR_IO when the writer is closed.</li> 1252 * <li>ERROR_IO when the writer is closed.</li>
1146 * </ul> 1253 * </ul>
1147 */ 1254 */
1148 public void writeLine(String line, int lineOffset) { 1255 public void writeLine(String line, int lineOffset) {
1149 if (isClosed) { 1256 if (isClosed_) {
1150 DWT.error(DWT.ERROR_IO); 1257 DWT.error(DWT.ERROR_IO);
1151 } 1258 }
1152 int writeOffset = startOffset - lineOffset; 1259 int writeOffset = startOffset - lineOffset;
1153 int lineLength = line.length(); 1260 int lineLength = line.length;
1154 int lineIndex; 1261 int lineIndex;
1155 if (writeOffset >= lineLength) { 1262 if (writeOffset >= lineLength) {
1156 return; // whole line is outside write range 1263 return; // whole line is outside write range
1157 } else if (writeOffset > 0) { 1264 } else if (writeOffset > 0) {
1158 lineIndex = writeOffset; // line starts before write start 1265 lineIndex = writeOffset; // line starts before write start
1171 * @exception DWTException <ul> 1278 * @exception DWTException <ul>
1172 * <li>ERROR_IO when the writer is closed.</li> 1279 * <li>ERROR_IO when the writer is closed.</li>
1173 * </ul> 1280 * </ul>
1174 */ 1281 */
1175 public void writeLineDelimiter(String lineDelimiter) { 1282 public void writeLineDelimiter(String lineDelimiter) {
1176 if (isClosed) { 1283 if (isClosed_) {
1177 DWT.error(DWT.ERROR_IO); 1284 DWT.error(DWT.ERROR_IO);
1178 } 1285 }
1179 write(lineDelimiter); 1286 write(lineDelimiter);
1180 } 1287 }
1181 } 1288 }
1184 * Constructs a new instance of this class given its parent 1291 * Constructs a new instance of this class given its parent
1185 * and a style value describing its behavior and appearance. 1292 * and a style value describing its behavior and appearance.
1186 * <p> 1293 * <p>
1187 * The style value is either one of the style constants defined in 1294 * The style value is either one of the style constants defined in
1188 * class <code>DWT</code> which is applicable to instances of this 1295 * class <code>DWT</code> which is applicable to instances of this
1189 * class, or must be built by <em>bitwise OR</em>'ing together 1296 * class, or must be built by <em>bitwise OR</em>'ing together
1190 * (that is, using the <code>int</code> "|" operator) two or more 1297 * (that is, using the <code>int</code> "|" operator) two or more
1191 * of those <code>DWT</code> style constants. The class description 1298 * of those <code>DWT</code> style constants. The class description
1192 * lists the style constants that are applicable to the class. 1299 * lists the style constants that are applicable to the class.
1193 * Style bits are also inherited from superclasses. 1300 * Style bits are also inherited from superclasses.
1194 * </p> 1301 * </p>
1209 * @see DWT#SINGLE 1316 * @see DWT#SINGLE
1210 * @see DWT#WRAP 1317 * @see DWT#WRAP
1211 * @see #getStyle 1318 * @see #getStyle
1212 */ 1319 */
1213 public this(Composite parent, int style) { 1320 public this(Composite parent, int style) {
1321 selection = new Point(0, 0);
1214 super(parent, checkStyle(style)); 1322 super(parent, checkStyle(style));
1215 // set the fg in the OS to ensure that these are the same as StyledText, necessary 1323 // set the fg in the OS to ensure that these are the same as StyledText, necessary
1216 // for ensuring that the bg/fg the IME box uses is the same as what StyledText uses 1324 // for ensuring that the bg/fg the IME box uses is the same as what StyledText uses
1217 super.setForeground(getForeground()); 1325 super.setForeground(getForeground());
1218 super.setDragDetect(false); 1326 super.setDragDetect(false);
1219 Display display = getDisplay(); 1327 Display display = getDisplay();
1220 isMirrored = (super.getStyle() & DWT.MIRRORED) !is 0; 1328 isMirrored_ = (super.getStyle() & DWT.MIRRORED) !is 0;
1221 fixedLineHeight = true; 1329 fixedLineHeight = true;
1222 if ((style & DWT.READ_ONLY) !is 0) { 1330 if ((style & DWT.READ_ONLY) !is 0) {
1223 setEditable(false); 1331 setEditable(false);
1224 } 1332 }
1225 leftMargin = rightMargin = isBidiCaret() ? BIDI_CARET_WIDTH - 1: 0; 1333 leftMargin = rightMargin = isBidiCaret() ? BIDI_CARET_WIDTH - 1: 0;
1238 if ((style & DWT.WRAP) !is 0) { 1346 if ((style & DWT.WRAP) !is 0) {
1239 setWordWrap(true); 1347 setWordWrap(true);
1240 } 1348 }
1241 if (isBidiCaret()) { 1349 if (isBidiCaret()) {
1242 createCaretBitmaps(); 1350 createCaretBitmaps();
1243 Runnable runnable = new Runnable() { 1351 Runnable runnable = new class() Runnable {
1244 public void run() { 1352 public void run() {
1245 int direction = BidiUtil.getKeyboardLanguage() is BidiUtil.KEYBOARD_BIDI ? DWT.RIGHT : DWT.LEFT; 1353 int direction = BidiUtil.getKeyboardLanguage() is BidiUtil.KEYBOARD_BIDI ? DWT.RIGHT : DWT.LEFT;
1246 if (direction is caretDirection) return; 1354 if (direction is caretDirection) return;
1247 if (getCaret() !is defaultCaret) return; 1355 if (getCaret() !is defaultCaret) return;
1248 Point newCaretPos = getPointAtOffset(caretOffset); 1356 Point newCaretPos = getPointAtOffset(caretOffset);
1249 setCaretLocation(newCaretPos, direction); 1357 setCaretLocation(newCaretPos, direction);
1250 } 1358 }
1251 }; 1359 };
1252 BidiUtil.addLanguageListener(this, runnable); 1360 BidiUtil.addLanguageListener(this, runnable);
1253 } 1361 }
1254 setCaret(defaultCaret); 1362 setCaret(defaultCaret);
1255 calculateScrollBars(); 1363 calculateScrollBars();
1256 createKeyBindings(); 1364 createKeyBindings();
1257 setCursor(display.getSystemCursor(DWT.CURSOR_IBEAM)); 1365 setCursor(display.getSystemCursor(DWT.CURSOR_IBEAM));
1258 installListeners(); 1366 installListeners();
1259 initializeAccessible(); 1367 initializeAccessible();
1260 setData("DEFAULT_DROP_TARGET_EFFECT", new StyledTextDropTargetEffect(this)); 1368 setData("DEFAULT_DROP_TARGET_EFFECT", new StyledTextDropTargetEffect(this));
1261 } 1369 }
1262 /** 1370 /**
1263 * Adds an extended modify listener. An ExtendedModify event is sent by the 1371 * Adds an extended modify listener. An ExtendedModify event is sent by the
1264 * widget when the widget text has changed. 1372 * widget when the widget text has changed.
1265 * 1373 *
1266 * @param extendedModifyListener the listener 1374 * @param extendedModifyListener the listener
1267 * @exception DWTException <ul> 1375 * @exception DWTException <ul>
1268 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1376 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1279 addListener(ExtendedModify, typedListener); 1387 addListener(ExtendedModify, typedListener);
1280 } 1388 }
1281 /** 1389 /**
1282 * Adds a bidirectional segment listener. 1390 * Adds a bidirectional segment listener.
1283 * <p> 1391 * <p>
1284 * A BidiSegmentEvent is sent 1392 * A BidiSegmentEvent is sent
1285 * whenever a line of text is measured or rendered. The user can 1393 * whenever a line of text is measured or rendered. The user can
1286 * specify text ranges in the line that should be treated as if they 1394 * specify text ranges in the line that should be treated as if they
1287 * had a different direction than the surrounding text. 1395 * had a different direction than the surrounding text.
1288 * This may be used when adjacent segments of right-to-left text should 1396 * This may be used when adjacent segments of right-to-left text should
1289 * not be reordered relative to each other. 1397 * not be reordered relative to each other.
1290 * E.g., Multiple Java String literals in a right-to-left language 1398 * E.g., Multiple Java string literals in a right-to-left language
1291 * should generally remain in logical order to each other, that is, the 1399 * should generally remain in logical order to each other, that is, the
1292 * way they are stored. 1400 * way they are stored.
1293 * </p> 1401 * </p>
1294 * 1402 *
1295 * @param listener the listener 1403 * @param listener the listener
1296 * @exception DWTException <ul> 1404 * @exception DWTException <ul>
1297 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1405 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1307 checkWidget(); 1415 checkWidget();
1308 if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); 1416 if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
1309 addListener(LineGetSegments, new StyledTextListener(listener)); 1417 addListener(LineGetSegments, new StyledTextListener(listener));
1310 } 1418 }
1311 /** 1419 /**
1312 * Adds a line background listener. A LineGetBackground event is sent by the 1420 * Adds a line background listener. A LineGetBackground event is sent by the
1313 * widget to determine the background color for a line. 1421 * widget to determine the background color for a line.
1314 * 1422 *
1315 * @param listener the listener 1423 * @param listener the listener
1316 * @exception DWTException <ul> 1424 * @exception DWTException <ul>
1317 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1425 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1328 renderer.clearLineBackground(0, content.getLineCount()); 1436 renderer.clearLineBackground(0, content.getLineCount());
1329 } 1437 }
1330 addListener(LineGetBackground, new StyledTextListener(listener)); 1438 addListener(LineGetBackground, new StyledTextListener(listener));
1331 } 1439 }
1332 /** 1440 /**
1333 * Adds a line style listener. A LineGetStyle event is sent by the widget to 1441 * Adds a line style listener. A LineGetStyle event is sent by the widget to
1334 * determine the styles for a line. 1442 * determine the styles for a line.
1335 * 1443 *
1336 * @param listener the listener 1444 * @param listener the listener
1337 * @exception DWTException <ul> 1445 * @exception DWTException <ul>
1338 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1446 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1349 setStyleRanges(0, 0, null, null, true); 1457 setStyleRanges(0, 0, null, null, true);
1350 renderer.clearLineStyle(0, content.getLineCount()); 1458 renderer.clearLineStyle(0, content.getLineCount());
1351 } 1459 }
1352 addListener(LineGetStyle, new StyledTextListener(listener)); 1460 addListener(LineGetStyle, new StyledTextListener(listener));
1353 } 1461 }
1354 /** 1462 /**
1355 * Adds a modify listener. A Modify event is sent by the widget when the widget text 1463 * Adds a modify listener. A Modify event is sent by the widget when the widget text
1356 * has changed. 1464 * has changed.
1357 * 1465 *
1358 * @param modifyListener the listener 1466 * @param modifyListener the listener
1359 * @exception DWTException <ul> 1467 * @exception DWTException <ul>
1360 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1468 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1367 public void addModifyListener(ModifyListener modifyListener) { 1475 public void addModifyListener(ModifyListener modifyListener) {
1368 checkWidget(); 1476 checkWidget();
1369 if (modifyListener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); 1477 if (modifyListener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
1370 addListener(DWT.Modify, new TypedListener(modifyListener)); 1478 addListener(DWT.Modify, new TypedListener(modifyListener));
1371 } 1479 }
1372 /** 1480 /**
1373 * Adds a paint object listener. A paint object event is sent by the widget when an object 1481 * Adds a paint object listener. A paint object event is sent by the widget when an object
1374 * needs to be drawn. 1482 * needs to be drawn.
1375 * 1483 *
1376 * @param listener the listener 1484 * @param listener the listener
1377 * @exception DWTException <ul> 1485 * @exception DWTException <ul>
1379 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1487 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1380 * </ul> 1488 * </ul>
1381 * @exception IllegalArgumentException <ul> 1489 * @exception IllegalArgumentException <ul>
1382 * <li>ERROR_NULL_ARGUMENT when listener is null</li> 1490 * <li>ERROR_NULL_ARGUMENT when listener is null</li>
1383 * </ul> 1491 * </ul>
1384 * 1492 *
1385 * @since 3.2 1493 * @since 3.2
1386 * 1494 *
1387 * @see PaintObjectListener 1495 * @see PaintObjectListener
1388 * @see PaintObjectEvent 1496 * @see PaintObjectEvent
1389 */ 1497 */
1390 public void addPaintObjectListener(PaintObjectListener listener) { 1498 public void addPaintObjectListener(PaintObjectListener listener) {
1391 checkWidget(); 1499 checkWidget();
1392 if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); 1500 if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
1393 addListener(PaintObject, new StyledTextListener(listener)); 1501 addListener(PaintObject, new StyledTextListener(listener));
1394 } 1502 }
1395 /** 1503 /**
1396 * Adds a selection listener. A Selection event is sent by the widget when the 1504 * Adds a selection listener. A Selection event is sent by the widget when the
1397 * user changes the selection. 1505 * user changes the selection.
1398 * <p> 1506 * <p>
1399 * When <code>widgetSelected</code> is called, the event x and y fields contain 1507 * When <code>widgetSelected</code> is called, the event x and y fields contain
1400 * the start and end caret indices of the selection. 1508 * the start and end caret indices of the selection.
1401 * <code>widgetDefaultSelected</code> is not called for StyledTexts. 1509 * <code>widgetDefaultSelected</code> is not called for StyledTexts.
1402 * </p> 1510 * </p>
1403 * 1511 *
1404 * @param listener the listener which should be notified when the user changes the receiver's selection 1512 * @param listener the listener which should be notified when the user changes the receiver's selection
1405 1513
1406 * @exception IllegalArgumentException <ul> 1514 * @exception IllegalArgumentException <ul>
1407 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> 1515 * <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
1408 * </ul> 1516 * </ul>
1418 public void addSelectionListener(SelectionListener listener) { 1526 public void addSelectionListener(SelectionListener listener) {
1419 checkWidget(); 1527 checkWidget();
1420 if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); 1528 if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
1421 addListener(DWT.Selection, new TypedListener(listener)); 1529 addListener(DWT.Selection, new TypedListener(listener));
1422 } 1530 }
1423 /** 1531 /**
1424 * Adds a verify key listener. A VerifyKey event is sent by the widget when a key 1532 * Adds a verify key listener. A VerifyKey event is sent by the widget when a key
1425 * is pressed. The widget ignores the key press if the listener sets the doit field 1533 * is pressed. The widget ignores the key press if the listener sets the doit field
1426 * of the event to false. 1534 * of the event to false.
1427 * 1535 *
1428 * @param listener the listener 1536 * @param listener the listener
1429 * @exception DWTException <ul> 1537 * @exception DWTException <ul>
1430 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1538 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1431 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1539 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1437 public void addVerifyKeyListener(VerifyKeyListener listener) { 1545 public void addVerifyKeyListener(VerifyKeyListener listener) {
1438 checkWidget(); 1546 checkWidget();
1439 if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); 1547 if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
1440 addListener(VerifyKey, new StyledTextListener(listener)); 1548 addListener(VerifyKey, new StyledTextListener(listener));
1441 } 1549 }
1442 /** 1550 /**
1443 * Adds a verify listener. A Verify event is sent by the widget when the widget text 1551 * Adds a verify listener. A Verify event is sent by the widget when the widget text
1444 * is about to change. The listener can set the event text and the doit field to 1552 * is about to change. The listener can set the event text and the doit field to
1445 * change the text that is set in the widget or to force the widget to ignore the 1553 * change the text that is set in the widget or to force the widget to ignore the
1446 * text change. 1554 * text change.
1447 * 1555 *
1448 * @param verifyListener the listener 1556 * @param verifyListener the listener
1449 * @exception DWTException <ul> 1557 * @exception DWTException <ul>
1450 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1558 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1457 public void addVerifyListener(VerifyListener verifyListener) { 1565 public void addVerifyListener(VerifyListener verifyListener) {
1458 checkWidget(); 1566 checkWidget();
1459 if (verifyListener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); 1567 if (verifyListener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
1460 addListener(DWT.Verify, new TypedListener(verifyListener)); 1568 addListener(DWT.Verify, new TypedListener(verifyListener));
1461 } 1569 }
1462 /** 1570 /**
1463 * Adds a word movement listener. A movement event is sent when the boundary 1571 * Adds a word movement listener. A movement event is sent when the boundary
1464 * of a word is needed. For example, this occurs during word next and word 1572 * of a word is needed. For example, this occurs during word next and word
1465 * previous actions. 1573 * previous actions.
1466 * 1574 *
1467 * @param movementListener the listener 1575 * @param movementListener the listener
1468 * @exception DWTException <ul> 1576 * @exception DWTException <ul>
1469 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1577 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1470 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1578 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1471 * </ul> 1579 * </ul>
1472 * @exception IllegalArgumentException <ul> 1580 * @exception IllegalArgumentException <ul>
1473 * <li>ERROR_NULL_ARGUMENT when listener is null</li> 1581 * <li>ERROR_NULL_ARGUMENT when listener is null</li>
1474 * </ul> 1582 * </ul>
1475 * 1583 *
1476 * @see MovementEvent 1584 * @see MovementEvent
1477 * @see MovementListener 1585 * @see MovementListener
1478 * @see #removeWordMovementListener 1586 * @see #removeWordMovementListener
1479 * 1587 *
1480 * @since 3.3 1588 * @since 3.3
1481 */ 1589 */
1482 public void addWordMovementListener(MovementListener movementListener) { 1590 public void addWordMovementListener(MovementListener movementListener) {
1483 checkWidget(); 1591 checkWidget();
1484 if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); 1592 if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
1485 addListener(WordNext, new StyledTextListener(movementListener)); 1593 addListener(WordNext, new StyledTextListener(movementListener));
1486 addListener(WordPrevious, new StyledTextListener(movementListener)); 1594 addListener(WordPrevious, new StyledTextListener(movementListener));
1487 } 1595 }
1488 /** 1596 /**
1489 * Appends a String to the text at the end of the widget. 1597 * Appends a string to the text at the end of the widget.
1490 * 1598 *
1491 * @param String the String to be appended 1599 * @param string the string to be appended
1492 * @see #replaceTextRange(int,int,String) 1600 * @see #replaceTextRange(int,int,String)
1493 * @exception DWTException <ul> 1601 * @exception DWTException <ul>
1494 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1602 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1495 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1603 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1496 * </ul> 1604 * </ul>
1497 * @exception IllegalArgumentException <ul> 1605 */
1498 * <li>ERROR_NULL_ARGUMENT when listener is null</li> 1606 public void append(String string) {
1499 * </ul> 1607 checkWidget();
1500 */ 1608 // DWT extension: allow null for zero length string
1501 public void append(String String) { 1609 // if (string is null) {
1502 checkWidget(); 1610 // DWT.error(DWT.ERROR_NULL_ARGUMENT);
1503 if (String is null) { 1611 // }
1504 DWT.error(DWT.ERROR_NULL_ARGUMENT);
1505 }
1506 int lastChar = Math.max(getCharCount(), 0); 1612 int lastChar = Math.max(getCharCount(), 0);
1507 replaceTextRange(lastChar, 0, String); 1613 replaceTextRange(lastChar, 0, string);
1508 } 1614 }
1509 /** 1615 /**
1510 * Calculates the scroll bars 1616 * Calculates the scroll bars
1511 */ 1617 */
1512 void calculateScrollBars() { 1618 void calculateScrollBars() {
1513 ScrollBar horizontalBar = getHorizontalBar(); 1619 ScrollBar horizontalBar = getHorizontalBar();
1514 ScrollBar verticalBar = getVerticalBar(); 1620 ScrollBar verticalBar = getVerticalBar();
1515 setScrollBars(true); 1621 setScrollBars(true);
1516 if (verticalBar !is null) { 1622 if (verticalBar !is null) {
1517 verticalBar.setIncrement(getVerticalIncrement()); 1623 verticalBar.setIncrement(getVerticalIncrement());
1518 } 1624 }
1519 if (horizontalBar !is null) { 1625 if (horizontalBar !is null) {
1520 horizontalBar.setIncrement(getHorizontalIncrement()); 1626 horizontalBar.setIncrement(getHorizontalIncrement());
1521 } 1627 }
1522 } 1628 }
1523 /** 1629 /**
1533 int verticalIncrement = getVerticalIncrement(); 1639 int verticalIncrement = getVerticalIncrement();
1534 if (verticalIncrement is 0) { 1640 if (verticalIncrement is 0) {
1535 return; 1641 return;
1536 } 1642 }
1537 topIndex = Compatibility.ceil(getVerticalScrollOffset(), verticalIncrement); 1643 topIndex = Compatibility.ceil(getVerticalScrollOffset(), verticalIncrement);
1538 // Set top index to partially visible top line if no line is fully 1644 // Set top index to partially visible top line if no line is fully
1539 // visible but at least some of the widget client area is visible. 1645 // visible but at least some of the widget client area is visible.
1540 // Fixes bug 15088. 1646 // Fixes bug 15088.
1541 if (topIndex > 0) { 1647 if (topIndex > 0) {
1542 if (clientAreaHeight > 0) { 1648 if (clientAreaHeight > 0) {
1543 int bottomPixel = getVerticalScrollOffset() + clientAreaHeight; 1649 int bottomPixel = getVerticalScrollOffset() + clientAreaHeight;
1544 int fullLineTopPixel = topIndex * verticalIncrement; 1650 int fullLineTopPixel = topIndex * verticalIncrement;
1545 int fullLineVisibleHeight = bottomPixel - fullLineTopPixel; 1651 int fullLineVisibleHeight = bottomPixel - fullLineTopPixel;
1546 // set top index to partially visible line if no line fully fits in 1652 // set top index to partially visible line if no line fully fits in
1547 // client area or if space is available but not used (the latter should 1653 // client area or if space is available but not used (the latter should
1548 // never happen because we use claimBottomFreeSpace) 1654 // never happen because we use claimBottomFreeSpace)
1549 if (fullLineVisibleHeight < verticalIncrement) { 1655 if (fullLineVisibleHeight < verticalIncrement) {
1550 topIndex--; 1656 topIndex--;
1551 } 1657 }
1606 } 1712 }
1607 style |= DWT.NO_REDRAW_RESIZE | DWT.DOUBLE_BUFFERED | DWT.NO_BACKGROUND; 1713 style |= DWT.NO_REDRAW_RESIZE | DWT.DOUBLE_BUFFERED | DWT.NO_BACKGROUND;
1608 return style; 1714 return style;
1609 } 1715 }
1610 /** 1716 /**
1611 * Scrolls down the text to use new space made available by a resize or by 1717 * Scrolls down the text to use new space made available by a resize or by
1612 * deleted lines. 1718 * deleted lines.
1613 */ 1719 */
1614 void claimBottomFreeSpace() { 1720 void claimBottomFreeSpace() {
1615 int clientAreaHeight = this.clientAreaHeight - topMargin - bottomMargin; 1721 int clientAreaHeight = this.clientAreaHeight - topMargin - bottomMargin;
1616 if (isFixedLineHeight()) { 1722 if (isFixedLineHeight()) {
1630 /** 1736 /**
1631 * Scrolls text to the right to use new space made available by a resize. 1737 * Scrolls text to the right to use new space made available by a resize.
1632 */ 1738 */
1633 void claimRightFreeSpace() { 1739 void claimRightFreeSpace() {
1634 int newHorizontalOffset = Math.max(0, renderer.getWidth() - (clientAreaWidth - leftMargin - rightMargin)); 1740 int newHorizontalOffset = Math.max(0, renderer.getWidth() - (clientAreaWidth - leftMargin - rightMargin));
1635 if (newHorizontalOffset < horizontalScrollOffset) { 1741 if (newHorizontalOffset < horizontalScrollOffset) {
1636 // item is no longer drawn past the right border of the client area 1742 // item is no longer drawn past the right border of the client area
1637 // align the right end of the item with the right border of the 1743 // align the right end of the item with the right border of the
1638 // client area (window is scrolled right). 1744 // client area (window is scrolled right).
1639 scrollHorizontal(newHorizontalOffset - horizontalScrollOffset, true); 1745 scrollHorizontal(newHorizontalOffset - horizontalScrollOffset, true);
1640 } 1746 }
1641 } 1747 }
1642 /** 1748 /**
1643 * Removes the widget selection. 1749 * Removes the widget selection.
1644 * 1750 *
1645 * @param sendEvent a Selection event is sent when set to true and when the selection is actually reset. 1751 * @param sendEvent a Selection event is sent when set to true and when the selection is actually reset.
1646 */ 1752 */
1647 void clearSelection(bool sendEvent) { 1753 void clearSelection(bool sendEvent) {
1648 int selectionStart = selection.x; 1754 int selectionStart = selection.x;
1649 int selectionEnd = selection.y; 1755 int selectionEnd = selection.y;
1650 resetSelection(); 1756 resetSelection();
1651 // redraw old selection, if any 1757 // redraw old selection, if any
1652 if (selectionEnd - selectionStart > 0) { 1758 if (selectionEnd - selectionStart > 0) {
1653 int length = content.getCharCount(); 1759 int length = content.getCharCount();
1654 // called internally to remove selection after text is removed 1760 // called internally to remove selection after text is removed
1661 if (sendEvent) { 1767 if (sendEvent) {
1662 sendSelectionEvent(); 1768 sendSelectionEvent();
1663 } 1769 }
1664 } 1770 }
1665 } 1771 }
1666 public Point computeSize (int wHint, int hHint, bool changed) { 1772 public override Point computeSize (int wHint, int hHint, bool changed) {
1667 checkWidget(); 1773 checkWidget();
1668 int lineCount = (getStyle() & DWT.SINGLE) !is 0 ? 1 : content.getLineCount(); 1774 int lineCount = (getStyle() & DWT.SINGLE) !is 0 ? 1 : content.getLineCount();
1669 int width = 0; 1775 int width = 0;
1670 int height = 0; 1776 int height = 0;
1671 if (wHint is DWT.DEFAULT || hHint is DWT.DEFAULT) { 1777 if (wHint is DWT.DEFAULT || hHint is DWT.DEFAULT) {
1699 /** 1805 /**
1700 * Copies the selected text to the <code>DND.CLIPBOARD</code> clipboard. 1806 * Copies the selected text to the <code>DND.CLIPBOARD</code> clipboard.
1701 * <p> 1807 * <p>
1702 * The text will be put on the clipboard in plain text format and RTF format. 1808 * The text will be put on the clipboard in plain text format and RTF format.
1703 * The <code>DND.CLIPBOARD</code> clipboard is used for data that is 1809 * The <code>DND.CLIPBOARD</code> clipboard is used for data that is
1704 * transferred by keyboard accelerator (such as Ctrl+C/Ctrl+V) or 1810 * transferred by keyboard accelerator (such as Ctrl+C/Ctrl+V) or
1705 * by menu action. 1811 * by menu action.
1706 * </p> 1812 * </p>
1707 * 1813 *
1708 * @exception DWTException <ul> 1814 * @exception DWTException <ul>
1709 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1815 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1713 public void copy() { 1819 public void copy() {
1714 checkWidget(); 1820 checkWidget();
1715 copy(DND.CLIPBOARD); 1821 copy(DND.CLIPBOARD);
1716 } 1822 }
1717 /** 1823 /**
1718 * Copies the selected text to the specified clipboard. The text will be put in the 1824 * Copies the selected text to the specified clipboard. The text will be put in the
1719 * clipboard in plain text format and RTF format. 1825 * clipboard in plain text format and RTF format.
1720 * <p> 1826 * <p>
1721 * The clipboardType is one of the clipboard constants defined in class 1827 * The clipboardType is one of the clipboard constants defined in class
1722 * <code>DND</code>. The <code>DND.CLIPBOARD</code> clipboard is 1828 * <code>DND</code>. The <code>DND.CLIPBOARD</code> clipboard is
1723 * used for data that is transferred by keyboard accelerator (such as Ctrl+C/Ctrl+V) 1829 * used for data that is transferred by keyboard accelerator (such as Ctrl+C/Ctrl+V)
1724 * or by menu action. The <code>DND.SELECTION_CLIPBOARD</code> 1830 * or by menu action. The <code>DND.SELECTION_CLIPBOARD</code>
1725 * clipboard is used for data that is transferred by selecting text and pasting 1831 * clipboard is used for data that is transferred by selecting text and pasting
1726 * with the middle mouse button. 1832 * with the middle mouse button.
1727 * </p> 1833 * </p>
1728 * 1834 *
1729 * @param clipboardType indicates the type of clipboard 1835 * @param clipboardType indicates the type of clipboard
1730 * 1836 *
1731 * @exception DWTException <ul> 1837 * @exception DWTException <ul>
1732 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1838 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1733 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1839 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1734 * </ul> 1840 * </ul>
1735 * 1841 *
1736 * @since 3.1 1842 * @since 3.1
1737 */ 1843 */
1738 public void copy(int clipboardType) { 1844 public void copy(int clipboardType) {
1739 checkWidget(); 1845 checkWidget();
1740 if (clipboardType !is DND.CLIPBOARD && clipboardType !is DND.SELECTION_CLIPBOARD) return; 1846 if (clipboardType !is DND.CLIPBOARD && clipboardType !is DND.SELECTION_CLIPBOARD) return;
1741 int length = selection.y - selection.x; 1847 int length = selection.y - selection.x;
1742 if (length > 0) { 1848 if (length > 0) {
1743 try { 1849 try {
1744 setClipboardContent(selection.x, length, clipboardType); 1850 setClipboardContent(selection.x, length, clipboardType);
1745 } catch (DWTError error) { 1851 } catch (DWTError error) {
1746 // Copy to clipboard failed. This happens when another application 1852 // Copy to clipboard failed. This happens when another application
1747 // is accessing the clipboard while we copy. Ignore the error. 1853 // is accessing the clipboard while we copy. Ignore the error.
1748 // Fixes 1GDQAVN 1854 // Fixes 1GDQAVN
1749 // Rethrow all other errors. Fixes bug 17578. 1855 // Rethrow all other errors. Fixes bug 17578.
1750 if (error.code !is DND.ERROR_CANNOT_SET_CLIPBOARD) { 1856 if (error.code !is DND.ERROR_CANNOT_SET_CLIPBOARD) {
1751 throw error; 1857 throw error;
1753 } 1859 }
1754 } 1860 }
1755 } 1861 }
1756 /** 1862 /**
1757 * Returns the alignment of the widget. 1863 * Returns the alignment of the widget.
1758 * 1864 *
1759 * @return the alignment 1865 * @return the alignment
1760 * 1866 *
1761 * @exception DWTException <ul> 1867 * @exception DWTException <ul>
1762 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 1868 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
1763 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 1869 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
1764 * </ul> 1870 * </ul>
1765 * 1871 *
1766 * @see #getLineAlignment(int) 1872 * @see #getLineAlignment(int)
1767 * 1873 *
1768 * @since 3.2 1874 * @since 3.2
1769 */ 1875 */
1770 public int getAlignment() { 1876 public int getAlignment() {
1771 checkWidget(); 1877 checkWidget();
1772 return alignment; 1878 return alignment;
1800 availableHeight += renderer.getLineHeight(lineIndex++); 1906 availableHeight += renderer.getLineHeight(lineIndex++);
1801 } 1907 }
1802 return Math.min(height, availableHeight); 1908 return Math.min(height, availableHeight);
1803 } 1909 }
1804 /** 1910 /**
1805 * Returns a String that uses only the line delimiter specified by the 1911 * Returns a string that uses only the line delimiter specified by the
1806 * StyledTextContent implementation. 1912 * StyledTextContent implementation.
1807 * <p> 1913 * <p>
1808 * Returns only the first line if the widget has the DWT.SINGLE style. 1914 * Returns only the first line if the widget has the DWT.SINGLE style.
1809 * </p> 1915 * </p>
1810 * 1916 *
1811 * @param text the text that may have line delimiters that don't 1917 * @param text the text that may have line delimiters that don't
1812 * match the model line delimiter. Possible line delimiters 1918 * match the model line delimiter. Possible line delimiters
1813 * are CR ('\r'), LF ('\n'), CR/LF ("\r\n") 1919 * are CR ('\r'), LF ('\n'), CR/LF ("\r\n")
1814 * @return the converted text that only uses the line delimiter 1920 * @return the converted text that only uses the line delimiter
1815 * specified by the model. Returns only the first line if the widget 1921 * specified by the model. Returns only the first line if the widget
1816 * has the DWT.SINGLE style. 1922 * has the DWT.SINGLE style.
1817 */ 1923 */
1818 String getModelDelimitedText(String text) { 1924 String getModelDelimitedText(String text) {
1819 int length = text.length(); 1925 int length = text.length;
1820 if (length is 0) { 1926 if (length is 0) {
1821 return text; 1927 return text;
1822 } 1928 }
1823 int crIndex = 0; 1929 int crIndex = 0;
1824 int lfIndex = 0; 1930 int lfIndex = 0;
1825 int i = 0; 1931 int i = 0;
1826 StringBuffer convertedText = new StringBuffer(length); 1932 StringBuffer convertedText = new StringBuffer(length);
1827 String delimiter = getLineDelimiter(); 1933 String delimiter = getLineDelimiter();
1828 while (i < length) { 1934 while (i < length) {
1829 if (crIndex !is -1) { 1935 if (crIndex !is -1) {
1830 crIndex = text.indexOf(DWT.CR, i); 1936 crIndex = text.indexOf (DWT.CR, i);
1831 } 1937 }
1832 if (lfIndex !is -1) { 1938 if (lfIndex !is -1) {
1833 lfIndex = text.indexOf(DWT.LF, i); 1939 lfIndex = text.indexOf (DWT.LF, i);
1834 } 1940 }
1835 if (lfIndex is -1 && crIndex is -1) { // no more line breaks? 1941 if (lfIndex is -1 && crIndex is -1) { // no more line breaks?
1836 break; 1942 break;
1837 } else if ((crIndex < lfIndex && crIndex !is -1) || lfIndex is -1) { 1943 } else if ((crIndex < lfIndex && crIndex !is -1) || lfIndex is -1) {
1838 convertedText.append(text.substring(i, crIndex)); 1944 convertedText.append(text.substring(i, crIndex));
1848 if (isSingleLine()) { 1954 if (isSingleLine()) {
1849 break; 1955 break;
1850 } 1956 }
1851 convertedText.append(delimiter); 1957 convertedText.append(delimiter);
1852 } 1958 }
1853 // copy remaining text if any and if not in single line mode or no 1959 // copy remaining text if any and if not in single line mode or no
1854 // text copied thus far (because there only is one line) 1960 // text copied thus far (because there only is one line)
1855 if (i < length && (!isSingleLine() || convertedText.length() is 0)) { 1961 if (i < length && (!isSingleLine() || convertedText.length() is 0)) {
1856 convertedText.append(text.substring(i)); 1962 convertedText.append(text.substring(i));
1857 } 1963 }
1858 return convertedText.toString(); 1964 return convertedText.toString();
1875 * Creates default key bindings. 1981 * Creates default key bindings.
1876 */ 1982 */
1877 void createKeyBindings() { 1983 void createKeyBindings() {
1878 int nextKey = isMirrored() ? DWT.ARROW_LEFT : DWT.ARROW_RIGHT; 1984 int nextKey = isMirrored() ? DWT.ARROW_LEFT : DWT.ARROW_RIGHT;
1879 int previousKey = isMirrored() ? DWT.ARROW_RIGHT : DWT.ARROW_LEFT; 1985 int previousKey = isMirrored() ? DWT.ARROW_RIGHT : DWT.ARROW_LEFT;
1880 1986
1881 // Navigation 1987 // Navigation
1882 setKeyBinding(DWT.ARROW_UP, ST.LINE_UP); 1988 setKeyBinding(DWT.ARROW_UP, ST.LINE_UP);
1883 setKeyBinding(DWT.ARROW_DOWN, ST.LINE_DOWN); 1989 setKeyBinding(DWT.ARROW_DOWN, ST.LINE_DOWN);
1884 if (IS_CARBON) { 1990 if (IS_CARBON) {
1885 setKeyBinding(previousKey | DWT.MOD1, ST.LINE_START); 1991 setKeyBinding(previousKey | DWT.MOD1, ST.LINE_START);
1886 setKeyBinding(nextKey | DWT.MOD1, ST.LINE_END); 1992 setKeyBinding(nextKey | DWT.MOD1, ST.LINE_END);
1887 setKeyBinding(DWT.HOME, ST.TEXT_START); 1993 setKeyBinding(DWT.HOME, ST.TEXT_START);
1902 setKeyBinding(DWT.PAGE_DOWN, ST.PAGE_DOWN); 2008 setKeyBinding(DWT.PAGE_DOWN, ST.PAGE_DOWN);
1903 setKeyBinding(DWT.PAGE_UP | DWT.MOD1, ST.WINDOW_START); 2009 setKeyBinding(DWT.PAGE_UP | DWT.MOD1, ST.WINDOW_START);
1904 setKeyBinding(DWT.PAGE_DOWN | DWT.MOD1, ST.WINDOW_END); 2010 setKeyBinding(DWT.PAGE_DOWN | DWT.MOD1, ST.WINDOW_END);
1905 setKeyBinding(nextKey, ST.COLUMN_NEXT); 2011 setKeyBinding(nextKey, ST.COLUMN_NEXT);
1906 setKeyBinding(previousKey, ST.COLUMN_PREVIOUS); 2012 setKeyBinding(previousKey, ST.COLUMN_PREVIOUS);
1907 2013
1908 // Selection 2014 // Selection
1909 setKeyBinding(DWT.ARROW_UP | DWT.MOD2, ST.SELECT_LINE_UP); 2015 setKeyBinding(DWT.ARROW_UP | DWT.MOD2, ST.SELECT_LINE_UP);
1910 setKeyBinding(DWT.ARROW_DOWN | DWT.MOD2, ST.SELECT_LINE_DOWN); 2016 setKeyBinding(DWT.ARROW_DOWN | DWT.MOD2, ST.SELECT_LINE_DOWN);
1911 if (IS_CARBON) { 2017 if (IS_CARBON) {
1912 setKeyBinding(previousKey | DWT.MOD1 | DWT.MOD2, ST.SELECT_LINE_START); 2018 setKeyBinding(previousKey | DWT.MOD1 | DWT.MOD2, ST.SELECT_LINE_START);
1913 setKeyBinding(nextKey | DWT.MOD1 | DWT.MOD2, ST.SELECT_LINE_END); 2019 setKeyBinding(nextKey | DWT.MOD1 | DWT.MOD2, ST.SELECT_LINE_END);
1914 setKeyBinding(DWT.HOME | DWT.MOD2, ST.SELECT_TEXT_START); 2020 setKeyBinding(DWT.HOME | DWT.MOD2, ST.SELECT_TEXT_START);
1915 setKeyBinding(DWT.END | DWT.MOD2, ST.SELECT_TEXT_END); 2021 setKeyBinding(DWT.END | DWT.MOD2, ST.SELECT_TEXT_END);
1916 setKeyBinding(DWT.ARROW_UP | DWT.MOD1 | DWT.MOD2, ST.SELECT_TEXT_START); 2022 setKeyBinding(DWT.ARROW_UP | DWT.MOD1 | DWT.MOD2, ST.SELECT_TEXT_START);
1917 setKeyBinding(DWT.ARROW_DOWN | DWT.MOD1 | DWT.MOD2, ST.SELECT_TEXT_END); 2023 setKeyBinding(DWT.ARROW_DOWN | DWT.MOD1 | DWT.MOD2, ST.SELECT_TEXT_END);
1918 setKeyBinding(nextKey | DWT.MOD2 | DWT.MOD3, ST.SELECT_WORD_NEXT); 2024 setKeyBinding(nextKey | DWT.MOD2 | DWT.MOD3, ST.SELECT_WORD_NEXT);
1919 setKeyBinding(previousKey | DWT.MOD2 | DWT.MOD3, ST.SELECT_WORD_PREVIOUS); 2025 setKeyBinding(previousKey | DWT.MOD2 | DWT.MOD3, ST.SELECT_WORD_PREVIOUS);
1920 } else { 2026 } else {
1921 setKeyBinding(DWT.HOME | DWT.MOD2, ST.SELECT_LINE_START); 2027 setKeyBinding(DWT.HOME | DWT.MOD2, ST.SELECT_LINE_START);
1922 setKeyBinding(DWT.END | DWT.MOD2, ST.SELECT_LINE_END); 2028 setKeyBinding(DWT.END | DWT.MOD2, ST.SELECT_LINE_END);
1923 setKeyBinding(DWT.HOME | DWT.MOD1 | DWT.MOD2, ST.SELECT_TEXT_START); 2029 setKeyBinding(DWT.HOME | DWT.MOD1 | DWT.MOD2, ST.SELECT_TEXT_START);
1924 setKeyBinding(DWT.END | DWT.MOD1 | DWT.MOD2, ST.SELECT_TEXT_END); 2030 setKeyBinding(DWT.END | DWT.MOD1 | DWT.MOD2, ST.SELECT_TEXT_END);
1925 setKeyBinding(nextKey | DWT.MOD1 | DWT.MOD2, ST.SELECT_WORD_NEXT); 2031 setKeyBinding(nextKey | DWT.MOD1 | DWT.MOD2, ST.SELECT_WORD_NEXT);
1926 setKeyBinding(previousKey | DWT.MOD1 | DWT.MOD2, ST.SELECT_WORD_PREVIOUS); 2032 setKeyBinding(previousKey | DWT.MOD1 | DWT.MOD2, ST.SELECT_WORD_PREVIOUS);
1927 } 2033 }
1928 setKeyBinding(DWT.PAGE_UP | DWT.MOD2, ST.SELECT_PAGE_UP); 2034 setKeyBinding(DWT.PAGE_UP | DWT.MOD2, ST.SELECT_PAGE_UP);
1929 setKeyBinding(DWT.PAGE_DOWN | DWT.MOD2, ST.SELECT_PAGE_DOWN); 2035 setKeyBinding(DWT.PAGE_DOWN | DWT.MOD2, ST.SELECT_PAGE_DOWN);
1930 setKeyBinding(DWT.PAGE_UP | DWT.MOD1 | DWT.MOD2, ST.SELECT_WINDOW_START); 2036 setKeyBinding(DWT.PAGE_UP | DWT.MOD1 | DWT.MOD2, ST.SELECT_WINDOW_START);
1931 setKeyBinding(DWT.PAGE_DOWN | DWT.MOD1 | DWT.MOD2, ST.SELECT_WINDOW_END); 2037 setKeyBinding(DWT.PAGE_DOWN | DWT.MOD1 | DWT.MOD2, ST.SELECT_WINDOW_END);
1932 setKeyBinding(nextKey | DWT.MOD2, ST.SELECT_COLUMN_NEXT); 2038 setKeyBinding(nextKey | DWT.MOD2, ST.SELECT_COLUMN_NEXT);
1933 setKeyBinding(previousKey | DWT.MOD2, ST.SELECT_COLUMN_PREVIOUS); 2039 setKeyBinding(previousKey | DWT.MOD2, ST.SELECT_COLUMN_PREVIOUS);
1934 2040
1935 // Modification 2041 // Modification
1936 // Cut, Copy, Paste 2042 // Cut, Copy, Paste
1937 setKeyBinding('X' | DWT.MOD1, ST.CUT); 2043 setKeyBinding('X' | DWT.MOD1, ST.CUT);
1938 setKeyBinding('C' | DWT.MOD1, ST.COPY); 2044 setKeyBinding('C' | DWT.MOD1, ST.COPY);
1939 setKeyBinding('V' | DWT.MOD1, ST.PASTE); 2045 setKeyBinding('V' | DWT.MOD1, ST.PASTE);
1950 setKeyBinding(DWT.BS | DWT.MOD2, ST.DELETE_PREVIOUS); 2056 setKeyBinding(DWT.BS | DWT.MOD2, ST.DELETE_PREVIOUS);
1951 setKeyBinding(DWT.BS, ST.DELETE_PREVIOUS); 2057 setKeyBinding(DWT.BS, ST.DELETE_PREVIOUS);
1952 setKeyBinding(DWT.DEL, ST.DELETE_NEXT); 2058 setKeyBinding(DWT.DEL, ST.DELETE_NEXT);
1953 setKeyBinding(DWT.BS | DWT.MOD1, ST.DELETE_WORD_PREVIOUS); 2059 setKeyBinding(DWT.BS | DWT.MOD1, ST.DELETE_WORD_PREVIOUS);
1954 setKeyBinding(DWT.DEL | DWT.MOD1, ST.DELETE_WORD_NEXT); 2060 setKeyBinding(DWT.DEL | DWT.MOD1, ST.DELETE_WORD_NEXT);
1955 2061
1956 // Miscellaneous 2062 // Miscellaneous
1957 setKeyBinding(DWT.INSERT, ST.TOGGLE_OVERWRITE); 2063 setKeyBinding(DWT.INSERT, ST.TOGGLE_OVERWRITE);
1958 } 2064 }
1959 /** 2065 /**
1960 * Create the bitmaps to use for the caret in bidi mode. This 2066 * Create the bitmaps to use for the caret in bidi mode. This
1963 */ 2069 */
1964 void createCaretBitmaps() { 2070 void createCaretBitmaps() {
1965 int caretWidth = BIDI_CARET_WIDTH; 2071 int caretWidth = BIDI_CARET_WIDTH;
1966 Display display = getDisplay(); 2072 Display display = getDisplay();
1967 if (leftCaretBitmap !is null) { 2073 if (leftCaretBitmap !is null) {
1968 if (defaultCaret !is null && leftCaretBitmap.opEquals(defaultCaret.getImage())) { 2074 if (defaultCaret !is null && leftCaretBitmap==/*eq*/defaultCaret.getImage()) {
1969 defaultCaret.setImage(null); 2075 defaultCaret.setImage(null);
1970 } 2076 }
1971 leftCaretBitmap.dispose(); 2077 leftCaretBitmap.dispose();
1972 } 2078 }
1973 int lineHeight = renderer.getLineHeight(); 2079 int lineHeight = renderer.getLineHeight();
1974 leftCaretBitmap = new Image(display, caretWidth, lineHeight); 2080 leftCaretBitmap = new Image(display, caretWidth, lineHeight);
1975 GC gc = new GC (leftCaretBitmap); 2081 GC gc = new GC (leftCaretBitmap);
1976 gc.setBackground(display.getSystemColor(DWT.COLOR_BLACK)); 2082 gc.setBackground(display.getSystemColor(DWT.COLOR_BLACK));
1977 gc.fillRectangle(0, 0, caretWidth, lineHeight); 2083 gc.fillRectangle(0, 0, caretWidth, lineHeight);
1978 gc.setForeground(display.getSystemColor(DWT.COLOR_WHITE)); 2084 gc.setForeground(display.getSystemColor(DWT.COLOR_WHITE));
1979 gc.drawLine(0,0,0,lineHeight); 2085 gc.drawLine(0,0,0,lineHeight);
1980 gc.drawLine(0,0,caretWidth-1,0); 2086 gc.drawLine(0,0,caretWidth-1,0);
1981 gc.drawLine(0,1,1,1); 2087 gc.drawLine(0,1,1,1);
1982 gc.dispose(); 2088 gc.dispose();
1983 2089
1984 if (rightCaretBitmap !is null) { 2090 if (rightCaretBitmap !is null) {
1985 if (defaultCaret !is null && rightCaretBitmap.opEquals(defaultCaret.getImage())) { 2091 if (defaultCaret !is null && rightCaretBitmap==/*eq*/defaultCaret.getImage()) {
1986 defaultCaret.setImage(null); 2092 defaultCaret.setImage(null);
1987 } 2093 }
1988 rightCaretBitmap.dispose(); 2094 rightCaretBitmap.dispose();
1989 } 2095 }
1990 rightCaretBitmap = new Image(display, caretWidth, lineHeight); 2096 rightCaretBitmap = new Image(display, caretWidth, lineHeight);
1991 gc = new GC (rightCaretBitmap); 2097 gc = new GC (rightCaretBitmap);
1992 gc.setBackground(display.getSystemColor(DWT.COLOR_BLACK)); 2098 gc.setBackground(display.getSystemColor(DWT.COLOR_BLACK));
1993 gc.fillRectangle(0, 0, caretWidth, lineHeight); 2099 gc.fillRectangle(0, 0, caretWidth, lineHeight);
1994 gc.setForeground(display.getSystemColor(DWT.COLOR_WHITE)); 2100 gc.setForeground(display.getSystemColor(DWT.COLOR_WHITE));
1995 gc.drawLine(caretWidth-1,0,caretWidth-1,lineHeight); 2101 gc.drawLine(caretWidth-1,0,caretWidth-1,lineHeight);
1996 gc.drawLine(0,0,caretWidth-1,0); 2102 gc.drawLine(0,0,caretWidth-1,0);
1997 gc.drawLine(caretWidth-1,1,1,1); 2103 gc.drawLine(caretWidth-1,1,1,1);
1998 gc.dispose(); 2104 gc.dispose();
1999 } 2105 }
2000 /** 2106 /**
2001 * Moves the selected text to the clipboard. The text will be put in the 2107 * Moves the selected text to the clipboard. The text will be put in the
2002 * clipboard in plain text format and RTF format. 2108 * clipboard in plain text format and RTF format.
2003 * 2109 *
2004 * @exception DWTException <ul> 2110 * @exception DWTException <ul>
2005 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 2111 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
2006 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 2112 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
2011 int length = selection.y - selection.x; 2117 int length = selection.y - selection.x;
2012 if (length > 0) { 2118 if (length > 0) {
2013 try { 2119 try {
2014 setClipboardContent(selection.x, length, DND.CLIPBOARD); 2120 setClipboardContent(selection.x, length, DND.CLIPBOARD);
2015 } catch (DWTError error) { 2121 } catch (DWTError error) {
2016 // Copy to clipboard failed. This happens when another application 2122 // Copy to clipboard failed. This happens when another application
2017 // is accessing the clipboard while we copy. Ignore the error. 2123 // is accessing the clipboard while we copy. Ignore the error.
2018 // Fixes 1GDQAVN 2124 // Fixes 1GDQAVN
2019 // Rethrow all other errors. Fixes bug 17578. 2125 // Rethrow all other errors. Fixes bug 17578.
2020 if (error.code !is DND.ERROR_CANNOT_SET_CLIPBOARD) { 2126 if (error.code !is DND.ERROR_CANNOT_SET_CLIPBOARD) {
2021 throw error; 2127 throw error;
2025 return; 2131 return;
2026 } 2132 }
2027 doDelete(); 2133 doDelete();
2028 } 2134 }
2029 } 2135 }
2030 /** 2136 /**
2031 * A mouse move event has occurred. See if we should start autoscrolling. If 2137 * A mouse move event has occurred. See if we should start autoscrolling. If
2032 * the move position is outside of the client area, initiate autoscrolling. 2138 * the move position is outside of the client area, initiate autoscrolling.
2033 * Otherwise, we've moved back into the widget so end autoscrolling. 2139 * Otherwise, we've moved back into the widget so end autoscrolling.
2034 */ 2140 */
2035 void doAutoScroll(Event event) { 2141 void doAutoScroll(Event event) {
2036 if (event.y > clientAreaHeight) { 2142 if (event.y > clientAreaHeight) {
2037 doAutoScroll(DWT.DOWN, event.y - clientAreaHeight); 2143 doAutoScroll(DWT.DOWN, event.y - clientAreaHeight);
2043 doAutoScroll(ST.COLUMN_NEXT, event.x - (clientAreaWidth - leftMargin - rightMargin)); 2149 doAutoScroll(ST.COLUMN_NEXT, event.x - (clientAreaWidth - leftMargin - rightMargin));
2044 } else { 2150 } else {
2045 endAutoScroll(); 2151 endAutoScroll();
2046 } 2152 }
2047 } 2153 }
2048 /** 2154 /**
2049 * Initiates autoscrolling. 2155 * Initiates autoscrolling.
2050 * 2156 *
2051 * @param direction DWT.UP, DWT.DOWN, DWT.COLUMN_NEXT, DWT.COLUMN_PREVIOUS 2157 * @param direction DWT.UP, DWT.DOWN, DWT.COLUMN_NEXT, DWT.COLUMN_PREVIOUS
2052 */ 2158 */
2053 void doAutoScroll(int direction, int distance) { 2159 void doAutoScroll(int direction, int distance) {
2054 autoScrollDistance = distance; 2160 autoScrollDistance = distance;
2055 // If we're already autoscrolling in the given direction do nothing 2161 // If we're already autoscrolling in the given direction do nothing
2056 if (autoScrollDirection is direction) { 2162 if (autoScrollDirection is direction) {
2057 return; 2163 return;
2058 } 2164 }
2059 2165
2060 Runnable timer = null; 2166 Runnable timer = null;
2061 final Display display = getDisplay(); 2167 final Display disp = getDisplay();
2062 // Set a timer that will simulate the user pressing and holding 2168 // Set a timer that will simulate the user pressing and holding
2063 // down a cursor key (i.e., arrowUp, arrowDown). 2169 // down a cursor key (i.e., arrowUp, arrowDown).
2064 if (direction is DWT.UP) { 2170 if (direction is DWT.UP) {
2065 timer = new Runnable() { 2171 timer = new class(disp) Runnable {
2172 Display display;
2173 this( Display d ){ this.display = d; }
2066 public void run() { 2174 public void run() {
2067 if (autoScrollDirection is DWT.UP) { 2175 if (autoScrollDirection is DWT.UP) {
2068 doSelectionPageUp(autoScrollDistance); 2176 doSelectionPageUp(autoScrollDistance);
2069 display.timerExec(V_SCROLL_RATE, this); 2177 display.timerExec(V_SCROLL_RATE, this);
2070 } 2178 }
2071 } 2179 }
2072 }; 2180 };
2073 autoScrollDirection = direction; 2181 autoScrollDirection = direction;
2074 display.timerExec(V_SCROLL_RATE, timer); 2182 display.timerExec(V_SCROLL_RATE, timer);
2075 } else if (direction is DWT.DOWN) { 2183 } else if (direction is DWT.DOWN) {
2076 timer = new Runnable() { 2184 timer = new class(disp) Runnable {
2185 Display display;
2186 this( Display d ){ this.display = d; }
2077 public void run() { 2187 public void run() {
2078 if (autoScrollDirection is DWT.DOWN) { 2188 if (autoScrollDirection is DWT.DOWN) {
2079 doSelectionPageDown(autoScrollDistance); 2189 doSelectionPageDown(autoScrollDistance);
2080 display.timerExec(V_SCROLL_RATE, this); 2190 display.timerExec(V_SCROLL_RATE, this);
2081 } 2191 }
2082 } 2192 }
2083 }; 2193 };
2084 autoScrollDirection = direction; 2194 autoScrollDirection = direction;
2085 display.timerExec(V_SCROLL_RATE, timer); 2195 display.timerExec(V_SCROLL_RATE, timer);
2086 } else if (direction is ST.COLUMN_NEXT) { 2196 } else if (direction is ST.COLUMN_NEXT) {
2087 timer = new Runnable() { 2197 timer = new class(disp) Runnable {
2198 Display display;
2199 this( Display d ){ this.display = d; }
2088 public void run() { 2200 public void run() {
2089 if (autoScrollDirection is ST.COLUMN_NEXT) { 2201 if (autoScrollDirection is ST.COLUMN_NEXT) {
2090 doVisualNext(); 2202 doVisualNext();
2091 setMouseWordSelectionAnchor(); 2203 setMouseWordSelectionAnchor();
2092 doMouseSelection(); 2204 doMouseSelection();
2095 } 2207 }
2096 }; 2208 };
2097 autoScrollDirection = direction; 2209 autoScrollDirection = direction;
2098 display.timerExec(H_SCROLL_RATE, timer); 2210 display.timerExec(H_SCROLL_RATE, timer);
2099 } else if (direction is ST.COLUMN_PREVIOUS) { 2211 } else if (direction is ST.COLUMN_PREVIOUS) {
2100 timer = new Runnable() { 2212 timer = new class(disp) Runnable {
2213 Display display;
2214 this( Display d ){ this.display = d; }
2101 public void run() { 2215 public void run() {
2102 if (autoScrollDirection is ST.COLUMN_PREVIOUS) { 2216 if (autoScrollDirection is ST.COLUMN_PREVIOUS) {
2103 doVisualPrevious(); 2217 doVisualPrevious();
2104 setMouseWordSelectionAnchor(); 2218 setMouseWordSelectionAnchor();
2105 doMouseSelection(); 2219 doMouseSelection();
2124 sendKeyEvent(event); 2238 sendKeyEvent(event);
2125 } else if (caretOffset > 0) { 2239 } else if (caretOffset > 0) {
2126 int lineIndex = content.getLineAtOffset(caretOffset); 2240 int lineIndex = content.getLineAtOffset(caretOffset);
2127 int lineOffset = content.getOffsetAtLine(lineIndex); 2241 int lineOffset = content.getOffsetAtLine(lineIndex);
2128 if (caretOffset is lineOffset) { 2242 if (caretOffset is lineOffset) {
2243 // DWT: on line start, delete line break
2129 lineOffset = content.getOffsetAtLine(lineIndex - 1); 2244 lineOffset = content.getOffsetAtLine(lineIndex - 1);
2130 event.start = lineOffset + content.getLine(lineIndex - 1).length(); 2245 event.start = lineOffset + content.getLine(lineIndex - 1).length;
2131 event.end = caretOffset; 2246 event.end = caretOffset;
2132 } else { 2247 } else {
2133 TextLayout layout = renderer.getTextLayout(lineIndex); 2248 TextLayout layout = renderer.getTextLayout(lineIndex);
2134 int start = layout.getPreviousOffset(caretOffset - lineOffset, DWT.MOVEMENT_CHAR); 2249 int start = layout.getPreviousOffset(caretOffset - lineOffset, DWT.MOVEMENT_CLUSTER);
2135 renderer.disposeTextLayout(layout); 2250 renderer.disposeTextLayout(layout);
2136 event.start = start + lineOffset; 2251 event.start = start + lineOffset;
2137 event.end = caretOffset; 2252 event.end = caretOffset;
2138 } 2253 }
2139 sendKeyEvent(event); 2254 sendKeyEvent(event);
2140 } 2255 }
2141 } 2256 }
2142 /** 2257 /**
2143 * Replaces the selection with the character or insert the character at the 2258 * Replaces the selection with the character or insert the character at the
2144 * current caret position if no selection exists. 2259 * current caret position if no selection exists.
2145 * <p> 2260 * <p>
2146 * If a carriage return was typed replace it with the line break character 2261 * If a carriage return was typed replace it with the line break character
2147 * used by the widget on this platform. 2262 * used by the widget on this platform.
2148 * </p> 2263 * </p>
2149 * 2264 *
2150 * @param key the character typed by the user 2265 * @param key the character typed by the user
2151 */ 2266 */
2152 void doContent(char key) { 2267 void doContent(dchar key) {
2153 Event event = new Event(); 2268 Event event = new Event();
2154 event.start = selection.x; 2269 event.start = selection.x;
2155 event.end = selection.y; 2270 event.end = selection.y;
2156 // replace a CR line break with the widget line break 2271 // replace a CR line break with the widget line break
2157 // CR does not make sense on Windows since most (all?) applications 2272 // CR does not make sense on Windows since most (all?) applications
2160 if (!isSingleLine()) { 2275 if (!isSingleLine()) {
2161 event.text = getLineDelimiter(); 2276 event.text = getLineDelimiter();
2162 } 2277 }
2163 } else if (selection.x is selection.y && overwrite && key !is TAB) { 2278 } else if (selection.x is selection.y && overwrite && key !is TAB) {
2164 // no selection and overwrite mode is on and the typed key is not a 2279 // no selection and overwrite mode is on and the typed key is not a
2165 // tab character (tabs are always inserted without overwriting)? 2280 // tab character (tabs are always inserted without overwriting)?
2166 int lineIndex = content.getLineAtOffset(event.end); 2281 int lineIndex = content.getLineAtOffset(event.end);
2167 int lineOffset = content.getOffsetAtLine(lineIndex); 2282 int lineOffset = content.getOffsetAtLine(lineIndex);
2168 String line = content.getLine(lineIndex); 2283 String line = content.getLine(lineIndex);
2169 // replace character at caret offset if the caret is not at the 2284 // replace character at caret offset if the caret is not at the
2170 // end of the line 2285 // end of the line
2171 if (event.end < lineOffset + line.length()) { 2286 if (event.end < lineOffset + line.length) {
2172 event.end++; 2287 event.end+=dcharToString( key ).length;
2173 } 2288 }
2174 event.text = new String(new char[] {key}); 2289 event.text = dcharToString( key );
2175 } else { 2290 } else {
2176 event.text = new String(new char[] {key}); 2291 event.text = dcharToString( key );
2177 } 2292 }
2178 if (event.text !is null) { 2293 if (event.text !is null) {
2179 if (textLimit > 0 && content.getCharCount() - (event.end - event.start) >= textLimit) { 2294 if (textLimit > 0 && content.getCharCount() - (event.end - event.start) >= textLimit) {
2180 return; 2295 return;
2181 } 2296 }
2184 } 2299 }
2185 /** 2300 /**
2186 * Moves the caret after the last character of the widget content. 2301 * Moves the caret after the last character of the widget content.
2187 */ 2302 */
2188 void doContentEnd() { 2303 void doContentEnd() {
2189 // place caret at end of first line if receiver is in single 2304 // place caret at end of first line if receiver is in single
2190 // line mode. fixes 4820. 2305 // line mode. fixes 4820.
2191 if (isSingleLine()) { 2306 if (isSingleLine()) {
2192 doLineEnd(); 2307 doLineEnd();
2193 } else { 2308 } else {
2194 int length = content.getCharCount(); 2309 int length = content.getCharCount();
2195 if (caretOffset < length) { 2310 if (caretOffset < length) {
2196 caretOffset = length; 2311 caretOffset = length;
2197 showCaret(); 2312 showCaret();
2198 } 2313 }
2199 } 2314 }
2207 showCaret(); 2322 showCaret();
2208 } 2323 }
2209 } 2324 }
2210 /** 2325 /**
2211 * Moves the caret to the start of the selection if a selection exists. 2326 * Moves the caret to the start of the selection if a selection exists.
2212 * Otherwise, if no selection exists move the cursor according to the 2327 * Otherwise, if no selection exists move the cursor according to the
2213 * cursor selection rules. 2328 * cursor selection rules.
2214 * 2329 *
2215 * @see #doSelectionCursorPrevious 2330 * @see #doSelectionCursorPrevious
2216 */ 2331 */
2217 void doCursorPrevious() { 2332 void doCursorPrevious() {
2223 doSelectionCursorPrevious(); 2338 doSelectionCursorPrevious();
2224 } 2339 }
2225 } 2340 }
2226 /** 2341 /**
2227 * Moves the caret to the end of the selection if a selection exists. 2342 * Moves the caret to the end of the selection if a selection exists.
2228 * Otherwise, if no selection exists move the cursor according to the 2343 * Otherwise, if no selection exists move the cursor according to the
2229 * cursor selection rules. 2344 * cursor selection rules.
2230 * 2345 *
2231 * @see #doSelectionCursorNext 2346 * @see #doSelectionCursorNext
2232 */ 2347 */
2233 void doCursorNext() { 2348 void doCursorNext() {
2250 event.end = selection.y; 2365 event.end = selection.y;
2251 sendKeyEvent(event); 2366 sendKeyEvent(event);
2252 } else if (caretOffset < content.getCharCount()) { 2367 } else if (caretOffset < content.getCharCount()) {
2253 int line = content.getLineAtOffset(caretOffset); 2368 int line = content.getLineAtOffset(caretOffset);
2254 int lineOffset = content.getOffsetAtLine(line); 2369 int lineOffset = content.getOffsetAtLine(line);
2255 int lineLength = content.getLine(line).length(); 2370 int lineLength = content.getLine(line).length;
2256 if (caretOffset is lineOffset + lineLength) { 2371 if (caretOffset is lineOffset + lineLength) {
2257 event.start = caretOffset; 2372 event.start = caretOffset;
2258 event.end = content.getOffsetAtLine(line + 1); 2373 event.end = content.getOffsetAtLine(line + 1);
2259 } else { 2374 } else {
2260 event.start = caretOffset; 2375 event.start = caretOffset;
2266 /** 2381 /**
2267 * Deletes the next word. 2382 * Deletes the next word.
2268 */ 2383 */
2269 void doDeleteWordNext() { 2384 void doDeleteWordNext() {
2270 if (selection.x !is selection.y) { 2385 if (selection.x !is selection.y) {
2271 // if a selection exists, treat the as if 2386 // if a selection exists, treat the as if
2272 // only the delete key was pressed 2387 // only the delete key was pressed
2273 doDelete(); 2388 doDelete();
2274 } else { 2389 } else {
2275 Event event = new Event(); 2390 Event event = new Event();
2276 event.text = ""; 2391 event.text = "";
2282 /** 2397 /**
2283 * Deletes the previous word. 2398 * Deletes the previous word.
2284 */ 2399 */
2285 void doDeleteWordPrevious() { 2400 void doDeleteWordPrevious() {
2286 if (selection.x !is selection.y) { 2401 if (selection.x !is selection.y) {
2287 // if a selection exists, treat as if 2402 // if a selection exists, treat as if
2288 // only the backspace key was pressed 2403 // only the backspace key was pressed
2289 doBackspace(); 2404 doBackspace();
2290 } else { 2405 } else {
2291 Event event = new Event(); 2406 Event event = new Event();
2292 event.text = ""; 2407 event.text = "";
2294 event.end = caretOffset; 2409 event.end = caretOffset;
2295 sendKeyEvent(event); 2410 sendKeyEvent(event);
2296 } 2411 }
2297 } 2412 }
2298 /** 2413 /**
2299 * Moves the caret one line down and to the same character offset relative 2414 * Moves the caret one line down and to the same character offset relative
2300 * to the beginning of the line. Move the caret to the end of the new line 2415 * to the beginning of the line. Move the caret to the end of the new line
2301 * if the new line is shorter than the character offset. 2416 * if the new line is shorter than the character offset.
2302 */ 2417 */
2303 void doLineDown(bool select) { 2418 void doLineDown(bool select) {
2304 int caretLine = getCaretLine(); 2419 int caretLine = getCaretLine();
2305 int lineCount = content.getLineCount(); 2420 int lineCount = content.getLineCount();
2328 caretOffset = getOffsetAtPoint(columnX, y, caretLine); 2443 caretOffset = getOffsetAtPoint(columnX, y, caretLine);
2329 } 2444 }
2330 int oldColumnX = columnX; 2445 int oldColumnX = columnX;
2331 int oldHScrollOffset = horizontalScrollOffset; 2446 int oldHScrollOffset = horizontalScrollOffset;
2332 if (select) { 2447 if (select) {
2333 setMouseWordSelectionAnchor(); 2448 setMouseWordSelectionAnchor();
2334 // select first and then scroll to reduce flash when key 2449 // select first and then scroll to reduce flash when key
2335 // repeat scrolls lots of lines 2450 // repeat scrolls lots of lines
2336 doSelection(ST.COLUMN_NEXT); 2451 doSelection(ST.COLUMN_NEXT);
2337 } 2452 }
2338 showCaret(); 2453 showCaret();
2339 int hScrollChange = oldHScrollOffset - horizontalScrollOffset; 2454 int hScrollChange = oldHScrollOffset - horizontalScrollOffset;
2342 /** 2457 /**
2343 * Moves the caret to the end of the line. 2458 * Moves the caret to the end of the line.
2344 */ 2459 */
2345 void doLineEnd() { 2460 void doLineEnd() {
2346 int caretLine = getCaretLine(); 2461 int caretLine = getCaretLine();
2347 int lineOffset = content.getOffsetAtLine(caretLine); 2462 int lineOffset = content.getOffsetAtLine(caretLine);
2348 int lineEndOffset; 2463 int lineEndOffset;
2349 if (wordWrap) { 2464 if (wordWrap) {
2350 TextLayout layout = renderer.getTextLayout(caretLine); 2465 TextLayout layout = renderer.getTextLayout(caretLine);
2351 int offsetInLine = caretOffset - lineOffset; 2466 int offsetInLine = caretOffset - lineOffset;
2352 int lineIndex = getVisualLineIndex(layout, offsetInLine); 2467 int lineIndex = getVisualLineIndex(layout, offsetInLine);
2353 int[] offsets = layout.getLineOffsets(); 2468 int[] offsets = layout.getLineOffsets();
2354 lineEndOffset = lineOffset + offsets[lineIndex + 1]; 2469 lineEndOffset = lineOffset + offsets[lineIndex + 1];
2355 renderer.disposeTextLayout(layout); 2470 renderer.disposeTextLayout(layout);
2356 } else { 2471 } else {
2357 int lineLength = content.getLine(caretLine).length(); 2472 int lineLength = content.getLine(caretLine).length;
2358 lineEndOffset = lineOffset + lineLength; 2473 lineEndOffset = lineOffset + lineLength;
2359 } 2474 }
2360 if (caretOffset < lineEndOffset) { 2475 if (caretOffset < lineEndOffset) {
2361 caretOffset = lineEndOffset; 2476 caretOffset = lineEndOffset;
2362 caretAlignment = PREVIOUS_OFFSET_TRAILING; 2477 caretAlignment = PREVIOUS_OFFSET_TRAILING;
2382 caretAlignment = OFFSET_LEADING; 2497 caretAlignment = OFFSET_LEADING;
2383 showCaret(); 2498 showCaret();
2384 } 2499 }
2385 } 2500 }
2386 /** 2501 /**
2387 * Moves the caret one line up and to the same character offset relative 2502 * Moves the caret one line up and to the same character offset relative
2388 * to the beginning of the line. Move the caret to the end of the new line 2503 * to the beginning of the line. Move the caret to the end of the new line
2389 * if the new line is shorter than the character offset. 2504 * if the new line is shorter than the character offset.
2390 */ 2505 */
2391 void doLineUp(bool select) { 2506 void doLineUp(bool select) {
2392 int caretLine = getCaretLine(), y = 0; 2507 int caretLine = getCaretLine(), y = 0;
2393 bool firstLine = false; 2508 bool firstLine = false;
2433 */ 2548 */
2434 void doMouseLocationChange(int x, int y, bool select) { 2549 void doMouseLocationChange(int x, int y, bool select) {
2435 int line = getLineIndex(y); 2550 int line = getLineIndex(y);
2436 2551
2437 updateCaretDirection = true; 2552 updateCaretDirection = true;
2438 // allow caret to be placed below first line only if receiver is 2553 // allow caret to be placed below first line only if receiver is
2439 // not in single line mode. fixes 4820. 2554 // not in single line mode. fixes 4820.
2440 if (line < 0 || (isSingleLine() && line > 0)) { 2555 if (line < 0 || (isSingleLine() && line > 0)) {
2441 return; 2556 return;
2442 } 2557 }
2443 int oldCaretAlignment = caretAlignment; 2558 int oldCaretAlignment = caretAlignment;
2444 int newCaretOffset = getOffsetAtPoint(x, y); 2559 int newCaretOffset = getOffsetAtPoint(x, y);
2445 2560
2446 if (doubleClickEnabled && clickCount > 1) { 2561 if (doubleClickEnabled && clickCount > 1) {
2447 newCaretOffset = doMouseWordSelect(x, newCaretOffset, line); 2562 newCaretOffset = doMouseWordSelect(x, newCaretOffset, line);
2448 } 2563 }
2449 2564
2450 int newCaretLine = content.getLineAtOffset(newCaretOffset); 2565 int newCaretLine = content.getLineAtOffset(newCaretOffset);
2451 2566
2452 // Is the mouse within the left client area border or on 2567 // Is the mouse within the left client area border or on
2453 // a different line? If not the autoscroll selection 2568 // a different line? If not the autoscroll selection
2454 // could be incorrectly reset. Fixes 1GKM3XS 2569 // could be incorrectly reset. Fixes 1GKM3XS
2455 if (0 <= y && y < clientAreaHeight && 2570 if (0 <= y && y < clientAreaHeight &&
2456 (0 <= x && x < clientAreaWidth || wordWrap || 2571 (0 <= x && x < clientAreaWidth || wordWrap ||
2457 newCaretLine !is content.getLineAtOffset(caretOffset))) { 2572 newCaretLine !is content.getLineAtOffset(caretOffset))) {
2458 if (newCaretOffset !is caretOffset || caretAlignment !is oldCaretAlignment) { 2573 if (newCaretOffset !is caretOffset || caretAlignment !is oldCaretAlignment) {
2459 caretOffset = newCaretOffset; 2574 caretOffset = newCaretOffset;
2460 if (select) doMouseSelection(); 2575 if (select) doMouseSelection();
2461 showCaret(); 2576 showCaret();
2468 } 2583 }
2469 /** 2584 /**
2470 * Updates the selection based on the caret position 2585 * Updates the selection based on the caret position
2471 */ 2586 */
2472 void doMouseSelection() { 2587 void doMouseSelection() {
2473 if (caretOffset <= selection.x || 2588 if (caretOffset <= selection.x ||
2474 (caretOffset > selection.x && 2589 (caretOffset > selection.x &&
2475 caretOffset < selection.y && selectionAnchor is selection.x)) { 2590 caretOffset < selection.y && selectionAnchor is selection.x)) {
2476 doSelection(ST.COLUMN_PREVIOUS); 2591 doSelection(ST.COLUMN_PREVIOUS);
2477 } else { 2592 } else {
2478 doSelection(ST.COLUMN_NEXT); 2593 doSelection(ST.COLUMN_NEXT);
2479 } 2594 }
2480 } 2595 }
2481 /** 2596 /**
2482 * Returns the offset of the word at the specified offset. 2597 * Returns the offset of the word at the specified offset.
2483 * If the current selection : from high index to low index 2598 * If the current selection extends from high index to low index
2484 * (i.e., right to left, or caret is at left border of selection on 2599 * (i.e., right to left, or caret is at left border of selection on
2485 * non-bidi platforms) the start offset of the word preceding the 2600 * non-bidi platforms) the start offset of the word preceding the
2486 * selection is returned. If the current selection : from 2601 * selection is returned. If the current selection extends from
2487 * low index to high index the end offset of the word following 2602 * low index to high index the end offset of the word following
2488 * the selection is returned. 2603 * the selection is returned.
2489 * 2604 *
2490 * @param x mouse x location 2605 * @param x mouse x location
2491 * @param newCaretOffset caret offset of the mouse cursor location 2606 * @param newCaretOffset caret offset of the mouse cursor location
2492 * @param line line index of the mouse cursor location 2607 * @param line line index of the mouse cursor location
2493 */ 2608 */
2494 int doMouseWordSelect(int x, int newCaretOffset, int line) { 2609 int doMouseWordSelect(int x, int newCaretOffset, int line) {
2495 // flip selection anchor based on word selection direction from 2610 // flip selection anchor based on word selection direction from
2496 // base double click. Always do this here (and don't rely on doAutoScroll) 2611 // base double click. Always do this here (and don't rely on doAutoScroll)
2497 // because auto scroll only does not cover all possible mouse selections 2612 // because auto scroll only does not cover all possible mouse selections
2498 // (e.g., mouse x < 0 && mouse y > caret line y) 2613 // (e.g., mouse x < 0 && mouse y > caret line y)
2499 if (newCaretOffset < selectionAnchor && selectionAnchor is selection.x) { 2614 if (newCaretOffset < selectionAnchor && selectionAnchor is selection.x) {
2500 selectionAnchor = doubleClickSelection.y; 2615 selectionAnchor = doubleClickSelection.y;
2515 } else { 2630 } else {
2516 int lineEnd = content.getCharCount(); 2631 int lineEnd = content.getCharCount();
2517 if (line + 1 < content.getLineCount()) { 2632 if (line + 1 < content.getLineCount()) {
2518 lineEnd = content.getOffsetAtLine(line + 1); 2633 lineEnd = content.getOffsetAtLine(line + 1);
2519 } 2634 }
2520 newCaretOffset = lineEnd; 2635 newCaretOffset = lineEnd;
2521 } 2636 }
2522 } 2637 }
2523 } 2638 }
2524 return newCaretOffset; 2639 return newCaretOffset;
2525 } 2640 }
2526 /** 2641 /**
2527 * Scrolls one page down so that the last line (truncated or whole) 2642 * Scrolls one page down so that the last line (truncated or whole)
2528 * of the current page becomes the fully visible top line. 2643 * of the current page becomes the fully visible top line.
2529 * <p> 2644 * <p>
2530 * The caret is scrolled the same number of lines so that its location 2645 * The caret is scrolled the same number of lines so that its location
2531 * relative to the top line remains the same. The exception is the end 2646 * relative to the top line remains the same. The exception is the end
2532 * of the text where a full page scroll is not possible. In this case 2647 * of the text where a full page scroll is not possible. In this case
2533 * the caret is moved after the last character. 2648 * the caret is moved after the last character.
2534 * </p> 2649 * </p>
2535 * 2650 *
2536 * @param select whether or not to select the page 2651 * @param select whether or not to select the page
2537 */ 2652 */
2544 int caretLine = getCaretLine(); 2659 int caretLine = getCaretLine();
2545 if (caretLine < lineCount - 1) { 2660 if (caretLine < lineCount - 1) {
2546 int lineHeight = renderer.getLineHeight(); 2661 int lineHeight = renderer.getLineHeight();
2547 int lines = (height is -1 ? clientAreaHeight : height) / lineHeight; 2662 int lines = (height is -1 ? clientAreaHeight : height) / lineHeight;
2548 int scrollLines = Math.min(lineCount - caretLine - 1, lines); 2663 int scrollLines = Math.min(lineCount - caretLine - 1, lines);
2549 // ensure that scrollLines never gets negative and at least one 2664 // ensure that scrollLines never gets negative and at least one
2550 // line is scrolled. fixes bug 5602. 2665 // line is scrolled. fixes bug 5602.
2551 scrollLines = Math.max(1, scrollLines); 2666 scrollLines = Math.max(1, scrollLines);
2552 caretOffset = getOffsetAtPoint(columnX, getLinePixel(caretLine + scrollLines)); 2667 caretOffset = getOffsetAtPoint(columnX, getLinePixel(caretLine + scrollLines));
2553 if (select) { 2668 if (select) {
2554 doSelection(ST.COLUMN_NEXT); 2669 doSelection(ST.COLUMN_NEXT);
2625 caretOffset = getOffsetAtPoint(columnX, caretHeight, lineIndex); 2740 caretOffset = getOffsetAtPoint(columnX, caretHeight, lineIndex);
2626 if (select) doSelection(ST.COLUMN_NEXT); 2741 if (select) doSelection(ST.COLUMN_NEXT);
2627 height = getAvailableHeightBellow(height); 2742 height = getAvailableHeightBellow(height);
2628 scrollVertical(height, true); 2743 scrollVertical(height, true);
2629 if (height is 0) setCaretLocation(); 2744 if (height is 0) setCaretLocation();
2630 } 2745 }
2631 showCaret(); 2746 showCaret();
2632 int hScrollChange = oldHScrollOffset - horizontalScrollOffset; 2747 int hScrollChange = oldHScrollOffset - horizontalScrollOffset;
2633 columnX = oldColumnX + hScrollChange; 2748 columnX = oldColumnX + hScrollChange;
2634 } 2749 }
2635 /** 2750 /**
2636 * Moves the cursor to the end of the last fully visible line. 2751 * Moves the cursor to the end of the last fully visible line.
2637 */ 2752 */
2638 void doPageEnd() { 2753 void doPageEnd() {
2650 Rectangle bounds = layout.getLineBounds(index); 2765 Rectangle bounds = layout.getLineBounds(index);
2651 if (y >= bounds.y + bounds.height) break; 2766 if (y >= bounds.y + bounds.height) break;
2652 index--; 2767 index--;
2653 } 2768 }
2654 if (index is -1 && lineIndex > 0) { 2769 if (index is -1 && lineIndex > 0) {
2655 bottomOffset = content.getOffsetAtLine(lineIndex - 1) + content.getLine(lineIndex - 1).length(); 2770 bottomOffset = content.getOffsetAtLine(lineIndex - 1) + content.getLine(lineIndex - 1).length;
2656 } else { 2771 } else {
2657 bottomOffset = content.getOffsetAtLine(lineIndex) + Math.max(0, layout.getLineOffsets()[index + 1] - 1); 2772 bottomOffset = content.getOffsetAtLine(lineIndex) + Math.max(0, layout.getLineOffsets()[index + 1] - 1);
2658 } 2773 }
2659 renderer.disposeTextLayout(layout); 2774 renderer.disposeTextLayout(layout);
2660 } else { 2775 } else {
2661 int lineIndex = getBottomIndex(); 2776 int lineIndex = getBottomIndex();
2662 bottomOffset = content.getOffsetAtLine(lineIndex) + content.getLine(lineIndex).length(); 2777 bottomOffset = content.getOffsetAtLine(lineIndex) + content.getLine(lineIndex).length;
2663 } 2778 }
2664 if (caretOffset < bottomOffset) { 2779 if (caretOffset < bottomOffset) {
2665 caretOffset = bottomOffset; 2780 caretOffset = bottomOffset;
2666 caretAlignment = OFFSET_LEADING; 2781 caretAlignment = OFFSET_LEADING;
2667 showCaret(); 2782 showCaret();
2693 if (index is lineCount) { 2808 if (index is lineCount) {
2694 topOffset = content.getOffsetAtLine(lineIndex + 1); 2809 topOffset = content.getOffsetAtLine(lineIndex + 1);
2695 } else { 2810 } else {
2696 topOffset = content.getOffsetAtLine(lineIndex) + layout.getLineOffsets()[index]; 2811 topOffset = content.getOffsetAtLine(lineIndex) + layout.getLineOffsets()[index];
2697 } 2812 }
2698 renderer.disposeTextLayout(layout); 2813 renderer.disposeTextLayout(layout);
2699 } else { 2814 } else {
2700 topOffset = content.getOffsetAtLine(topIndex); 2815 topOffset = content.getOffsetAtLine(topIndex);
2701 } 2816 }
2702 if (caretOffset > topOffset) { 2817 if (caretOffset > topOffset) {
2703 caretOffset = topOffset; 2818 caretOffset = topOffset;
2706 } 2821 }
2707 } 2822 }
2708 /** 2823 /**
2709 * Scrolls one page up so that the first line (truncated or whole) 2824 * Scrolls one page up so that the first line (truncated or whole)
2710 * of the current page becomes the fully visible last line. 2825 * of the current page becomes the fully visible last line.
2711 * The caret is scrolled the same number of lines so that its location 2826 * The caret is scrolled the same number of lines so that its location
2712 * relative to the top line remains the same. The exception is the beginning 2827 * relative to the top line remains the same. The exception is the beginning
2713 * of the text where a full page scroll is not possible. In this case the 2828 * of the text where a full page scroll is not possible. In this case the
2714 * caret is moved in front of the first character. 2829 * caret is moved in front of the first character.
2715 */ 2830 */
2716 void doPageUp(bool select, int height) { 2831 void doPageUp(bool select, int height) {
2717 if (isSingleLine()) return; 2832 if (isSingleLine()) return;
2718 int oldHScrollOffset = horizontalScrollOffset; 2833 int oldHScrollOffset = horizontalScrollOffset;
2719 int oldColumnX = columnX; 2834 int oldColumnX = columnX;
2720 if (isFixedLineHeight()) { 2835 if (isFixedLineHeight()) {
2721 int caretLine = getCaretLine(); 2836 int caretLine = getCaretLine();
2722 if (caretLine > 0) { 2837 if (caretLine > 0) {
2723 int lineHeight = renderer.getLineHeight(); 2838 int lineHeight = renderer.getLineHeight();
2724 int lines = (height is -1 ? clientAreaHeight : height) / lineHeight; 2839 int lines = (height is -1 ? clientAreaHeight : height) / lineHeight;
2725 int scrollLines = Math.max(1, Math.min(caretLine, lines)); 2840 int scrollLines = Math.max(1, Math.min(caretLine, lines));
2726 caretLine -= scrollLines; 2841 caretLine -= scrollLines;
2796 while (caretHeight - lineHeight >= 0 && lineIndex > 0) { 2911 while (caretHeight - lineHeight >= 0 && lineIndex > 0) {
2797 caretHeight -= lineHeight; 2912 caretHeight -= lineHeight;
2798 lineHeight = renderer.getLineHeight(--lineIndex); 2913 lineHeight = renderer.getLineHeight(--lineIndex);
2799 } 2914 }
2800 lineHeight = renderer.getLineHeight(lineIndex); 2915 lineHeight = renderer.getLineHeight(lineIndex);
2801 caretOffset = getOffsetAtPoint(columnX, lineHeight - caretHeight, lineIndex); 2916 caretOffset = getOffsetAtPoint(columnX, lineHeight - caretHeight, lineIndex);
2802 if (select) doSelection(ST.COLUMN_PREVIOUS); 2917 if (select) doSelection(ST.COLUMN_PREVIOUS);
2803 height = getAvailableHeightAbove(height); 2918 height = getAvailableHeightAbove(height);
2804 scrollVertical(-height, true); 2919 scrollVertical(-height, true);
2805 if (height is 0) setCaretLocation(); 2920 if (height is 0) setCaretLocation();
2806 } 2921 }
2807 showCaret(); 2922 showCaret();
2808 int hScrollChange = oldHScrollOffset - horizontalScrollOffset; 2923 int hScrollChange = oldHScrollOffset - horizontalScrollOffset;
2809 columnX = oldColumnX + hScrollChange; 2924 columnX = oldColumnX + hScrollChange;
2810 } 2925 }
2811 /** 2926 /**
2812 * Updates the selection to extend to the current caret position. 2927 * Updates the selection to extend to the current caret position.
2813 */ 2928 */
2814 void doSelection(int direction) { 2929 void doSelection(int direction) {
2815 int redrawStart = -1; 2930 int redrawStart = -1;
2816 int redrawEnd = -1; 2931 int redrawEnd = -1;
2817 if (selectionAnchor is -1) { 2932 if (selectionAnchor is -1) {
2818 selectionAnchor = selection.x; 2933 selectionAnchor = selection.x;
2819 } 2934 }
2820 if (direction is ST.COLUMN_PREVIOUS) { 2935 if (direction is ST.COLUMN_PREVIOUS) {
2821 if (caretOffset < selection.x) { 2936 if (caretOffset < selection.x) {
2822 // grow selection 2937 // grow selection
2823 redrawEnd = selection.x; 2938 redrawEnd = selection.x;
2824 redrawStart = selection.x = caretOffset; 2939 redrawStart = selection.x = caretOffset;
2825 // check if selection has reversed direction 2940 // check if selection has reversed direction
2826 if (selection.y !is selectionAnchor) { 2941 if (selection.y !is selectionAnchor) {
2827 redrawEnd = selection.y; 2942 redrawEnd = selection.y;
2828 selection.y = selectionAnchor; 2943 selection.y = selectionAnchor;
2829 } 2944 }
2830 // test whether selection actually changed. Fixes 1G71EO1 2945 // test whether selection actually changed. Fixes 1G71EO1
2831 } else if (selectionAnchor is selection.x && caretOffset < selection.y) { 2946 } else if (selectionAnchor is selection.x && caretOffset < selection.y) {
2832 // caret moved towards selection anchor (left side of selection). 2947 // caret moved towards selection anchor (left side of selection).
2833 // shrink selection 2948 // shrink selection
2834 redrawEnd = selection.y; 2949 redrawEnd = selection.y;
2835 redrawStart = selection.y = caretOffset; 2950 redrawStart = selection.y = caretOffset;
2836 } 2951 }
2837 } else { 2952 } else {
2838 if (caretOffset > selection.y) { 2953 if (caretOffset > selection.y) {
2839 // grow selection 2954 // grow selection
2840 redrawStart = selection.y; 2955 redrawStart = selection.y;
2841 redrawEnd = selection.y = caretOffset; 2956 redrawEnd = selection.y = caretOffset;
2842 // check if selection has reversed direction 2957 // check if selection has reversed direction
2843 if (selection.x !is selectionAnchor) { 2958 if (selection.x !is selectionAnchor) {
2844 redrawStart = selection.x; 2959 redrawStart = selection.x;
2845 selection.x = selectionAnchor; 2960 selection.x = selectionAnchor;
2846 } 2961 }
2847 // test whether selection actually changed. Fixes 1G71EO1 2962 // test whether selection actually changed. Fixes 1G71EO1
2848 } else if (selectionAnchor is selection.y && caretOffset > selection.x) { 2963 } else if (selectionAnchor is selection.y && caretOffset > selection.x) {
2849 // caret moved towards selection anchor (right side of selection). 2964 // caret moved towards selection anchor (right side of selection).
2850 // shrink selection 2965 // shrink selection
2851 redrawStart = selection.x; 2966 redrawStart = selection.x;
2852 redrawEnd = selection.x = caretOffset; 2967 redrawEnd = selection.x = caretOffset;
2853 } 2968 }
2854 } 2969 }
2855 if (redrawStart !is -1 && redrawEnd !is -1) { 2970 if (redrawStart !is -1 && redrawEnd !is -1) {
2856 internalRedrawRange(redrawStart, redrawEnd - redrawStart); 2971 internalRedrawRange(redrawStart, redrawEnd - redrawStart);
2857 sendSelectionEvent(); 2972 sendSelectionEvent();
2858 } 2973 }
2859 } 2974 }
2860 /** 2975 /**
2861 * Moves the caret to the next character or to the beginning of the 2976 * Moves the caret to the next character or to the beginning of the
2862 * next line if the cursor is at the end of a line. 2977 * next line if the cursor is at the end of a line.
2863 */ 2978 */
2864 void doSelectionCursorNext() { 2979 void doSelectionCursorNext() {
2865 int caretLine = getCaretLine(); 2980 int caretLine = getCaretLine();
2866 int lineOffset = content.getOffsetAtLine(caretLine); 2981 int lineOffset = content.getOffsetAtLine(caretLine);
2867 int offsetInLine = caretOffset - lineOffset; 2982 int offsetInLine = caretOffset - lineOffset;
2868 if (offsetInLine < content.getLine(caretLine).length()) { 2983 if (offsetInLine < content.getLine(caretLine).length) {
2869 TextLayout layout = renderer.getTextLayout(caretLine); 2984 TextLayout layout = renderer.getTextLayout(caretLine);
2870 offsetInLine = layout.getNextOffset(offsetInLine, DWT.MOVEMENT_CLUSTER); 2985 offsetInLine = layout.getNextOffset(offsetInLine, DWT.MOVEMENT_CLUSTER);
2871 int lineStart = layout.getLineOffsets()[layout.getLineIndex(offsetInLine)]; 2986 int lineStart = layout.getLineOffsets()[layout.getLineIndex(offsetInLine)];
2872 renderer.disposeTextLayout(layout); 2987 renderer.disposeTextLayout(layout);
2873 caretOffset = offsetInLine + lineOffset; 2988 caretOffset = offsetInLine + lineOffset;
2874 caretAlignment = offsetInLine is lineStart ? OFFSET_LEADING : PREVIOUS_OFFSET_TRAILING; 2989 caretAlignment = offsetInLine is lineStart ? OFFSET_LEADING : PREVIOUS_OFFSET_TRAILING;
2875 showCaret(); 2990 showCaret();
2876 } else if (caretLine < content.getLineCount() - 1 && !isSingleLine()) { 2991 } else if (caretLine < content.getLineCount() - 1 && !isSingleLine()) {
2877 caretLine++; 2992 caretLine++;
2878 caretOffset = content.getOffsetAtLine(caretLine); 2993 caretOffset = content.getOffsetAtLine(caretLine);
2879 caretAlignment = PREVIOUS_OFFSET_TRAILING; 2994 caretAlignment = PREVIOUS_OFFSET_TRAILING;
2880 showCaret(); 2995 showCaret();
2881 } 2996 }
2882 } 2997 }
2883 /** 2998 /**
2884 * Moves the caret to the previous character or to the end of the previous 2999 * Moves the caret to the previous character or to the end of the previous
2885 * line if the cursor is at the beginning of a line. 3000 * line if the cursor is at the beginning of a line.
2886 */ 3001 */
2887 void doSelectionCursorPrevious() { 3002 void doSelectionCursorPrevious() {
2888 int caretLine = getCaretLine(); 3003 int caretLine = getCaretLine();
2889 int lineOffset = content.getOffsetAtLine(caretLine); 3004 int lineOffset = content.getOffsetAtLine(caretLine);
2890 int offsetInLine = caretOffset - lineOffset; 3005 int offsetInLine = caretOffset - lineOffset;
2891 caretAlignment = OFFSET_LEADING; 3006 caretAlignment = OFFSET_LEADING;
3007
2892 if (offsetInLine > 0) { 3008 if (offsetInLine > 0) {
2893 caretOffset = getClusterPrevious(caretOffset, caretLine); 3009 caretOffset = getClusterPrevious(caretOffset, caretLine);
2894 showCaret(); 3010 showCaret();
2895 } else if (caretLine > 0) { 3011 } else if (caretLine > 0) {
2896 caretLine--; 3012 caretLine--;
2897 lineOffset = content.getOffsetAtLine(caretLine); 3013 lineOffset = content.getOffsetAtLine(caretLine);
2898 caretOffset = lineOffset + content.getLine(caretLine).length(); 3014 caretOffset = lineOffset + content.getLine(caretLine).length;
2899 showCaret(); 3015 showCaret();
2900 } 3016 }
2901 } 3017 }
2902 /** 3018 /**
2903 * Moves the caret one line down and to the same character offset relative 3019 * Moves the caret one line down and to the same character offset relative
2904 * to the beginning of the line. Moves the caret to the end of the new line 3020 * to the beginning of the line. Moves the caret to the end of the new line
2905 * if the new line is shorter than the character offset. 3021 * if the new line is shorter than the character offset.
2906 * Moves the caret to the end of the text if the caret already is on the 3022 * Moves the caret to the end of the text if the caret already is on the
2907 * last line. 3023 * last line.
2908 * Adjusts the selection according to the caret change. This can either add 3024 * Adjusts the selection according to the caret change. This can either add
2909 * to or subtract from the old selection, depending on the previous selection 3025 * to or subtract from the old selection, depending on the previous selection
2910 * direction. 3026 * direction.
2911 */ 3027 */
2913 int oldColumnX = columnX = getPointAtOffset(caretOffset).x; 3029 int oldColumnX = columnX = getPointAtOffset(caretOffset).x;
2914 doLineDown(true); 3030 doLineDown(true);
2915 columnX = oldColumnX; 3031 columnX = oldColumnX;
2916 } 3032 }
2917 /** 3033 /**
2918 * Moves the caret one line up and to the same character offset relative 3034 * Moves the caret one line up and to the same character offset relative
2919 * to the beginning of the line. Moves the caret to the end of the new line 3035 * to the beginning of the line. Moves the caret to the end of the new line
2920 * if the new line is shorter than the character offset. 3036 * if the new line is shorter than the character offset.
2921 * Moves the caret to the beginning of the document if it is already on the 3037 * Moves the caret to the beginning of the document if it is already on the
2922 * first line. 3038 * first line.
2923 * Adjusts the selection according to the caret change. This can either add 3039 * Adjusts the selection according to the caret change. This can either add
2924 * to or subtract from the old selection, depending on the previous selection 3040 * to or subtract from the old selection, depending on the previous selection
2925 * direction. 3041 * direction.
2926 */ 3042 */
2927 void doSelectionLineUp() { 3043 void doSelectionLineUp() {
2928 int oldColumnX = columnX = getPointAtOffset(caretOffset).x; 3044 int oldColumnX = columnX = getPointAtOffset(caretOffset).x;
2929 doLineUp(true); 3045 doLineUp(true);
2930 columnX = oldColumnX; 3046 columnX = oldColumnX;
2931 } 3047 }
2932 /** 3048 /**
2933 * Scrolls one page down so that the last line (truncated or whole) 3049 * Scrolls one page down so that the last line (truncated or whole)
2934 * of the current page becomes the fully visible top line. 3050 * of the current page becomes the fully visible top line.
2935 * <p> 3051 * <p>
2936 * The caret is scrolled the same number of lines so that its location 3052 * The caret is scrolled the same number of lines so that its location
2937 * relative to the top line remains the same. The exception is the end 3053 * relative to the top line remains the same. The exception is the end
2938 * of the text where a full page scroll is not possible. In this case 3054 * of the text where a full page scroll is not possible. In this case
2939 * the caret is moved after the last character. 3055 * the caret is moved after the last character.
2940 * <p></p> 3056 * <p></p>
2941 * Adjusts the selection according to the caret change. This can either add 3057 * Adjusts the selection according to the caret change. This can either add
2942 * to or subtract from the old selection, depending on the previous selection 3058 * to or subtract from the old selection, depending on the previous selection
2943 * direction. 3059 * direction.
2950 } 3066 }
2951 /** 3067 /**
2952 * Scrolls one page up so that the first line (truncated or whole) 3068 * Scrolls one page up so that the first line (truncated or whole)
2953 * of the current page becomes the fully visible last line. 3069 * of the current page becomes the fully visible last line.
2954 * <p> 3070 * <p>
2955 * The caret is scrolled the same number of lines so that its location 3071 * The caret is scrolled the same number of lines so that its location
2956 * relative to the top line remains the same. The exception is the beginning 3072 * relative to the top line remains the same. The exception is the beginning
2957 * of the text where a full page scroll is not possible. In this case the 3073 * of the text where a full page scroll is not possible. In this case the
2958 * caret is moved in front of the first character. 3074 * caret is moved in front of the first character.
2959 * </p><p> 3075 * </p><p>
2960 * Adjusts the selection according to the caret change. This can either add 3076 * Adjusts the selection according to the caret change. This can either add
2961 * to or subtract from the old selection, depending on the previous selection 3077 * to or subtract from the old selection, depending on the previous selection
2972 */ 3088 */
2973 void doSelectionWordNext() { 3089 void doSelectionWordNext() {
2974 int newCaretOffset = getWordNext(caretOffset, DWT.MOVEMENT_WORD); 3090 int newCaretOffset = getWordNext(caretOffset, DWT.MOVEMENT_WORD);
2975 // Force symmetrical movement for word next and previous. Fixes 14536 3091 // Force symmetrical movement for word next and previous. Fixes 14536
2976 caretAlignment = OFFSET_LEADING; 3092 caretAlignment = OFFSET_LEADING;
2977 // don't change caret position if in single line mode and the cursor 3093 // don't change caret position if in single line mode and the cursor
2978 // would be on a different line. fixes 5673 3094 // would be on a different line. fixes 5673
2979 if (!isSingleLine() || 3095 if (!isSingleLine() ||
2980 content.getLineAtOffset(caretOffset) is content.getLineAtOffset(newCaretOffset)) { 3096 content.getLineAtOffset(caretOffset) is content.getLineAtOffset(newCaretOffset)) {
2981 caretOffset = newCaretOffset; 3097 caretOffset = newCaretOffset;
2982 showCaret(); 3098 showCaret();
2983 } 3099 }
2984 } 3100 }
2997 } 3113 }
2998 showCaret(); 3114 showCaret();
2999 } 3115 }
3000 /** 3116 /**
3001 * Moves the caret one character to the left. Do not go to the previous line. 3117 * Moves the caret one character to the left. Do not go to the previous line.
3002 * When in a bidi locale and at a R2L character the caret is moved to the 3118 * When in a bidi locale and at a R2L character the caret is moved to the
3003 * beginning of the R2L segment (visually right) and then one character to the 3119 * beginning of the R2L segment (visually right) and then one character to the
3004 * left (visually left because it's now in a L2R segment). 3120 * left (visually left because it's now in a L2R segment).
3005 */ 3121 */
3006 void doVisualPrevious() { 3122 void doVisualPrevious() {
3007 caretOffset = getClusterPrevious(caretOffset, getCaretLine()); 3123 caretOffset = getClusterPrevious(caretOffset, getCaretLine());
3008 showCaret(); 3124 showCaret();
3009 } 3125 }
3010 /** 3126 /**
3011 * Moves the caret one character to the right. Do not go to the next line. 3127 * Moves the caret one character to the right. Do not go to the next line.
3012 * When in a bidi locale and at a R2L character the caret is moved to the 3128 * When in a bidi locale and at a R2L character the caret is moved to the
3013 * end of the R2L segment (visually left) and then one character to the 3129 * end of the R2L segment (visually left) and then one character to the
3014 * right (visually right because it's now in a L2R segment). 3130 * right (visually right because it's now in a L2R segment).
3015 */ 3131 */
3016 void doVisualNext() { 3132 void doVisualNext() {
3017 caretOffset = getClusterNext(caretOffset, getCaretLine()); 3133 caretOffset = getClusterNext(caretOffset, getCaretLine());
3018 showCaret(); 3134 showCaret();
3041 showCaret(); 3157 showCaret();
3042 } else { 3158 } else {
3043 doSelectionWordPrevious(); 3159 doSelectionWordPrevious();
3044 } 3160 }
3045 } 3161 }
3046 /** 3162 /**
3047 * Ends the autoscroll process. 3163 * Ends the autoscroll process.
3048 */ 3164 */
3049 void endAutoScroll() { 3165 void endAutoScroll() {
3050 autoScrollDirection = DWT.NULL; 3166 autoScrollDirection = DWT.NULL;
3051 } 3167 }
3052 public Color getBackground() { 3168 public override Color getBackground() {
3053 checkWidget(); 3169 checkWidget();
3054 if (background is null) { 3170 if (background is null) {
3055 return getDisplay().getSystemColor(DWT.COLOR_LIST_BACKGROUND); 3171 return getDisplay().getSystemColor(DWT.COLOR_LIST_BACKGROUND);
3056 } 3172 }
3057 return background; 3173 return background;
3058 } 3174 }
3059 /** 3175 /**
3060 * Returns the baseline, in pixels. 3176 * Returns the baseline, in pixels.
3061 * 3177 *
3062 * Note: this API should not be used if a StyleRange attribute causes lines to 3178 * Note: this API should not be used if a StyleRange attribute causes lines to
3063 * have different heights (i.e. different fonts, rise, etc). 3179 * have different heights (i.e. different fonts, rise, etc).
3064 * 3180 *
3065 * @return baseline the baseline 3181 * @return baseline the baseline
3066 * @exception DWTException <ul> 3182 * @exception DWTException <ul>
3067 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3183 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3068 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 3184 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3069 * </ul> 3185 * </ul>
3070 * @since 3.0 3186 * @since 3.0
3071 * 3187 *
3072 * @see #getBaseline(int) 3188 * @see #getBaseline(int)
3073 */ 3189 */
3074 public int getBaseline() { 3190 public int getBaseline() {
3075 checkWidget(); 3191 checkWidget();
3076 return renderer.getBaseline(); 3192 return renderer.getBaseline();
3077 } 3193 }
3078 /** 3194 /**
3079 * Returns the baseline at the given offset, in pixels. 3195 * Returns the baseline at the given offset, in pixels.
3080 * 3196 *
3081 * @param offset the offset 3197 * @param offset the offset
3082 * 3198 *
3083 * @return baseline the baseline 3199 * @return baseline the baseline
3084 * 3200 *
3085 * @exception DWTException <ul> 3201 * @exception DWTException <ul>
3086 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3202 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3087 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 3203 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3088 * </ul> 3204 * </ul>
3089 * @exception IllegalArgumentException <ul> 3205 * @exception IllegalArgumentException <ul>
3090 * <li>ERROR_INVALID_RANGE when the offset is outside the valid range (< 0 or > getCharCount())</li> 3206 * <li>ERROR_INVALID_RANGE when the offset is outside the valid range (< 0 or > getCharCount())</li>
3091 * </ul> 3207 * </ul>
3092 * 3208 *
3093 * @since 3.2 3209 * @since 3.2
3094 */ 3210 */
3095 public int getBaseline(int offset) { 3211 public int getBaseline(int offset) {
3096 checkWidget(); 3212 checkWidget();
3097 if (!(0 <= offset && offset <= content.getCharCount())) { 3213 if (!(0 <= offset && offset <= content.getCharCount())) {
3101 return renderer.getBaseline(); 3217 return renderer.getBaseline();
3102 } 3218 }
3103 int lineIndex = content.getLineAtOffset(offset); 3219 int lineIndex = content.getLineAtOffset(offset);
3104 int lineOffset = content.getOffsetAtLine(lineIndex); 3220 int lineOffset = content.getOffsetAtLine(lineIndex);
3105 TextLayout layout = renderer.getTextLayout(lineIndex); 3221 TextLayout layout = renderer.getTextLayout(lineIndex);
3106 int lineInParagraph = layout.getLineIndex(Math.min(offset - lineOffset, layout.getText().length())); 3222 int lineInParagraph = layout.getLineIndex(Math.min(offset - lineOffset, layout.getText().length));
3107 FontMetrics metrics = layout.getLineMetrics(lineInParagraph); 3223 FontMetrics metrics = layout.getLineMetrics(lineInParagraph);
3108 renderer.disposeTextLayout(layout); 3224 renderer.disposeTextLayout(layout);
3109 return metrics.getAscent() + metrics.getLeading(); 3225 return metrics.getAscent() + metrics.getLeading();
3110 } 3226 }
3111 /** 3227 /**
3116 * @return the current coloring mode 3232 * @return the current coloring mode
3117 * @exception DWTException <ul> 3233 * @exception DWTException <ul>
3118 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3234 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3119 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 3235 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3120 * </ul> 3236 * </ul>
3121 * 3237 *
3122 * @deprecated use BidiSegmentListener instead. 3238 * @deprecated use BidiSegmentListener instead.
3123 */ 3239 */
3124 public bool getBidiColoring() { 3240 public bool getBidiColoring() {
3125 checkWidget(); 3241 checkWidget();
3126 return bidiColoring; 3242 return bidiColoring;
3127 } 3243 }
3128 /** 3244 /**
3129 * Returns the index of the last fully visible line. 3245 * Returns the index of the last fully visible line.
3130 * 3246 *
3131 * @return index of the last fully visible line. 3247 * @return index of the last fully visible line.
3132 */ 3248 */
3133 int getBottomIndex() { 3249 int getBottomIndex() {
3159 Rectangle getBoundsAtOffset(int offset) { 3275 Rectangle getBoundsAtOffset(int offset) {
3160 int lineIndex = content.getLineAtOffset(offset); 3276 int lineIndex = content.getLineAtOffset(offset);
3161 int lineOffset = content.getOffsetAtLine(lineIndex); 3277 int lineOffset = content.getOffsetAtLine(lineIndex);
3162 String line = content.getLine(lineIndex); 3278 String line = content.getLine(lineIndex);
3163 Rectangle bounds; 3279 Rectangle bounds;
3164 if (line.length() !is 0) { 3280 if (line.length !is 0) {
3165 int offsetInLine = offset - lineOffset; 3281 int offsetInLine = offset - lineOffset;
3166 TextLayout layout = renderer.getTextLayout(lineIndex); 3282 TextLayout layout = renderer.getTextLayout(lineIndex);
3167 bounds = layout.getBounds(offsetInLine, offsetInLine); 3283 bounds = layout.getBounds(offsetInLine, offsetInLine);
3168 renderer.disposeTextLayout(layout); 3284 renderer.disposeTextLayout(layout);
3169 } else { 3285 } else {
3170 bounds = new Rectangle (0, 0, 0, renderer.getLineHeight()); 3286 bounds = new Rectangle (0, 0, 0, renderer.getLineHeight());
3171 } 3287 }
3172 if (offset is caretOffset) { 3288 if (offset is caretOffset) {
3173 int lineEnd = lineOffset + line.length(); 3289 int lineEnd = lineOffset + line.length;
3174 if (offset is lineEnd && caretAlignment is PREVIOUS_OFFSET_TRAILING) { 3290 if (offset is lineEnd && caretAlignment is PREVIOUS_OFFSET_TRAILING) {
3175 bounds.width += getCaretWidth(); 3291 bounds.width += getCaretWidth();
3176 } 3292 }
3177 } 3293 }
3178 bounds.x += leftMargin - horizontalScrollOffset; 3294 bounds.x += leftMargin - horizontalScrollOffset;
3205 Object getClipboardContent(int clipboardType) { 3321 Object getClipboardContent(int clipboardType) {
3206 TextTransfer plainTextTransfer = TextTransfer.getInstance(); 3322 TextTransfer plainTextTransfer = TextTransfer.getInstance();
3207 return clipboard.getContents(plainTextTransfer, clipboardType); 3323 return clipboard.getContents(plainTextTransfer, clipboardType);
3208 } 3324 }
3209 int getClusterNext(int offset, int lineIndex) { 3325 int getClusterNext(int offset, int lineIndex) {
3210 int lineOffset = content.getOffsetAtLine(lineIndex); 3326 int lineOffset = content.getOffsetAtLine(lineIndex);
3211 TextLayout layout = renderer.getTextLayout(lineIndex); 3327 TextLayout layout = renderer.getTextLayout(lineIndex);
3212 offset -= lineOffset; 3328 offset -= lineOffset;
3213 offset = layout.getNextOffset(offset, DWT.MOVEMENT_CLUSTER); 3329 offset = layout.getNextOffset(offset, DWT.MOVEMENT_CLUSTER);
3214 offset += lineOffset; 3330 offset += lineOffset;
3215 renderer.disposeTextLayout(layout); 3331 renderer.disposeTextLayout(layout);
3216 return offset; 3332 return offset;
3217 } 3333 }
3218 int getClusterPrevious(int offset, int lineIndex) { 3334 int getClusterPrevious(int offset, int lineIndex) {
3219 int lineOffset = content.getOffsetAtLine(lineIndex); 3335 int lineOffset = content.getOffsetAtLine(lineIndex);
3220 TextLayout layout = renderer.getTextLayout(lineIndex); 3336 TextLayout layout = renderer.getTextLayout(lineIndex);
3221 offset -= lineOffset; 3337 offset -= lineOffset;
3222 offset = layout.getPreviousOffset(offset, DWT.MOVEMENT_CLUSTER); 3338 offset = layout.getPreviousOffset(offset, DWT.MOVEMENT_CLUSTER);
3223 offset += lineOffset; 3339 offset += lineOffset;
3224 renderer.disposeTextLayout(layout); 3340 renderer.disposeTextLayout(layout);
3225 return offset; 3341 return offset;
3226 } 3342 }
3227 /** 3343 /**
3228 * Returns the content implementation that is used for text storage. 3344 * Returns the content implementation that is used for text storage.
3229 * 3345 *
3230 * @return content the user defined content implementation that is used for 3346 * @return content the user defined content implementation that is used for
3231 * text storage or the default content implementation if no user defined 3347 * text storage or the default content implementation if no user defined
3232 * content implementation has been set. 3348 * content implementation has been set.
3233 * @exception DWTException <ul> 3349 * @exception DWTException <ul>
3234 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3350 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3235 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 3351 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3236 * </ul> 3352 * </ul>
3237 */ 3353 */
3238 public StyledTextContent getContent() { 3354 public StyledTextContent getContent() {
3239 checkWidget(); 3355 checkWidget();
3240 return content; 3356 return content;
3241 } 3357 }
3242 public bool getDragDetect () { 3358 public override bool getDragDetect () {
3243 checkWidget (); 3359 checkWidget ();
3244 return dragDetect; 3360 return dragDetect_;
3245 } 3361 }
3246 /** 3362 /**
3247 * Returns whether the widget : double click mouse behavior. 3363 * Returns whether the widget implements double click mouse behavior.
3248 * 3364 *
3249 * @return true if double clicking a word selects the word, false if double clicks 3365 * @return true if double clicking a word selects the word, false if double clicks
3250 * have the same effect as regular mouse clicks 3366 * have the same effect as regular mouse clicks
3251 * @exception DWTException <ul> 3367 * @exception DWTException <ul>
3252 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3368 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3268 */ 3384 */
3269 public bool getEditable() { 3385 public bool getEditable() {
3270 checkWidget(); 3386 checkWidget();
3271 return editable; 3387 return editable;
3272 } 3388 }
3273 public Color getForeground() { 3389 public override Color getForeground() {
3274 checkWidget(); 3390 checkWidget();
3275 if (foreground is null) { 3391 if (foreground is null) {
3276 return getDisplay().getSystemColor(DWT.COLOR_LIST_FOREGROUND); 3392 return getDisplay().getSystemColor(DWT.COLOR_LIST_FOREGROUND);
3277 } 3393 }
3278 return foreground; 3394 return foreground;
3279 } 3395 }
3280 /** 3396 /**
3281 * Returns the horizontal scroll increment. 3397 * Returns the horizontal scroll increment.
3282 * 3398 *
3283 * @return horizontal scroll increment. 3399 * @return horizontal scroll increment.
3284 */ 3400 */
3285 int getHorizontalIncrement() { 3401 int getHorizontalIncrement() {
3286 return renderer.averageCharWidth; 3402 return renderer.averageCharWidth;
3287 } 3403 }
3288 /** 3404 /**
3289 * Returns the horizontal scroll offset relative to the start of the line. 3405 * Returns the horizontal scroll offset relative to the start of the line.
3290 * 3406 *
3291 * @return horizontal scroll offset relative to the start of the line, 3407 * @return horizontal scroll offset relative to the start of the line,
3292 * measured in character increments starting at 0, if > 0 the content is scrolled 3408 * measured in character increments starting at 0, if > 0 the content is scrolled
3293 * @exception DWTException <ul> 3409 * @exception DWTException <ul>
3297 */ 3413 */
3298 public int getHorizontalIndex() { 3414 public int getHorizontalIndex() {
3299 checkWidget(); 3415 checkWidget();
3300 return horizontalScrollOffset / getHorizontalIncrement(); 3416 return horizontalScrollOffset / getHorizontalIncrement();
3301 } 3417 }
3302 /** 3418 /**
3303 * Returns the horizontal scroll offset relative to the start of the line. 3419 * Returns the horizontal scroll offset relative to the start of the line.
3304 * 3420 *
3305 * @return the horizontal scroll offset relative to the start of the line, 3421 * @return the horizontal scroll offset relative to the start of the line,
3306 * measured in pixel starting at 0, if > 0 the content is scrolled. 3422 * measured in pixel starting at 0, if > 0 the content is scrolled.
3307 * @exception DWTException <ul> 3423 * @exception DWTException <ul>
3313 checkWidget(); 3429 checkWidget();
3314 return horizontalScrollOffset; 3430 return horizontalScrollOffset;
3315 } 3431 }
3316 /** 3432 /**
3317 * Returns the line indentation of the widget. 3433 * Returns the line indentation of the widget.
3318 * 3434 *
3319 * @return the line indentation 3435 * @return the line indentation
3320 * 3436 *
3321 * @exception DWTException <ul> 3437 * @exception DWTException <ul>
3322 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3438 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3323 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 3439 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3324 * </ul> 3440 * </ul>
3325 * 3441 *
3326 * @see #getLineIndent(int) 3442 * @see #getLineIndent(int)
3327 * 3443 *
3328 * @since 3.2 3444 * @since 3.2
3329 */ 3445 */
3330 public int getIndent() { 3446 public int getIndent() {
3331 checkWidget(); 3447 checkWidget();
3332 return indent; 3448 return indent;
3333 } 3449 }
3334 /** 3450 /**
3335 * Returns whether the widget justifies lines. 3451 * Returns whether the widget justifies lines.
3336 * 3452 *
3337 * @return whether lines are justified 3453 * @return whether lines are justified
3338 * 3454 *
3339 * @exception DWTException <ul> 3455 * @exception DWTException <ul>
3340 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3456 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3341 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 3457 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3342 * </ul> 3458 * </ul>
3343 * 3459 *
3344 * @see #getLineJustify(int) 3460 * @see #getLineJustify(int)
3345 * 3461 *
3346 * @since 3.2 3462 * @since 3.2
3347 */ 3463 */
3348 public bool getJustify() { 3464 public bool getJustify() {
3349 checkWidget(); 3465 checkWidget();
3350 return justify; 3466 return justify;
3351 } 3467 }
3352 /** 3468 /**
3353 * Returns the action assigned to the key. 3469 * Returns the action assigned to the key.
3354 * Returns DWT.NULL if there is no action associated with the key. 3470 * Returns DWT.NULL if there is no action associated with the key.
3355 * 3471 *
3356 * @param key a key code defined in DWT.java or a character. 3472 * @param key a key code defined in DWT.java or a character.
3357 * Optionally ORd with a state mask. Preferred state masks are one or more of 3473 * Optionally ORd with a state mask. Preferred state masks are one or more of
3358 * DWT.MOD1, DWT.MOD2, DWT.MOD3, since these masks account for modifier platform 3474 * DWT.MOD1, DWT.MOD2, DWT.MOD3, since these masks account for modifier platform
3359 * differences. However, there may be cases where using the specific state masks 3475 * differences. However, there may be cases where using the specific state masks
3360 * (i.e., DWT.CTRL, DWT.SHIFT, DWT.ALT, DWT.COMMAND) makes sense. 3476 * (i.e., DWT.CTRL, DWT.SHIFT, DWT.ALT, DWT.COMMAND) makes sense.
3361 * @return one of the predefined actions defined in ST.java or DWT.NULL 3477 * @return one of the predefined actions defined in ST.java or DWT.NULL
3362 * if there is no action associated with the key. 3478 * if there is no action associated with the key.
3363 * @exception DWTException <ul> 3479 * @exception DWTException <ul>
3364 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3480 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3365 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 3481 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3366 * </ul> 3482 * </ul>
3367 */ 3483 */
3368 public int getKeyBinding(int key) { 3484 public int getKeyBinding(int key) {
3369 checkWidget(); 3485 checkWidget();
3370 Integer action = cast(Integer) keyActionMap.get(new Integer(key)); 3486 if( auto p = key in keyActionMap ){
3371 return action is null ? DWT.NULL : action.intValue(); 3487 return *p;
3488 }
3489 return DWT.NULL;
3372 } 3490 }
3373 /** 3491 /**
3374 * Gets the number of characters. 3492 * Gets the number of characters.
3375 * 3493 *
3376 * @return number of characters in the widget 3494 * @return number of characters in the widget
3384 return content.getCharCount(); 3502 return content.getCharCount();
3385 } 3503 }
3386 /** 3504 /**
3387 * Returns the line at the given line index without delimiters. 3505 * Returns the line at the given line index without delimiters.
3388 * Index 0 is the first line of the content. When there are not 3506 * Index 0 is the first line of the content. When there are not
3389 * any lines, getLine(0) is a valid call that answers an empty String. 3507 * any lines, getLine(0) is a valid call that answers an empty string.
3390 * <p> 3508 * <p>
3391 * 3509 *
3392 * @param lineIndex index of the line to return. 3510 * @param lineIndex index of the line to return.
3393 * @return the line text without delimiters 3511 * @return the line text without delimiters
3394 * 3512 *
3395 * @exception DWTException <ul> 3513 * @exception DWTException <ul>
3396 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3514 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3397 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 3515 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3398 * </ul> 3516 * </ul>
3399 * @exception IllegalArgumentException <ul> 3517 * @exception IllegalArgumentException <ul>
3400 * <li>ERROR_INVALID_RANGE when the line index is outside the valid range (< 0 or >= getLineCount())</li> 3518 * <li>ERROR_INVALID_RANGE when the line index is outside the valid range (< 0 or >= getLineCount())</li>
3401 * </ul> 3519 * </ul>
3402 * @since 3.4 3520 * @since 3.4
3403 */ 3521 */
3404 public String getLine(int lineIndex) { 3522 public String getLine(int lineIndex) {
3405 checkWidget(); 3523 checkWidget();
3406 if (lineIndex < 0 || 3524 if (lineIndex < 0 ||
3407 (lineIndex > 0 && lineIndex >= content.getLineCount())) { 3525 (lineIndex > 0 && lineIndex >= content.getLineCount())) {
3408 DWT.error(DWT.ERROR_INVALID_RANGE); 3526 DWT.error(DWT.ERROR_INVALID_RANGE);
3409 } 3527 }
3410 return content.getLine(lineIndex); 3528 return content.getLine(lineIndex);
3411 } 3529 }
3412 /** 3530 /**
3413 * Returns the alignment of the line at the given index. 3531 * Returns the alignment of the line at the given index.
3414 * 3532 *
3415 * @param index the index of the line 3533 * @param index the index of the line
3416 * 3534 *
3417 * @return the line alignment 3535 * @return the line alignment
3418 * 3536 *
3419 * @exception DWTException <ul> 3537 * @exception DWTException <ul>
3420 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3538 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3421 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 3539 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3422 * </ul> 3540 * </ul>
3423 * @exception IllegalArgumentException <ul> 3541 * @exception IllegalArgumentException <ul>
3424 * <li>ERROR_INVALID_ARGUMENT when the index is invalid</li> 3542 * <li>ERROR_INVALID_ARGUMENT when the index is invalid</li>
3425 * </ul> 3543 * </ul>
3426 * 3544 *
3427 * @see #getAlignment() 3545 * @see #getAlignment()
3428 * 3546 *
3429 * @since 3.2 3547 * @since 3.2
3430 */ 3548 */
3431 public int getLineAlignment(int index) { 3549 public int getLineAlignment(int index) {
3432 checkWidget(); 3550 checkWidget();
3433 if (index < 0 || index > content.getLineCount()) { 3551 if (index < 0 || index > content.getLineCount()) {
3438 /** 3556 /**
3439 * Returns the line at the specified offset in the text 3557 * Returns the line at the specified offset in the text
3440 * where 0 &lt; offset &lt; getCharCount() so that getLineAtOffset(getCharCount()) 3558 * where 0 &lt; offset &lt; getCharCount() so that getLineAtOffset(getCharCount())
3441 * returns the line of the insert location. 3559 * returns the line of the insert location.
3442 * 3560 *
3443 * @param offset offset relative to the start of the content. 3561 * @param offset offset relative to the start of the content.
3444 * 0 <= offset <= getCharCount() 3562 * 0 <= offset <= getCharCount()
3445 * @return line at the specified offset in the text 3563 * @return line at the specified offset in the text
3446 * @exception DWTException <ul> 3564 * @exception DWTException <ul>
3447 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3565 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3448 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 3566 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3449 * </ul> 3567 * </ul>
3450 * @exception IllegalArgumentException <ul> 3568 * @exception IllegalArgumentException <ul>
3451 * <li>ERROR_INVALID_RANGE when the offset is outside the valid range (< 0 or > getCharCount())</li> 3569 * <li>ERROR_INVALID_RANGE when the offset is outside the valid range (< 0 or > getCharCount())</li>
3452 * </ul> 3570 * </ul>
3453 */ 3571 */
3454 public int getLineAtOffset(int offset) { 3572 public int getLineAtOffset(int offset) {
3455 checkWidget(); 3573 checkWidget();
3456 if (offset < 0 || offset > getCharCount()) { 3574 if (offset < 0 || offset > getCharCount()) {
3457 DWT.error(DWT.ERROR_INVALID_RANGE); 3575 DWT.error(DWT.ERROR_INVALID_RANGE);
3458 } 3576 }
3459 return content.getLineAtOffset(offset); 3577 return content.getLineAtOffset(offset);
3460 } 3578 }
3461 /** 3579 /**
3462 * Returns the background color of the line at the given index. 3580 * Returns the background color of the line at the given index.
3463 * Returns null if a LineBackgroundListener has been set or if no background 3581 * Returns null if a LineBackgroundListener has been set or if no background
3464 * color has been specified for the line. Should not be called if a 3582 * color has been specified for the line. Should not be called if a
3465 * LineBackgroundListener has been set since the listener maintains the 3583 * LineBackgroundListener has been set since the listener maintains the
3466 * line background colors. 3584 * line background colors.
3467 * 3585 *
3468 * @param index the index of the line 3586 * @param index the index of the line
3469 * @return the background color of the line at the given index. 3587 * @return the background color of the line at the given index.
3470 * 3588 *
3471 * @exception DWTException <ul> 3589 * @exception DWTException <ul>
3472 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3590 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3473 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 3591 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3474 * </ul> 3592 * </ul>
3475 * @exception IllegalArgumentException <ul> 3593 * @exception IllegalArgumentException <ul>
3483 } 3601 }
3484 return isListening(LineGetBackground) ? null : renderer.getLineBackground(index, null); 3602 return isListening(LineGetBackground) ? null : renderer.getLineBackground(index, null);
3485 } 3603 }
3486 /** 3604 /**
3487 * Returns the bullet of the line at the given index. 3605 * Returns the bullet of the line at the given index.
3488 * 3606 *
3489 * @param index the index of the line 3607 * @param index the index of the line
3490 * 3608 *
3491 * @return the line bullet 3609 * @return the line bullet
3492 * 3610 *
3493 * @exception DWTException <ul> 3611 * @exception DWTException <ul>
3494 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3612 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3495 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 3613 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3496 * </ul> 3614 * </ul>
3497 * @exception IllegalArgumentException <ul> 3615 * @exception IllegalArgumentException <ul>
3498 * <li>ERROR_INVALID_ARGUMENT when the index is invalid</li> 3616 * <li>ERROR_INVALID_ARGUMENT when the index is invalid</li>
3499 * </ul> 3617 * </ul>
3500 * 3618 *
3501 * @since 3.2 3619 * @since 3.2
3502 */ 3620 */
3503 public Bullet getLineBullet(int index) { 3621 public Bullet getLineBullet(int index) {
3504 checkWidget(); 3622 checkWidget();
3505 if (index < 0 || index > content.getLineCount()) { 3623 if (index < 0 || index > content.getLineCount()) {
3506 DWT.error(DWT.ERROR_INVALID_ARGUMENT); 3624 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
3507 } 3625 }
3508 return isListening(LineGetStyle) ? null : renderer.getLineBullet(index, null); 3626 return isListening(LineGetStyle) ? null : renderer.getLineBullet(index, null);
3509 } 3627 }
3510 /** 3628 /**
3511 * Returns the line background data for the given line or null if 3629 * Returns the line background data for the given line or null if
3512 * there is none. 3630 * there is none.
3513 * 3631 *
3514 * @param lineOffset offset of the line start relative to the start 3632 * @param lineOffset offset of the line start relative to the start
3515 * of the content. 3633 * of the content.
3516 * @param line line to get line background data for 3634 * @param line line to get line background data for
3517 * @return line background data for the given line. 3635 * @return line background data for the given line.
3518 */ 3636 */
3519 StyledTextEvent getLineBackgroundData(int lineOffset, String line) { 3637 StyledTextEvent getLineBackgroundData(int lineOffset, String line) {
3520 return sendLineEvent(LineGetBackground, lineOffset, line); 3638 return sendLineEvent(LineGetBackground, lineOffset, line);
3521 } 3639 }
3522 /** 3640 /**
3523 * Gets the number of text lines. 3641 * Gets the number of text lines.
3524 * 3642 *
3525 * @return the number of lines in the widget 3643 * @return the number of lines in the widget
3526 * @exception DWTException <ul> 3644 * @exception DWTException <ul>
3527 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3645 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3531 public int getLineCount() { 3649 public int getLineCount() {
3532 checkWidget(); 3650 checkWidget();
3533 return content.getLineCount(); 3651 return content.getLineCount();
3534 } 3652 }
3535 /** 3653 /**
3536 * Returns the number of lines that can be completely displayed in the 3654 * Returns the number of lines that can be completely displayed in the
3537 * widget client area. 3655 * widget client area.
3538 * 3656 *
3539 * @return number of lines that can be completely displayed in the widget 3657 * @return number of lines that can be completely displayed in the widget
3540 * client area. 3658 * client area.
3541 */ 3659 */
3542 int getLineCountWhole() { 3660 int getLineCountWhole() {
3543 if (isFixedLineHeight()) { 3661 if (isFixedLineHeight()) {
3544 int lineHeight = renderer.getLineHeight(); 3662 int lineHeight = renderer.getLineHeight();
3562 return content.getLineDelimiter(); 3680 return content.getLineDelimiter();
3563 } 3681 }
3564 /** 3682 /**
3565 * Returns the line height. 3683 * Returns the line height.
3566 * <p> 3684 * <p>
3567 * Note: this API should not be used if a StyleRange attribute causes lines to 3685 * Note: this API should not be used if a StyleRange attribute causes lines to
3568 * have different heights (i.e. different fonts, rise, etc). 3686 * have different heights (i.e. different fonts, rise, etc).
3569 * </p> 3687 * </p>
3570 * 3688 *
3571 * @return line height in pixel. 3689 * @return line height in pixel.
3572 * @exception DWTException <ul> 3690 * @exception DWTException <ul>
3581 } 3699 }
3582 /** 3700 /**
3583 * Returns the line height at the given offset. 3701 * Returns the line height at the given offset.
3584 * 3702 *
3585 * @param offset the offset 3703 * @param offset the offset
3586 * 3704 *
3587 * @return line height in pixels 3705 * @return line height in pixels
3588 * 3706 *
3589 * @exception DWTException <ul> 3707 * @exception DWTException <ul>
3590 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3708 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3591 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 3709 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3592 * </ul> 3710 * </ul>
3593 * @exception IllegalArgumentException <ul> 3711 * @exception IllegalArgumentException <ul>
3594 * <li>ERROR_INVALID_RANGE when the offset is outside the valid range (< 0 or > getCharCount())</li> 3712 * <li>ERROR_INVALID_RANGE when the offset is outside the valid range (< 0 or > getCharCount())</li>
3595 * </ul> 3713 * </ul>
3596 * 3714 *
3597 * @since 3.2 3715 * @since 3.2
3598 */ 3716 */
3599 public int getLineHeight(int offset) { 3717 public int getLineHeight(int offset) {
3600 checkWidget(); 3718 checkWidget();
3601 if (!(0 <= offset && offset <= content.getCharCount())) { 3719 if (!(0 <= offset && offset <= content.getCharCount())) {
3605 return renderer.getLineHeight(); 3723 return renderer.getLineHeight();
3606 } 3724 }
3607 int lineIndex = content.getLineAtOffset(offset); 3725 int lineIndex = content.getLineAtOffset(offset);
3608 int lineOffset = content.getOffsetAtLine(lineIndex); 3726 int lineOffset = content.getOffsetAtLine(lineIndex);
3609 TextLayout layout = renderer.getTextLayout(lineIndex); 3727 TextLayout layout = renderer.getTextLayout(lineIndex);
3610 int lineInParagraph = layout.getLineIndex(Math.min(offset - lineOffset, layout.getText().length())); 3728 int lineInParagraph = layout.getLineIndex(Math.min(offset - lineOffset, layout.getText().length));
3611 int height = layout.getLineBounds(lineInParagraph).height; 3729 int height = layout.getLineBounds(lineInParagraph).height;
3612 renderer.disposeTextLayout(layout); 3730 renderer.disposeTextLayout(layout);
3613 return height; 3731 return height;
3614 } 3732 }
3615 /** 3733 /**
3616 * Returns the indentation of the line at the given index. 3734 * Returns the indentation of the line at the given index.
3617 * 3735 *
3618 * @param index the index of the line 3736 * @param index the index of the line
3619 * 3737 *
3620 * @return the line indentation 3738 * @return the line indentation
3621 * 3739 *
3622 * @exception DWTException <ul> 3740 * @exception DWTException <ul>
3623 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3741 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3624 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 3742 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3625 * </ul> 3743 * </ul>
3626 * @exception IllegalArgumentException <ul> 3744 * @exception IllegalArgumentException <ul>
3627 * <li>ERROR_INVALID_ARGUMENT when the index is invalid</li> 3745 * <li>ERROR_INVALID_ARGUMENT when the index is invalid</li>
3628 * </ul> 3746 * </ul>
3629 * 3747 *
3630 * @see #getIndent() 3748 * @see #getIndent()
3631 * 3749 *
3632 * @since 3.2 3750 * @since 3.2
3633 */ 3751 */
3634 public int getLineIndent(int index) { 3752 public int getLineIndent(int index) {
3635 checkWidget(); 3753 checkWidget();
3636 if (index < 0 || index > content.getLineCount()) { 3754 if (index < 0 || index > content.getLineCount()) {
3638 } 3756 }
3639 return isListening(LineGetStyle) ? 0 : renderer.getLineIndent(index, indent); 3757 return isListening(LineGetStyle) ? 0 : renderer.getLineIndent(index, indent);
3640 } 3758 }
3641 /** 3759 /**
3642 * Returns whether the line at the given index is justified. 3760 * Returns whether the line at the given index is justified.
3643 * 3761 *
3644 * @param index the index of the line 3762 * @param index the index of the line
3645 * 3763 *
3646 * @return whether the line is justified 3764 * @return whether the line is justified
3647 * 3765 *
3648 * @exception DWTException <ul> 3766 * @exception DWTException <ul>
3649 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3767 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3650 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 3768 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3651 * </ul> 3769 * </ul>
3652 * @exception IllegalArgumentException <ul> 3770 * @exception IllegalArgumentException <ul>
3653 * <li>ERROR_INVALID_ARGUMENT when the index is invalid</li> 3771 * <li>ERROR_INVALID_ARGUMENT when the index is invalid</li>
3654 * </ul> 3772 * </ul>
3655 * 3773 *
3656 * @see #getJustify() 3774 * @see #getJustify()
3657 * 3775 *
3658 * @since 3.2 3776 * @since 3.2
3659 */ 3777 */
3660 public bool getLineJustify(int index) { 3778 public bool getLineJustify(int index) {
3661 checkWidget(); 3779 checkWidget();
3662 if (index < 0 || index > content.getLineCount()) { 3780 if (index < 0 || index > content.getLineCount()) {
3663 DWT.error(DWT.ERROR_INVALID_ARGUMENT); 3781 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
3664 } 3782 }
3665 return isListening(LineGetStyle) ? false : renderer.getLineJustify(index, justify); 3783 return isListening(LineGetStyle) ? false : renderer.getLineJustify(index, justify);
3666 } 3784 }
3667 /** 3785 /**
3668 * Returns the line spacing of the widget. 3786 * Returns the line spacing of the widget.
3669 * 3787 *
3670 * @return the line spacing 3788 * @return the line spacing
3671 * 3789 *
3672 * @exception DWTException <ul> 3790 * @exception DWTException <ul>
3673 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3791 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3674 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 3792 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3675 * </ul> 3793 * </ul>
3676 * 3794 *
3677 * @since 3.2 3795 * @since 3.2
3678 */ 3796 */
3679 public int getLineSpacing() { 3797 public int getLineSpacing() {
3680 checkWidget(); 3798 checkWidget();
3681 return lineSpacing; 3799 return lineSpacing;
3682 } 3800 }
3683 /** 3801 /**
3684 * Returns the line style data for the given line or null if there is 3802 * Returns the line style data for the given line or null if there is
3685 * none. 3803 * none.
3686 * <p> 3804 * <p>
3687 * If there is a LineStyleListener but it does not set any styles, 3805 * If there is a LineStyleListener but it does not set any styles,
3688 * the StyledTextEvent.styles field will be initialized to an empty 3806 * the StyledTextEvent.styles field will be initialized to an empty
3689 * array. 3807 * array.
3690 * </p> 3808 * </p>
3691 * 3809 *
3692 * @param lineOffset offset of the line start relative to the start of 3810 * @param lineOffset offset of the line start relative to the start of
3693 * the content. 3811 * the content.
3694 * @param line line to get line styles for 3812 * @param line line to get line styles for
3695 * @return line style data for the given line. Styles may start before 3813 * @return line style data for the given line. Styles may start before
3696 * line start and end after line end 3814 * line start and end after line end
3697 */ 3815 */
3698 StyledTextEvent getLineStyleData(int lineOffset, String line) { 3816 StyledTextEvent getLineStyleData(int lineOffset, String line) {
3699 return sendLineEvent(LineGetStyle, lineOffset, line); 3817 return sendLineEvent(LineGetStyle, lineOffset, line);
3700 } 3818 }
3701 /** 3819 /**
3702 * Returns the top pixel, relative to the client area, of a given line. 3820 * Returns the top pixel, relative to the client area, of a given line.
3703 * Clamps out of ranges index. 3821 * Clamps out of ranges index.
3704 * 3822 *
3705 * @param lineIndex the line index, the max value is lineCount. If 3823 * @param lineIndex the line index, the max value is lineCount. If
3706 * lineIndex is lineCount it returns the bottom pixel of the last line. 3824 * lineIndex is lineCount it returns the bottom pixel of the last line.
3707 * It means this function can be used to retrieve the bottom pixel of any line. 3825 * It means this function can be used to retrieve the bottom pixel of any line.
3708 * 3826 *
3827 * @return the top pixel of a given line index
3828 *
3709 * @since 3.2 3829 * @since 3.2
3710 */ 3830 */
3711 public int getLinePixel(int lineIndex) { 3831 public int getLinePixel(int lineIndex) {
3712 checkWidget(); 3832 checkWidget();
3713 int lineCount = content.getLineCount(); 3833 int lineCount = content.getLineCount();
3730 return height + topMargin; 3850 return height + topMargin;
3731 } 3851 }
3732 /** 3852 /**
3733 * Returns the line index for a y, relative to the client area. 3853 * Returns the line index for a y, relative to the client area.
3734 * The line index returned is always in the range 0..lineCount - 1. 3854 * The line index returned is always in the range 0..lineCount - 1.
3855 *
3856 * @param y the y-coordinate pixel
3857 *
3858 * @return the line index for a given y-coordinate pixel
3735 * 3859 *
3736 * @since 3.2 3860 * @since 3.2
3737 */ 3861 */
3738 public int getLineIndex(int y) { 3862 public int getLineIndex(int y) {
3739 checkWidget(); 3863 checkWidget();
3760 } 3884 }
3761 } 3885 }
3762 return line; 3886 return line;
3763 } 3887 }
3764 /** 3888 /**
3765 * Returns the x, y location of the upper left corner of the character 3889 * Returns the x, y location of the upper left corner of the character
3766 * bounding box at the specified offset in the text. The point is 3890 * bounding box at the specified offset in the text. The point is
3767 * relative to the upper left corner of the widget client area. 3891 * relative to the upper left corner of the widget client area.
3768 * 3892 *
3769 * @param offset offset relative to the start of the content. 3893 * @param offset offset relative to the start of the content.
3770 * 0 <= offset <= getCharCount() 3894 * 0 <= offset <= getCharCount()
3771 * @return x, y location of the upper left corner of the character 3895 * @return x, y location of the upper left corner of the character
3772 * bounding box at the specified offset in the text. 3896 * bounding box at the specified offset in the text.
3773 * @exception DWTException <ul> 3897 * @exception DWTException <ul>
3774 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3898 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3775 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 3899 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3776 * </ul> 3900 * </ul>
3777 * @exception IllegalArgumentException <ul> 3901 * @exception IllegalArgumentException <ul>
3778 * <li>ERROR_INVALID_RANGE when the offset is outside the valid range (< 0 or > getCharCount())</li> 3902 * <li>ERROR_INVALID_RANGE when the offset is outside the valid range (< 0 or > getCharCount())</li>
3779 * </ul> 3903 * </ul>
3780 */ 3904 */
3781 public Point getLocationAtOffset(int offset) { 3905 public Point getLocationAtOffset(int offset) {
3782 checkWidget(); 3906 checkWidget();
3783 if (offset < 0 || offset > getCharCount()) { 3907 if (offset < 0 || offset > getCharCount()) {
3784 DWT.error(DWT.ERROR_INVALID_RANGE); 3908 DWT.error(DWT.ERROR_INVALID_RANGE);
3785 } 3909 }
3786 return getPointAtOffset(offset); 3910 return getPointAtOffset(offset);
3787 } 3911 }
3788 /** 3912 /**
3789 * Returns the character offset of the first character of the given line. 3913 * Returns the character offset of the first character of the given line.
3790 * 3914 *
3791 * @param lineIndex index of the line, 0 based relative to the first 3915 * @param lineIndex index of the line, 0 based relative to the first
3792 * line in the content. 0 <= lineIndex < getLineCount(), except 3916 * line in the content. 0 <= lineIndex < getLineCount(), except
3793 * lineIndex may always be 0 3917 * lineIndex may always be 0
3794 * @return offset offset of the first character of the line, relative to 3918 * @return offset offset of the first character of the line, relative to
3795 * the beginning of the document. The first character of the document is 3919 * the beginning of the document. The first character of the document is
3796 * at offset 0. 3920 * at offset 0.
3797 * When there are not any lines, getOffsetAtLine(0) is a valid call that 3921 * When there are not any lines, getOffsetAtLine(0) is a valid call that
3798 * answers 0. 3922 * answers 0.
3799 * @exception DWTException <ul> 3923 * @exception DWTException <ul>
3800 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3924 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3801 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 3925 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3802 * </ul> 3926 * </ul>
3803 * @exception IllegalArgumentException <ul> 3927 * @exception IllegalArgumentException <ul>
3804 * <li>ERROR_INVALID_RANGE when the line index is outside the valid range (< 0 or >= getLineCount())</li> 3928 * <li>ERROR_INVALID_RANGE when the line index is outside the valid range (< 0 or >= getLineCount())</li>
3805 * </ul> 3929 * </ul>
3806 * @since 2.0 3930 * @since 2.0
3807 */ 3931 */
3808 public int getOffsetAtLine(int lineIndex) { 3932 public int getOffsetAtLine(int lineIndex) {
3809 checkWidget(); 3933 checkWidget();
3810 if (lineIndex < 0 || 3934 if (lineIndex < 0 ||
3811 (lineIndex > 0 && lineIndex >= content.getLineCount())) { 3935 (lineIndex > 0 && lineIndex >= content.getLineCount())) {
3812 DWT.error(DWT.ERROR_INVALID_RANGE); 3936 DWT.error(DWT.ERROR_INVALID_RANGE);
3813 } 3937 }
3814 return content.getOffsetAtLine(lineIndex); 3938 return content.getOffsetAtLine(lineIndex);
3815 } 3939 }
3816 /** 3940 /**
3817 * Returns the offset of the character at the given location relative 3941 * Returns the offset of the character at the given location relative
3818 * to the first character in the document. 3942 * to the first character in the document.
3819 * <p> 3943 * <p>
3820 * The return value reflects the character offset that the caret will 3944 * The return value reflects the character offset that the caret will
3821 * be placed at if a mouse click occurred at the specified location. 3945 * be placed at if a mouse click occurred at the specified location.
3822 * If the x coordinate of the location is beyond the center of a character 3946 * If the x coordinate of the location is beyond the center of a character
3823 * the returned offset will be behind the character. 3947 * the returned offset will be behind the character.
3824 * </p> 3948 * </p>
3825 * 3949 *
3826 * @param point the origin of character bounding box relative to 3950 * @param point the origin of character bounding box relative to
3827 * the origin of the widget client area. 3951 * the origin of the widget client area.
3828 * @return offset of the character at the given location relative 3952 * @return offset of the character at the given location relative
3829 * to the first character in the document. 3953 * to the first character in the document.
3830 * @exception DWTException <ul> 3954 * @exception DWTException <ul>
3831 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 3955 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3832 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 3956 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3833 * </ul> 3957 * </ul>
3862 * relative to the beginning of the document 3986 * relative to the beginning of the document
3863 */ 3987 */
3864 int getOffsetAtPoint(int x, int y, int lineIndex) { 3988 int getOffsetAtPoint(int x, int y, int lineIndex) {
3865 TextLayout layout = renderer.getTextLayout(lineIndex); 3989 TextLayout layout = renderer.getTextLayout(lineIndex);
3866 x += horizontalScrollOffset - leftMargin; 3990 x += horizontalScrollOffset - leftMargin;
3867 int[] trailing = new int[1]; 3991 int[1] trailing;
3868 int offsetInLine = layout.getOffset(x, y, trailing); 3992 int offsetInLine = layout.getOffset(x, y, trailing);
3869 caretAlignment = OFFSET_LEADING; 3993 caretAlignment = OFFSET_LEADING;
3870 if (trailing[0] !is 0) { 3994 if (trailing[0] !is 0) {
3871 int lineInParagraph = layout.getLineIndex(offsetInLine + trailing[0]); 3995 int lineInParagraph = layout.getLineIndex(offsetInLine + trailing[0]);
3872 int lineStart = layout.getLineOffsets()[lineInParagraph]; 3996 int lineStart = layout.getLineOffsets()[lineInParagraph];
3873 if (offsetInLine + trailing[0] is lineStart) { 3997 if (offsetInLine + trailing[0] is lineStart) {
3874 offsetInLine += trailing[0]; 3998 offsetInLine += trailing[0];
3875 caretAlignment = PREVIOUS_OFFSET_TRAILING; 3999 caretAlignment = PREVIOUS_OFFSET_TRAILING;
3876 } else { 4000 } else {
3877 String line = content.getLine(lineIndex); 4001 String line = content.getLine(lineIndex);
3878 int level; 4002 int level;
3879 int offset = offsetInLine; 4003 int offset = offsetInLine;
3880 while (offset > 0 && Character.isDigit(line.charAt(offset))) offset--; 4004 while (offset > 0 && tango.text.Unicode.isDigit(line[offset])) offset--;
3881 if (offset is 0 && Character.isDigit(line.charAt(offset))) { 4005 if (offset is 0 && tango.text.Unicode.isDigit(line[offset])) {
3882 level = isMirrored() ? 1 : 0; 4006 level = isMirrored() ? 1 : 0;
3883 } else { 4007 } else {
3884 level = layout.getLevel(offset) & 0x1; 4008 level = layout.getLevel(offset) & 0x1;
3885 } 4009 }
3886 offsetInLine += trailing[0]; 4010 offsetInLine += trailing[0];
3904 if (inTextOnly && y > height) { 4028 if (inTextOnly && y > height) {
3905 return -1; 4029 return -1;
3906 } 4030 }
3907 int lineIndex = getLineIndex(y); 4031 int lineIndex = getLineIndex(y);
3908 int lineOffset = content.getOffsetAtLine(lineIndex); 4032 int lineOffset = content.getOffsetAtLine(lineIndex);
3909 TextLayout layout = renderer.getTextLayout(lineIndex); 4033 TextLayout layout = renderer.getTextLayout(lineIndex);
3910 x += horizontalScrollOffset - leftMargin ; 4034 x += horizontalScrollOffset - leftMargin ;
3911 y -= getLinePixel(lineIndex); 4035 y -= getLinePixel(lineIndex);
3912 int offset = layout.getOffset(x, y, trailing); 4036 int offset = layout.getOffset(x, y, trailing);
3913 Rectangle rect = layout.getLineBounds(layout.getLineIndex(offset)); 4037 Rectangle rect = layout.getLineBounds(layout.getLineIndex(offset));
3914 renderer.disposeTextLayout(layout); 4038 renderer.disposeTextLayout(layout);
3919 } 4043 }
3920 /** 4044 /**
3921 * Returns the orientation of the receiver. 4045 * Returns the orientation of the receiver.
3922 * 4046 *
3923 * @return the orientation style 4047 * @return the orientation style
3924 * 4048 *
3925 * @exception DWTException <ul> 4049 * @exception DWTException <ul>
3926 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 4050 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
3927 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 4051 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
3928 * </ul> 4052 * </ul>
3929 * 4053 *
3930 * @since 2.1.2 4054 * @since 2.1.2
3931 */ 4055 */
3932 public int getOrientation () { 4056 public int getOrientation () {
3933 checkWidget(); 4057 checkWidget();
3934 return isMirrored() ? DWT.RIGHT_TO_LEFT : DWT.LEFT_TO_RIGHT; 4058 return isMirrored() ? DWT.RIGHT_TO_LEFT : DWT.LEFT_TO_RIGHT;
3935 } 4059 }
3936 /** 4060 /**
3937 * Returns the index of the last partially visible line. 4061 * Returns the index of the last partially visible line.
3938 * 4062 *
3939 * @return index of the last partially visible line. 4063 * @return index of the last partially visible line.
3940 */ 4064 */
3941 int getPartialBottomIndex() { 4065 int getPartialBottomIndex() {
3944 int partialLineCount = Compatibility.ceil(clientAreaHeight, lineHeight); 4068 int partialLineCount = Compatibility.ceil(clientAreaHeight, lineHeight);
3945 return Math.max(0, Math.min(content.getLineCount(), topIndex + partialLineCount) - 1); 4069 return Math.max(0, Math.min(content.getLineCount(), topIndex + partialLineCount) - 1);
3946 } 4070 }
3947 return getLineIndex(clientAreaHeight - bottomMargin); 4071 return getLineIndex(clientAreaHeight - bottomMargin);
3948 } 4072 }
3949 /** 4073 /**
3950 * Returns the index of the first partially visible line. 4074 * Returns the index of the first partially visible line.
3951 * 4075 *
3952 * @return index of the first partially visible line. 4076 * @return index of the first partially visible line.
3953 */ 4077 */
3954 int getPartialTopIndex() { 4078 int getPartialTopIndex() {
3957 return getVerticalScrollOffset() / lineHeight; 4081 return getVerticalScrollOffset() / lineHeight;
3958 } 4082 }
3959 return topIndexY <= 0 ? topIndex : topIndex - 1; 4083 return topIndexY <= 0 ? topIndex : topIndex - 1;
3960 } 4084 }
3961 /** 4085 /**
3962 * Returns the content in the specified range using the platform line 4086 * Returns the content in the specified range using the platform line
3963 * delimiter to separate lines. 4087 * delimiter to separate lines.
3964 * 4088 *
3965 * @param writer the TextWriter to write line text into 4089 * @param writer the TextWriter to write line text into
3966 * @return the content in the specified range using the platform line 4090 * @return the content in the specified range using the platform line
3967 * delimiter to separate lines as written by the specified TextWriter. 4091 * delimiter to separate lines as written by the specified TextWriter.
3968 */ 4092 */
3969 String getPlatformDelimitedText(TextWriter writer) { 4093 String getPlatformDelimitedText(TextWriter writer) {
3970 int end = writer.getStart() + writer.getCharCount(); 4094 int end = writer.getStart() + writer.getCharCount();
3971 int startLine = content.getLineAtOffset(writer.getStart()); 4095 int startLine = content.getLineAtOffset(writer.getStart());
3972 int endLine = content.getLineAtOffset(end); 4096 int endLine = content.getLineAtOffset(end);
3973 String endLineText = content.getLine(endLine); 4097 String endLineText = content.getLine(endLine);
3974 int endLineOffset = content.getOffsetAtLine(endLine); 4098 int endLineOffset = content.getOffsetAtLine(endLine);
3975 4099
3976 for (int i = startLine; i <= endLine; i++) { 4100 for (int i = startLine; i <= endLine; i++) {
3977 writer.writeLine(content.getLine(i), content.getOffsetAtLine(i)); 4101 writer.writeLine(content.getLine(i), content.getOffsetAtLine(i));
3978 if (i < endLine) { 4102 if (i < endLine) {
3979 writer.writeLineDelimiter(PlatformLineDelimiter); 4103 writer.writeLineDelimiter(PlatformLineDelimiter);
3980 } 4104 }
3981 } 4105 }
3982 if (end > endLineOffset + endLineText.length()) { 4106 if (end > endLineOffset + endLineText.length) {
3983 writer.writeLineDelimiter(PlatformLineDelimiter); 4107 writer.writeLineDelimiter(PlatformLineDelimiter);
3984 } 4108 }
3985 writer.close(); 4109 writer.close();
3986 return writer.toString(); 4110 return writer.toString();
3987 } 4111 }
3988 /** 4112 /**
3989 * Returns all the ranges of text that have an associated StyleRange. 4113 * Returns all the ranges of text that have an associated StyleRange.
3990 * Returns an empty array if a LineStyleListener has been set. 4114 * Returns an empty array if a LineStyleListener has been set.
3991 * Should not be called if a LineStyleListener has been set since the 4115 * Should not be called if a LineStyleListener has been set since the
3992 * listener maintains the styles. 4116 * listener maintains the styles.
3993 * <p> 4117 * <p>
3994 * The ranges array contains start and length pairs. Each pair refers to 4118 * The ranges array contains start and length pairs. Each pair refers to
3995 * the corresponding style in the styles array. For example, the pair 4119 * the corresponding style in the styles array. For example, the pair
3996 * that starts at ranges[n] with length ranges[n+1] uses the style 4120 * that starts at ranges[n] with length ranges[n+1] uses the style
3997 * at styles[n/2] returned by <code>getStyleRanges(int, int, bool)</code>. 4121 * at styles[n/2] returned by <code>getStyleRanges(int, int, bool)</code>.
3998 * </p> 4122 * </p>
3999 * 4123 *
4000 * @return the ranges or an empty array if a LineStyleListener has been set. 4124 * @return the ranges or an empty array if a LineStyleListener has been set.
4001 * 4125 *
4002 * @exception DWTException <ul> 4126 * @exception DWTException <ul>
4003 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 4127 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4004 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 4128 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4005 * </ul> 4129 * </ul>
4006 * 4130 *
4007 * @since 3.2 4131 * @since 3.2
4008 * 4132 *
4009 * @see #getStyleRanges(bool) 4133 * @see #getStyleRanges(bool)
4010 */ 4134 */
4011 public int[] getRanges() { 4135 public int[] getRanges() {
4012 checkWidget(); 4136 checkWidget();
4013 if (!isListening(LineGetStyle)) { 4137 if (!isListening(LineGetStyle)) {
4016 } 4140 }
4017 return new int[0]; 4141 return new int[0];
4018 } 4142 }
4019 /** 4143 /**
4020 * Returns the ranges of text that have an associated StyleRange. 4144 * Returns the ranges of text that have an associated StyleRange.
4021 * Returns an empty array if a LineStyleListener has been set. 4145 * Returns an empty array if a LineStyleListener has been set.
4022 * Should not be called if a LineStyleListener has been set since the 4146 * Should not be called if a LineStyleListener has been set since the
4023 * listener maintains the styles. 4147 * listener maintains the styles.
4024 * <p> 4148 * <p>
4025 * The ranges array contains start and length pairs. Each pair refers to 4149 * The ranges array contains start and length pairs. Each pair refers to
4026 * the corresponding style in the styles array. For example, the pair 4150 * the corresponding style in the styles array. For example, the pair
4027 * that starts at ranges[n] with length ranges[n+1] uses the style 4151 * that starts at ranges[n] with length ranges[n+1] uses the style
4028 * at styles[n/2] returned by <code>getStyleRanges(int, int, bool)</code>. 4152 * at styles[n/2] returned by <code>getStyleRanges(int, int, bool)</code>.
4029 * </p> 4153 * </p>
4030 * 4154 *
4031 * @param start the start offset of the style ranges to return 4155 * @param start the start offset of the style ranges to return
4032 * @param length the number of style ranges to return 4156 * @param length the number of style ranges to return
4033 * 4157 *
4034 * @return the ranges or an empty array if a LineStyleListener has been set. 4158 * @return the ranges or an empty array if a LineStyleListener has been set.
4035 * 4159 *
4036 * @exception DWTException <ul> 4160 * @exception DWTException <ul>
4037 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 4161 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4038 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 4162 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4039 * </ul> 4163 * </ul>
4040 * @exception IllegalArgumentException <ul> 4164 * @exception IllegalArgumentException <ul>
4041 * <li>ERROR_INVALID_RANGE if start or length are outside the widget content</li> 4165 * <li>ERROR_INVALID_RANGE if start or length are outside the widget content</li>
4042 * </ul> 4166 * </ul>
4043 * 4167 *
4044 * @since 3.2 4168 * @since 3.2
4045 * 4169 *
4046 * @see #getStyleRanges(int, int, bool) 4170 * @see #getStyleRanges(int, int, bool)
4047 */ 4171 */
4048 public int[] getRanges(int start, int length) { 4172 public int[] getRanges(int start, int length) {
4049 checkWidget(); 4173 checkWidget();
4050 int contentLength = getCharCount(); 4174 int contentLength = getCharCount();
4060 } 4184 }
4061 /** 4185 /**
4062 * Returns the selection. 4186 * Returns the selection.
4063 * <p> 4187 * <p>
4064 * Text selections are specified in terms of caret positions. In a text 4188 * Text selections are specified in terms of caret positions. In a text
4065 * widget that contains N characters, there are N+1 caret positions, 4189 * widget that contains N characters, there are N+1 caret positions,
4066 * ranging from 0..N 4190 * ranging from 0..N
4067 * </p> 4191 * </p>
4068 * 4192 *
4069 * @return start and end of the selection, x is the offset of the first 4193 * @return start and end of the selection, x is the offset of the first
4070 * selected character, y is the offset after the last selected character. 4194 * selected character, y is the offset after the last selected character.
4071 * The selection values returned are visual (i.e., x will always always be 4195 * The selection values returned are visual (i.e., x will always always be
4072 * <= y). To determine if a selection is right-to-left cast(RtoL) vs. left-to-right 4196 * <= y). To determine if a selection is right-to-left (RtoL) vs. left-to-right
4073 * cast(LtoR), compare the caretOffset to the start and end of the selection 4197 * (LtoR), compare the caretOffset to the start and end of the selection
4074 * (e.g., caretOffset is start of selection implies that the selection is RtoL). 4198 * (e.g., caretOffset is start of selection implies that the selection is RtoL).
4075 * @see #getSelectionRange 4199 * @see #getSelectionRange
4076 * @exception DWTException <ul> 4200 * @exception DWTException <ul>
4077 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 4201 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4078 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 4202 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4083 return new Point(selection.x, selection.y); 4207 return new Point(selection.x, selection.y);
4084 } 4208 }
4085 /** 4209 /**
4086 * Returns the selection. 4210 * Returns the selection.
4087 * 4211 *
4088 * @return start and length of the selection, x is the offset of the 4212 * @return start and length of the selection, x is the offset of the
4089 * first selected character, relative to the first character of the 4213 * first selected character, relative to the first character of the
4090 * widget content. y is the length of the selection. 4214 * widget content. y is the length of the selection.
4091 * The selection values returned are visual (i.e., length will always always be 4215 * The selection values returned are visual (i.e., length will always always be
4092 * positive). To determine if a selection is right-to-left cast(RtoL) vs. left-to-right 4216 * positive). To determine if a selection is right-to-left (RtoL) vs. left-to-right
4093 * cast(LtoR), compare the caretOffset to the start and end of the selection 4217 * (LtoR), compare the caretOffset to the start and end of the selection
4094 * (e.g., caretOffset is start of selection implies that the selection is RtoL). 4218 * (e.g., caretOffset is start of selection implies that the selection is RtoL).
4095 * @exception DWTException <ul> 4219 * @exception DWTException <ul>
4096 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 4220 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4097 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 4221 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4098 * </ul> 4222 * </ul>
4161 */ 4285 */
4162 public String getSelectionText() { 4286 public String getSelectionText() {
4163 checkWidget(); 4287 checkWidget();
4164 return content.getTextRange(selection.x, selection.y - selection.x); 4288 return content.getTextRange(selection.x, selection.y - selection.x);
4165 } 4289 }
4166 public int getStyle() { 4290 public override int getStyle() {
4167 int style = super.getStyle(); 4291 int style = super.getStyle();
4168 style &= ~(DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT | DWT.MIRRORED); 4292 style &= ~(DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT | DWT.MIRRORED);
4169 if (isMirrored()) { 4293 if (isMirrored()) {
4170 style |= DWT.RIGHT_TO_LEFT | DWT.MIRRORED; 4294 style |= DWT.RIGHT_TO_LEFT | DWT.MIRRORED;
4171 } else { 4295 } else {
4173 } 4297 }
4174 return style; 4298 return style;
4175 } 4299 }
4176 4300
4177 /** 4301 /**
4178 * Returns the text segments that should be treated as if they 4302 * Returns the text segments that should be treated as if they
4179 * had a different direction than the surrounding text. 4303 * had a different direction than the surrounding text.
4180 * 4304 *
4181 * @param lineOffset offset of the first character in the line. 4305 * @param lineOffset offset of the first character in the line.
4182 * 0 based from the beginning of the document. 4306 * 0 based from the beginning of the document.
4183 * @param line text of the line to specify bidi segments for 4307 * @param line text of the line to specify bidi segments for
4184 * @return text segments that should be treated as if they had a 4308 * @return text segments that should be treated as if they had a
4185 * different direction than the surrounding text. Only the start 4309 * different direction than the surrounding text. Only the start
4186 * index of a segment is specified, relative to the start of the 4310 * index of a segment is specified, relative to the start of the
4187 * line. Always starts with 0 and ends with the line length. 4311 * line. Always starts with 0 and ends with the line length.
4188 * @exception IllegalArgumentException <ul> 4312 * @exception IllegalArgumentException <ul>
4189 * <li>ERROR_INVALID_ARGUMENT - if the segment indices returned 4313 * <li>ERROR_INVALID_ARGUMENT - if the segment indices returned
4190 * by the listener do not start with 0, are not in ascending order, 4314 * by the listener do not start with 0, are not in ascending order,
4191 * exceed the line length or have duplicates</li> 4315 * exceed the line length or have duplicates</li>
4192 * </ul> 4316 * </ul>
4193 */ 4317 */
4194 int [] getBidiSegments(int lineOffset, String line) { 4318 int [] getBidiSegments(int lineOffset, String line) {
4195 if (!isBidi()) return null; 4319 if (!isBidi()) return null;
4196 if (!isListening(LineGetSegments)) { 4320 if (!isListening(LineGetSegments)) {
4197 return getBidiSegmentsCompatibility(line, lineOffset); 4321 return getBidiSegmentsCompatibility(line, lineOffset);
4198 } 4322 }
4199 StyledTextEvent event = sendLineEvent(LineGetSegments, lineOffset, line); 4323 StyledTextEvent event = sendLineEvent(LineGetSegments, lineOffset, line);
4200 int lineLength = line.length(); 4324 int lineLength = line.length;
4201 int[] segments; 4325 int[] segments;
4202 if (event is null || event.segments is null || event.segments.length is 0) { 4326 if (event is null || event.segments is null || event.segments.length is 0) {
4203 segments = new int[] {0, lineLength}; 4327 segments = [0, lineLength];
4204 } else { 4328 } else {
4205 int segmentCount = event.segments.length; 4329 int segmentCount = event.segments.length;
4206 4330
4207 // test segment index consistency 4331 // test segment index consistency
4208 if (event.segments[0] !is 0) { 4332 if (event.segments[0] !is 0) {
4209 DWT.error(DWT.ERROR_INVALID_ARGUMENT); 4333 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
4210 } 4334 }
4211 for (int i = 1; i < segmentCount; i++) { 4335 for (int i = 1; i < segmentCount; i++) {
4212 if (event.segments[i] <= event.segments[i - 1] || event.segments[i] > lineLength) { 4336 if (event.segments[i] <= event.segments[i - 1] || event.segments[i] > lineLength) {
4213 DWT.error(DWT.ERROR_INVALID_ARGUMENT); 4337 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
4214 } 4338 }
4215 } 4339 }
4216 // ensure that last segment index is line end offset 4340 // ensure that last segment index is line end offset
4217 if (event.segments[segmentCount - 1] !is lineLength) { 4341 if (event.segments[segmentCount - 1] !is lineLength) {
4218 segments = new int[segmentCount + 1]; 4342 segments = new int[segmentCount + 1];
4219 System.arraycopy(event.segments, 0, segments, 0, segmentCount); 4343 System.arraycopy(event.segments, 0, segments, 0, segmentCount);
4227 /** 4351 /**
4228 * @see #getBidiSegments 4352 * @see #getBidiSegments
4229 * Supports deprecated setBidiColoring API. Remove when API is removed. 4353 * Supports deprecated setBidiColoring API. Remove when API is removed.
4230 */ 4354 */
4231 int [] getBidiSegmentsCompatibility(String line, int lineOffset) { 4355 int [] getBidiSegmentsCompatibility(String line, int lineOffset) {
4232 int lineLength = line.length(); 4356 int lineLength = line.length;
4233 if (!bidiColoring) { 4357 if (!bidiColoring) {
4234 return new int[] {0, lineLength}; 4358 return [0, lineLength];
4235 } 4359 }
4236 StyleRange [] styles = null; 4360 StyleRange [] styles = null;
4237 StyledTextEvent event = getLineStyleData(lineOffset, line); 4361 StyledTextEvent event = getLineStyleData(lineOffset, line);
4238 if (event !is null) { 4362 if (event !is null) {
4239 styles = event.styles; 4363 styles = event.styles;
4240 } else { 4364 } else {
4241 styles = renderer.getStyleRanges(lineOffset, lineLength, true); 4365 styles = renderer.getStyleRanges(lineOffset, lineLength, true);
4242 } 4366 }
4243 if (styles is null || styles.length is 0) { 4367 if (styles is null || styles.length is 0) {
4244 return new int[] {0, lineLength}; 4368 return [0, lineLength];
4245 } 4369 }
4246 int k=0, count = 1; 4370 int k=0, count = 1;
4247 while (k < styles.length && styles[k].start is 0 && styles[k].length is lineLength) { 4371 while (k < styles.length && styles[k].start is 0 && styles[k].length is lineLength) {
4248 k++; 4372 k++;
4249 } 4373 }
4250 int[] offsets = new int[(styles.length - k) * 2 + 2]; 4374 int[] offsets = new int[(styles.length - k) * 2 + 2];
4251 for (int i = k; i < styles.length; i++) { 4375 for (int i = k; i < styles.length; i++) {
4252 StyleRange style = styles[i]; 4376 StyleRange style = styles[i];
4253 int styleLineStart = Math.max(style.start - lineOffset, 0); 4377 int styleLineStart = Math.max(style.start - lineOffset, 0);
4254 int styleLineEnd = Math.max(style.start + style.length - lineOffset, styleLineStart); 4378 int styleLineEnd = Math.max(style.start + style.length - lineOffset, styleLineStart);
4255 styleLineEnd = Math.min (styleLineEnd, line.length ()); 4379 styleLineEnd = Math.min (styleLineEnd, line.length );
4256 if (i > 0 && count > 1 && 4380 if (i > 0 && count > 1 &&
4257 ((styleLineStart >= offsets[count-2] && styleLineStart <= offsets[count-1]) || 4381 ((styleLineStart >= offsets[count-2] && styleLineStart <= offsets[count-1]) ||
4258 (styleLineEnd >= offsets[count-2] && styleLineEnd <= offsets[count-1])) && 4382 (styleLineEnd >= offsets[count-2] && styleLineEnd <= offsets[count-1])) &&
4259 style.similarTo(styles[i-1])) { 4383 style.similarTo(styles[i-1])) {
4260 offsets[count-2] = Math.min(offsets[count-2], styleLineStart); 4384 offsets[count-2] = Math.min(offsets[count-2], styleLineStart);
4282 } 4406 }
4283 /** 4407 /**
4284 * Returns the style range at the given offset. 4408 * Returns the style range at the given offset.
4285 * <p> 4409 * <p>
4286 * Returns null if a LineStyleListener has been set or if a style is not set 4410 * Returns null if a LineStyleListener has been set or if a style is not set
4287 * for the offset. 4411 * for the offset.
4288 * Should not be called if a LineStyleListener has been set since the 4412 * Should not be called if a LineStyleListener has been set since the
4289 * listener maintains the styles. 4413 * listener maintains the styles.
4290 * </p> 4414 * </p>
4291 * 4415 *
4292 * @param offset the offset to return the style for. 4416 * @param offset the offset to return the style for.
4293 * 0 <= offset < getCharCount() must be true. 4417 * 0 <= offset < getCharCount() must be true.
4294 * @return a StyleRange with start is offset and length is 1, indicating 4418 * @return a StyleRange with start is offset and length is 1, indicating
4295 * the style at the given offset. null if a LineStyleListener has been set 4419 * the style at the given offset. null if a LineStyleListener has been set
4296 * or if a style is not set for the given offset. 4420 * or if a style is not set for the given offset.
4297 * @exception DWTException <ul> 4421 * @exception DWTException <ul>
4298 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 4422 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4299 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 4423 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4300 * </ul> 4424 * </ul>
4314 return null; 4438 return null;
4315 } 4439 }
4316 /** 4440 /**
4317 * Returns the styles. 4441 * Returns the styles.
4318 * <p> 4442 * <p>
4319 * Returns an empty array if a LineStyleListener has been set. 4443 * Returns an empty array if a LineStyleListener has been set.
4320 * Should not be called if a LineStyleListener has been set since the 4444 * Should not be called if a LineStyleListener has been set since the
4321 * listener maintains the styles. 4445 * listener maintains the styles.
4322 * <p></p> 4446 * <p></p>
4323 * Note: Because a StyleRange includes the start and length, the 4447 * Note: Because a StyleRange includes the start and length, the
4324 * same instance cannot occur multiple times in the array of styles. 4448 * same instance cannot occur multiple times in the array of styles.
4325 * If the same style attributes, such as font and color, occur in 4449 * If the same style attributes, such as font and color, occur in
4331 * 4455 *
4332 * @exception DWTException <ul> 4456 * @exception DWTException <ul>
4333 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 4457 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4334 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 4458 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4335 * </ul> 4459 * </ul>
4336 * 4460 *
4337 * @see #getStyleRanges(bool) 4461 * @see #getStyleRanges(bool)
4338 */ 4462 */
4339 public StyleRange[] getStyleRanges() { 4463 public StyleRange[] getStyleRanges() {
4340 checkWidget(); 4464 checkWidget();
4341 return getStyleRanges(0, content.getCharCount(), true); 4465 return getStyleRanges(0, content.getCharCount(), true);
4342 } 4466 }
4343 /** 4467 /**
4344 * Returns the styles. 4468 * Returns the styles.
4345 * <p> 4469 * <p>
4346 * Returns an empty array if a LineStyleListener has been set. 4470 * Returns an empty array if a LineStyleListener has been set.
4347 * Should not be called if a LineStyleListener has been set since the 4471 * Should not be called if a LineStyleListener has been set since the
4348 * listener maintains the styles. 4472 * listener maintains the styles.
4349 * </p><p> 4473 * </p><p>
4350 * Note: When <code>includeRanges</code> is true, the start and length 4474 * Note: When <code>includeRanges</code> is true, the start and length
4351 * fields of each StyleRange will be valid, however the StyleRange 4475 * fields of each StyleRange will be valid, however the StyleRange
4352 * objects may need to be cloned. When <code>includeRanges</code> is 4476 * objects may need to be cloned. When <code>includeRanges</code> is
4353 * false, <code>getRanges(int, int)</code> can be used to get the 4477 * false, <code>getRanges(int, int)</code> can be used to get the
4354 * associated ranges. 4478 * associated ranges.
4355 * </p> 4479 * </p>
4356 * 4480 *
4357 * @param includeRanges whether the start and length field of the StyleRanges should be set. 4481 * @param includeRanges whether the start and length field of the StyleRanges should be set.
4358 * 4482 *
4359 * @return the styles or an empty array if a LineStyleListener has been set. 4483 * @return the styles or an empty array if a LineStyleListener has been set.
4360 * 4484 *
4361 * @exception DWTException <ul> 4485 * @exception DWTException <ul>
4362 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 4486 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4363 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 4487 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4364 * </ul> 4488 * </ul>
4365 * 4489 *
4366 * @since 3.2 4490 * @since 3.2
4367 * 4491 *
4368 * @see #getRanges(int, int) 4492 * @see #getRanges(int, int)
4369 * @see #setStyleRanges(int[], StyleRange[]) 4493 * @see #setStyleRanges(int[], StyleRange[])
4370 */ 4494 */
4371 public StyleRange[] getStyleRanges(bool includeRanges) { 4495 public StyleRange[] getStyleRanges(bool includeRanges) {
4372 checkWidget(); 4496 checkWidget();
4373 return getStyleRanges(0, content.getCharCount(), includeRanges); 4497 return getStyleRanges(0, content.getCharCount(), includeRanges);
4374 } 4498 }
4375 /** 4499 /**
4376 * Returns the styles for the given text range. 4500 * Returns the styles for the given text range.
4377 * <p> 4501 * <p>
4378 * Returns an empty array if a LineStyleListener has been set. 4502 * Returns an empty array if a LineStyleListener has been set.
4379 * Should not be called if a LineStyleListener has been set since the 4503 * Should not be called if a LineStyleListener has been set since the
4380 * listener maintains the styles. 4504 * listener maintains the styles.
4381 * </p><p> 4505 * </p><p>
4382 * Note: Because the StyleRange includes the start and length, the 4506 * Note: Because the StyleRange includes the start and length, the
4383 * same instance cannot occur multiple times in the array of styles. 4507 * same instance cannot occur multiple times in the array of styles.
4384 * If the same style attributes, such as font and color, occur in 4508 * If the same style attributes, such as font and color, occur in
4386 * can be used to get the styles without the ranges. 4510 * can be used to get the styles without the ranges.
4387 * </p> 4511 * </p>
4388 * @param start the start offset of the style ranges to return 4512 * @param start the start offset of the style ranges to return
4389 * @param length the number of style ranges to return 4513 * @param length the number of style ranges to return
4390 * 4514 *
4391 * @return the styles or an empty array if a LineStyleListener has 4515 * @return the styles or an empty array if a LineStyleListener has
4392 * been set. The returned styles will reflect the given range. The first 4516 * been set. The returned styles will reflect the given range. The first
4393 * returned <code>StyleRange</code> will have a starting offset >= start 4517 * returned <code>StyleRange</code> will have a starting offset >= start
4394 * and the last returned <code>StyleRange</code> will have an ending 4518 * and the last returned <code>StyleRange</code> will have an ending
4395 * offset <= start + length - 1 4519 * offset <= start + length - 1
4396 * 4520 *
4397 * @exception DWTException <ul> 4521 * @exception DWTException <ul>
4398 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 4522 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4399 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 4523 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4400 * </ul> 4524 * </ul>
4401 * @exception IllegalArgumentException <ul> 4525 * @exception IllegalArgumentException <ul>
4402 * <li>ERROR_INVALID_RANGE when start and/or end are outside the widget content</li> 4526 * <li>ERROR_INVALID_RANGE when start and/or end are outside the widget content</li>
4403 * </ul> 4527 * </ul>
4404 * 4528 *
4405 * @see #getStyleRanges(int, int, bool) 4529 * @see #getStyleRanges(int, int, bool)
4406 * 4530 *
4407 * @since 3.0 4531 * @since 3.0
4408 */ 4532 */
4409 public StyleRange[] getStyleRanges(int start, int length) { 4533 public StyleRange[] getStyleRanges(int start, int length) {
4410 checkWidget(); 4534 checkWidget();
4411 return getStyleRanges(start, length, true); 4535 return getStyleRanges(start, length, true);
4412 } 4536 }
4413 /** 4537 /**
4414 * Returns the styles for the given text range. 4538 * Returns the styles for the given text range.
4415 * <p> 4539 * <p>
4416 * Returns an empty array if a LineStyleListener has been set. 4540 * Returns an empty array if a LineStyleListener has been set.
4417 * Should not be called if a LineStyleListener has been set since the 4541 * Should not be called if a LineStyleListener has been set since the
4418 * listener maintains the styles. 4542 * listener maintains the styles.
4419 * </p><p> 4543 * </p><p>
4420 * Note: When <code>includeRanges</code> is true, the start and length 4544 * Note: When <code>includeRanges</code> is true, the start and length
4421 * fields of each StyleRange will be valid, however the StyleRange 4545 * fields of each StyleRange will be valid, however the StyleRange
4422 * objects may need to be cloned. When <code>includeRanges</code> is 4546 * objects may need to be cloned. When <code>includeRanges</code> is
4423 * false, <code>getRanges(int, int)</code> can be used to get the 4547 * false, <code>getRanges(int, int)</code> can be used to get the
4424 * associated ranges. 4548 * associated ranges.
4425 * </p> 4549 * </p>
4426 * 4550 *
4427 * @param start the start offset of the style ranges to return 4551 * @param start the start offset of the style ranges to return
4428 * @param length the number of style ranges to return 4552 * @param length the number of style ranges to return
4429 * @param includeRanges whether the start and length field of the StyleRanges should be set. 4553 * @param includeRanges whether the start and length field of the StyleRanges should be set.
4430 * 4554 *
4431 * @return the styles or an empty array if a LineStyleListener has 4555 * @return the styles or an empty array if a LineStyleListener has
4432 * been set. The returned styles will reflect the given range. The first 4556 * been set. The returned styles will reflect the given range. The first
4433 * returned <code>StyleRange</code> will have a starting offset >= start 4557 * returned <code>StyleRange</code> will have a starting offset >= start
4434 * and the last returned <code>StyleRange</code> will have an ending 4558 * and the last returned <code>StyleRange</code> will have an ending
4435 * offset <= start + length - 1 4559 * offset <= start + length - 1
4436 * 4560 *
4437 * @exception DWTException <ul> 4561 * @exception DWTException <ul>
4438 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 4562 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4439 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 4563 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4440 * </ul> 4564 * </ul>
4441 * @exception IllegalArgumentException <ul> 4565 * @exception IllegalArgumentException <ul>
4442 * <li>ERROR_INVALID_RANGE when start and/or end are outside the widget content</li> 4566 * <li>ERROR_INVALID_RANGE when start and/or end are outside the widget content</li>
4443 * </ul> 4567 * </ul>
4444 * 4568 *
4445 * @since 3.2 4569 * @since 3.2
4446 * 4570 *
4447 * @see #getRanges(int, int) 4571 * @see #getRanges(int, int)
4448 * @see #setStyleRanges(int[], StyleRange[]) 4572 * @see #setStyleRanges(int[], StyleRange[])
4449 */ 4573 */
4450 public StyleRange[] getStyleRanges(int start, int length, bool includeRanges) { 4574 public StyleRange[] getStyleRanges(int start, int length, bool includeRanges) {
4451 checkWidget(); 4575 checkWidget();
4488 } 4612 }
4489 /** 4613 /**
4490 * Returns the widget content between the two offsets. 4614 * Returns the widget content between the two offsets.
4491 * 4615 *
4492 * @param start offset of the first character in the returned String 4616 * @param start offset of the first character in the returned String
4493 * @param end offset of the last character in the returned String 4617 * @param end offset of the last character in the returned String
4494 * @return widget content starting at start and ending at end 4618 * @return widget content starting at start and ending at end
4495 * @see #getTextRange(int,int) 4619 * @see #getTextRange(int,int)
4496 * @exception DWTException <ul> 4620 * @exception DWTException <ul>
4497 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 4621 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4498 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 4622 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4499 * </ul> 4623 * </ul>
4500 * @exception IllegalArgumentException <ul> 4624 * @exception IllegalArgumentException <ul>
4501 * <li>ERROR_INVALID_RANGE when start and/or end are outside the widget content</li> 4625 * <li>ERROR_INVALID_RANGE when start and/or end are outside the widget content</li>
4502 * </ul> 4626 * </ul>
4503 */ 4627 */
4504 public String getText(int start, int end) { 4628 public String getText(int start, int end) {
4505 checkWidget(); 4629 checkWidget();
4506 int contentLength = getCharCount(); 4630 int contentLength = getCharCount();
4511 } 4635 }
4512 /** 4636 /**
4513 * Returns the smallest bounding rectangle that includes the characters between two offsets. 4637 * Returns the smallest bounding rectangle that includes the characters between two offsets.
4514 * 4638 *
4515 * @param start offset of the first character included in the bounding box 4639 * @param start offset of the first character included in the bounding box
4516 * @param end offset of the last character included in the bounding box 4640 * @param end offset of the last character included in the bounding box
4517 * @return bounding box of the text between start and end 4641 * @return bounding box of the text between start and end
4518 * @exception DWTException <ul> 4642 * @exception DWTException <ul>
4519 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 4643 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4520 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 4644 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4521 * </ul> 4645 * </ul>
4522 * @exception IllegalArgumentException <ul> 4646 * @exception IllegalArgumentException <ul>
4523 * <li>ERROR_INVALID_RANGE when start and/or end are outside the widget content</li> 4647 * <li>ERROR_INVALID_RANGE when start and/or end are outside the widget content</li>
4524 * </ul> 4648 * </ul>
4525 * @since 3.1 4649 * @since 3.1
4526 */ 4650 */
4527 public Rectangle getTextBounds(int start, int end) { 4651 public Rectangle getTextBounds(int start, int end) {
4528 checkWidget(); 4652 checkWidget();
4529 int contentLength = getCharCount(); 4653 int contentLength = getCharCount();
4530 if (start < 0 || start >= contentLength || end < 0 || end >= contentLength || start > end) { 4654 if (start < 0 || start >= contentLength || end < 0 || end >= contentLength || start > end) {
4531 DWT.error(DWT.ERROR_INVALID_RANGE); 4655 DWT.error(DWT.ERROR_INVALID_RANGE);
4532 } 4656 }
4533 int lineStart = content.getLineAtOffset(start); 4657 int lineStart = content.getLineAtOffset(start);
4534 int lineEnd = content.getLineAtOffset(end); 4658 int lineEnd = content.getLineAtOffset(end);
4535 Rectangle rect; 4659 Rectangle rect;
4536 int y = getLinePixel(lineStart); 4660 int y = getLinePixel(lineStart);
4537 int height = 0; 4661 int height = 0;
4538 int left = 0x7fffffff, right = 0; 4662 int left = 0x7fffffff, right = 0;
4539 for (int i = lineStart; i <= lineEnd; i++) { 4663 for (int i = lineStart; i <= lineEnd; i++) {
4540 int lineOffset = content.getOffsetAtLine(i); 4664 int lineOffset = content.getOffsetAtLine(i);
4541 TextLayout layout = renderer.getTextLayout(i); 4665 TextLayout layout = renderer.getTextLayout(i);
4542 int length = layout.getText().length(); 4666 int length = layout.getText().length;
4543 if (length > 0) { 4667 if (length > 0) {
4544 if (i is lineStart) { 4668 if (i is lineStart) {
4545 if (i is lineEnd) { 4669 if (i is lineEnd) {
4546 rect = layout.getBounds(start - lineOffset, end - lineOffset); 4670 rect = layout.getBounds(start - lineOffset, end - lineOffset);
4547 } else { 4671 } else {
4567 } 4691 }
4568 /** 4692 /**
4569 * Returns the widget content starting at start for length characters. 4693 * Returns the widget content starting at start for length characters.
4570 * 4694 *
4571 * @param start offset of the first character in the returned String 4695 * @param start offset of the first character in the returned String
4572 * @param length number of characters to return 4696 * @param length number of characters to return
4573 * @return widget content starting at start and extending length characters. 4697 * @return widget content starting at start and extending length characters.
4574 * @exception DWTException <ul> 4698 * @exception DWTException <ul>
4575 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 4699 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4576 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 4700 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4577 * </ul> 4701 * </ul>
4578 * @exception IllegalArgumentException <ul> 4702 * @exception IllegalArgumentException <ul>
4579 * <li>ERROR_INVALID_RANGE when start and/or length are outside the widget content</li> 4703 * <li>ERROR_INVALID_RANGE when start and/or length are outside the widget content</li>
4580 * </ul> 4704 * </ul>
4581 */ 4705 */
4582 public String getTextRange(int start, int length) { 4706 public String getTextRange(int start, int length) {
4583 checkWidget(); 4707 checkWidget();
4584 int contentLength = getCharCount(); 4708 int contentLength = getCharCount();
4585 int end = start + length; 4709 int end = start + length;
4586 if (start > end || start < 0 || end > contentLength) { 4710 if (start > end || start < 0 || end > contentLength) {
4587 DWT.error(DWT.ERROR_INVALID_RANGE); 4711 DWT.error(DWT.ERROR_INVALID_RANGE);
4588 } 4712 }
4589 return content.getTextRange(start, length); 4713 return content.getTextRange(start, length);
4590 } 4714 }
4591 /** 4715 /**
4592 * Returns the maximum number of characters that the receiver is capable of holding. 4716 * Returns the maximum number of characters that the receiver is capable of holding.
4593 * 4717 *
4594 * @return the text limit 4718 * @return the text limit
4595 * 4719 *
4596 * @exception DWTException <ul> 4720 * @exception DWTException <ul>
4597 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 4721 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4598 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 4722 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4603 return textLimit; 4727 return textLimit;
4604 } 4728 }
4605 /** 4729 /**
4606 * Gets the top index. 4730 * Gets the top index.
4607 * <p> 4731 * <p>
4608 * The top index is the index of the fully visible line that is currently 4732 * The top index is the index of the fully visible line that is currently
4609 * at the top of the widget or the topmost partially visible line if no line is fully visible. 4733 * at the top of the widget or the topmost partially visible line if no line is fully visible.
4610 * The top index changes when the widget is scrolled. Indexing is zero based. 4734 * The top index changes when the widget is scrolled. Indexing is zero based.
4611 * </p> 4735 * </p>
4612 * 4736 *
4613 * @return the index of the top line 4737 * @return the index of the top line
4614 * @exception DWTException <ul> 4738 * @exception DWTException <ul>
4621 return topIndex; 4745 return topIndex;
4622 } 4746 }
4623 /** 4747 /**
4624 * Gets the top pixel. 4748 * Gets the top pixel.
4625 * <p> 4749 * <p>
4626 * The top pixel is the pixel position of the line that is 4750 * The top pixel is the pixel position of the line that is
4627 * currently at the top of the widget. The text widget can be scrolled by pixels 4751 * currently at the top of the widget. The text widget can be scrolled by pixels
4628 * by dragging the scroll thumb so that a partial line may be displayed at the top 4752 * by dragging the scroll thumb so that a partial line may be displayed at the top
4629 * the widget. The top pixel changes when the widget is scrolled. The top pixel 4753 * the widget. The top pixel changes when the widget is scrolled. The top pixel
4630 * does not include the widget trimming. 4754 * does not include the widget trimming.
4631 * </p> 4755 * </p>
4632 * 4756 *
4633 * @return pixel position of the top line 4757 * @return pixel position of the top line
4634 * @exception DWTException <ul> 4758 * @exception DWTException <ul>
4638 */ 4762 */
4639 public int getTopPixel() { 4763 public int getTopPixel() {
4640 checkWidget(); 4764 checkWidget();
4641 return getVerticalScrollOffset(); 4765 return getVerticalScrollOffset();
4642 } 4766 }
4643 /** 4767 /**
4644 * Returns the vertical scroll increment. 4768 * Returns the vertical scroll increment.
4645 * 4769 *
4646 * @return vertical scroll increment. 4770 * @return vertical scroll increment.
4647 */ 4771 */
4648 int getVerticalIncrement() { 4772 int getVerticalIncrement() {
4677 updateCaretDirection = false; 4801 updateCaretDirection = false;
4678 int caretLine = getCaretLine(); 4802 int caretLine = getCaretLine();
4679 int lineOffset = content.getOffsetAtLine(caretLine); 4803 int lineOffset = content.getOffsetAtLine(caretLine);
4680 String line = content.getLine(caretLine); 4804 String line = content.getLine(caretLine);
4681 int offset = caretOffset - lineOffset; 4805 int offset = caretOffset - lineOffset;
4682 int lineLength = line.length(); 4806 int lineLength = line.length;
4683 if (lineLength is 0) return isMirrored() ? DWT.RIGHT : DWT.LEFT; 4807 if (lineLength is 0) return isMirrored() ? DWT.RIGHT : DWT.LEFT;
4684 if (caretAlignment is PREVIOUS_OFFSET_TRAILING && offset > 0) offset--; 4808 if (caretAlignment is PREVIOUS_OFFSET_TRAILING && offset > 0) offset--;
4685 if (offset is lineLength && offset > 0) offset--; 4809 if (offset is lineLength && offset > 0) offset--;
4686 while (offset > 0 && Character.isDigit(line.charAt(offset))) offset--; 4810 while (offset > 0 && tango.text.Unicode.isDigit(line[offset])) offset--;
4687 if (offset is 0 && Character.isDigit(line.charAt(offset))) { 4811 if (offset is 0 && tango.text.Unicode.isDigit(line[offset])) {
4688 return isMirrored() ? DWT.RIGHT : DWT.LEFT; 4812 return isMirrored() ? DWT.RIGHT : DWT.LEFT;
4689 } 4813 }
4690 TextLayout layout = renderer.getTextLayout(caretLine); 4814 TextLayout layout = renderer.getTextLayout(caretLine);
4691 int level = layout.getLevel(offset); 4815 int level = layout.getLevel(offset);
4692 renderer.disposeTextLayout(layout); 4816 renderer.disposeTextLayout(layout);
4715 lineText = content.getLine(lineIndex); 4839 lineText = content.getLine(lineIndex);
4716 } else { 4840 } else {
4717 int lineIndex = content.getLineAtOffset(offset); 4841 int lineIndex = content.getLineAtOffset(offset);
4718 lineOffset = content.getOffsetAtLine(lineIndex); 4842 lineOffset = content.getOffsetAtLine(lineIndex);
4719 lineText = content.getLine(lineIndex); 4843 lineText = content.getLine(lineIndex);
4720 int lineLength = lineText.length(); 4844 int lineLength = lineText.length;
4721 if (offset is lineOffset + lineLength) { 4845 if (offset is lineOffset + lineLength) {
4722 newOffset = content.getOffsetAtLine(lineIndex + 1); 4846 newOffset = content.getOffsetAtLine(lineIndex + 1);
4723 } else { 4847 } else {
4724 TextLayout layout = renderer.getTextLayout(lineIndex); 4848 TextLayout layout = renderer.getTextLayout(lineIndex);
4725 newOffset = lineOffset + layout.getNextOffset(offset - lineOffset, movement); 4849 newOffset = lineOffset + layout.getNextOffset(offset - lineOffset, movement);
4740 int lineIndex = content.getLineAtOffset(offset); 4864 int lineIndex = content.getLineAtOffset(offset);
4741 lineOffset = content.getOffsetAtLine(lineIndex); 4865 lineOffset = content.getOffsetAtLine(lineIndex);
4742 lineText = content.getLine(lineIndex); 4866 lineText = content.getLine(lineIndex);
4743 if (offset is lineOffset) { 4867 if (offset is lineOffset) {
4744 String nextLineText = content.getLine(lineIndex - 1); 4868 String nextLineText = content.getLine(lineIndex - 1);
4745 int nextLineOffset = content.getOffsetAtLine(lineIndex - 1); 4869 int nextLineOffset = content.getOffsetAtLine(lineIndex - 1);
4746 newOffset = nextLineOffset + nextLineText.length(); 4870 newOffset = nextLineOffset + nextLineText.length;
4747 } else { 4871 } else {
4748 TextLayout layout = renderer.getTextLayout(lineIndex); 4872 TextLayout layout = renderer.getTextLayout(lineIndex);
4749 newOffset = lineOffset + layout.getPreviousOffset(offset - lineOffset, movement); 4873 newOffset = lineOffset + layout.getPreviousOffset(offset - lineOffset, movement);
4750 renderer.disposeTextLayout(layout); 4874 renderer.disposeTextLayout(layout);
4751 } 4875 }
4752 } 4876 }
4753 return sendWordBoundaryEvent(WordPrevious, movement, offset, newOffset, lineText, lineOffset); 4877 return sendWordBoundaryEvent(WordPrevious, movement, offset, newOffset, lineText, lineOffset);
4754 } 4878 }
4755 /** 4879 /**
4760 */ 4884 */
4761 public bool getWordWrap() { 4885 public bool getWordWrap() {
4762 checkWidget(); 4886 checkWidget();
4763 return wordWrap; 4887 return wordWrap;
4764 } 4888 }
4765 /** 4889 /**
4766 * Returns the location of the given offset. 4890 * Returns the location of the given offset.
4767 * <p> 4891 * <p>
4768 * <b>NOTE:</b> Does not return correct values for true italic fonts (vs. slanted fonts). 4892 * <b>NOTE:</b> Does not return correct values for true italic fonts (vs. slanted fonts).
4769 * </p> 4893 * </p>
4770 * 4894 *
4773 Point getPointAtOffset(int offset) { 4897 Point getPointAtOffset(int offset) {
4774 int lineIndex = content.getLineAtOffset(offset); 4898 int lineIndex = content.getLineAtOffset(offset);
4775 String line = content.getLine(lineIndex); 4899 String line = content.getLine(lineIndex);
4776 int lineOffset = content.getOffsetAtLine(lineIndex); 4900 int lineOffset = content.getOffsetAtLine(lineIndex);
4777 int offsetInLine = offset - lineOffset; 4901 int offsetInLine = offset - lineOffset;
4778 int lineLength = line.length(); 4902 int lineLength = line.length;
4779 if (lineIndex < content.getLineCount() - 1) { 4903 if (lineIndex < content.getLineCount() - 1) {
4780 int endLineOffset = content.getOffsetAtLine(lineIndex + 1) - 1; 4904 int endLineOffset = content.getOffsetAtLine(lineIndex + 1) - 1;
4781 if (lineLength < offsetInLine && offsetInLine <= endLineOffset) { 4905 if (lineLength < offsetInLine && offsetInLine <= endLineOffset) {
4782 offsetInLine = lineLength; 4906 offsetInLine = lineLength;
4783 } 4907 }
4784 } 4908 }
4785 Point point; 4909 Point point;
4786 TextLayout layout = renderer.getTextLayout(lineIndex); 4910 TextLayout layout = renderer.getTextLayout(lineIndex);
4787 if (lineLength !is 0 && offsetInLine <= lineLength) { 4911 if (lineLength !is 0 && offsetInLine <= lineLength) {
4788 if (offsetInLine is lineLength) { 4912 if (offsetInLine is lineLength) {
4789 point = layout.getLocation(offsetInLine - 1, true); 4913 // DWT: Instead of go back one byte, go back one codepoint
4914 int offsetInLine_m1 = layout.getPreviousOffset(offsetInLine, DWT.MOVEMENT_CLUSTER);
4915 point = layout.getLocation(offsetInLine_m1, true);
4790 } else { 4916 } else {
4791 switch (caretAlignment) { 4917 switch (caretAlignment) {
4792 case OFFSET_LEADING: 4918 case OFFSET_LEADING:
4793 point = layout.getLocation(offsetInLine, false); 4919 point = layout.getLocation(offsetInLine, false);
4794 break; 4920 break;
4795 case PREVIOUS_OFFSET_TRAILING: 4921 case PREVIOUS_OFFSET_TRAILING:
4796 default: 4922 default:
4797 if (offsetInLine is 0) { 4923 if (offsetInLine is 0) {
4798 point = layout.getLocation(offsetInLine, false); 4924 point = layout.getLocation(offsetInLine, false);
4799 } else { 4925 } else {
4800 point = layout.getLocation(offsetInLine - 1, true); 4926 // DWT: Instead of go back one byte, go back one codepoint
4927 int offsetInLine_m1 = layout.getPreviousOffset(offsetInLine, DWT.MOVEMENT_CLUSTER);
4928 point = layout.getLocation(offsetInLine_m1, true);
4801 } 4929 }
4802 break; 4930 break;
4803 } 4931 }
4804 } 4932 }
4805 } else { 4933 } else {
4808 renderer.disposeTextLayout(layout); 4936 renderer.disposeTextLayout(layout);
4809 point.x += leftMargin - horizontalScrollOffset; 4937 point.x += leftMargin - horizontalScrollOffset;
4810 point.y += getLinePixel(lineIndex); 4938 point.y += getLinePixel(lineIndex);
4811 return point; 4939 return point;
4812 } 4940 }
4813 /** 4941 /**
4814 * Inserts a String. The old selection is replaced with the new text. 4942 * Inserts a string. The old selection is replaced with the new text.
4815 * 4943 *
4816 * @param String the String 4944 * @param string the string
4817 * @see #replaceTextRange(int,int,String) 4945 * @see #replaceTextRange(int,int,String)
4818 * @exception DWTException <ul> 4946 * @exception DWTException <ul>
4819 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 4947 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
4820 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 4948 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
4821 * </ul> 4949 * </ul>
4822 * @exception IllegalArgumentException <ul> 4950 */
4823 * <li>ERROR_NULL_ARGUMENT when String is null</li> 4951 public void insert(String string) {
4824 * </ul> 4952 checkWidget();
4825 */ 4953 // DWT extension: allow null for zero length string
4826 public void insert(String String) { 4954 // if (string is null) {
4827 checkWidget(); 4955 // DWT.error(DWT.ERROR_NULL_ARGUMENT);
4828 if (String is null) { 4956 // }
4829 DWT.error(DWT.ERROR_NULL_ARGUMENT);
4830 }
4831 Point sel = getSelectionRange(); 4957 Point sel = getSelectionRange();
4832 replaceTextRange(sel.x, sel.y, String); 4958 replaceTextRange(sel.x, sel.y, string);
4833 } 4959 }
4834 /** 4960 /**
4835 * Creates content change listeners and set the default content model. 4961 * Creates content change listeners and set the default content model.
4836 */ 4962 */
4837 void installDefaultContent() { 4963 void installDefaultContent() {
4838 textChangeListener = new TextChangeListener() { 4964 textChangeListener = new class() TextChangeListener {
4839 public void textChanging(TextChangingEvent event) { 4965 public void textChanging(TextChangingEvent event) {
4840 handleTextChanging(event); 4966 handleTextChanging(event);
4841 } 4967 }
4842 public void textChanged(TextChangedEvent event) { 4968 public void textChanged(TextChangedEvent event) {
4843 handleTextChanged(event); 4969 handleTextChanged(event);
4847 } 4973 }
4848 }; 4974 };
4849 content = new DefaultContent(); 4975 content = new DefaultContent();
4850 content.addTextChangeListener(textChangeListener); 4976 content.addTextChangeListener(textChangeListener);
4851 } 4977 }
4852 /** 4978 /**
4853 * Adds event listeners 4979 * Adds event listeners
4854 */ 4980 */
4855 void installListeners() { 4981 void installListeners() {
4856 ScrollBar verticalBar = getVerticalBar(); 4982 ScrollBar verticalBar = getVerticalBar();
4857 ScrollBar horizontalBar = getHorizontalBar(); 4983 ScrollBar horizontalBar = getHorizontalBar();
4858 4984
4859 listener = new Listener() { 4985 listener = new class() Listener {
4860 public void handleEvent(Event event) { 4986 public void handleEvent(Event event) {
4861 switch (event.type) { 4987 switch (event.type) {
4862 case DWT.Dispose: handleDispose(event); break; 4988 case DWT.Dispose: handleDispose(event); break;
4863 case DWT.KeyDown: handleKeyDown(event); break; 4989 case DWT.KeyDown: handleKeyDown(event); break;
4864 case DWT.KeyUp: handleKeyUp(event); break; 4990 case DWT.KeyUp: handleKeyUp(event); break;
4866 case DWT.MouseUp: handleMouseUp(event); break; 4992 case DWT.MouseUp: handleMouseUp(event); break;
4867 case DWT.MouseMove: handleMouseMove(event); break; 4993 case DWT.MouseMove: handleMouseMove(event); break;
4868 case DWT.Paint: handlePaint(event); break; 4994 case DWT.Paint: handlePaint(event); break;
4869 case DWT.Resize: handleResize(event); break; 4995 case DWT.Resize: handleResize(event); break;
4870 case DWT.Traverse: handleTraverse(event); break; 4996 case DWT.Traverse: handleTraverse(event); break;
4871 } 4997 default:
4872 } 4998 }
4999 }
4873 }; 5000 };
4874 addListener(DWT.Dispose, listener); 5001 addListener(DWT.Dispose, listener);
4875 addListener(DWT.KeyDown, listener); 5002 addListener(DWT.KeyDown, listener);
4876 addListener(DWT.KeyUp, listener); 5003 addListener(DWT.KeyUp, listener);
4877 addListener(DWT.MouseDown, listener); 5004 addListener(DWT.MouseDown, listener);
4878 addListener(DWT.MouseUp, listener); 5005 addListener(DWT.MouseUp, listener);
4879 addListener(DWT.MouseMove, listener); 5006 addListener(DWT.MouseMove, listener);
4880 addListener(DWT.Paint, listener); 5007 addListener(DWT.Paint, listener);
4881 addListener(DWT.Resize, listener); 5008 addListener(DWT.Resize, listener);
4882 addListener(DWT.Traverse, listener); 5009 addListener(DWT.Traverse, listener);
4883 ime.addListener(DWT.ImeComposition, new Listener() { 5010 ime.addListener(DWT.ImeComposition, new class() Listener {
4884 public void handleEvent(Event event) { 5011 public void handleEvent(Event event) {
4885 switch (event.detail) { 5012 switch (event.detail) {
4886 case DWT.COMPOSITION_SELECTION: handleCompositionSelection(event); break; 5013 case DWT.COMPOSITION_SELECTION: handleCompositionSelection(event); break;
4887 case DWT.COMPOSITION_CHANGED: handleCompositionChanged(event); break; 5014 case DWT.COMPOSITION_CHANGED: handleCompositionChanged(event); break;
4888 case DWT.COMPOSITION_OFFSET: handleCompositionOffset(event); break; 5015 case DWT.COMPOSITION_OFFSET: handleCompositionOffset(event); break;
5016 default:
4889 } 5017 }
4890 } 5018 }
4891 }); 5019 });
4892 if (verticalBar !is null) { 5020 if (verticalBar !is null) {
4893 verticalBar.addListener(DWT.Selection, new Listener() { 5021 verticalBar.addListener(DWT.Selection, new class() Listener {
4894 public void handleEvent(Event event) { 5022 public void handleEvent(Event event) {
4895 handleVerticalScroll(event); 5023 handleVerticalScroll(event);
4896 } 5024 }
4897 }); 5025 });
4898 } 5026 }
4899 if (horizontalBar !is null) { 5027 if (horizontalBar !is null) {
4900 horizontalBar.addListener(DWT.Selection, new Listener() { 5028 horizontalBar.addListener(DWT.Selection, new class() Listener {
4901 public void handleEvent(Event event) { 5029 public void handleEvent(Event event) {
4902 handleHorizontalScroll(event); 5030 handleHorizontalScroll(event);
4903 } 5031 }
4904 }); 5032 });
4905 } 5033 }
4928 } 5056 }
4929 5057
4930 TextLayout layout = renderer.getTextLayout(startLine); 5058 TextLayout layout = renderer.getTextLayout(startLine);
4931 int lineX = leftMargin - horizontalScrollOffset, startLineY = getLinePixel(startLine); 5059 int lineX = leftMargin - horizontalScrollOffset, startLineY = getLinePixel(startLine);
4932 int[] offsets = layout.getLineOffsets(); 5060 int[] offsets = layout.getLineOffsets();
4933 int startIndex = layout.getLineIndex(Math.min(start, layout.getText().length())); 5061 int startIndex = layout.getLineIndex(Math.min(start, layout.getText().length));
4934 5062
4935 /* Redraw end of line before start line if wrapped and start offset is first char */ 5063 /* Redraw end of line before start line if wrapped and start offset is first char */
4936 if (wordWrap && startIndex > 0 && offsets[startIndex] is start) { 5064 if (wordWrap && startIndex > 0 && offsets[startIndex] is start) {
4937 Rectangle rect = layout.getLineBounds(startIndex - 1); 5065 Rectangle rect = layout.getLineBounds(startIndex - 1);
4938 rect.x = rect.width; 5066 rect.x = rect.width;
4939 rect.width = clientAreaWidth - rightMargin - rect.x; 5067 rect.width = clientAreaWidth - rightMargin - rect.x;
4940 rect.x += lineX; 5068 rect.x += lineX;
4941 rect.y += startLineY; 5069 rect.y += startLineY;
4942 super.redraw(rect.x, rect.y, rect.width, rect.height, false); 5070 super.redraw(rect.x, rect.y, rect.width, rect.height, false);
4943 } 5071 }
4944 5072
4945 if (startLine is endLine) { 5073 if (startLine is endLine) {
4946 int endIndex = layout.getLineIndex(Math.min(end, layout.getText().length())); 5074 int endIndex = layout.getLineIndex(Math.min(end, layout.getText().length));
4947 if (startIndex is endIndex) { 5075 if (startIndex is endIndex) {
4948 /* Redraw rect between start and end offset if start and end offsets are in same wrapped line */ 5076 /* Redraw rect between start and end offset if start and end offsets are in same wrapped line */
4949 Rectangle rect = layout.getBounds(start, end - 1); 5077 Rectangle rect = layout.getBounds(start, end - 1);
4950 rect.x += lineX; 5078 rect.x += lineX;
4951 rect.y += startLineY; 5079 rect.y += startLineY;
4972 if (startLine !is endLine) { 5100 if (startLine !is endLine) {
4973 renderer.disposeTextLayout(layout); 5101 renderer.disposeTextLayout(layout);
4974 layout = renderer.getTextLayout(endLine); 5102 layout = renderer.getTextLayout(endLine);
4975 offsets = layout.getLineOffsets(); 5103 offsets = layout.getLineOffsets();
4976 } 5104 }
4977 int endIndex = layout.getLineIndex(Math.min(end, layout.getText().length())); 5105 int endIndex = layout.getLineIndex(Math.min(end, layout.getText().length));
4978 Rectangle endRect = layout.getBounds(offsets[endIndex], end - 1); 5106 Rectangle endRect = layout.getBounds(offsets[endIndex], end - 1);
4979 if (endRect.height is 0) { 5107 if (endRect.height is 0) {
4980 Rectangle bounds = layout.getLineBounds(endIndex); 5108 Rectangle bounds = layout.getLineBounds(endIndex);
4981 endRect.y = bounds.y; 5109 endRect.y = bounds.y;
4982 endRect.height = bounds.height; 5110 endRect.height = bounds.height;
5004 } 5132 }
5005 void handleCompositionChanged(Event event) { 5133 void handleCompositionChanged(Event event) {
5006 String text = event.text; 5134 String text = event.text;
5007 int start = event.start; 5135 int start = event.start;
5008 int end = event.end; 5136 int end = event.end;
5009 int length = text.length(); 5137 int length = text.length;
5010 if (length is ime.getCommitCount()) { 5138 if (length is ime.getCommitCount()) {
5011 content.replaceTextRange(start, end - start, ""); 5139 content.replaceTextRange(start, end - start, "");
5012 caretOffset = start; 5140 caretOffset = ime.getCompositionOffset();
5013 caretWidth = 0; 5141 caretWidth = 0;
5014 caretDirection = DWT.NULL; 5142 caretDirection = DWT.NULL;
5015 } else { 5143 } else {
5016 content.replaceTextRange(start, end - start, text); 5144 content.replaceTextRange(start, end - start, text);
5017 caretOffset = ime.getCaretOffset(); 5145 caretOffset = ime.getCaretOffset();
5018 if (ime.getWideCaret()) { 5146 if (ime.getWideCaret()) {
5147 start = ime.getCompositionOffset();
5019 int lineIndex = getCaretLine(); 5148 int lineIndex = getCaretLine();
5020 int lineOffset = content.getOffsetAtLine(lineIndex); 5149 int lineOffset = content.getOffsetAtLine(lineIndex);
5021 TextLayout layout = renderer.getTextLayout(lineIndex); 5150 TextLayout layout = renderer.getTextLayout(lineIndex);
5022 caretWidth = layout.getBounds(start - lineOffset, start + length - 1 - lineOffset).width; 5151 caretWidth = layout.getBounds(start - lineOffset, start + length - 1 - lineOffset).width;
5023 renderer.disposeTextLayout(layout); 5152 renderer.disposeTextLayout(layout);
5024 } 5153 }
5025 } 5154 }
5026 showCaret(); 5155 showCaret();
5027 } 5156 }
5028 /** 5157 /**
5029 * Frees resources. 5158 * Frees resources.
5030 */ 5159 */
5031 void handleDispose(Event event) { 5160 void handleDispose(Event event) {
5032 removeListener(DWT.Dispose, listener); 5161 removeListener(DWT.Dispose, listener);
5033 notifyListeners(DWT.Dispose, event); 5162 notifyListeners(DWT.Dispose, event);
5065 keyActionMap = null; 5194 keyActionMap = null;
5066 background = null; 5195 background = null;
5067 foreground = null; 5196 foreground = null;
5068 clipboard = null; 5197 clipboard = null;
5069 } 5198 }
5070 /** 5199 /**
5071 * Scrolls the widget horizontally. 5200 * Scrolls the widget horizontally.
5072 */ 5201 */
5073 void handleHorizontalScroll(Event event) { 5202 void handleHorizontalScroll(Event event) {
5074 int scrollPixel = getHorizontalBar().getSelection() - horizontalScrollOffset; 5203 int scrollPixel = getHorizontalBar().getSelection() - horizontalScrollOffset;
5075 scrollHorizontal(scrollPixel, false); 5204 scrollHorizontal(scrollPixel, false);
5099 } 5228 }
5100 } 5229 }
5101 } 5230 }
5102 if (action is DWT.NULL) { 5231 if (action is DWT.NULL) {
5103 bool ignore = false; 5232 bool ignore = false;
5104 5233
5105 if (IS_CARBON) { 5234 if (IS_CARBON) {
5106 // Ignore accelerator key combinations (we do not want to 5235 // Ignore accelerator key combinations (we do not want to
5107 // insert a character in the text in this instance). Do not 5236 // insert a character in the text in this instance). Do not
5108 // ignore COMMAND+ALT combinations since that key sequence 5237 // ignore COMMAND+ALT combinations since that key sequence
5109 // produces characters on the mac. 5238 // produces characters on the mac.
5110 ignore = (event.stateMask ^ DWT.COMMAND) is 0 || 5239 ignore = (event.stateMask ^ DWT.COMMAND) is 0 ||
5111 (event.stateMask ^ (DWT.COMMAND | DWT.SHIFT)) is 0; 5240 (event.stateMask ^ (DWT.COMMAND | DWT.SHIFT)) is 0;
5112 } else if (IS_MOTIF) { 5241 } else if (IS_MOTIF) {
5113 // Ignore accelerator key combinations (we do not want to 5242 // Ignore accelerator key combinations (we do not want to
5114 // insert a character in the text in this instance). Do not 5243 // insert a character in the text in this instance). Do not
5115 // ignore ALT combinations since this key sequence 5244 // ignore ALT combinations since this key sequence
5116 // produces characters on motif. 5245 // produces characters on motif.
5117 ignore = (event.stateMask ^ DWT.CTRL) is 0 || 5246 ignore = (event.stateMask ^ DWT.CTRL) is 0 ||
5118 (event.stateMask ^ (DWT.CTRL | DWT.SHIFT)) is 0; 5247 (event.stateMask ^ (DWT.CTRL | DWT.SHIFT)) is 0;
5119 } else { 5248 } else {
5120 // Ignore accelerator key combinations (we do not want to 5249 // Ignore accelerator key combinations (we do not want to
5121 // insert a character in the text in this instance). Don't 5250 // insert a character in the text in this instance). Don't
5122 // ignore CTRL+ALT combinations since that is the Alt Gr 5251 // ignore CTRL+ALT combinations since that is the Alt Gr
5123 // key on some keyboards. See bug 20953. 5252 // key on some keyboards. See bug 20953.
5124 ignore = (event.stateMask ^ DWT.ALT) is 0 || 5253 ignore = (event.stateMask ^ DWT.ALT) is 0 ||
5125 (event.stateMask ^ DWT.CTRL) is 0 || 5254 (event.stateMask ^ DWT.CTRL) is 0 ||
5126 (event.stateMask ^ (DWT.ALT | DWT.SHIFT)) is 0 || 5255 (event.stateMask ^ (DWT.ALT | DWT.SHIFT)) is 0 ||
5127 (event.stateMask ^ (DWT.CTRL | DWT.SHIFT)) is 0; 5256 (event.stateMask ^ (DWT.CTRL | DWT.SHIFT)) is 0;
5128 } 5257 }
5129 // -ignore anything below SPACE except for line delimiter keys and tab. 5258 // -ignore anything below SPACE except for line delimiter keys and tab.
5130 // -ignore DEL 5259 // -ignore DEL
5131 if (!ignore && event.character > 31 && event.character !is DWT.DEL || 5260 if (!ignore && event.character > 31 && event.character !is DWT.DEL ||
5132 event.character is DWT.CR || event.character is DWT.LF || 5261 event.character is DWT.CR || event.character is DWT.LF ||
5133 event.character is TAB) { 5262 event.character is TAB) {
5134 doContent(event.character); 5263 doContent(event.character);
5135 update(); 5264 update();
5136 } 5265 }
5137 } else { 5266 } else {
5146 */ 5275 */
5147 void handleKeyDown(Event event) { 5276 void handleKeyDown(Event event) {
5148 if (clipboardSelection is null) { 5277 if (clipboardSelection is null) {
5149 clipboardSelection = new Point(selection.x, selection.y); 5278 clipboardSelection = new Point(selection.x, selection.y);
5150 } 5279 }
5151 5280
5152 Event verifyEvent = new Event(); 5281 Event verifyEvent = new Event();
5153 verifyEvent.character = event.character; 5282 verifyEvent.character = event.character;
5154 verifyEvent.keyCode = event.keyCode; 5283 verifyEvent.keyCode = event.keyCode;
5155 verifyEvent.stateMask = event.stateMask; 5284 verifyEvent.stateMask = event.stateMask;
5156 verifyEvent.doit = true; 5285 verifyEvent.doit = true;
5170 try { 5299 try {
5171 if (selection.y - selection.x > 0) { 5300 if (selection.y - selection.x > 0) {
5172 setClipboardContent(selection.x, selection.y - selection.x, DND.SELECTION_CLIPBOARD); 5301 setClipboardContent(selection.x, selection.y - selection.x, DND.SELECTION_CLIPBOARD);
5173 } 5302 }
5174 } catch (DWTError error) { 5303 } catch (DWTError error) {
5175 // Copy to clipboard failed. This happens when another application 5304 // Copy to clipboard failed. This happens when another application
5176 // is accessing the clipboard while we copy. Ignore the error. 5305 // is accessing the clipboard while we copy. Ignore the error.
5177 // Fixes 1GDQAVN 5306 // Fixes 1GDQAVN
5178 // Rethrow all other errors. Fixes bug 17578. 5307 // Rethrow all other errors. Fixes bug 17578.
5179 if (error.code !is DND.ERROR_CANNOT_SET_CLIPBOARD) { 5308 if (error.code !is DND.ERROR_CANNOT_SET_CLIPBOARD) {
5180 throw error; 5309 throw error;
5182 } 5311 }
5183 } 5312 }
5184 } 5313 }
5185 clipboardSelection = null; 5314 clipboardSelection = null;
5186 } 5315 }
5187 /** 5316 /**
5188 * Updates the caret location and selection if mouse button 1 has been 5317 * Updates the caret location and selection if mouse button 1 has been
5189 * pressed. 5318 * pressed.
5190 */ 5319 */
5191 void handleMouseDown(Event event) { 5320 void handleMouseDown(Event event) {
5192 //force focus (object support) 5321 //force focus (object support)
5193 forceFocus(); 5322 forceFocus();
5194 5323
5195 //drag detect 5324 //drag detect
5196 if (dragDetect && checkDragDetect(event)) return; 5325 if (dragDetect_ && checkDragDetect(event)) return;
5197 5326
5198 //paste clipboard selection 5327 //paste clipboard selection
5199 if (event.button is 2) { 5328 if (event.button is 2) {
5200 String text = cast(String)getClipboardContent(DND.SELECTION_CLIPBOARD); 5329 auto o = cast(ArrayWrapperString)getClipboardContent(DND.SELECTION_CLIPBOARD);
5201 if (text !is null && text.length() > 0) { 5330 String text = o.array;
5331 if (text !is null && text.length > 0) {
5202 // position cursor 5332 // position cursor
5203 doMouseLocationChange(event.x, event.y, false); 5333 doMouseLocationChange(event.x, event.y, false);
5204 // insert text 5334 // insert text
5205 Event e = new Event(); 5335 Event e = new Event();
5206 e.start = selection.x; 5336 e.start = selection.x;
5207 e.end = selection.y; 5337 e.end = selection.y;
5208 e.text = getModelDelimitedText(text); 5338 e.text = getModelDelimitedText(text);
5209 sendKeyEvent(e); 5339 sendKeyEvent(e);
5210 } 5340 }
5211 } 5341 }
5212 5342
5213 //set selection 5343 //set selection
5214 if ((event.button !is 1) || (IS_CARBON && (event.stateMask & DWT.MOD4) !is 0)) { 5344 if ((event.button !is 1) || (IS_CARBON && (event.stateMask & DWT.MOD4) !is 0)) {
5215 return; 5345 return;
5216 } 5346 }
5217 clickCount = event.count; 5347 clickCount = event.count;
5218 if (clickCount is 1) { 5348 if (clickCount is 1) {
5219 bool select = (event.stateMask & DWT.MOD2) !is 0; 5349 bool select = (event.stateMask & DWT.MOD2) !is 0;
5220 doMouseLocationChange(event.x, event.y, select); 5350 doMouseLocationChange(event.x, event.y, select);
5243 doMouseSelection(); 5373 doMouseSelection();
5244 doubleClickSelection = new Point(selection.x, selection.y); 5374 doubleClickSelection = new Point(selection.x, selection.y);
5245 } 5375 }
5246 } 5376 }
5247 } 5377 }
5248 /** 5378 /**
5249 * Updates the caret location and selection if mouse button 1 is pressed 5379 * Updates the caret location and selection if mouse button 1 is pressed
5250 * during the mouse move. 5380 * during the mouse move.
5251 */ 5381 */
5252 void handleMouseMove(Event event) { 5382 void handleMouseMove(Event event) {
5253 if (clickCount is 0) return; 5383 if (clickCount is 0) return;
5254 doMouseLocationChange(event.x, event.y, true); 5384 doMouseLocationChange(event.x, event.y, true);
5255 update(); 5385 update();
5256 doAutoScroll(event); 5386 doAutoScroll(event);
5257 } 5387 }
5258 /** 5388 /**
5259 * Autoscrolling ends when the mouse button is released. 5389 * Autoscrolling ends when the mouse button is released.
5260 */ 5390 */
5261 void handleMouseUp(Event event) { 5391 void handleMouseUp(Event event) {
5262 clickCount = 0; 5392 clickCount = 0;
5263 endAutoScroll(); 5393 endAutoScroll();
5265 try { 5395 try {
5266 if (selection.y - selection.x > 0) { 5396 if (selection.y - selection.x > 0) {
5267 setClipboardContent(selection.x, selection.y - selection.x, DND.SELECTION_CLIPBOARD); 5397 setClipboardContent(selection.x, selection.y - selection.x, DND.SELECTION_CLIPBOARD);
5268 } 5398 }
5269 } catch (DWTError error) { 5399 } catch (DWTError error) {
5270 // Copy to clipboard failed. This happens when another application 5400 // Copy to clipboard failed. This happens when another application
5271 // is accessing the clipboard while we copy. Ignore the error. 5401 // is accessing the clipboard while we copy. Ignore the error.
5272 // Fixes 1GDQAVN 5402 // Fixes 1GDQAVN
5273 // Rethrow all other errors. Fixes bug 17578. 5403 // Rethrow all other errors. Fixes bug 17578.
5274 if (error.code !is DND.ERROR_CANNOT_SET_CLIPBOARD) { 5404 if (error.code !is DND.ERROR_CANNOT_SET_CLIPBOARD) {
5275 throw error; 5405 throw error;
5317 if (rightMargin > 0) { 5447 if (rightMargin > 0) {
5318 drawBackground(gc, clientAreaWidth - rightMargin, 0, rightMargin, clientAreaHeight); 5448 drawBackground(gc, clientAreaWidth - rightMargin, 0, rightMargin, clientAreaHeight);
5319 } 5449 }
5320 } 5450 }
5321 /** 5451 /**
5322 * Recalculates the scroll bars. Rewraps all lines when in word 5452 * Recalculates the scroll bars. Rewraps all lines when in word
5323 * wrap mode. 5453 * wrap mode.
5324 * 5454 *
5325 * @param event resize event 5455 * @param event resize event
5326 */ 5456 */
5327 void handleResize(Event event) { 5457 void handleResize(Event event) {
5331 clientAreaHeight = clientArea.height; 5461 clientAreaHeight = clientArea.height;
5332 clientAreaWidth = clientArea.width; 5462 clientAreaWidth = clientArea.width;
5333 /* Redraw the old or new right/bottom margin if needed */ 5463 /* Redraw the old or new right/bottom margin if needed */
5334 if (oldWidth !is clientAreaWidth) { 5464 if (oldWidth !is clientAreaWidth) {
5335 if (rightMargin > 0) { 5465 if (rightMargin > 0) {
5336 int x = (oldWidth < clientAreaWidth ? oldWidth : clientAreaWidth) - rightMargin; 5466 int x = (oldWidth < clientAreaWidth ? oldWidth : clientAreaWidth) - rightMargin;
5337 super.redraw(x, 0, rightMargin, oldHeight, false); 5467 super.redraw(x, 0, rightMargin, oldHeight, false);
5338 } 5468 }
5339 } 5469 }
5340 if (oldHeight !is clientAreaHeight) { 5470 if (oldHeight !is clientAreaHeight) {
5341 if (bottomMargin > 0) { 5471 if (bottomMargin > 0) {
5342 int y = (oldHeight < clientAreaHeight ? oldHeight : clientAreaHeight) - bottomMargin; 5472 int y = (oldHeight < clientAreaHeight ? oldHeight : clientAreaHeight) - bottomMargin;
5343 super.redraw(0, y, oldWidth, bottomMargin, false); 5473 super.redraw(0, y, oldWidth, bottomMargin, false);
5344 } 5474 }
5345 } 5475 }
5346 if (wordWrap) { 5476 if (wordWrap) {
5347 if (oldWidth !is clientAreaWidth) { 5477 if (oldWidth !is clientAreaWidth) {
5376 // if (oldHeight !is clientAreaHeight || wordWrap) { 5506 // if (oldHeight !is clientAreaHeight || wordWrap) {
5377 // calculateTopIndex(0); 5507 // calculateTopIndex(0);
5378 // } 5508 // }
5379 } 5509 }
5380 /** 5510 /**
5381 * Updates the caret position and selection and the scroll bars to reflect 5511 * Updates the caret position and selection and the scroll bars to reflect
5382 * the content change. 5512 * the content change.
5383 */ 5513 */
5384 void handleTextChanged(TextChangedEvent event) { 5514 void handleTextChanged(TextChangedEvent event) {
5515 int offset = ime.getCompositionOffset();
5516 if (offset !is -1 && lastTextChangeStart < offset) {
5517 ime.setCompositionOffset(offset + lastTextChangeNewCharCount - lastTextChangeReplaceCharCount);
5518 }
5385 int firstLine = content.getLineAtOffset(lastTextChangeStart); 5519 int firstLine = content.getLineAtOffset(lastTextChangeStart);
5386 resetCache(firstLine, 0); 5520 resetCache(firstLine, 0);
5387 if (!isFixedLineHeight() && topIndex > firstLine) { 5521 if (!isFixedLineHeight() && topIndex > firstLine) {
5388 topIndex = firstLine; 5522 topIndex = firstLine;
5389 topIndexY = 0; 5523 topIndexY = 0;
5392 int lastLine = firstLine + lastTextChangeNewLineCount; 5526 int lastLine = firstLine + lastTextChangeNewLineCount;
5393 int firstLineTop = getLinePixel(firstLine); 5527 int firstLineTop = getLinePixel(firstLine);
5394 int newLastLineBottom = getLinePixel(lastLine + 1); 5528 int newLastLineBottom = getLinePixel(lastLine + 1);
5395 if (lastLineBottom !is newLastLineBottom) { 5529 if (lastLineBottom !is newLastLineBottom) {
5396 super.redraw(); 5530 super.redraw();
5397 if (wordWrap) setCaretLocation();
5398 } else { 5531 } else {
5399 super.redraw(0, firstLineTop, clientAreaWidth, newLastLineBottom - firstLineTop, false); 5532 super.redraw(0, firstLineTop, clientAreaWidth, newLastLineBottom - firstLineTop, false);
5400 redrawLinesBullet(renderer.redrawLines); 5533 redrawLinesBullet(renderer.redrawLines);
5401 } 5534 }
5402 } 5535 }
5403 renderer.redrawLines = null; 5536 renderer.redrawLines = null;
5404 // update selection/caret location after styles have been changed. 5537 // update selection/caret location after styles have been changed.
5405 // otherwise any text measuring could be incorrect 5538 // otherwise any text measuring could be incorrect
5406 // 5539 //
5407 // also, this needs to be done after all scrolling. Otherwise, 5540 // also, this needs to be done after all scrolling. Otherwise,
5408 // selection redraw would be flushed during scroll which is wrong. 5541 // selection redraw would be flushed during scroll which is wrong.
5409 // in some cases new text would be drawn in scroll source area even 5542 // in some cases new text would be drawn in scroll source area even
5410 // though the intent is to scroll it. 5543 // though the intent is to scroll it.
5411 updateSelection(lastTextChangeStart, lastTextChangeReplaceCharCount, lastTextChangeNewCharCount); 5544 updateSelection(lastTextChangeStart, lastTextChangeReplaceCharCount, lastTextChangeNewCharCount);
5412 if (lastTextChangeReplaceLineCount > 0 || wordWrap) { 5545 if (lastTextChangeReplaceLineCount > 0 || wordWrap) {
5413 claimBottomFreeSpace(); 5546 claimBottomFreeSpace();
5414 } 5547 }
5418 } 5551 }
5419 /** 5552 /**
5420 * Updates the screen to reflect a pending content change. 5553 * Updates the screen to reflect a pending content change.
5421 * 5554 *
5422 * @param event .start the start offset of the change 5555 * @param event .start the start offset of the change
5423 * @param event .newText text that is going to be inserted or empty String 5556 * @param event .newText text that is going to be inserted or empty String
5424 * if no text will be inserted 5557 * if no text will be inserted
5425 * @param event .replaceCharCount length of text that is going to be replaced 5558 * @param event .replaceCharCount length of text that is going to be replaced
5426 * @param event .newCharCount length of text that is going to be inserted 5559 * @param event .newCharCount length of text that is going to be inserted
5427 * @param event .replaceLineCount number of lines that are going to be replaced 5560 * @param event .replaceLineCount number of lines that are going to be replaced
5428 * @param event .newLineCount number of new lines that are going to be inserted 5561 * @param event .newLineCount number of new lines that are going to be inserted
5434 } 5567 }
5435 lastTextChangeStart = event.start; 5568 lastTextChangeStart = event.start;
5436 lastTextChangeNewLineCount = event.newLineCount; 5569 lastTextChangeNewLineCount = event.newLineCount;
5437 lastTextChangeNewCharCount = event.newCharCount; 5570 lastTextChangeNewCharCount = event.newCharCount;
5438 lastTextChangeReplaceLineCount = event.replaceLineCount; 5571 lastTextChangeReplaceLineCount = event.replaceLineCount;
5439 lastTextChangeReplaceCharCount = event.replaceCharCount; 5572 lastTextChangeReplaceCharCount = event.replaceCharCount;
5440 int lineIndex = content.getLineAtOffset(event.start); 5573 int lineIndex = content.getLineAtOffset(event.start);
5441 int srcY = getLinePixel(lineIndex + event.replaceLineCount + 1); 5574 int srcY = getLinePixel(lineIndex + event.replaceLineCount + 1);
5442 int destY = getLinePixel(lineIndex + 1) + event.newLineCount * renderer.getLineHeight(); 5575 int destY = getLinePixel(lineIndex + 1) + event.newLineCount * renderer.getLineHeight();
5443 lastLineBottom = destY; 5576 lastLineBottom = destY;
5444 if (srcY < 0 && destY < 0) { 5577 if (srcY < 0 && destY < 0) {
5449 } else { 5582 } else {
5450 scrollText(srcY, destY); 5583 scrollText(srcY, destY);
5451 } 5584 }
5452 5585
5453 renderer.textChanging(event); 5586 renderer.textChanging(event);
5454 5587
5455 // Update the caret offset if it is greater than the length of the content. 5588 // Update the caret offset if it is greater than the length of the content.
5456 // This is necessary since style range API may be called between the 5589 // This is necessary since style range API may be called between the
5457 // handleTextChanging and handleTextChanged events and this API sets the 5590 // handleTextChanging and handleTextChanged events and this API sets the
5458 // caretOffset. 5591 // caretOffset.
5459 int newEndOfText = content.getCharCount() - event.replaceCharCount + event.newCharCount; 5592 int newEndOfText = content.getCharCount() - event.replaceCharCount + event.newCharCount;
5460 if (caretOffset > newEndOfText) caretOffset = newEndOfText; 5593 if (caretOffset > newEndOfText) caretOffset = newEndOfText;
5461 } 5594 }
5462 /** 5595 /**
5463 * Called when the widget content is set programmatically, overwriting 5596 * Called when the widget content is set programmatically, overwriting
5464 * the old content. Resets the caret position, selection and scroll offsets. 5597 * the old content. Resets the caret position, selection and scroll offsets.
5465 * Recalculates the content width and scroll bars. Redraws the widget. 5598 * Recalculates the content width and scroll bars. Redraws the widget.
5466 * 5599 *
5467 * @param event text change event. 5600 * @param event text change event.
5468 */ 5601 */
5469 void handleTextSet(TextChangedEvent event) { 5602 void handleTextSet(TextChangedEvent event) {
5470 reset(); 5603 reset();
5471 } 5604 }
5472 /** 5605 /**
5473 * Called when a traversal key is pressed. 5606 * Called when a traversal key is pressed.
5474 * Allow tab next traversal to occur when the widget is in single 5607 * Allow tab next traversal to occur when the widget is in single
5475 * line mode or in multi line and non-editable mode . 5608 * line mode or in multi line and non-editable mode .
5476 * When in editable multi line mode we want to prevent the tab 5609 * When in editable multi line mode we want to prevent the tab
5477 * traversal and receive the tab key event instead. 5610 * traversal and receive the tab key event instead.
5478 * 5611 *
5479 * @param event the event 5612 * @param event the event
5480 */ 5613 */
5481 void handleTraverse(Event event) { 5614 void handleTraverse(Event event) {
5494 if (!editable || (event.stateMask & DWT.MODIFIER_MASK) !is 0) { 5627 if (!editable || (event.stateMask & DWT.MODIFIER_MASK) !is 0) {
5495 event.doit = true; 5628 event.doit = true;
5496 } 5629 }
5497 } 5630 }
5498 break; 5631 break;
5499 } 5632 default:
5500 } 5633 }
5501 /** 5634 }
5635 /**
5502 * Scrolls the widget vertically. 5636 * Scrolls the widget vertically.
5503 */ 5637 */
5504 void handleVerticalScroll(Event event) { 5638 void handleVerticalScroll(Event event) {
5505 int scrollPixel = getVerticalBar().getSelection() - getVerticalScrollOffset(); 5639 int scrollPixel = getVerticalBar().getSelection() - getVerticalScrollOffset();
5506 scrollVertical(scrollPixel, false); 5640 scrollVertical(scrollPixel, false);
5508 /** 5642 /**
5509 * Add accessibility support for the widget. 5643 * Add accessibility support for the widget.
5510 */ 5644 */
5511 void initializeAccessible() { 5645 void initializeAccessible() {
5512 final Accessible accessible = getAccessible(); 5646 final Accessible accessible = getAccessible();
5513 accessible.addAccessibleListener(new AccessibleAdapter() { 5647 accessible.addAccessibleListener(new class() AccessibleAdapter {
5514 public void getName (AccessibleEvent e) { 5648 public void getName (AccessibleEvent e) {
5515 String name = null; 5649 String name = null;
5516 Label label = getAssociatedLabel (); 5650 Label label = getAssociatedLabel ();
5517 if (label !is null) { 5651 if (label !is null) {
5518 name = stripMnemonic (label.getText()); 5652 name = stripMnemonic (label.getText());
5526 String shortcut = null; 5660 String shortcut = null;
5527 Label label = getAssociatedLabel (); 5661 Label label = getAssociatedLabel ();
5528 if (label !is null) { 5662 if (label !is null) {
5529 String text = label.getText (); 5663 String text = label.getText ();
5530 if (text !is null) { 5664 if (text !is null) {
5531 char mnemonic = _findMnemonic (text); 5665 dchar mnemonic = _findMnemonic (text);
5532 if (mnemonic !is '\0') { 5666 if (mnemonic !is '\0') {
5533 shortcut = "Alt+"+mnemonic; //$NON-NLS-1$ 5667 shortcut = "Alt+"~tango.text.convert.Utf.toString( [mnemonic] ); //$NON-NLS-1$
5534 } 5668 }
5535 } 5669 }
5536 } 5670 }
5537 e.result = shortcut; 5671 e.result = shortcut;
5538 } 5672 }
5539 }); 5673 });
5540 accessible.addAccessibleTextListener(new AccessibleTextAdapter() { 5674 accessible.addAccessibleTextListener(new class() AccessibleTextAdapter {
5541 public void getCaretOffset(AccessibleTextEvent e) { 5675 public void getCaretOffset(AccessibleTextEvent e) {
5542 e.offset = StyledText.this.getCaretOffset(); 5676 e.offset = this.outer.getCaretOffset();
5543 } 5677 }
5544 public void getSelectionRange(AccessibleTextEvent e) { 5678 public void getSelectionRange(AccessibleTextEvent e) {
5545 Point selection = StyledText.this.getSelectionRange(); 5679 Point selection = this.outer.getSelectionRange();
5546 e.offset = selection.x; 5680 e.offset = selection.x;
5547 e.length = selection.y; 5681 e.length = selection.y;
5548 } 5682 }
5549 }); 5683 });
5550 accessible.addAccessibleControlListener(new AccessibleControlAdapter() { 5684 accessible.addAccessibleControlListener(new class() AccessibleControlAdapter {
5551 public void getRole(AccessibleControlEvent e) { 5685 public void getRole(AccessibleControlEvent e) {
5552 e.detail = ACC.ROLE_TEXT; 5686 e.detail = ACC.ROLE_TEXT;
5553 } 5687 }
5554 public void getState(AccessibleControlEvent e) { 5688 public void getState(AccessibleControlEvent e) {
5555 int state = 0; 5689 int state = 0;
5558 if (!isVisible()) state |= ACC.STATE_INVISIBLE; 5692 if (!isVisible()) state |= ACC.STATE_INVISIBLE;
5559 if (!getEditable()) state |= ACC.STATE_READONLY; 5693 if (!getEditable()) state |= ACC.STATE_READONLY;
5560 e.detail = state; 5694 e.detail = state;
5561 } 5695 }
5562 public void getValue(AccessibleControlEvent e) { 5696 public void getValue(AccessibleControlEvent e) {
5563 e.result = StyledText.this.getText(); 5697 e.result = this.outer.getText();
5564 } 5698 }
5565 }); 5699 });
5566 addListener(DWT.FocusIn, new Listener() { 5700 addListener(DWT.FocusIn, new class(accessible) Listener {
5701 Accessible acc;
5702 this( Accessible acc ){ this.acc = acc; }
5567 public void handleEvent(Event event) { 5703 public void handleEvent(Event event) {
5568 accessible.setFocus(ACC.CHILDID_SELF); 5704 acc.setFocus(ACC.CHILDID_SELF);
5569 } 5705 }
5570 }); 5706 });
5571 } 5707 }
5572 /* 5708 /*
5573 * Return the Label immediately preceding the receiver in the z-order, 5709 * Return the Label immediately preceding the receiver in the z-order,
5574 * or null if none. 5710 * or null if none.
5575 */ 5711 */
5576 Label getAssociatedLabel () { 5712 Label getAssociatedLabel () {
5577 Control[] siblings = getParent ().getChildren (); 5713 Control[] siblings = getParent ().getChildren ();
5578 for (int i = 0; i < siblings.length; i++) { 5714 for (int i = 0; i < siblings.length; i++) {
5579 if (siblings [i] is StyledText.this) { 5715 if (siblings [i] is this) {
5580 if (i > 0 && siblings [i-1] instanceof Label) { 5716 if (i > 0 && ( null !is cast(Label)siblings [i-1])) {
5581 return cast(Label) siblings [i-1]; 5717 return cast(Label) siblings [i-1];
5582 } 5718 }
5583 } 5719 }
5584 } 5720 }
5585 return null; 5721 return null;
5586 } 5722 }
5587 String stripMnemonic (String String) { 5723 String stripMnemonic (String string) {
5588 int index = 0; 5724 int index = 0;
5589 int length = String.length (); 5725 int length_ = string.length;
5590 do { 5726 do {
5591 while ((index < length) && (String.charAt (index) !is '&')) index++; 5727 while ((index < length_) && (string[index] !is '&')) index++;
5592 if (++index >= length) return String; 5728 if (++index >= length_) return string;
5593 if (String.charAt (index) !is '&') { 5729 if (string[index] !is '&') {
5594 return String.substring(0, index-1) + String.substring(index, length); 5730 return string.substring(0, index-1) ~ string.substring(index, length_);
5595 } 5731 }
5596 index++; 5732 index++;
5597 } while (index < length); 5733 } while (index < length_);
5598 return String; 5734 return string;
5599 } 5735 }
5600 /* 5736 /*
5601 * Return the lowercase of the first non-'&' character following 5737 * Return the lowercase of the first non-'&' character following
5602 * an '&' character in the given String. If there are no '&' 5738 * an '&' character in the given string. If there are no '&'
5603 * characters in the given String, return '\0'. 5739 * characters in the given string, return '\0'.
5604 */ 5740 */
5605 char _findMnemonic (String String) { 5741 dchar _findMnemonic (String string) {
5606 if (String is null) return '\0'; 5742 if (string is null) return '\0';
5607 int index = 0; 5743 int index = 0;
5608 int length = String.length (); 5744 int length_ = string.length;
5609 do { 5745 do {
5610 while (index < length && String.charAt (index) !is '&') index++; 5746 while (index < length_ && string[index] !is '&') index++;
5611 if (++index >= length) return '\0'; 5747 if (++index >= length_) return '\0';
5612 if (String.charAt (index) !is '&') return Character.toLowerCase (String.charAt (index)); 5748 if (string[index] !is '&') return CharacterFirstToLower(string[index .. $ ] );
5613 index++; 5749 index++;
5614 } while (index < length); 5750 } while (index < length_);
5615 return '\0'; 5751 return '\0';
5616 } 5752 }
5617 /** 5753 /**
5618 * Executes the action. 5754 * Executes the action.
5619 * 5755 *
5678 break; 5814 break;
5679 case ST.WINDOW_END: 5815 case ST.WINDOW_END:
5680 doPageEnd(); 5816 doPageEnd();
5681 clearSelection(true); 5817 clearSelection(true);
5682 break; 5818 break;
5683 // Selection 5819 // Selection
5684 case ST.SELECT_LINE_UP: 5820 case ST.SELECT_LINE_UP:
5685 doSelectionLineUp(); 5821 doSelectionLineUp();
5686 break; 5822 break;
5687 case ST.SELECT_ALL: 5823 case ST.SELECT_ALL:
5688 selectAll(); 5824 selectAll();
5734 break; 5870 break;
5735 case ST.SELECT_WINDOW_END: 5871 case ST.SELECT_WINDOW_END:
5736 doPageEnd(); 5872 doPageEnd();
5737 doSelection(ST.COLUMN_NEXT); 5873 doSelection(ST.COLUMN_NEXT);
5738 break; 5874 break;
5739 // Modification 5875 // Modification
5740 case ST.CUT: 5876 case ST.CUT:
5741 cut(); 5877 cut();
5742 break; 5878 break;
5743 case ST.COPY: 5879 case ST.COPY:
5744 copy(); 5880 copy();
5760 break; 5896 break;
5761 // Miscellaneous 5897 // Miscellaneous
5762 case ST.TOGGLE_OVERWRITE: 5898 case ST.TOGGLE_OVERWRITE:
5763 overwrite = !overwrite; // toggle insert/overwrite mode 5899 overwrite = !overwrite; // toggle insert/overwrite mode
5764 break; 5900 break;
5901 default:
5765 } 5902 }
5766 } 5903 }
5767 /** 5904 /**
5768 * Temporary until DWT provides this 5905 * Temporary until DWT provides this
5769 */ 5906 */
5770 bool isBidi() { 5907 bool isBidi() {
5771 return IS_GTK || IS_CARBON || BidiUtil.isBidiPlatform() || isMirrored; 5908 return IS_GTK || IS_CARBON || BidiUtil.isBidiPlatform() || isMirrored_;
5772 } 5909 }
5773 bool isBidiCaret() { 5910 bool isBidiCaret() {
5774 return BidiUtil.isBidiPlatform(); 5911 return BidiUtil.isBidiPlatform();
5775 } 5912 }
5776 bool isFixedLineHeight() { 5913 bool isFixedLineHeight() {
5777 return fixedLineHeight; 5914 return fixedLineHeight;
5778 } 5915 }
5779 /** 5916 /**
5780 * Returns whether the given offset is inside a multi byte line delimiter. 5917 * Returns whether the given offset is inside a multi byte line delimiter.
5781 * Example: 5918 * Example:
5782 * "Line1\r\n" isLineDelimiter(5) is false but isLineDelimiter(6) is true 5919 * "Line1\r\n" isLineDelimiter(5) is false but isLineDelimiter(6) is true
5783 * 5920 *
5784 * @return true if the given offset is inside a multi byte line delimiter. 5921 * @return true if the given offset is inside a multi byte line delimiter.
5785 * false if the given offset is before or after a line delimiter. 5922 * false if the given offset is before or after a line delimiter.
5786 */ 5923 */
5787 bool isLineDelimiter(int offset) { 5924 bool isLineDelimiter(int offset) {
5788 int line = content.getLineAtOffset(offset); 5925 int line = content.getLineAtOffset(offset);
5789 int lineOffset = content.getOffsetAtLine(line); 5926 int lineOffset = content.getOffsetAtLine(line);
5790 int offsetInLine = offset - lineOffset; 5927 int offsetInLine = offset - lineOffset;
5791 // offsetInLine will be greater than line length if the line 5928 // offsetInLine will be greater than line length if the line
5792 // delimiter is longer than one character and the offset is set 5929 // delimiter is longer than one character and the offset is set
5793 // in between parts of the line delimiter. 5930 // in between parts of the line delimiter.
5794 return offsetInLine > content.getLine(line).length(); 5931 return offsetInLine > content.getLine(line).length;
5795 } 5932 }
5796 /** 5933 /**
5797 * Returns whether the widget is mirrored (right oriented/right to left 5934 * Returns whether the widget is mirrored (right oriented/right to left
5798 * writing order). 5935 * writing order).
5799 * 5936 *
5800 * @return isMirrored true=the widget is right oriented, false=the widget 5937 * @return isMirrored true=the widget is right oriented, false=the widget
5801 * is left oriented 5938 * is left oriented
5802 */ 5939 */
5803 bool isMirrored() { 5940 bool isMirrored() {
5804 return isMirrored; 5941 return isMirrored_;
5805 } 5942 }
5806 /** 5943 /**
5807 * Returns whether the widget can have only one line. 5944 * Returns whether the widget can have only one line.
5808 * 5945 *
5809 * @return true if widget can have only one line, false if widget can have 5946 * @return true if widget can have only one line, false if widget can have
5810 * multiple lines 5947 * multiple lines
5811 */ 5948 */
5812 bool isSingleLine() { 5949 bool isSingleLine() {
5813 return (getStyle() & DWT.SINGLE) !is 0; 5950 return (getStyle() & DWT.SINGLE) !is 0;
5814 } 5951 }
5815 /** 5952 /**
5816 * Sends the specified verify event, replace/insert text as defined by 5953 * Sends the specified verify event, replace/insert text as defined by
5817 * the event and send a modify event. 5954 * the event and send a modify event.
5818 * 5955 *
5819 * @param event the text change event. 5956 * @param event the text change event.
5820 * <ul> 5957 * <ul>
5821 * <li>event.start - the replace start offset</li> 5958 * <li>event.start - the replace start offset</li>
5822 * <li>event.end - the replace end offset</li> 5959 * <li>event.end - the replace end offset</li>
5823 * <li>event.text - the new text</li> 5960 * <li>event.text - the new text</li>
5824 * </ul> 5961 * </ul>
5832 StyledTextEvent styledTextEvent = null; 5969 StyledTextEvent styledTextEvent = null;
5833 int replacedLength = event.end - event.start; 5970 int replacedLength = event.end - event.start;
5834 if (isListening(ExtendedModify)) { 5971 if (isListening(ExtendedModify)) {
5835 styledTextEvent = new StyledTextEvent(content); 5972 styledTextEvent = new StyledTextEvent(content);
5836 styledTextEvent.start = event.start; 5973 styledTextEvent.start = event.start;
5837 styledTextEvent.end = event.start + event.text.length(); 5974 styledTextEvent.end = event.start + event.text.length;
5838 styledTextEvent.text = content.getTextRange(event.start, replacedLength); 5975 styledTextEvent.text = content.getTextRange(event.start, replacedLength);
5839 } 5976 }
5840 if (updateCaret) { 5977 if (updateCaret) {
5841 //Fix advancing flag for delete/backspace key on direction boundary 5978 //Fix advancing flag for delete/backspace key on direction boundary
5842 if (event.text.length() is 0) { 5979 if (event.text.length is 0) {
5843 int lineIndex = content.getLineAtOffset(event.start); 5980 int lineIndex = content.getLineAtOffset(event.start);
5844 int lineOffset = content.getOffsetAtLine(lineIndex); 5981 int lineOffset = content.getOffsetAtLine(lineIndex);
5845 TextLayout layout = renderer.getTextLayout(lineIndex); 5982 TextLayout layout = renderer.getTextLayout(lineIndex);
5846 int levelStart = layout.getLevel(event.start - lineOffset); 5983 int levelStart = layout.getLevel(event.start - lineOffset);
5847 int lineIndexEnd = content.getLineAtOffset(event.end); 5984 int lineIndexEnd = content.getLineAtOffset(event.end);
5862 content.replaceTextRange(event.start, replacedLength, event.text); 5999 content.replaceTextRange(event.start, replacedLength, event.text);
5863 // set the caret position prior to sending the modify event. 6000 // set the caret position prior to sending the modify event.
5864 // fixes 1GBB8NJ 6001 // fixes 1GBB8NJ
5865 if (updateCaret) { 6002 if (updateCaret) {
5866 // always update the caret location. fixes 1G8FODP 6003 // always update the caret location. fixes 1G8FODP
5867 setSelection(event.start + event.text.length(), 0, true); 6004 setSelection(event.start + event.text.length, 0, true);
5868 showCaret(); 6005 showCaret();
5869 } 6006 }
5870 sendModifyEvent(event); 6007 sendModifyEvent(event);
5871 if (isListening(ExtendedModify)) { 6008 if (isListening(ExtendedModify)) {
5872 notifyListeners(ExtendedModify, styledTextEvent); 6009 notifyListeners(ExtendedModify, styledTextEvent);
5885 event.bullet = bullet; 6022 event.bullet = bullet;
5886 event.bulletIndex = bulletIndex; 6023 event.bulletIndex = bulletIndex;
5887 notifyListeners(PaintObject, event); 6024 notifyListeners(PaintObject, event);
5888 } 6025 }
5889 } 6026 }
5890 /** 6027 /**
5891 * Replaces the selection with the text on the <code>DND.CLIPBOARD</code> 6028 * Replaces the selection with the text on the <code>DND.CLIPBOARD</code>
5892 * clipboard or, if there is no selection, inserts the text at the current 6029 * clipboard or, if there is no selection, inserts the text at the current
5893 * caret offset. If the widget has the DWT.SINGLE style and the 6030 * caret offset. If the widget has the DWT.SINGLE style and the
5894 * clipboard text contains more than one line, only the first line without 6031 * clipboard text contains more than one line, only the first line without
5895 * line delimiters is inserted in the widget. 6032 * line delimiters is inserted in the widget.
5896 * 6033 *
5897 * @exception DWTException <ul> 6034 * @exception DWTException <ul>
5898 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6035 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
5899 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6036 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
5900 * </ul> 6037 * </ul>
5901 */ 6038 */
5902 public void paste(){ 6039 public void paste(){
5903 checkWidget(); 6040 checkWidget();
5904 String text = cast(String) getClipboardContent(DND.CLIPBOARD); 6041 String text = null;
5905 if (text !is null && text.length() > 0) { 6042 if( auto o = cast(ArrayWrapperString) getClipboardContent(DND.CLIPBOARD)){
6043 text = o.array;
6044 }
6045 if (text !is null && text.length > 0) {
5906 Event event = new Event(); 6046 Event event = new Event();
5907 event.start = selection.x; 6047 event.start = selection.x;
5908 event.end = selection.y; 6048 event.end = selection.y;
5909 event.text = getModelDelimitedText(text); 6049 event.text = getModelDelimitedText(text);
5910 sendKeyEvent(event); 6050 sendKeyEvent(event);
5911 } 6051 }
5912 } 6052 }
5913 /** 6053 /**
5914 * Prints the widget's text to the default printer. 6054 * Prints the widget's text to the default printer.
5915 * 6055 *
5916 * @exception DWTException <ul> 6056 * @exception DWTException <ul>
5917 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6057 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
5918 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6058 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
5923 Printer printer = new Printer(); 6063 Printer printer = new Printer();
5924 StyledTextPrintOptions options = new StyledTextPrintOptions(); 6064 StyledTextPrintOptions options = new StyledTextPrintOptions();
5925 options.printTextForeground = true; 6065 options.printTextForeground = true;
5926 options.printTextBackground = true; 6066 options.printTextBackground = true;
5927 options.printTextFontStyle = true; 6067 options.printTextFontStyle = true;
5928 options.printLineBackground = true; 6068 options.printLineBackground = true;
5929 new Printing(this, printer, options).run(); 6069 (new Printing(this, printer, options)).run();
5930 printer.dispose(); 6070 printer.dispose();
5931 } 6071 }
5932 /** 6072 /**
5933 * Returns a runnable that will print the widget's text 6073 * Returns a runnable that will print the widget's text
5934 * to the specified printer. 6074 * to the specified printer.
5935 * <p> 6075 * <p>
5936 * The runnable may be run in a non-UI thread. 6076 * The runnable may be run in a non-UI thread.
5937 * </p> 6077 * </p>
5938 * 6078 *
5939 * @param printer the printer to print to 6079 * @param printer the printer to print to
6080 *
6081 * @return a <code>Runnable</code> for printing the receiver's text
6082 *
5940 * @exception DWTException <ul> 6083 * @exception DWTException <ul>
5941 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6084 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
5942 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6085 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
5943 * </ul> 6086 * </ul>
5944 * @exception IllegalArgumentException <ul> 6087 * @exception IllegalArgumentException <ul>
5945 * <li>ERROR_NULL_ARGUMENT when printer is null</li> 6088 * <li>ERROR_NULL_ARGUMENT when printer is null</li>
5946 * </ul> 6089 * </ul>
5947 */ 6090 */
5948 public Runnable print(Printer printer) { 6091 public Runnable print(Printer printer) {
5949 checkWidget(); 6092 checkWidget();
5950 if (printer is null) { 6093 if (printer is null) {
5951 DWT.error(DWT.ERROR_NULL_ARGUMENT); 6094 DWT.error(DWT.ERROR_NULL_ARGUMENT);
5952 } 6095 }
5953 StyledTextPrintOptions options = new StyledTextPrintOptions(); 6096 StyledTextPrintOptions options = new StyledTextPrintOptions();
5954 options.printTextForeground = true; 6097 options.printTextForeground = true;
5955 options.printTextBackground = true; 6098 options.printTextBackground = true;
5956 options.printTextFontStyle = true; 6099 options.printTextFontStyle = true;
5957 options.printLineBackground = true; 6100 options.printLineBackground = true;
5958 return print(printer, options); 6101 return print(printer, options);
5959 } 6102 }
5960 /** 6103 /**
5961 * Returns a runnable that will print the widget's text 6104 * Returns a runnable that will print the widget's text
5962 * to the specified printer. 6105 * to the specified printer.
5963 * <p> 6106 * <p>
5964 * The runnable may be run in a non-UI thread. 6107 * The runnable may be run in a non-UI thread.
5965 * </p> 6108 * </p>
5966 * 6109 *
5967 * @param printer the printer to print to 6110 * @param printer the printer to print to
5968 * @param options print options to use during printing 6111 * @param options print options to use during printing
6112 *
6113 * @return a <code>Runnable</code> for printing the receiver's text
6114 *
5969 * @exception DWTException <ul> 6115 * @exception DWTException <ul>
5970 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6116 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
5971 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6117 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
5972 * </ul> 6118 * </ul>
5973 * @exception IllegalArgumentException <ul> 6119 * @exception IllegalArgumentException <ul>
5986 * Causes the entire bounds of the receiver to be marked 6132 * Causes the entire bounds of the receiver to be marked
5987 * as needing to be redrawn. The next time a paint request 6133 * as needing to be redrawn. The next time a paint request
5988 * is processed, the control will be completely painted. 6134 * is processed, the control will be completely painted.
5989 * <p> 6135 * <p>
5990 * Recalculates the content width for all lines in the bounds. 6136 * Recalculates the content width for all lines in the bounds.
5991 * When a <code>LineStyleListener</code> is used a redraw call 6137 * When a <code>LineStyleListener</code> is used a redraw call
5992 * is the only notification to the widget that styles have changed 6138 * is the only notification to the widget that styles have changed
5993 * and that the content width may have changed. 6139 * and that the content width may have changed.
5994 * </p> 6140 * </p>
5995 * 6141 *
5996 * @exception DWTException <ul> 6142 * @exception DWTException <ul>
5997 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6143 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
5998 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6144 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
5999 * </ul> 6145 * </ul>
6000 * 6146 *
6001 * @see Control#update() 6147 * @see Control#update()
6002 */ 6148 */
6003 public void redraw() { 6149 public override void redraw() {
6004 super.redraw(); 6150 super.redraw();
6005 int itemCount = getPartialBottomIndex() - topIndex + 1; 6151 int itemCount = getPartialBottomIndex() - topIndex + 1;
6006 renderer.reset(topIndex, itemCount); 6152 renderer.reset(topIndex, itemCount);
6007 renderer.calculate(topIndex, itemCount); 6153 renderer.calculate(topIndex, itemCount);
6008 setScrollBars(false); 6154 setScrollBars(false);
6009 } 6155 }
6010 /** 6156 /**
6011 * Causes the rectangular area of the receiver specified by 6157 * Causes the rectangular area of the receiver specified by
6012 * the arguments to be marked as needing to be redrawn. 6158 * the arguments to be marked as needing to be redrawn.
6013 * The next time a paint request is processed, that area of 6159 * The next time a paint request is processed, that area of
6014 * the receiver will be painted. If the <code>all</code> flag 6160 * the receiver will be painted. If the <code>all</code> flag
6015 * is <code>true</code>, any children of the receiver which 6161 * is <code>true</code>, any children of the receiver which
6016 * intersect with the specified area will also paint their 6162 * intersect with the specified area will also paint their
6017 * intersecting areas. If the <code>all</code> flag is 6163 * intersecting areas. If the <code>all</code> flag is
6018 * <code>false</code>, the children will not be painted. 6164 * <code>false</code>, the children will not be painted.
6019 * <p> 6165 * <p>
6020 * Marks the content width of all lines in the specified rectangle 6166 * Marks the content width of all lines in the specified rectangle
6021 * as unknown. Recalculates the content width of all visible lines. 6167 * as unknown. Recalculates the content width of all visible lines.
6022 * When a <code>LineStyleListener</code> is used a redraw call 6168 * When a <code>LineStyleListener</code> is used a redraw call
6023 * is the only notification to the widget that styles have changed 6169 * is the only notification to the widget that styles have changed
6024 * and that the content width may have changed. 6170 * and that the content width may have changed.
6025 * </p> 6171 * </p>
6026 * 6172 *
6027 * @param x the x coordinate of the area to draw 6173 * @param x the x coordinate of the area to draw
6028 * @param y the y coordinate of the area to draw 6174 * @param y the y coordinate of the area to draw
6035 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6181 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
6036 * </ul> 6182 * </ul>
6037 * 6183 *
6038 * @see Control#update() 6184 * @see Control#update()
6039 */ 6185 */
6040 public void redraw(int x, int y, int width, int height, bool all) { 6186 public override void redraw(int x, int y, int width, int height, bool all) {
6041 super.redraw(x, y, width, height, all); 6187 super.redraw(x, y, width, height, all);
6042 if (height > 0) { 6188 if (height > 0) {
6043 int firstLine = getLineIndex(y); 6189 int firstLine = getLineIndex(y);
6044 int lastLine = getLineIndex(y + height); 6190 int lastLine = getLineIndex(y + height);
6045 resetCache(firstLine, lastLine - firstLine + 1); 6191 resetCache(firstLine, lastLine - firstLine + 1);
6046 } 6192 }
6047 } 6193 }
6048 void redrawLines(int startLine, int lineCount) { 6194 void redrawLines(int startLine, int lineCount) {
6049 // do nothing if redraw range is completely invisible 6195 // do nothing if redraw range is completely invisible
6050 int partialBottomIndex = getPartialBottomIndex(); 6196 int partialBottomIndex = getPartialBottomIndex();
6051 if (startLine > partialBottomIndex || startLine + lineCount - 1 < topIndex) { 6197 if (startLine > partialBottomIndex || startLine + lineCount - 1 < topIndex) {
6052 return; 6198 return;
6053 } 6199 }
6054 // only redraw visible lines 6200 // only redraw visible lines
6060 lineCount = partialBottomIndex - startLine + 1; 6206 lineCount = partialBottomIndex - startLine + 1;
6061 } 6207 }
6062 startLine -= topIndex; 6208 startLine -= topIndex;
6063 int redrawTop = getLinePixel(startLine); 6209 int redrawTop = getLinePixel(startLine);
6064 int redrawBottom = getLinePixel(startLine + lineCount); 6210 int redrawBottom = getLinePixel(startLine + lineCount);
6065 int redrawWidth = clientAreaWidth - leftMargin - rightMargin; 6211 int redrawWidth = clientAreaWidth - leftMargin - rightMargin;
6066 super.redraw(leftMargin, redrawTop, redrawWidth, redrawBottom - redrawTop, true); 6212 super.redraw(leftMargin, redrawTop, redrawWidth, redrawBottom - redrawTop, true);
6067 } 6213 }
6068 void redrawLinesBullet (int[] redrawLines) { 6214 void redrawLinesBullet (int[] redrawLines) {
6069 if (redrawLines is null) return; 6215 if (redrawLines is null) return;
6070 int topIndex = getPartialTopIndex(); 6216 int topIndex = getPartialTopIndex();
6083 int height = renderer.getLineHeight(lineIndex); 6229 int height = renderer.getLineHeight(lineIndex);
6084 int y = getLinePixel(lineIndex); 6230 int y = getLinePixel(lineIndex);
6085 super.redraw(0, y, width, height, false); 6231 super.redraw(0, y, width, height, false);
6086 } 6232 }
6087 } 6233 }
6088 /** 6234 /**
6089 * Redraws the specified text range. 6235 * Redraws the specified text range.
6090 * 6236 *
6091 * @param start offset of the first character to redraw 6237 * @param start offset of the first character to redraw
6092 * @param length number of characters to redraw 6238 * @param length number of characters to redraw
6093 * @param clearBackground true if the background should be cleared as 6239 * @param clearBackground true if the background should be cleared as
6094 * part of the redraw operation. If true, the entire redraw range will 6240 * part of the redraw operation. If true, the entire redraw range will
6095 * be cleared before anything is redrawn. If the redraw range includes 6241 * be cleared before anything is redrawn. If the redraw range includes
6096 * the last character of a line (i.e., the entire line is redrawn) the 6242 * the last character of a line (i.e., the entire line is redrawn) the
6097 * line is cleared all the way to the right border of the widget. 6243 * line is cleared all the way to the right border of the widget.
6098 * The redraw operation will be faster and smoother if clearBackground 6244 * The redraw operation will be faster and smoother if clearBackground
6099 * is set to false. Whether or not the flag can be set to false depends 6245 * is set to false. Whether or not the flag can be set to false depends
6100 * on the type of change that has taken place. If font styles or 6246 * on the type of change that has taken place. If font styles or
6101 * background colors for the redraw range have changed, clearBackground 6247 * background colors for the redraw range have changed, clearBackground
6102 * should be set to true. If only foreground colors have changed for 6248 * should be set to true. If only foreground colors have changed for
6103 * the redraw range, clearBackground can be set to false. 6249 * the redraw range, clearBackground can be set to false.
6104 * @exception DWTException <ul> 6250 * @exception DWTException <ul>
6105 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6251 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
6106 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6252 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
6107 * </ul> 6253 * </ul>
6108 * @exception IllegalArgumentException <ul> 6254 * @exception IllegalArgumentException <ul>
6109 * <li>ERROR_INVALID_RANGE when start and/or end are outside the widget content</li> 6255 * <li>ERROR_INVALID_RANGE when start and/or end are outside the widget content</li>
6110 * </ul> 6256 * </ul>
6111 */ 6257 */
6112 public void redrawRange(int start, int length, bool clearBackground) { 6258 public void redrawRange(int start, int length, bool clearBackground) {
6113 checkWidget(); 6259 checkWidget();
6114 int end = start + length; 6260 int end = start + length;
6122 internalRedrawRange(start, length); 6268 internalRedrawRange(start, length);
6123 } 6269 }
6124 /** 6270 /**
6125 * Removes the specified bidirectional segment listener. 6271 * Removes the specified bidirectional segment listener.
6126 * 6272 *
6127 * @param listener the listener 6273 * @param listener the listener which should no longer be notified
6274 *
6128 * @exception DWTException <ul> 6275 * @exception DWTException <ul>
6129 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6276 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
6130 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6277 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
6131 * </ul> 6278 * </ul>
6132 * @exception IllegalArgumentException <ul> 6279 * @exception IllegalArgumentException <ul>
6133 * <li>ERROR_NULL_ARGUMENT when listener is null</li> 6280 * <li>ERROR_NULL_ARGUMENT when listener is null</li>
6134 * </ul> 6281 * </ul>
6282 *
6135 * @since 2.0 6283 * @since 2.0
6136 */ 6284 */
6137 public void removeBidiSegmentListener(BidiSegmentListener listener) { 6285 public void removeBidiSegmentListener(BidiSegmentListener listener) {
6138 checkWidget(); 6286 checkWidget();
6139 if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); 6287 if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
6140 removeListener(LineGetSegments, listener); 6288 removeListener(LineGetSegments, listener);
6141 } 6289 }
6142 /** 6290 /**
6143 * Removes the specified extended modify listener. 6291 * Removes the specified extended modify listener.
6144 * 6292 *
6145 * @param extendedModifyListener the listener 6293 * @param extendedModifyListener the listener which should no longer be notified
6294 *
6146 * @exception DWTException <ul> 6295 * @exception DWTException <ul>
6147 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6296 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
6148 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6297 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
6149 * </ul> 6298 * </ul>
6150 * @exception IllegalArgumentException <ul> 6299 * @exception IllegalArgumentException <ul>
6152 * </ul> 6301 * </ul>
6153 */ 6302 */
6154 public void removeExtendedModifyListener(ExtendedModifyListener extendedModifyListener) { 6303 public void removeExtendedModifyListener(ExtendedModifyListener extendedModifyListener) {
6155 checkWidget(); 6304 checkWidget();
6156 if (extendedModifyListener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); 6305 if (extendedModifyListener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
6157 removeListener(ExtendedModify, extendedModifyListener); 6306 removeListener(ExtendedModify, extendedModifyListener);
6158 } 6307 }
6159 /** 6308 /**
6160 * Removes the specified line background listener. 6309 * Removes the specified line background listener.
6161 * 6310 *
6162 * @param listener the listener 6311 * @param listener the listener which should no longer be notified
6312 *
6163 * @exception DWTException <ul> 6313 * @exception DWTException <ul>
6164 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6314 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
6165 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6315 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
6166 * </ul> 6316 * </ul>
6167 * @exception IllegalArgumentException <ul> 6317 * @exception IllegalArgumentException <ul>
6174 removeListener(LineGetBackground, listener); 6324 removeListener(LineGetBackground, listener);
6175 } 6325 }
6176 /** 6326 /**
6177 * Removes the specified line style listener. 6327 * Removes the specified line style listener.
6178 * 6328 *
6179 * @param listener the listener 6329 * @param listener the listener which should no longer be notified
6330 *
6180 * @exception DWTException <ul> 6331 * @exception DWTException <ul>
6181 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6332 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
6182 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6333 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
6183 * </ul> 6334 * </ul>
6184 * @exception IllegalArgumentException <ul> 6335 * @exception IllegalArgumentException <ul>
6191 removeListener(LineGetStyle, listener); 6342 removeListener(LineGetStyle, listener);
6192 } 6343 }
6193 /** 6344 /**
6194 * Removes the specified modify listener. 6345 * Removes the specified modify listener.
6195 * 6346 *
6196 * @param modifyListener the listener 6347 * @param modifyListener the listener which should no longer be notified
6348 *
6197 * @exception DWTException <ul> 6349 * @exception DWTException <ul>
6198 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6350 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
6199 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6351 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
6200 * </ul> 6352 * </ul>
6201 * @exception IllegalArgumentException <ul> 6353 * @exception IllegalArgumentException <ul>
6208 removeListener(DWT.Modify, modifyListener); 6360 removeListener(DWT.Modify, modifyListener);
6209 } 6361 }
6210 /** 6362 /**
6211 * Removes the specified listener. 6363 * Removes the specified listener.
6212 * 6364 *
6213 * @param listener the listener 6365 * @param listener the listener which should no longer be notified
6366 *
6214 * @exception DWTException <ul> 6367 * @exception DWTException <ul>
6215 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6368 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
6216 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6369 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
6217 * </ul> 6370 * </ul>
6218 * @exception IllegalArgumentException <ul> 6371 * @exception IllegalArgumentException <ul>
6248 removeListener(DWT.Selection, listener); 6401 removeListener(DWT.Selection, listener);
6249 } 6402 }
6250 /** 6403 /**
6251 * Removes the specified verify listener. 6404 * Removes the specified verify listener.
6252 * 6405 *
6253 * @param verifyListener the listener 6406 * @param verifyListener the listener which should no longer be notified
6407 *
6254 * @exception DWTException <ul> 6408 * @exception DWTException <ul>
6255 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6409 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
6256 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6410 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
6257 * </ul> 6411 * </ul>
6258 * @exception IllegalArgumentException <ul> 6412 * @exception IllegalArgumentException <ul>
6265 removeListener(DWT.Verify, verifyListener); 6419 removeListener(DWT.Verify, verifyListener);
6266 } 6420 }
6267 /** 6421 /**
6268 * Removes the specified key verify listener. 6422 * Removes the specified key verify listener.
6269 * 6423 *
6270 * @param listener the listener 6424 * @param listener the listener which should no longer be notified
6425 *
6271 * @exception DWTException <ul> 6426 * @exception DWTException <ul>
6272 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6427 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
6273 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6428 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
6274 * </ul> 6429 * </ul>
6275 * @exception IllegalArgumentException <ul> 6430 * @exception IllegalArgumentException <ul>
6281 removeListener(VerifyKey, listener); 6436 removeListener(VerifyKey, listener);
6282 } 6437 }
6283 /** 6438 /**
6284 * Removes the specified word movement listener. 6439 * Removes the specified word movement listener.
6285 * 6440 *
6286 * @param listener the listener 6441 * @param listener the listener which should no longer be notified
6442 *
6287 * @exception DWTException <ul> 6443 * @exception DWTException <ul>
6288 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6444 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
6289 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6445 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
6290 * </ul> 6446 * </ul>
6291 * @exception IllegalArgumentException <ul> 6447 * @exception IllegalArgumentException <ul>
6292 * <li>ERROR_NULL_ARGUMENT when listener is null</li> 6448 * <li>ERROR_NULL_ARGUMENT when listener is null</li>
6293 * </ul> 6449 * </ul>
6294 * 6450 *
6295 * @see MovementEvent 6451 * @see MovementEvent
6296 * @see MovementListener 6452 * @see MovementListener
6297 * @see #addWordMovementListener 6453 * @see #addWordMovementListener
6298 * 6454 *
6299 * @since 3.3 6455 * @since 3.3
6300 */ 6456 */
6301 6457
6302 public void removeWordMovementListener(MovementListener listener) { 6458 public void removeWordMovementListener(MovementListener listener) {
6303 checkWidget(); 6459 checkWidget();
6304 if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); 6460 if (listener is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
6305 removeListener(WordNext, listener); 6461 removeListener(WordNext, listener);
6306 removeListener(WordPrevious, listener); 6462 removeListener(WordPrevious, listener);
6307 } 6463 }
6308 /** 6464 /**
6309 * Replaces the styles in the given range with new styles. This method 6465 * Replaces the styles in the given range with new styles. This method
6310 * effectively deletes the styles in the given range and then adds the 6466 * effectively deletes the styles in the given range and then adds the
6311 * the new styles. 6467 * the new styles.
6312 * <p> 6468 * <p>
6313 * Note: Because a StyleRange includes the start and length, the 6469 * Note: Because a StyleRange includes the start and length, the
6314 * same instance cannot occur multiple times in the array of styles. 6470 * same instance cannot occur multiple times in the array of styles.
6315 * If the same style attributes, such as font and color, occur in 6471 * If the same style attributes, such as font and color, occur in
6316 * multiple StyleRanges, <code>setStyleRanges(int, int, int[], StyleRange[])</code> 6472 * multiple StyleRanges, <code>setStyleRanges(int, int, int[], StyleRange[])</code>
6317 * can be used to share styles and reduce memory usage. 6473 * can be used to share styles and reduce memory usage.
6318 * </p><p> 6474 * </p><p>
6319 * Should not be called if a LineStyleListener has been set since the 6475 * Should not be called if a LineStyleListener has been set since the
6320 * listener maintains the styles. 6476 * listener maintains the styles.
6321 * </p> 6477 * </p>
6322 * 6478 *
6323 * @param start offset of first character where styles will be deleted 6479 * @param start offset of first character where styles will be deleted
6324 * @param length length of the range to delete styles in 6480 * @param length length of the range to delete styles in
6325 * @param ranges StyleRange objects containing the new style information. 6481 * @param ranges StyleRange objects containing the new style information.
6326 * The ranges should not overlap and should be within the specified start 6482 * The ranges should not overlap and should be within the specified start
6327 * and length. The style rendering is undefined if the ranges do overlap 6483 * and length. The style rendering is undefined if the ranges do overlap
6328 * or are ill-defined. Must not be null. 6484 * or are ill-defined. Must not be null.
6329 * @exception DWTException <ul> 6485 * @exception DWTException <ul>
6330 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6486 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
6331 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6487 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
6332 * </ul> 6488 * </ul>
6333 * @exception IllegalArgumentException <ul> 6489 * @exception IllegalArgumentException <ul>
6334 * <li>ERROR_INVALID_RANGE when either start or end is outside the valid range (0 <= offset <= getCharCount())</li> 6490 * <li>ERROR_INVALID_RANGE when either start or end is outside the valid range (0 <= offset <= getCharCount())</li>
6335 * <li>ERROR_NULL_ARGUMENT when ranges is null</li> 6491 * </ul>
6336 * </ul> 6492 *
6337 *
6338 * @since 2.0 6493 * @since 2.0
6339 * 6494 *
6340 * @see #setStyleRanges(int, int, int[], StyleRange[]) 6495 * @see #setStyleRanges(int, int, int[], StyleRange[])
6341 */ 6496 */
6342 public void replaceStyleRanges(int start, int length, StyleRange[] ranges) { 6497 public void replaceStyleRanges(int start, int length, StyleRange[] ranges) {
6343 checkWidget(); 6498 checkWidget();
6344 if (isListening(LineGetStyle)) return; 6499 if (isListening(LineGetStyle)) return;
6345 if (ranges is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); 6500 // DWT extension: allow null for zero length string
6501 //if (ranges is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
6346 setStyleRanges(start, length, null, ranges, false); 6502 setStyleRanges(start, length, null, ranges, false);
6347 } 6503 }
6348 /** 6504 /**
6349 * Replaces the given text range with new text. 6505 * Replaces the given text range with new text.
6350 * If the widget has the DWT.SINGLE style and "text" contains more than 6506 * If the widget has the DWT.SINGLE style and "text" contains more than
6351 * one line, only the first line is rendered but the text is stored 6507 * one line, only the first line is rendered but the text is stored
6352 * unchanged. A subsequent call to getText will return the same text 6508 * unchanged. A subsequent call to getText will return the same text
6353 * that was set. Note that only a single line of text should be set when 6509 * that was set. Note that only a single line of text should be set when
6354 * the DWT.SINGLE style is used. 6510 * the DWT.SINGLE style is used.
6355 * <p> 6511 * <p>
6356 * <b>NOTE:</b> During the replace operation the current selection is 6512 * <b>NOTE:</b> During the replace operation the current selection is
6357 * changed as follows: 6513 * changed as follows:
6358 * <ul> 6514 * <ul>
6359 * <li>selection before replaced text: selection unchanged 6515 * <li>selection before replaced text: selection unchanged
6360 * <li>selection after replaced text: adjust the selection so that same text 6516 * <li>selection after replaced text: adjust the selection so that same text
6361 * remains selected 6517 * remains selected
6362 * <li>selection intersects replaced text: selection is cleared and caret 6518 * <li>selection intersects replaced text: selection is cleared and caret
6363 * is placed after inserted text 6519 * is placed after inserted text
6364 * </ul> 6520 * </ul>
6365 * </p> 6521 * </p>
6370 * @exception DWTException <ul> 6526 * @exception DWTException <ul>
6371 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6527 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
6372 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6528 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
6373 * </ul> 6529 * </ul>
6374 * @exception IllegalArgumentException <ul> 6530 * @exception IllegalArgumentException <ul>
6375 * <li>ERROR_INVALID_RANGE when either start or end is outside the valid range (0 <= offset <= getCharCount())</li> 6531 * <li>ERROR_INVALID_RANGE when either start or end is outside the valid range (0 <= offset <= getCharCount())</li>
6376 * <li>ERROR_INVALID_ARGUMENT when either start or end is inside a multi byte line delimiter. 6532 * <li>ERROR_INVALID_ARGUMENT when either start or end is inside a multi byte line delimiter.
6377 * Splitting a line delimiter for example by inserting text in between the CR and LF and deleting part of a line delimiter is not supported</li> 6533 * Splitting a line delimiter for example by inserting text in between the CR and LF and deleting part of a line delimiter is not supported</li>
6378 * <li>ERROR_NULL_ARGUMENT when String is null</li>
6379 * </ul> 6534 * </ul>
6380 */ 6535 */
6381 public void replaceTextRange(int start, int length, String text) { 6536 public void replaceTextRange(int start, int length, String text) {
6382 checkWidget(); 6537 checkWidget();
6383 if (text is null) { 6538 // DWT extension: allow null for zero length string
6384 DWT.error(DWT.ERROR_NULL_ARGUMENT); 6539 // if (text is null) {
6385 } 6540 // DWT.error(DWT.ERROR_NULL_ARGUMENT);
6541 // }
6386 int contentLength = getCharCount(); 6542 int contentLength = getCharCount();
6387 int end = start + length; 6543 int end = start + length;
6388 if (start > end || start < 0 || end > contentLength) { 6544 if (start > end || start < 0 || end > contentLength) {
6389 DWT.error(DWT.ERROR_INVALID_RANGE); 6545 DWT.error(DWT.ERROR_INVALID_RANGE);
6390 } 6546 }
6403 ScrollBar horizontalBar = getHorizontalBar(); 6559 ScrollBar horizontalBar = getHorizontalBar();
6404 caretOffset = 0; 6560 caretOffset = 0;
6405 topIndex = 0; 6561 topIndex = 0;
6406 topIndexY = 0; 6562 topIndexY = 0;
6407 verticalScrollOffset = 0; 6563 verticalScrollOffset = 0;
6408 horizontalScrollOffset = 0; 6564 horizontalScrollOffset = 0;
6409 resetSelection(); 6565 resetSelection();
6410 renderer.setContent(content); 6566 renderer.setContent(content);
6411 if (verticalBar !is null) { 6567 if (verticalBar !is null) {
6412 verticalBar.setSelection(0); 6568 verticalBar.setSelection(0);
6413 } 6569 }
6414 if (horizontalBar !is null) { 6570 if (horizontalBar !is null) {
6415 horizontalBar.setSelection(0); 6571 horizontalBar.setSelection(0);
6416 } 6572 }
6417 resetCache(0, 0); 6573 resetCache(0, 0);
6418 setCaretLocation(); 6574 setCaretLocation();
6419 super.redraw(); 6575 super.redraw();
6420 } 6576 }
6439 void resetSelection() { 6595 void resetSelection() {
6440 selection.x = selection.y = caretOffset; 6596 selection.x = selection.y = caretOffset;
6441 selectionAnchor = -1; 6597 selectionAnchor = -1;
6442 } 6598 }
6443 6599
6444 public void scroll(int destX, int destY, int x, int y, int width, int height, bool all) { 6600 public override void scroll(int destX, int destY, int x, int y, int width, int height, bool all) {
6445 super.scroll(destX, destY, x, y, width, height, false); 6601 super.scroll(destX, destY, x, y, width, height, false);
6446 if (all) { 6602 if (all) {
6447 int deltaX = destX - x, deltaY = destY - y; 6603 int deltaX = destX - x, deltaY = destY - y;
6448 Control[] children = getChildren(); 6604 Control[] children = getChildren();
6449 for (int i=0; i<children.length; i++) { 6605 for (int i=0; i<children.length; i++) {
6457 /** 6613 /**
6458 * Scrolls the widget horizontally. 6614 * Scrolls the widget horizontally.
6459 * 6615 *
6460 * @param pixels number of pixels to scroll, > 0 = scroll left, 6616 * @param pixels number of pixels to scroll, > 0 = scroll left,
6461 * < 0 scroll right 6617 * < 0 scroll right
6462 * @param adjustScrollBar 6618 * @param adjustScrollBar
6463 * true= the scroll thumb will be moved to reflect the new scroll offset. 6619 * true= the scroll thumb will be moved to reflect the new scroll offset.
6464 * false = the scroll thumb will not be moved 6620 * false = the scroll thumb will not be moved
6465 * @return 6621 * @return
6466 * true=the widget was scrolled 6622 * true=the widget was scrolled
6467 * false=the widget was not scrolled, the given offset is not valid. 6623 * false=the widget was not scrolled, the given offset is not valid.
6468 */ 6624 */
6469 bool scrollHorizontal(int pixels, bool adjustScrollBar) { 6625 bool scrollHorizontal(int pixels, bool adjustScrollBar) {
6470 if (pixels is 0) { 6626 if (pixels is 0) {
6471 return false; 6627 return false;
6500 } 6656 }
6501 /** 6657 /**
6502 * Scrolls the widget vertically. 6658 * Scrolls the widget vertically.
6503 * 6659 *
6504 * @param pixel the new vertical scroll offset 6660 * @param pixel the new vertical scroll offset
6505 * @param adjustScrollBar 6661 * @param adjustScrollBar
6506 * true= the scroll thumb will be moved to reflect the new scroll offset. 6662 * true= the scroll thumb will be moved to reflect the new scroll offset.
6507 * false = the scroll thumb will not be moved 6663 * false = the scroll thumb will not be moved
6508 * @return 6664 * @return
6509 * true=the widget was scrolled 6665 * true=the widget was scrolled
6510 * false=the widget was not scrolled 6666 * false=the widget was not scrolled
6511 */ 6667 */
6512 bool scrollVertical(int pixels, bool adjustScrollBar) { 6668 bool scrollVertical(int pixels, bool adjustScrollBar) {
6513 if (pixels is 0) { 6669 if (pixels is 0) {
6514 return false; 6670 return false;
6572 } 6728 }
6573 if ((clientAreaHeight - bottomMargin < destY + scrollHeight) && (clientAreaHeight > destY)) { 6729 if ((clientAreaHeight - bottomMargin < destY + scrollHeight) && (clientAreaHeight > destY)) {
6574 super.redraw(leftMargin, clientAreaHeight - bottomMargin, scrollWidth, bottomMargin, false); 6730 super.redraw(leftMargin, clientAreaHeight - bottomMargin, scrollWidth, bottomMargin, false);
6575 } 6731 }
6576 } 6732 }
6577 /** 6733 /**
6578 * Selects all the text. 6734 * Selects all the text.
6579 * 6735 *
6580 * @exception DWTException <ul> 6736 * @exception DWTException <ul>
6581 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6737 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
6582 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6738 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
6587 setSelection(0, Math.max(getCharCount(),0)); 6743 setSelection(0, Math.max(getCharCount(),0));
6588 } 6744 }
6589 /** 6745 /**
6590 * Replaces/inserts text as defined by the event. 6746 * Replaces/inserts text as defined by the event.
6591 * 6747 *
6592 * @param event the text change event. 6748 * @param event the text change event.
6593 * <ul> 6749 * <ul>
6594 * <li>event.start - the replace start offset</li> 6750 * <li>event.start - the replace start offset</li>
6595 * <li>event.end - the replace end offset</li> 6751 * <li>event.end - the replace end offset</li>
6596 * <li>event.text - the new text</li> 6752 * <li>event.text - the new text</li>
6597 * </ul> 6753 * </ul>
6600 if (editable) { 6756 if (editable) {
6601 modifyContent(event, true); 6757 modifyContent(event, true);
6602 } 6758 }
6603 } 6759 }
6604 /** 6760 /**
6605 * Returns a StyledTextEvent that can be used to request data such 6761 * Returns a StyledTextEvent that can be used to request data such
6606 * as styles and background color for a line. 6762 * as styles and background color for a line.
6607 * <p> 6763 * <p>
6608 * The specified line may be a visual (wrapped) line if in word 6764 * The specified line may be a visual (wrapped) line if in word
6609 * wrap mode. The returned object will always be for a logical 6765 * wrap mode. The returned object will always be for a logical
6610 * (unwrapped) line. 6766 * (unwrapped) line.
6611 * </p> 6767 * </p>
6612 * 6768 *
6613 * @param lineOffset offset of the line. This may be the offset of 6769 * @param lineOffset offset of the line. This may be the offset of
6614 * a visual line if the widget is in word wrap mode. 6770 * a visual line if the widget is in word wrap mode.
6615 * @param line line text. This may be the text of a visual line if 6771 * @param line line text. This may be the text of a visual line if
6616 * the widget is in word wrap mode. 6772 * the widget is in word wrap mode.
6617 * @return StyledTextEvent that can be used to request line data 6773 * @return StyledTextEvent that can be used to request line data
6618 * for the given line. 6774 * for the given line.
6619 */ 6775 */
6620 StyledTextEvent sendLineEvent(int eventType, int lineOffset, String line) { 6776 StyledTextEvent sendLineEvent(int eventType, int lineOffset, String line) {
6621 StyledTextEvent event = null; 6777 StyledTextEvent event = null;
6622 if (isListening(eventType)) { 6778 if (isListening(eventType)) {
6630 } 6786 }
6631 return event; 6787 return event;
6632 } 6788 }
6633 void sendModifyEvent(Event event) { 6789 void sendModifyEvent(Event event) {
6634 Accessible accessible = getAccessible(); 6790 Accessible accessible = getAccessible();
6635 if (event.text.length() is 0) { 6791 if (event.text.length is 0) {
6636 accessible.textChanged(ACC.TEXT_DELETE, event.start, event.end - event.start); 6792 accessible.textChanged(ACC.TEXT_DELETE, event.start, event.end - event.start);
6637 } else { 6793 } else {
6638 if (event.start is event.end) { 6794 if (event.start is event.end) {
6639 accessible.textChanged(ACC.TEXT_INSERT, event.start, event.text.length()); 6795 accessible.textChanged(ACC.TEXT_INSERT, event.start, event.text.length);
6640 } else { 6796 } else {
6641 accessible.textChanged(ACC.TEXT_DELETE, event.start, event.end - event.start); 6797 accessible.textChanged(ACC.TEXT_DELETE, event.start, event.end - event.start);
6642 accessible.textChanged(ACC.TEXT_INSERT, event.start, event.text.length()); 6798 accessible.textChanged(ACC.TEXT_INSERT, event.start, event.text.length);
6643 } 6799 }
6644 } 6800 }
6645 notifyListeners(DWT.Modify, event); 6801 notifyListeners(DWT.Modify, event);
6646 } 6802 }
6647 /** 6803 /**
6679 return offset; 6835 return offset;
6680 } 6836 }
6681 return newOffset; 6837 return newOffset;
6682 } 6838 }
6683 /** 6839 /**
6684 * Sets the alignment of the widget. The argument should be one of <code>DWT.LEFT</code>, 6840 * Sets the alignment of the widget. The argument should be one of <code>DWT.LEFT</code>,
6685 * <code>DWT.CENTER</code> or <code>DWT.RIGHT</code>. The alignment applies for all lines. 6841 * <code>DWT.CENTER</code> or <code>DWT.RIGHT</code>. The alignment applies for all lines.
6686 * </p><p> 6842 * </p><p>
6687 * Note that if <code>DWT.MULTI</code> is set, then <code>DWT.WRAP</code> must also be set 6843 * Note that if <code>DWT.MULTI</code> is set, then <code>DWT.WRAP</code> must also be set
6688 * in order to stabilize the right edge before setting alignment. 6844 * in order to stabilize the right edge before setting alignment.
6689 * </p> 6845 * </p>
6690 * 6846 *
6691 * @param alignment the new alignment 6847 * @param alignment the new alignment
6692 * 6848 *
6693 * @exception DWTException <ul> 6849 * @exception DWTException <ul>
6694 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6850 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
6695 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6851 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
6696 * </ul> 6852 * </ul>
6697 * 6853 *
6698 * @see #setLineAlignment(int, int, int) 6854 * @see #setLineAlignment(int, int, int)
6699 * 6855 *
6700 * @since 3.2 6856 * @since 3.2
6701 */ 6857 */
6702 public void setAlignment(int alignment) { 6858 public void setAlignment(int alignment) {
6703 checkWidget(); 6859 checkWidget();
6704 alignment &= (DWT.LEFT | DWT.RIGHT | DWT.CENTER); 6860 alignment &= (DWT.LEFT | DWT.RIGHT | DWT.CENTER);
6709 super.redraw(); 6865 super.redraw();
6710 } 6866 }
6711 /** 6867 /**
6712 * @see Control#setBackground(Color) 6868 * @see Control#setBackground(Color)
6713 */ 6869 */
6714 public void setBackground(Color color) { 6870 public override void setBackground(Color color) {
6715 checkWidget(); 6871 checkWidget();
6716 background = color; 6872 background = color;
6717 super.setBackground(color); 6873 super.setBackground(color);
6718 super.redraw(); 6874 super.redraw();
6719 } 6875 }
6720 /** 6876 /**
6721 * Sets the receiver's caret. Set the caret's height and location. 6877 * Sets the receiver's caret. Set the caret's height and location.
6722 * 6878 *
6723 * </p> 6879 * </p>
6724 * @param caret the new caret for the receiver 6880 * @param caret the new caret for the receiver
6725 * 6881 *
6726 * @exception DWTException <ul> 6882 * @exception DWTException <ul>
6727 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6883 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
6728 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6884 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
6729 * </ul> 6885 * </ul>
6730 */ 6886 */
6731 public void setCaret(Caret caret) { 6887 public override void setCaret(Caret caret) {
6732 checkWidget (); 6888 checkWidget ();
6733 super.setCaret(caret); 6889 super.setCaret(caret);
6734 caretDirection = DWT.NULL; 6890 caretDirection = DWT.NULL;
6735 if (caret !is null) { 6891 if (caret !is null) {
6736 setCaretLocation(); 6892 setCaretLocation();
6744 * @param mode the new coloring mode 6900 * @param mode the new coloring mode
6745 * @exception DWTException <ul> 6901 * @exception DWTException <ul>
6746 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6902 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
6747 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6903 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
6748 * </ul> 6904 * </ul>
6749 * 6905 *
6750 * @deprecated use BidiSegmentListener instead. 6906 * @deprecated use BidiSegmentListener instead.
6751 */ 6907 */
6752 public void setBidiColoring(bool mode) { 6908 public void setBidiColoring(bool mode) {
6753 checkWidget(); 6909 checkWidget();
6754 bidiColoring = mode; 6910 bidiColoring = mode;
6816 * @exception DWTException <ul> 6972 * @exception DWTException <ul>
6817 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 6973 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
6818 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 6974 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
6819 * </ul> 6975 * </ul>
6820 * @exception IllegalArgumentException <ul> 6976 * @exception IllegalArgumentException <ul>
6821 * <li>ERROR_INVALID_ARGUMENT when either the start or the end of the selection range is inside a 6977 * <li>ERROR_INVALID_ARGUMENT when either the start or the end of the selection range is inside a
6822 * multi byte line delimiter (and thus neither clearly in front of or after the line delimiter) 6978 * multi byte line delimiter (and thus neither clearly in front of or after the line delimiter)
6823 * </ul> 6979 * </ul>
6824 */ 6980 */
6825 public void setCaretOffset(int offset) { 6981 public void setCaretOffset(int offset) {
6826 checkWidget(); 6982 checkWidget();
6830 caretOffset = 0; 6986 caretOffset = 0;
6831 } else if (offset > length) { 6987 } else if (offset > length) {
6832 caretOffset = length; 6988 caretOffset = length;
6833 } else { 6989 } else {
6834 if (isLineDelimiter(offset)) { 6990 if (isLineDelimiter(offset)) {
6835 // offset is inside a multi byte line delimiter. This is an 6991 // offset is inside a multi byte line delimiter. This is an
6836 // illegal operation and an exception is thrown. Fixes 1GDKK3R 6992 // illegal operation and an exception is thrown. Fixes 1GDKK3R
6837 DWT.error(DWT.ERROR_INVALID_ARGUMENT); 6993 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
6838 } 6994 }
6839 caretOffset = offset; 6995 caretOffset = offset;
6840 } 6996 }
6842 // clear the selection if the caret is moved. 6998 // clear the selection if the caret is moved.
6843 // don't notify listeners about the selection change. 6999 // don't notify listeners about the selection change.
6844 clearSelection(false); 7000 clearSelection(false);
6845 } 7001 }
6846 setCaretLocation(); 7002 setCaretLocation();
6847 } 7003 }
6848 /** 7004 /**
6849 * Copies the specified text range to the clipboard. The text will be placed 7005 * Copies the specified text range to the clipboard. The text will be placed
6850 * in the clipboard in plain text format and RTF format. 7006 * in the clipboard in plain text format and RTF format.
6851 * 7007 *
6852 * @param start start index of the text 7008 * @param start start index of the text
6853 * @param length length of text to place in clipboard 7009 * @param length length of text to place in clipboard
6854 * 7010 *
6855 * @exception DWTError, see Clipboard.setContents 7011 * @exception DWTError, see Clipboard.setContents
6856 * @see dwt.dnd.Clipboard#setContents 7012 * @see dwt.dnd.Clipboard#setContents
6857 */ 7013 */
6858 void setClipboardContent(int start, int length, int clipboardType) { 7014 void setClipboardContent(int start, int length, int clipboardType) {
6859 if (clipboardType is DND.SELECTION_CLIPBOARD && !(IS_MOTIF || IS_GTK)) return; 7015 if (clipboardType is DND.SELECTION_CLIPBOARD && !(IS_MOTIF || IS_GTK)) return;
6861 TextWriter plainTextWriter = new TextWriter(start, length); 7017 TextWriter plainTextWriter = new TextWriter(start, length);
6862 String plainText = getPlatformDelimitedText(plainTextWriter); 7018 String plainText = getPlatformDelimitedText(plainTextWriter);
6863 Object[] data; 7019 Object[] data;
6864 Transfer[] types; 7020 Transfer[] types;
6865 if (clipboardType is DND.SELECTION_CLIPBOARD) { 7021 if (clipboardType is DND.SELECTION_CLIPBOARD) {
6866 data = new Object[]{plainText}; 7022 data = [ cast(Object) new ArrayWrapperString(plainText) ];
6867 types = new Transfer[]{plainTextTransfer}; 7023 types = [plainTextTransfer];
6868 } else { 7024 } else {
6869 RTFTransfer rtfTransfer = RTFTransfer.getInstance(); 7025 RTFTransfer rtfTransfer = RTFTransfer.getInstance();
6870 RTFWriter rtfWriter = new RTFWriter(start, length); 7026 RTFWriter rtfWriter = new RTFWriter(start, length);
6871 String rtfText = getPlatformDelimitedText(rtfWriter); 7027 String rtfText = getPlatformDelimitedText(rtfWriter);
6872 data = new Object[]{rtfText, plainText}; 7028 data = [ cast(Object) new ArrayWrapperString(rtfText), new ArrayWrapperString(plainText) ];
6873 types = new Transfer[]{rtfTransfer, plainTextTransfer}; 7029 types = [ cast(Transfer)rtfTransfer, plainTextTransfer];
6874 } 7030 }
6875 clipboard.setContents(data, types, clipboardType); 7031 clipboard.setContents(data, types, clipboardType);
6876 } 7032 }
6877 /** 7033 /**
6878 * Sets the content implementation to use for text storage. 7034 * Sets the content implementation to use for text storage.
6885 * @exception IllegalArgumentException <ul> 7041 * @exception IllegalArgumentException <ul>
6886 * <li>ERROR_NULL_ARGUMENT when listener is null</li> 7042 * <li>ERROR_NULL_ARGUMENT when listener is null</li>
6887 * </ul> 7043 * </ul>
6888 */ 7044 */
6889 public void setContent(StyledTextContent newContent) { 7045 public void setContent(StyledTextContent newContent) {
6890 checkWidget(); 7046 checkWidget();
6891 if (newContent is null) { 7047 if (newContent is null) {
6892 DWT.error(DWT.ERROR_NULL_ARGUMENT); 7048 DWT.error(DWT.ERROR_NULL_ARGUMENT);
6893 } 7049 }
6894 if (content !is null) { 7050 if (content !is null) {
6895 content.removeTextChangeListener(textChangeListener); 7051 content.removeTextChangeListener(textChangeListener);
6898 content.addTextChangeListener(textChangeListener); 7054 content.addTextChangeListener(textChangeListener);
6899 reset(); 7055 reset();
6900 } 7056 }
6901 /** 7057 /**
6902 * Sets the receiver's cursor to the cursor specified by the 7058 * Sets the receiver's cursor to the cursor specified by the
6903 * argument. Overridden to handle the null case since the 7059 * argument. Overridden to handle the null case since the
6904 * StyledText widget uses an ibeam as its default cursor. 7060 * StyledText widget uses an ibeam as its default cursor.
6905 * 7061 *
6906 * @see Control#setCursor(Cursor) 7062 * @see Control#setCursor(Cursor)
6907 */ 7063 */
6908 public void setCursor (Cursor cursor) { 7064 public override void setCursor (Cursor cursor) {
6909 if (cursor is null) { 7065 if (cursor is null) {
6910 Display display = getDisplay(); 7066 Display display = getDisplay();
6911 super.setCursor(display.getSystemCursor(DWT.CURSOR_IBEAM)); 7067 super.setCursor(display.getSystemCursor(DWT.CURSOR_IBEAM));
6912 } else { 7068 } else {
6913 super.setCursor(cursor); 7069 super.setCursor(cursor);
6914 } 7070 }
6915 } 7071 }
6916 /** 7072 /**
6917 * Sets whether the widget : double click mouse behavior. 7073 * Sets whether the widget : double click mouse behavior.
6918 * </p> 7074 * </p>
6919 * 7075 *
6920 * @param enable if true double clicking a word selects the word, if false 7076 * @param enable if true double clicking a word selects the word, if false
6921 * double clicks have the same effect as regular mouse clicks. 7077 * double clicks have the same effect as regular mouse clicks.
6926 */ 7082 */
6927 public void setDoubleClickEnabled(bool enable) { 7083 public void setDoubleClickEnabled(bool enable) {
6928 checkWidget(); 7084 checkWidget();
6929 doubleClickEnabled = enable; 7085 doubleClickEnabled = enable;
6930 } 7086 }
6931 public void setDragDetect (bool dragDetect) { 7087 public override void setDragDetect (bool dragDetect_) {
6932 checkWidget (); 7088 checkWidget ();
6933 this.dragDetect = dragDetect; 7089 this.dragDetect_ = dragDetect_;
6934 } 7090 }
6935 /** 7091 /**
6936 * Sets whether the widget content can be edited. 7092 * Sets whether the widget content can be edited.
6937 * </p> 7093 * </p>
6938 * 7094 *
6939 * @param editable if true content can be edited, if false content can not be 7095 * @param editable if true content can be edited, if false content can not be
6940 * edited 7096 * edited
6941 * @exception DWTException <ul> 7097 * @exception DWTException <ul>
6942 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7098 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
6943 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7099 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
6944 * </ul> 7100 * </ul>
6958 * @exception DWTException <ul> 7114 * @exception DWTException <ul>
6959 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7115 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
6960 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7116 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
6961 * </ul> 7117 * </ul>
6962 */ 7118 */
6963 public void setFont(Font font) { 7119 public override void setFont(Font font) {
6964 checkWidget(); 7120 checkWidget();
6965 int oldLineHeight = renderer.getLineHeight(); 7121 int oldLineHeight = renderer.getLineHeight();
6966 super.setFont(font); 7122 super.setFont(font);
6967 renderer.setFont(getFont(), tabLength); 7123 renderer.setFont(getFont(), tabLength);
6968 // keep the same top line visible. fixes 5815 7124 // keep the same top line visible. fixes 5815
6969 if (isFixedLineHeight()) { 7125 if (isFixedLineHeight()) {
6970 int lineHeight = renderer.getLineHeight(); 7126 int lineHeight = renderer.getLineHeight();
6971 if (lineHeight !is oldLineHeight) { 7127 if (lineHeight !is oldLineHeight) {
6972 int vscroll = (getVerticalScrollOffset() * lineHeight / oldLineHeight) - getVerticalScrollOffset(); 7128 int vscroll = (getVerticalScrollOffset() * lineHeight / oldLineHeight) - getVerticalScrollOffset();
6973 scrollVertical(vscroll, true); 7129 scrollVertical(vscroll, true);
6974 } 7130 }
6975 } 7131 }
6976 resetCache(0, content.getLineCount()); 7132 resetCache(0, content.getLineCount());
6977 claimBottomFreeSpace(); 7133 claimBottomFreeSpace();
6978 calculateScrollBars(); 7134 calculateScrollBars();
6979 if (isBidiCaret()) createCaretBitmaps(); 7135 if (isBidiCaret()) createCaretBitmaps();
6980 caretDirection = DWT.NULL; 7136 caretDirection = DWT.NULL;
6981 setCaretLocation(); 7137 setCaretLocation();
6982 super.redraw(); 7138 super.redraw();
6983 } 7139 }
6984 /** 7140 public override void setForeground(Color color) {
6985 * @see dwt.widgets.Control#setForeground
6986 */
6987 public void setForeground(Color color) {
6988 checkWidget(); 7141 checkWidget();
6989 foreground = color; 7142 foreground = color;
6990 super.setForeground(getForeground()); 7143 super.setForeground(getForeground());
6991 super.redraw(); 7144 super.redraw();
6992 } 7145 }
6993 /** 7146 /**
6994 * Sets the horizontal scroll offset relative to the start of the line. 7147 * Sets the horizontal scroll offset relative to the start of the line.
6995 * Do nothing if there is no text set. 7148 * Do nothing if there is no text set.
6996 * <p> 7149 * <p>
6997 * <b>NOTE:</b> The horizontal index is reset to 0 when new text is set in the 7150 * <b>NOTE:</b> The horizontal index is reset to 0 when new text is set in the
6998 * widget. 7151 * widget.
6999 * </p> 7152 * </p>
7000 * 7153 *
7001 * @param offset horizontal scroll offset relative to the start 7154 * @param offset horizontal scroll offset relative to the start
7002 * of the line, measured in character increments starting at 0, if 7155 * of the line, measured in character increments starting at 0, if
7003 * equal to 0 the content is not scrolled, if > 0 = the content is scrolled. 7156 * equal to 0 the content is not scrolled, if > 0 = the content is scrolled.
7004 * @exception DWTException <ul> 7157 * @exception DWTException <ul>
7005 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7158 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7006 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7159 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7007 * </ul> 7160 * </ul>
7008 */ 7161 */
7009 public void setHorizontalIndex(int offset) { 7162 public void setHorizontalIndex(int offset) {
7010 checkWidget(); 7163 checkWidget();
7011 if (getCharCount() is 0) { 7164 if (getCharCount() is 0) {
7012 return; 7165 return;
7013 } 7166 }
7014 if (offset < 0) { 7167 if (offset < 0) {
7015 offset = 0; 7168 offset = 0;
7016 } 7169 }
7017 offset *= getHorizontalIncrement(); 7170 offset *= getHorizontalIncrement();
7018 // allow any value if client area width is unknown or 0. 7171 // allow any value if client area width is unknown or 0.
7019 // offset will be checked in resize handler. 7172 // offset will be checked in resize handler.
7020 // don't use isVisible since width is known even if widget 7173 // don't use isVisible since width is known even if widget
7021 // is temporarily invisible 7174 // is temporarily invisible
7022 if (clientAreaWidth > 0) { 7175 if (clientAreaWidth > 0) {
7023 int width = renderer.getWidth(); 7176 int width = renderer.getWidth();
7024 // prevent scrolling if the content fits in the client area. 7177 // prevent scrolling if the content fits in the client area.
7025 // align end of longest line with right border of client area 7178 // align end of longest line with right border of client area
7028 offset = Math.max(0, width - clientAreaWidth); 7181 offset = Math.max(0, width - clientAreaWidth);
7029 } 7182 }
7030 } 7183 }
7031 scrollHorizontal(offset - horizontalScrollOffset, true); 7184 scrollHorizontal(offset - horizontalScrollOffset, true);
7032 } 7185 }
7033 /** 7186 /**
7034 * Sets the horizontal pixel offset relative to the start of the line. 7187 * Sets the horizontal pixel offset relative to the start of the line.
7035 * Do nothing if there is no text set. 7188 * Do nothing if there is no text set.
7036 * <p> 7189 * <p>
7037 * <b>NOTE:</b> The horizontal pixel offset is reset to 0 when new text 7190 * <b>NOTE:</b> The horizontal pixel offset is reset to 0 when new text
7038 * is set in the widget. 7191 * is set in the widget.
7039 * </p> 7192 * </p>
7040 * 7193 *
7041 * @param pixel horizontal pixel offset relative to the start 7194 * @param pixel horizontal pixel offset relative to the start
7042 * of the line. 7195 * of the line.
7043 * @exception DWTException <ul> 7196 * @exception DWTException <ul>
7044 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7197 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7045 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7198 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7046 * </ul> 7199 * </ul>
7048 */ 7201 */
7049 public void setHorizontalPixel(int pixel) { 7202 public void setHorizontalPixel(int pixel) {
7050 checkWidget(); 7203 checkWidget();
7051 if (getCharCount() is 0) { 7204 if (getCharCount() is 0) {
7052 return; 7205 return;
7053 } 7206 }
7054 if (pixel < 0) { 7207 if (pixel < 0) {
7055 pixel = 0; 7208 pixel = 0;
7056 } 7209 }
7057 // allow any value if client area width is unknown or 0. 7210 // allow any value if client area width is unknown or 0.
7058 // offset will be checked in resize handler. 7211 // offset will be checked in resize handler.
7059 // don't use isVisible since width is known even if widget 7212 // don't use isVisible since width is known even if widget
7060 // is temporarily invisible 7213 // is temporarily invisible
7061 if (clientAreaWidth > 0) { 7214 if (clientAreaWidth > 0) {
7062 int width = renderer.getWidth(); 7215 int width = renderer.getWidth();
7063 // prevent scrolling if the content fits in the client area. 7216 // prevent scrolling if the content fits in the client area.
7064 // align end of longest line with right border of client area 7217 // align end of longest line with right border of client area
7070 scrollHorizontal(pixel - horizontalScrollOffset, true); 7223 scrollHorizontal(pixel - horizontalScrollOffset, true);
7071 } 7224 }
7072 /** 7225 /**
7073 * Sets the line indentation of the widget. 7226 * Sets the line indentation of the widget.
7074 * <p> 7227 * <p>
7075 * It is the amount of blank space, in pixels, at the beginning of each line. 7228 * It is the amount of blank space, in pixels, at the beginning of each line.
7076 * When a line wraps in several lines only the first one is indented. 7229 * When a line wraps in several lines only the first one is indented.
7077 * </p> 7230 * </p>
7078 * 7231 *
7079 * @param indent the new indent 7232 * @param indent the new indent
7080 * 7233 *
7081 * @exception DWTException <ul> 7234 * @exception DWTException <ul>
7082 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7235 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7083 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7236 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7084 * </ul> 7237 * </ul>
7085 * 7238 *
7086 * @see #setLineIndent(int, int, int) 7239 * @see #setLineIndent(int, int, int)
7087 * 7240 *
7088 * @since 3.2 7241 * @since 3.2
7089 */ 7242 */
7090 public void setIndent(int indent) { 7243 public void setIndent(int indent) {
7091 checkWidget(); 7244 checkWidget();
7092 if (this.indent is indent || indent < 0) return; 7245 if (this.indent is indent || indent < 0) return;
7093 this.indent = indent; 7246 this.indent = indent;
7094 resetCache(0, content.getLineCount()); 7247 resetCache(0, content.getLineCount());
7095 setCaretLocation(); 7248 setCaretLocation();
7096 super.redraw(); 7249 super.redraw();
7097 } 7250 }
7098 /** 7251 /**
7099 * Sets whether the widget should justify lines. 7252 * Sets whether the widget should justify lines.
7100 * 7253 *
7101 * @param justify whether lines should be justified 7254 * @param justify whether lines should be justified
7102 * 7255 *
7103 * @exception DWTException <ul> 7256 * @exception DWTException <ul>
7104 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7257 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7105 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7258 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7106 * </ul> 7259 * </ul>
7107 * 7260 *
7108 * @see #setLineJustify(int, int, bool) 7261 * @see #setLineJustify(int, int, bool)
7109 * 7262 *
7110 * @since 3.2 7263 * @since 3.2
7111 */ 7264 */
7112 public void setJustify(bool justify) { 7265 public void setJustify(bool justify) {
7113 checkWidget(); 7266 checkWidget();
7114 if (this.justify is justify) return; 7267 if (this.justify is justify) return;
7115 this.justify = justify; 7268 this.justify = justify;
7116 resetCache(0, content.getLineCount()); 7269 resetCache(0, content.getLineCount());
7117 setCaretLocation(); 7270 setCaretLocation();
7118 super.redraw(); 7271 super.redraw();
7119 } 7272 }
7120 /** 7273 /**
7121 * Maps a key to an action. 7274 * Maps a key to an action.
7122 * <p> 7275 * <p>
7123 * One action can be associated with N keys. However, each key can only 7276 * One action can be associated with N keys. However, each key can only
7124 * have one action (key:action is N:1 relation). 7277 * have one action (key:action is N:1 relation).
7125 * </p> 7278 * </p>
7126 * 7279 *
7127 * @param key a key code defined in DWT.java or a character. 7280 * @param key a key code defined in DWT.java or a character.
7128 * Optionally ORd with a state mask. Preferred state masks are one or more of 7281 * Optionally ORd with a state mask. Preferred state masks are one or more of
7129 * DWT.MOD1, DWT.MOD2, DWT.MOD3, since these masks account for modifier platform 7282 * DWT.MOD1, DWT.MOD2, DWT.MOD3, since these masks account for modifier platform
7130 * differences. However, there may be cases where using the specific state masks 7283 * differences. However, there may be cases where using the specific state masks
7131 * (i.e., DWT.CTRL, DWT.SHIFT, DWT.ALT, DWT.COMMAND) makes sense. 7284 * (i.e., DWT.CTRL, DWT.SHIFT, DWT.ALT, DWT.COMMAND) makes sense.
7132 * @param action one of the predefined actions defined in ST.java. 7285 * @param action one of the predefined actions defined in ST.java.
7133 * Use DWT.NULL to remove a key binding. 7286 * Use DWT.NULL to remove a key binding.
7134 * @exception DWTException <ul> 7287 * @exception DWTException <ul>
7135 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7288 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7136 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7289 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7137 * </ul> 7290 * </ul>
7138 */ 7291 */
7139 public void setKeyBinding(int key, int action) { 7292 public void setKeyBinding(int key, int action) {
7140 checkWidget(); 7293 checkWidget();
7141 int modifierValue = key & DWT.MODIFIER_MASK; 7294 int modifierValue = key & DWT.MODIFIER_MASK;
7142 char keyChar = cast(wchar)(key & DWT.KEY_MASK); 7295 char keyChar = cast(char)(key & DWT.KEY_MASK);
7143 if (Compatibility.isLetter(keyChar)) { 7296 if (Compatibility.isLetter(keyChar)) {
7144 // make the keybinding case insensitive by adding it 7297 // make the keybinding case insensitive by adding it
7145 // in its upper and lower case form 7298 // in its upper and lower case form
7146 char ch = Character.toUpperCase(keyChar); 7299 char ch = CharacterToUpper(keyChar);
7147 int newKey = ch | modifierValue; 7300 int newKey = ch | modifierValue;
7148 if (action is DWT.NULL) { 7301 if (action is DWT.NULL) {
7149 keyActionMap.remove(new Integer(newKey)); 7302 keyActionMap.remove(newKey);
7150 } else { 7303 } else {
7151 keyActionMap.put(new Integer(newKey), new Integer(action)); 7304 keyActionMap[newKey] = action;
7152 } 7305 }
7153 ch = Character.toLowerCase(keyChar); 7306 ch = CharacterToLower(keyChar);
7154 newKey = ch | modifierValue; 7307 newKey = ch | modifierValue;
7155 if (action is DWT.NULL) { 7308 if (action is DWT.NULL) {
7156 keyActionMap.remove(new Integer(newKey)); 7309 keyActionMap.remove(newKey);
7157 } else { 7310 } else {
7158 keyActionMap.put(new Integer(newKey), new Integer(action)); 7311 keyActionMap[newKey] = action;
7159 } 7312 }
7160 } else { 7313 } else {
7161 if (action is DWT.NULL) { 7314 if (action is DWT.NULL) {
7162 keyActionMap.remove(new Integer(key)); 7315 keyActionMap.remove(key);
7163 } else { 7316 } else {
7164 keyActionMap.put(new Integer(key), new Integer(action)); 7317 keyActionMap[key]=action;
7165 } 7318 }
7166 } 7319 }
7167 } 7320 }
7168 /** 7321 /**
7169 * Sets the alignment of the specified lines. The argument should be one of <code>DWT.LEFT</code>, 7322 * Sets the alignment of the specified lines. The argument should be one of <code>DWT.LEFT</code>,
7170 * <code>DWT.CENTER</code> or <code>DWT.RIGHT</code>. 7323 * <code>DWT.CENTER</code> or <code>DWT.RIGHT</code>.
7171 * <p><p> 7324 * <p><p>
7172 * Note that if <code>DWT.MULTI</code> is set, then <code>DWT.WRAP</code> must also be set 7325 * Note that if <code>DWT.MULTI</code> is set, then <code>DWT.WRAP</code> must also be set
7173 * in order to stabilize the right edge before setting alignment. 7326 * in order to stabilize the right edge before setting alignment.
7174 * </p> 7327 * </p>
7175 * Should not be called if a LineStyleListener has been set since the listener 7328 * Should not be called if a LineStyleListener has been set since the listener
7176 * maintains the line attributes. 7329 * maintains the line attributes.
7177 * </p><p> 7330 * </p><p>
7178 * All line attributes are maintained relative to the line text, not the 7331 * All line attributes are maintained relative to the line text, not the
7179 * line index that is specified in this method call. 7332 * line index that is specified in this method call.
7180 * During text changes, when entire lines are inserted or removed, the line 7333 * During text changes, when entire lines are inserted or removed, the line
7181 * attributes that are associated with the lines after the change 7334 * attributes that are associated with the lines after the change
7182 * will "move" with their respective text. An entire line is defined as 7335 * will "move" with their respective text. An entire line is defined as
7183 * extending from the first character on a line to the last and including the 7336 * extending from the first character on a line to the last and including the
7184 * line delimiter. 7337 * line delimiter.
7185 * </p><p> 7338 * </p><p>
7186 * When two lines are joined by deleting a line delimiter, the top line 7339 * When two lines are joined by deleting a line delimiter, the top line
7187 * attributes take precedence and the attributes of the bottom line are deleted. 7340 * attributes take precedence and the attributes of the bottom line are deleted.
7188 * For all other text changes line attributes will remain unchanged. 7341 * For all other text changes line attributes will remain unchanged.
7189 * 7342 *
7190 * @param startLine first line the alignment is applied to, 0 based 7343 * @param startLine first line the alignment is applied to, 0 based
7191 * @param lineCount number of lines the alignment applies to. 7344 * @param lineCount number of lines the alignment applies to.
7192 * @param alignment line alignment 7345 * @param alignment line alignment
7193 * 7346 *
7194 * @exception DWTException <ul> 7347 * @exception DWTException <ul>
7195 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7348 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7196 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7349 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7197 * </ul> 7350 * </ul>
7198 * @exception IllegalArgumentException <ul> 7351 * @exception IllegalArgumentException <ul>
7214 int caretLine = getCaretLine(); 7367 int caretLine = getCaretLine();
7215 if (startLine <= caretLine && caretLine < startLine + lineCount) { 7368 if (startLine <= caretLine && caretLine < startLine + lineCount) {
7216 setCaretLocation(); 7369 setCaretLocation();
7217 } 7370 }
7218 } 7371 }
7219 /** 7372 /**
7220 * Sets the background color of the specified lines. 7373 * Sets the background color of the specified lines.
7221 * <p> 7374 * <p>
7222 * The background color is drawn for the width of the widget. All 7375 * The background color is drawn for the width of the widget. All
7223 * line background colors are discarded when setText is called. 7376 * line background colors are discarded when setText is called.
7224 * The text background color if defined in a StyleRange overlays the 7377 * The text background color if defined in a StyleRange overlays the
7225 * line background color. 7378 * line background color.
7226 * </p><p> 7379 * </p><p>
7227 * Should not be called if a LineBackgroundListener has been set since the 7380 * Should not be called if a LineBackgroundListener has been set since the
7228 * listener maintains the line backgrounds. 7381 * listener maintains the line backgrounds.
7229 * </p><p> 7382 * </p><p>
7230 * All line attributes are maintained relative to the line text, not the 7383 * All line attributes are maintained relative to the line text, not the
7231 * line index that is specified in this method call. 7384 * line index that is specified in this method call.
7232 * During text changes, when entire lines are inserted or removed, the line 7385 * During text changes, when entire lines are inserted or removed, the line
7233 * attributes that are associated with the lines after the change 7386 * attributes that are associated with the lines after the change
7234 * will "move" with their respective text. An entire line is defined as 7387 * will "move" with their respective text. An entire line is defined as
7235 * extending from the first character on a line to the last and including the 7388 * extending from the first character on a line to the last and including the
7236 * line delimiter. 7389 * line delimiter.
7237 * </p><p> 7390 * </p><p>
7238 * When two lines are joined by deleting a line delimiter, the top line 7391 * When two lines are joined by deleting a line delimiter, the top line
7239 * attributes take precedence and the attributes of the bottom line are deleted. 7392 * attributes take precedence and the attributes of the bottom line are deleted.
7240 * For all other text changes line attributes will remain unchanged. 7393 * For all other text changes line attributes will remain unchanged.
7241 * </p> 7394 * </p>
7242 * 7395 *
7243 * @param startLine first line the color is applied to, 0 based 7396 * @param startLine first line the color is applied to, 0 based
7244 * @param lineCount number of lines the color applies to. 7397 * @param lineCount number of lines the color applies to.
7245 * @param background line background color 7398 * @param background line background color
7246 * @exception DWTException <ul> 7399 * @exception DWTException <ul>
7247 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7400 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7250 * @exception IllegalArgumentException <ul> 7403 * @exception IllegalArgumentException <ul>
7251 * <li>ERROR_INVALID_ARGUMENT when the specified line range is invalid</li> 7404 * <li>ERROR_INVALID_ARGUMENT when the specified line range is invalid</li>
7252 * </ul> 7405 * </ul>
7253 */ 7406 */
7254 public void setLineBackground(int startLine, int lineCount, Color background) { 7407 public void setLineBackground(int startLine, int lineCount, Color background) {
7255 checkWidget(); 7408 checkWidget();
7256 if (isListening(LineGetBackground)) return; 7409 if (isListening(LineGetBackground)) return;
7257 if (startLine < 0 || startLine + lineCount > content.getLineCount()) { 7410 if (startLine < 0 || startLine + lineCount > content.getLineCount()) {
7258 DWT.error(DWT.ERROR_INVALID_ARGUMENT); 7411 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
7259 } 7412 }
7260 if (background !is null) { 7413 if (background !is null) {
7265 redrawLines(startLine, lineCount); 7418 redrawLines(startLine, lineCount);
7266 } 7419 }
7267 /** 7420 /**
7268 * Sets the bullet of the specified lines. 7421 * Sets the bullet of the specified lines.
7269 * <p> 7422 * <p>
7270 * Should not be called if a LineStyleListener has been set since the listener 7423 * Should not be called if a LineStyleListener has been set since the listener
7271 * maintains the line attributes. 7424 * maintains the line attributes.
7272 * </p><p> 7425 * </p><p>
7273 * All line attributes are maintained relative to the line text, not the 7426 * All line attributes are maintained relative to the line text, not the
7274 * line index that is specified in this method call. 7427 * line index that is specified in this method call.
7275 * During text changes, when entire lines are inserted or removed, the line 7428 * During text changes, when entire lines are inserted or removed, the line
7276 * attributes that are associated with the lines after the change 7429 * attributes that are associated with the lines after the change
7277 * will "move" with their respective text. An entire line is defined as 7430 * will "move" with their respective text. An entire line is defined as
7278 * extending from the first character on a line to the last and including the 7431 * extending from the first character on a line to the last and including the
7279 * line delimiter. 7432 * line delimiter.
7280 * </p><p> 7433 * </p><p>
7281 * When two lines are joined by deleting a line delimiter, the top line 7434 * When two lines are joined by deleting a line delimiter, the top line
7282 * attributes take precedence and the attributes of the bottom line are deleted. 7435 * attributes take precedence and the attributes of the bottom line are deleted.
7283 * For all other text changes line attributes will remain unchanged. 7436 * For all other text changes line attributes will remain unchanged.
7284 * </p> 7437 * </p>
7285 * 7438 *
7286 * @param startLine first line the bullet is applied to, 0 based 7439 * @param startLine first line the bullet is applied to, 0 based
7287 * @param lineCount number of lines the bullet applies to. 7440 * @param lineCount number of lines the bullet applies to.
7288 * @param bullet line bullet 7441 * @param bullet line bullet
7289 * 7442 *
7290 * @exception DWTException <ul> 7443 * @exception DWTException <ul>
7291 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7444 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7292 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7445 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7293 * </ul> 7446 * </ul>
7294 * @exception IllegalArgumentException <ul> 7447 * @exception IllegalArgumentException <ul>
7296 * </ul> 7449 * </ul>
7297 * @since 3.2 7450 * @since 3.2
7298 */ 7451 */
7299 public void setLineBullet(int startLine, int lineCount, Bullet bullet) { 7452 public void setLineBullet(int startLine, int lineCount, Bullet bullet) {
7300 checkWidget(); 7453 checkWidget();
7301 if (isListening(LineGetStyle)) return; 7454 if (isListening(LineGetStyle)) return;
7302 if (startLine < 0 || startLine + lineCount > content.getLineCount()) { 7455 if (startLine < 0 || startLine + lineCount > content.getLineCount()) {
7303 DWT.error(DWT.ERROR_INVALID_ARGUMENT); 7456 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
7304 } 7457 }
7305 7458
7306 renderer.setLineBullet(startLine, lineCount, bullet); 7459 renderer.setLineBullet(startLine, lineCount, bullet);
7317 renderer.calculateIdle(); 7470 renderer.calculateIdle();
7318 } 7471 }
7319 /** 7472 /**
7320 * Sets the indent of the specified lines. 7473 * Sets the indent of the specified lines.
7321 * <p> 7474 * <p>
7322 * Should not be called if a LineStyleListener has been set since the listener 7475 * Should not be called if a LineStyleListener has been set since the listener
7323 * maintains the line attributes. 7476 * maintains the line attributes.
7324 * </p><p> 7477 * </p><p>
7325 * All line attributes are maintained relative to the line text, not the 7478 * All line attributes are maintained relative to the line text, not the
7326 * line index that is specified in this method call. 7479 * line index that is specified in this method call.
7327 * During text changes, when entire lines are inserted or removed, the line 7480 * During text changes, when entire lines are inserted or removed, the line
7328 * attributes that are associated with the lines after the change 7481 * attributes that are associated with the lines after the change
7329 * will "move" with their respective text. An entire line is defined as 7482 * will "move" with their respective text. An entire line is defined as
7330 * extending from the first character on a line to the last and including the 7483 * extending from the first character on a line to the last and including the
7331 * line delimiter. 7484 * line delimiter.
7332 * </p><p> 7485 * </p><p>
7333 * When two lines are joined by deleting a line delimiter, the top line 7486 * When two lines are joined by deleting a line delimiter, the top line
7334 * attributes take precedence and the attributes of the bottom line are deleted. 7487 * attributes take precedence and the attributes of the bottom line are deleted.
7335 * For all other text changes line attributes will remain unchanged. 7488 * For all other text changes line attributes will remain unchanged.
7336 * </p> 7489 * </p>
7337 * 7490 *
7338 * @param startLine first line the indent is applied to, 0 based 7491 * @param startLine first line the indent is applied to, 0 based
7339 * @param lineCount number of lines the indent applies to. 7492 * @param lineCount number of lines the indent applies to.
7340 * @param indent line indent 7493 * @param indent line indent
7341 * 7494 *
7342 * @exception DWTException <ul> 7495 * @exception DWTException <ul>
7343 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7496 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7344 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7497 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7345 * </ul> 7498 * </ul>
7346 * @exception IllegalArgumentException <ul> 7499 * @exception IllegalArgumentException <ul>
7365 } 7518 }
7366 } 7519 }
7367 /** 7520 /**
7368 * Sets the justify of the specified lines. 7521 * Sets the justify of the specified lines.
7369 * <p> 7522 * <p>
7370 * Should not be called if a LineStyleListener has been set since the listener 7523 * Should not be called if a LineStyleListener has been set since the listener
7371 * maintains the line attributes. 7524 * maintains the line attributes.
7372 * </p><p> 7525 * </p><p>
7373 * All line attributes are maintained relative to the line text, not the 7526 * All line attributes are maintained relative to the line text, not the
7374 * line index that is specified in this method call. 7527 * line index that is specified in this method call.
7375 * During text changes, when entire lines are inserted or removed, the line 7528 * During text changes, when entire lines are inserted or removed, the line
7376 * attributes that are associated with the lines after the change 7529 * attributes that are associated with the lines after the change
7377 * will "move" with their respective text. An entire line is defined as 7530 * will "move" with their respective text. An entire line is defined as
7378 * extending from the first character on a line to the last and including the 7531 * extending from the first character on a line to the last and including the
7379 * line delimiter. 7532 * line delimiter.
7380 * </p><p> 7533 * </p><p>
7381 * When two lines are joined by deleting a line delimiter, the top line 7534 * When two lines are joined by deleting a line delimiter, the top line
7382 * attributes take precedence and the attributes of the bottom line are deleted. 7535 * attributes take precedence and the attributes of the bottom line are deleted.
7383 * For all other text changes line attributes will remain unchanged. 7536 * For all other text changes line attributes will remain unchanged.
7384 * </p> 7537 * </p>
7385 * 7538 *
7386 * @param startLine first line the justify is applied to, 0 based 7539 * @param startLine first line the justify is applied to, 0 based
7387 * @param lineCount number of lines the justify applies to. 7540 * @param lineCount number of lines the justify applies to.
7388 * @param justify true if lines should be justified 7541 * @param justify true if lines should be justified
7389 * 7542 *
7390 * @exception DWTException <ul> 7543 * @exception DWTException <ul>
7391 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7544 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7392 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7545 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7393 * </ul> 7546 * </ul>
7394 * @exception IllegalArgumentException <ul> 7547 * @exception IllegalArgumentException <ul>
7412 setCaretLocation(); 7565 setCaretLocation();
7413 } 7566 }
7414 } 7567 }
7415 /** 7568 /**
7416 * Sets the line spacing of the widget. The line spacing applies for all lines. 7569 * Sets the line spacing of the widget. The line spacing applies for all lines.
7417 * 7570 *
7418 * @param lineSpacing the line spacing 7571 * @param lineSpacing the line spacing
7419 * @exception DWTException <ul> 7572 * @exception DWTException <ul>
7420 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7573 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7421 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7574 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7422 * </ul> 7575 * </ul>
7423 * @since 3.2 7576 * @since 3.2
7424 */ 7577 */
7425 public void setLineSpacing(int lineSpacing) { 7578 public void setLineSpacing(int lineSpacing) {
7426 checkWidget(); 7579 checkWidget();
7427 if (this.lineSpacing is lineSpacing || lineSpacing < 0) return; 7580 if (this.lineSpacing is lineSpacing || lineSpacing < 0) return;
7428 this.lineSpacing = lineSpacing; 7581 this.lineSpacing = lineSpacing;
7429 setVariableLineHeight(); 7582 setVariableLineHeight();
7430 resetCache(0, content.getLineCount()); 7583 resetCache(0, content.getLineCount());
7431 setCaretLocation(); 7584 setCaretLocation();
7432 super.redraw(); 7585 super.redraw();
7433 } 7586 }
7454 /** 7607 /**
7455 * Sets the orientation of the receiver, which must be one 7608 * Sets the orientation of the receiver, which must be one
7456 * of the constants <code>DWT.LEFT_TO_RIGHT</code> or <code>DWT.RIGHT_TO_LEFT</code>. 7609 * of the constants <code>DWT.LEFT_TO_RIGHT</code> or <code>DWT.RIGHT_TO_LEFT</code>.
7457 * 7610 *
7458 * @param orientation new orientation style 7611 * @param orientation new orientation style
7459 * 7612 *
7460 * @exception DWTException <ul> 7613 * @exception DWTException <ul>
7461 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7614 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7462 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7615 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7463 * </ul> 7616 * </ul>
7464 * 7617 *
7465 * @since 2.1.2 7618 * @since 2.1.2
7466 */ 7619 */
7467 public void setOrientation(int orientation) { 7620 public void setOrientation(int orientation) {
7468 if ((orientation & (DWT.RIGHT_TO_LEFT | DWT.LEFT_TO_RIGHT)) is 0) { 7621 if ((orientation & (DWT.RIGHT_TO_LEFT | DWT.LEFT_TO_RIGHT)) is 0) {
7469 return; 7622 return;
7470 } 7623 }
7471 if ((orientation & DWT.RIGHT_TO_LEFT) !is 0 && (orientation & DWT.LEFT_TO_RIGHT) !is 0) { 7624 if ((orientation & DWT.RIGHT_TO_LEFT) !is 0 && (orientation & DWT.LEFT_TO_RIGHT) !is 0) {
7472 return; 7625 return;
7473 } 7626 }
7474 if ((orientation & DWT.RIGHT_TO_LEFT) !is 0 && isMirrored()) { 7627 if ((orientation & DWT.RIGHT_TO_LEFT) !is 0 && isMirrored()) {
7475 return; 7628 return;
7476 } 7629 }
7477 if ((orientation & DWT.LEFT_TO_RIGHT) !is 0 && !isMirrored()) { 7630 if ((orientation & DWT.LEFT_TO_RIGHT) !is 0 && !isMirrored()) {
7478 return; 7631 return;
7479 } 7632 }
7480 if (!BidiUtil.setOrientation(this, orientation)) { 7633 if (!BidiUtil.setOrientation(this, orientation)) {
7481 return; 7634 return;
7482 } 7635 }
7483 isMirrored = (orientation & DWT.RIGHT_TO_LEFT) !is 0; 7636 isMirrored_ = (orientation & DWT.RIGHT_TO_LEFT) !is 0;
7484 caretDirection = DWT.NULL; 7637 caretDirection = DWT.NULL;
7485 resetCache(0, content.getLineCount()); 7638 resetCache(0, content.getLineCount());
7486 setCaretLocation(); 7639 setCaretLocation();
7487 keyActionMap.clear(); 7640 keyActionMap = null;
7488 createKeyBindings(); 7641 createKeyBindings();
7489 super.redraw(); 7642 super.redraw();
7490 } 7643 }
7491 /** 7644 /**
7492 * Adjusts the maximum and the page size of the scroll bars to 7645 * Adjusts the maximum and the page size of the scroll bars to
7493 * reflect content width/length changes. 7646 * reflect content width/length changes.
7494 * 7647 *
7495 * @param vertical indicates if the vertical scrollbar also needs to be set 7648 * @param vertical indicates if the vertical scrollbar also needs to be set
7496 */ 7649 */
7497 void setScrollBars(bool vertical) { 7650 void setScrollBars(bool vertical) {
7498 int inactive = 1; 7651 int inactive = 1;
7499 if (vertical || !isFixedLineHeight()) { 7652 if (vertical || !isFixedLineHeight()) {
7500 ScrollBar verticalBar = getVerticalBar(); 7653 ScrollBar verticalBar = getVerticalBar();
7501 if (verticalBar !is null) { 7654 if (verticalBar !is null) {
7502 int maximum = renderer.getHeight(); 7655 int maximum = renderer.getHeight();
7503 // only set the real values if the scroll bar can be used 7656 // only set the real values if the scroll bar can be used
7504 // (ie. because the thumb size is less than the scroll maximum) 7657 // (ie. because the thumb size is less than the scroll maximum)
7505 // avoids flashing on Motif, fixes 1G7RE1J and 1G5SE92 7658 // avoids flashing on Motif, fixes 1G7RE1J and 1G5SE92
7506 if (clientAreaHeight < maximum) { 7659 if (clientAreaHeight < maximum) {
7507 verticalBar.setMaximum(maximum); 7660 verticalBar.setMaximum(maximum);
7508 verticalBar.setThumb(clientAreaHeight); 7661 verticalBar.setThumb(clientAreaHeight);
7519 } 7672 }
7520 } 7673 }
7521 ScrollBar horizontalBar = getHorizontalBar(); 7674 ScrollBar horizontalBar = getHorizontalBar();
7522 if (horizontalBar !is null && horizontalBar.getVisible()) { 7675 if (horizontalBar !is null && horizontalBar.getVisible()) {
7523 int maximum = renderer.getWidth(); 7676 int maximum = renderer.getWidth();
7524 // only set the real values if the scroll bar can be used 7677 // only set the real values if the scroll bar can be used
7525 // (ie. because the thumb size is less than the scroll maximum) 7678 // (ie. because the thumb size is less than the scroll maximum)
7526 // avoids flashing on Motif, fixes 1G7RE1J and 1G5SE92 7679 // avoids flashing on Motif, fixes 1G7RE1J and 1G5SE92
7527 if (clientAreaWidth < maximum) { 7680 if (clientAreaWidth < maximum) {
7528 horizontalBar.setMaximum(maximum); 7681 horizontalBar.setMaximum(maximum);
7529 horizontalBar.setThumb(clientAreaWidth - leftMargin - rightMargin); 7682 horizontalBar.setThumb(clientAreaWidth - leftMargin - rightMargin);
7537 horizontalBar.getIncrement(), 7690 horizontalBar.getIncrement(),
7538 inactive); 7691 inactive);
7539 } 7692 }
7540 } 7693 }
7541 } 7694 }
7542 /** 7695 /**
7543 * Sets the selection to the given position and scrolls it into view. Equivalent to setSelection(start,start). 7696 * Sets the selection to the given position and scrolls it into view. Equivalent to setSelection(start,start).
7544 * 7697 *
7545 * @param start new caret position 7698 * @param start new caret position
7546 * @see #setSelection(int,int) 7699 * @see #setSelection(int,int)
7547 * @exception DWTException <ul> 7700 * @exception DWTException <ul>
7548 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7701 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7549 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7702 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7550 * </ul> 7703 * </ul>
7551 * @exception IllegalArgumentException <ul> 7704 * @exception IllegalArgumentException <ul>
7552 * <li>ERROR_INVALID_ARGUMENT when either the start or the end of the selection range is inside a 7705 * <li>ERROR_INVALID_ARGUMENT when either the start or the end of the selection range is inside a
7553 * multi byte line delimiter (and thus neither clearly in front of or after the line delimiter) 7706 * multi byte line delimiter (and thus neither clearly in front of or after the line delimiter)
7554 * </ul> 7707 * </ul>
7555 */ 7708 */
7556 public void setSelection(int start) { 7709 public void setSelection(int start) {
7557 // checkWidget test done in setSelectionRange 7710 // checkWidget test done in setSelectionRange
7558 setSelection(start, start); 7711 setSelection(start, start);
7559 } 7712 }
7560 /** 7713 /**
7561 * Sets the selection and scrolls it into view. 7714 * Sets the selection and scrolls it into view.
7562 * <p> 7715 * <p>
7563 * Indexing is zero based. Text selections are specified in terms of 7716 * Indexing is zero based. Text selections are specified in terms of
7564 * caret positions. In a text widget that contains N characters, there are 7717 * caret positions. In a text widget that contains N characters, there are
7565 * N+1 caret positions, ranging from 0..N 7718 * N+1 caret positions, ranging from 0..N
7566 * </p> 7719 * </p>
7567 * 7720 *
7568 * @param point x=selection start offset, y=selection end offset 7721 * @param point x=selection start offset, y=selection end offset
7569 * The caret will be placed at the selection start when x > y. 7722 * The caret will be placed at the selection start when x > y.
7572 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7725 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7573 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7726 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7574 * </ul> 7727 * </ul>
7575 * @exception IllegalArgumentException <ul> 7728 * @exception IllegalArgumentException <ul>
7576 * <li>ERROR_NULL_ARGUMENT when point is null</li> 7729 * <li>ERROR_NULL_ARGUMENT when point is null</li>
7577 * <li>ERROR_INVALID_ARGUMENT when either the start or the end of the selection range is inside a 7730 * <li>ERROR_INVALID_ARGUMENT when either the start or the end of the selection range is inside a
7578 * multi byte line delimiter (and thus neither clearly in front of or after the line delimiter) 7731 * multi byte line delimiter (and thus neither clearly in front of or after the line delimiter)
7579 * </ul> 7732 * </ul>
7580 */ 7733 */
7581 public void setSelection(Point point) { 7734 public void setSelection(Point point) {
7582 checkWidget(); 7735 checkWidget();
7583 if (point is null) DWT.error (DWT.ERROR_NULL_ARGUMENT); 7736 if (point is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
7584 setSelection(point.x, point.y); 7737 setSelection(point.x, point.y);
7585 } 7738 }
7586 /** 7739 /**
7587 * Sets the receiver's selection background color to the color specified 7740 * Sets the receiver's selection background color to the color specified
7588 * by the argument, or to the default system color for the control 7741 * by the argument, or to the default system color for the control
7589 * if the argument is null. 7742 * if the argument is null.
7590 * 7743 *
7591 * @param color the new color (or null) 7744 * @param color the new color (or null)
7592 * 7745 *
7593 * @exception IllegalArgumentException <ul> 7746 * @exception IllegalArgumentException <ul>
7594 * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> 7747 * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
7595 * </ul> 7748 * </ul>
7596 * @exception DWTException <ul> 7749 * @exception DWTException <ul>
7597 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7750 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7598 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7751 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7599 * </ul> 7752 * </ul>
7608 super.redraw(); 7761 super.redraw();
7609 } 7762 }
7610 /** 7763 /**
7611 * Sets the receiver's selection foreground color to the color specified 7764 * Sets the receiver's selection foreground color to the color specified
7612 * by the argument, or to the default system color for the control 7765 * by the argument, or to the default system color for the control
7613 * if the argument is null. 7766 * if the argument is null.
7614 * <p> 7767 * <p>
7615 * Note that this is a <em>HINT</em>. Some platforms do not allow the application 7768 * Note that this is a <em>HINT</em>. Some platforms do not allow the application
7616 * to change the selection foreground color. 7769 * to change the selection foreground color.
7617 * </p> 7770 * </p>
7618 * @param color the new color (or null) 7771 * @param color the new color (or null)
7619 * 7772 *
7620 * @exception IllegalArgumentException <ul> 7773 * @exception IllegalArgumentException <ul>
7621 * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li> 7774 * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
7622 * </ul> 7775 * </ul>
7623 * @exception DWTException <ul> 7776 * @exception DWTException <ul>
7624 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7777 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7625 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7778 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7626 * </ul> 7779 * </ul>
7632 if (color.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT); 7785 if (color.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
7633 } 7786 }
7634 selectionForeground = color; 7787 selectionForeground = color;
7635 super.redraw(); 7788 super.redraw();
7636 } 7789 }
7637 /** 7790 /**
7638 * Sets the selection and scrolls it into view. 7791 * Sets the selection and scrolls it into view.
7639 * <p> 7792 * <p>
7640 * Indexing is zero based. Text selections are specified in terms of 7793 * Indexing is zero based. Text selections are specified in terms of
7641 * caret positions. In a text widget that contains N characters, there are 7794 * caret positions. In a text widget that contains N characters, there are
7642 * N+1 caret positions, ranging from 0..N 7795 * N+1 caret positions, ranging from 0..N
7643 * </p> 7796 * </p>
7644 * 7797 *
7645 * @param start selection start offset. The caret will be placed at the 7798 * @param start selection start offset. The caret will be placed at the
7646 * selection start when start > end. 7799 * selection start when start > end.
7647 * @param end selection end offset 7800 * @param end selection end offset
7648 * @see #setSelectionRange(int,int) 7801 * @see #setSelectionRange(int,int)
7649 * @exception DWTException <ul> 7802 * @exception DWTException <ul>
7650 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7803 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7651 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7804 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7652 * </ul> 7805 * </ul>
7653 * @exception IllegalArgumentException <ul> 7806 * @exception IllegalArgumentException <ul>
7654 * <li>ERROR_INVALID_ARGUMENT when either the start or the end of the selection range is inside a 7807 * <li>ERROR_INVALID_ARGUMENT when either the start or the end of the selection range is inside a
7655 * multi byte line delimiter (and thus neither clearly in front of or after the line delimiter) 7808 * multi byte line delimiter (and thus neither clearly in front of or after the line delimiter)
7656 * </ul> 7809 * </ul>
7657 */ 7810 */
7658 public void setSelection(int start, int end) { 7811 public void setSelection(int start, int end) {
7659 setSelectionRange(start, end - start); 7812 setSelectionRange(start, end - start);
7660 showSelection(); 7813 showSelection();
7661 } 7814 }
7662 /** 7815 /**
7663 * Sets the selection. 7816 * Sets the selection.
7664 * <p> 7817 * <p>
7665 * The new selection may not be visible. Call showSelection to scroll 7818 * The new selection may not be visible. Call showSelection to scroll
7666 * the selection into view. 7819 * the selection into view.
7667 * </p> 7820 * </p>
7668 * 7821 *
7669 * @param start offset of the first selected character, start >= 0 must be true. 7822 * @param start offset of the first selected character, start >= 0 must be true.
7670 * @param length number of characters to select, 0 <= start + length 7823 * @param length number of characters to select, 0 <= start + length
7671 * <= getCharCount() must be true. 7824 * <= getCharCount() must be true.
7672 * A negative length places the caret at the selection start. 7825 * A negative length places the caret at the selection start.
7673 * @param sendEvent a Selection event is sent when set to true and when 7826 * @param sendEvent a Selection event is sent when set to true and when
7674 * the selection is reset. 7827 * the selection is reset.
7675 */ 7828 */
7676 void setSelection(int start, int length, bool sendEvent) { 7829 void setSelection(int start, int length, bool sendEvent) {
7677 int end = start + length; 7830 int end = start + length;
7831 start = content.utf8AdjustOffset(start);
7832 end = content.utf8AdjustOffset(end);
7678 if (start > end) { 7833 if (start > end) {
7679 int temp = end; 7834 int temp = end;
7680 end = start; 7835 end = start;
7681 start = temp; 7836 start = temp;
7682 } 7837 }
7683 // is the selection range different or is the selection direction 7838 // is the selection range different or is the selection direction
7684 // different? 7839 // different?
7685 if (selection.x !is start || selection.y !is end || 7840 if (selection.x !is start || selection.y !is end ||
7686 (length > 0 && selectionAnchor !is selection.x) || 7841 (length > 0 && selectionAnchor !is selection.x) ||
7687 (length < 0 && selectionAnchor !is selection.y)) { 7842 (length < 0 && selectionAnchor !is selection.y)) {
7688 clearSelection(sendEvent); 7843 clearSelection(sendEvent);
7689 if (length < 0) { 7844 if (length < 0) {
7690 selectionAnchor = selection.y = end; 7845 selectionAnchor = selection.y = end;
7691 caretOffset = selection.x = start; 7846 caretOffset = selection.x = start;
7695 } 7850 }
7696 caretAlignment = PREVIOUS_OFFSET_TRAILING; 7851 caretAlignment = PREVIOUS_OFFSET_TRAILING;
7697 internalRedrawRange(selection.x, selection.y - selection.x); 7852 internalRedrawRange(selection.x, selection.y - selection.x);
7698 } 7853 }
7699 } 7854 }
7700 /** 7855 /**
7701 * Sets the selection. 7856 * Sets the selection.
7702 * <p> 7857 * <p>
7703 * The new selection may not be visible. Call showSelection to scroll the selection 7858 * The new selection may not be visible. Call showSelection to scroll the selection
7704 * into view. A negative length places the caret at the visual start of the selection. 7859 * into view. A negative length places the caret at the visual start of the selection.
7705 * </p> 7860 * </p>
7706 * 7861 *
7707 * @param start offset of the first selected character 7862 * @param start offset of the first selected character
7708 * @param length number of characters to select 7863 * @param length number of characters to select
7709 * 7864 *
7710 * @exception DWTException <ul> 7865 * @exception DWTException <ul>
7711 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7866 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7712 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7867 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7713 * </ul> 7868 * </ul>
7714 * @exception IllegalArgumentException <ul> 7869 * @exception IllegalArgumentException <ul>
7715 * <li>ERROR_INVALID_ARGUMENT when either the start or the end of the selection range is inside a 7870 * <li>ERROR_INVALID_ARGUMENT when either the start or the end of the selection range is inside a
7716 * multi byte line delimiter (and thus neither clearly in front of or after the line delimiter) 7871 * multi byte line delimiter (and thus neither clearly in front of or after the line delimiter)
7717 * </ul> 7872 * </ul>
7718 */ 7873 */
7719 public void setSelectionRange(int start, int length) { 7874 public void setSelectionRange(int start, int length) {
7720 checkWidget(); 7875 checkWidget();
7725 length = -start; 7880 length = -start;
7726 } else { 7881 } else {
7727 if (end > contentLength) length = contentLength - start; 7882 if (end > contentLength) length = contentLength - start;
7728 } 7883 }
7729 if (isLineDelimiter(start) || isLineDelimiter(start + length)) { 7884 if (isLineDelimiter(start) || isLineDelimiter(start + length)) {
7730 // the start offset or end offset of the selection range is inside a 7885 // the start offset or end offset of the selection range is inside a
7731 // multi byte line delimiter. This is an illegal operation and an exception 7886 // multi byte line delimiter. This is an illegal operation and an exception
7732 // is thrown. Fixes 1GDKK3R 7887 // is thrown. Fixes 1GDKK3R
7733 DWT.error(DWT.ERROR_INVALID_ARGUMENT); 7888 DWT.error(DWT.ERROR_INVALID_ARGUMENT);
7734 } 7889 }
7735 setSelection(start, length, false); 7890 setSelection(start, length, false);
7736 setCaretLocation(); 7891 setCaretLocation();
7737 } 7892 }
7738 /** 7893 /**
7739 * Adds the specified style. 7894 * Adds the specified style.
7740 * <p> 7895 * <p>
7741 * The new style overwrites existing styles for the specified range. 7896 * The new style overwrites existing styles for the specified range.
7742 * Existing style ranges are adjusted if they partially overlap with 7897 * Existing style ranges are adjusted if they partially overlap with
7743 * the new style. To clear an individual style, call setStyleRange 7898 * the new style. To clear an individual style, call setStyleRange
7744 * with a StyleRange that has null attributes. 7899 * with a StyleRange that has null attributes.
7745 * </p><p> 7900 * </p><p>
7746 * Should not be called if a LineStyleListener has been set since the 7901 * Should not be called if a LineStyleListener has been set since the
7747 * listener maintains the styles. 7902 * listener maintains the styles.
7748 * </p> 7903 * </p>
7749 * 7904 *
7750 * @param range StyleRange object containing the style information. 7905 * @param range StyleRange object containing the style information.
7751 * Overwrites the old style in the given range. May be null to delete 7906 * Overwrites the old style in the given range. May be null to delete
7753 * @exception DWTException <ul> 7908 * @exception DWTException <ul>
7754 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7909 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7755 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7910 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7756 * </ul> 7911 * </ul>
7757 * @exception IllegalArgumentException <ul> 7912 * @exception IllegalArgumentException <ul>
7758 * <li>ERROR_INVALID_RANGE when the style range is outside the valid range (> getCharCount())</li> 7913 * <li>ERROR_INVALID_RANGE when the style range is outside the valid range (> getCharCount())</li>
7759 * </ul> 7914 * </ul>
7760 */ 7915 */
7761 public void setStyleRange(StyleRange range) { 7916 public void setStyleRange(StyleRange range) {
7762 checkWidget(); 7917 checkWidget();
7763 if (isListening(LineGetStyle)) return; 7918 if (isListening(LineGetStyle)) return;
7764 if (range !is null) { 7919 if (range !is null) {
7765 if (range.isUnstyled()) { 7920 if (range.isUnstyled()) {
7766 setStyleRanges(range.start, range.length, null, null, false); 7921 setStyleRanges(range.start, range.length, null, null, false);
7767 } else { 7922 } else {
7768 setStyleRanges(range.start, 0, null, new StyleRange[]{range}, false); 7923 setStyleRanges(range.start, 0, null, [range], false);
7769 } 7924 }
7770 } else { 7925 } else {
7771 setStyleRanges(0, 0, null, null, true); 7926 setStyleRanges(0, 0, null, null, true);
7772 } 7927 }
7773 } 7928 }
7774 /** 7929 /**
7775 * Clears the styles in the range specified by <code>start</code> and 7930 * Clears the styles in the range specified by <code>start</code> and
7776 * <code>length</code> and adds the new styles. 7931 * <code>length</code> and adds the new styles.
7777 * <p> 7932 * <p>
7778 * The ranges array contains start and length pairs. Each pair refers to 7933 * The ranges array contains start and length pairs. Each pair refers to
7779 * the corresponding style in the styles array. For example, the pair 7934 * the corresponding style in the styles array. For example, the pair
7780 * that starts at ranges[n] with length ranges[n+1] uses the style 7935 * that starts at ranges[n] with length ranges[n+1] uses the style
7782 * If ranges or styles is null, the specified range is cleared. 7937 * If ranges or styles is null, the specified range is cleared.
7783 * </p><p> 7938 * </p><p>
7784 * Note: It is expected that the same instance of a StyleRange will occur 7939 * Note: It is expected that the same instance of a StyleRange will occur
7785 * multiple times within the styles array, reducing memory usage. 7940 * multiple times within the styles array, reducing memory usage.
7786 * </p><p> 7941 * </p><p>
7787 * Should not be called if a LineStyleListener has been set since the 7942 * Should not be called if a LineStyleListener has been set since the
7788 * listener maintains the styles. 7943 * listener maintains the styles.
7789 * </p> 7944 * </p>
7790 * 7945 *
7791 * @param start offset of first character where styles will be deleted 7946 * @param start offset of first character where styles will be deleted
7792 * @param length length of the range to delete styles in 7947 * @param length length of the range to delete styles in
7793 * @param ranges the array of ranges. The ranges must not overlap and must be in order. 7948 * @param ranges the array of ranges. The ranges must not overlap and must be in order.
7794 * @param styles the array of StyleRanges. The range fields within the StyleRange are unused. 7949 * @param styles the array of StyleRanges. The range fields within the StyleRange are unused.
7795 * 7950 *
7796 * @exception DWTException <ul> 7951 * @exception DWTException <ul>
7797 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7952 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7798 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7953 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7799 * </ul> 7954 * </ul>
7800 * @exception IllegalArgumentException <ul> 7955 * @exception IllegalArgumentException <ul>
7801 * <li>ERROR_NULL_ARGUMENT when an element in the styles array is null</li> 7956 * <li>ERROR_NULL_ARGUMENT when an element in the styles array is null</li>
7802 * <li>ERROR_INVALID_RANGE when the number of ranges and style do not match (ranges.length * 2 is styles.length)</li> 7957 * <li>ERROR_INVALID_RANGE when the number of ranges and style do not match (ranges.length * 2 is styles.length)</li>
7803 * <li>ERROR_INVALID_RANGE when a range is outside the valid range (> getCharCount() or less than zero)</li> 7958 * <li>ERROR_INVALID_RANGE when a range is outside the valid range (> getCharCount() or less than zero)</li>
7804 * <li>ERROR_INVALID_RANGE when a range overlaps</li> 7959 * <li>ERROR_INVALID_RANGE when a range overlaps</li>
7805 * </ul> 7960 * </ul>
7806 * 7961 *
7807 * @since 3.2 7962 * @since 3.2
7808 */ 7963 */
7809 public void setStyleRanges(int start, int length, int[] ranges, StyleRange[] styles) { 7964 public void setStyleRanges(int start, int length, int[] ranges, StyleRange[] styles) {
7810 checkWidget(); 7965 checkWidget();
7811 if (isListening(LineGetStyle)) return; 7966 if (isListening(LineGetStyle)) return;
7812 if (ranges is null || styles is null) { 7967 if (ranges is null || styles is null) {
7813 setStyleRanges(start, length, null, null, false); 7968 setStyleRanges(start, length, null, null, false);
7814 } else { 7969 } else {
7815 setStyleRanges(start, length, ranges, styles, false); 7970 setStyleRanges(start, length, ranges, styles, false);
7816 } 7971 }
7817 } 7972 }
7818 /** 7973 /**
7819 * Sets styles to be used for rendering the widget content. 7974 * Sets styles to be used for rendering the widget content.
7820 * <p> 7975 * <p>
7821 * All styles in the widget will be replaced with the given set of ranges and styles. 7976 * All styles in the widget will be replaced with the given set of ranges and styles.
7822 * The ranges array contains start and length pairs. Each pair refers to 7977 * The ranges array contains start and length pairs. Each pair refers to
7823 * the corresponding style in the styles array. For example, the pair 7978 * the corresponding style in the styles array. For example, the pair
7826 * If either argument is null, the styles are cleared. 7981 * If either argument is null, the styles are cleared.
7827 * </p><p> 7982 * </p><p>
7828 * Note: It is expected that the same instance of a StyleRange will occur 7983 * Note: It is expected that the same instance of a StyleRange will occur
7829 * multiple times within the styles array, reducing memory usage. 7984 * multiple times within the styles array, reducing memory usage.
7830 * </p><p> 7985 * </p><p>
7831 * Should not be called if a LineStyleListener has been set since the 7986 * Should not be called if a LineStyleListener has been set since the
7832 * listener maintains the styles. 7987 * listener maintains the styles.
7833 * </p> 7988 * </p>
7834 * 7989 *
7835 * @param ranges the array of ranges. The ranges must not overlap and must be in order. 7990 * @param ranges the array of ranges. The ranges must not overlap and must be in order.
7836 * @param styles the array of StyleRanges. The range fields within the StyleRange are unused. 7991 * @param styles the array of StyleRanges. The range fields within the StyleRange are unused.
7837 * 7992 *
7838 * @exception DWTException <ul> 7993 * @exception DWTException <ul>
7839 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 7994 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7840 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 7995 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7841 * </ul> 7996 * </ul>
7842 * @exception IllegalArgumentException <ul> 7997 * @exception IllegalArgumentException <ul>
7843 * <li>ERROR_NULL_ARGUMENT when an element in the styles array is null</li> 7998 * <li>ERROR_NULL_ARGUMENT when an element in the styles array is null</li>
7844 * <li>ERROR_INVALID_RANGE when the number of ranges and style do not match (ranges.length * 2 is styles.length)</li> 7999 * <li>ERROR_INVALID_RANGE when the number of ranges and style do not match (ranges.length * 2 is styles.length)</li>
7845 * <li>ERROR_INVALID_RANGE when a range is outside the valid range (> getCharCount() or less than zero)</li> 8000 * <li>ERROR_INVALID_RANGE when a range is outside the valid range (> getCharCount() or less than zero)</li>
7846 * <li>ERROR_INVALID_RANGE when a range overlaps</li> 8001 * <li>ERROR_INVALID_RANGE when a range overlaps</li>
7847 * </ul> 8002 * </ul>
7848 * 8003 *
7849 * @since 3.2 8004 * @since 3.2
7850 */ 8005 */
7851 public void setStyleRanges(int[] ranges, StyleRange[] styles) { 8006 public void setStyleRanges(int[] ranges, StyleRange[] styles) {
7852 checkWidget(); 8007 checkWidget();
7853 if (isListening(LineGetStyle)) return; 8008 if (isListening(LineGetStyle)) return;
7854 if (ranges is null || styles is null) { 8009 if (ranges is null || styles is null) {
7869 } 8024 }
7870 if (ranges !is null) { 8025 if (ranges !is null) {
7871 if (ranges.length !is styles.length << 1) DWT.error(DWT.ERROR_INVALID_ARGUMENT); 8026 if (ranges.length !is styles.length << 1) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
7872 } 8027 }
7873 int lastOffset = 0; 8028 int lastOffset = 0;
7874 bool variableHeight = false; 8029 bool variableHeight = false;
7875 for (int i = 0; i < styles.length; i ++) { 8030 for (int i = 0; i < styles.length; i ++) {
7876 if (styles[i] is null) DWT.error(DWT.ERROR_INVALID_ARGUMENT); 8031 if (styles[i] is null) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
7877 int rangeStart, rangeLength; 8032 int rangeStart, rangeLength;
7878 if (ranges !is null) { 8033 if (ranges !is null) {
7879 rangeStart = ranges[i << 1]; 8034 rangeStart = ranges[i << 1];
7880 rangeLength = ranges[(i << 1) + 1]; 8035 rangeLength = ranges[(i << 1) + 1];
7881 } else { 8036 } else {
7882 rangeStart = styles[i].start; 8037 rangeStart = styles[i].start;
7883 rangeLength = styles[i].length; 8038 rangeLength = styles[i].length;
7884 } 8039 }
7885 if (rangeLength < 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT); 8040 if (rangeLength < 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
7886 if (!(0 <= rangeStart && rangeStart + rangeLength <= charCount)) DWT.error(DWT.ERROR_INVALID_ARGUMENT); 8041 if (!(0 <= rangeStart && rangeStart + rangeLength <= charCount)) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
7887 if (lastOffset > rangeStart) DWT.error(DWT.ERROR_INVALID_ARGUMENT); 8042 if (lastOffset > rangeStart) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
7888 variableHeight |= styles[i].isVariableHeight(); 8043 variableHeight |= styles[i].isVariableHeight();
7889 lastOffset = rangeStart + rangeLength; 8044 lastOffset = rangeStart + rangeLength;
7890 } 8045 }
7939 if (!isFixedLineHeight()) { 8094 if (!isFixedLineHeight()) {
7940 scrollText(lastLineBottom, newLastLineBottom); 8095 scrollText(lastLineBottom, newLastLineBottom);
7941 } 8096 }
7942 height = newLastLineBottom - y; 8097 height = newLastLineBottom - y;
7943 } 8098 }
7944 super.redraw(0, y, clientAreaWidth, height, false); 8099 super.redraw(0, y, clientAreaWidth, height, false);
7945 } 8100 }
7946 } 8101 }
7947 setCaretLocation(); 8102 setCaretLocation();
7948 } 8103 }
7949 /** 8104 /**
7950 * Sets styles to be used for rendering the widget content. All styles 8105 * Sets styles to be used for rendering the widget content. All styles
7951 * in the widget will be replaced with the given set of styles. 8106 * in the widget will be replaced with the given set of styles.
7952 * <p> 8107 * <p>
7953 * Note: Because a StyleRange includes the start and length, the 8108 * Note: Because a StyleRange includes the start and length, the
7954 * same instance cannot occur multiple times in the array of styles. 8109 * same instance cannot occur multiple times in the array of styles.
7955 * If the same style attributes, such as font and color, occur in 8110 * If the same style attributes, such as font and color, occur in
7956 * multiple StyleRanges, <code>setStyleRanges(int[], StyleRange[])</code> 8111 * multiple StyleRanges, <code>setStyleRanges(int[], StyleRange[])</code>
7957 * can be used to share styles and reduce memory usage. 8112 * can be used to share styles and reduce memory usage.
7958 * </p><p> 8113 * </p><p>
7959 * Should not be called if a LineStyleListener has been set since the 8114 * Should not be called if a LineStyleListener has been set since the
7960 * listener maintains the styles. 8115 * listener maintains the styles.
7961 * </p> 8116 * </p>
7962 * 8117 *
7963 * @param ranges StyleRange objects containing the style information. 8118 * @param ranges StyleRange objects containing the style information.
7964 * The ranges should not overlap. The style rendering is undefined if 8119 * The ranges should not overlap. The style rendering is undefined if
7965 * the ranges do overlap. Must not be null. The styles need to be in order. 8120 * the ranges do overlap. Must not be null. The styles need to be in order.
7966 * @exception DWTException <ul> 8121 * @exception DWTException <ul>
7967 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 8122 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7968 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 8123 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7969 * </ul> 8124 * </ul>
7970 * @exception IllegalArgumentException <ul> 8125 * @exception IllegalArgumentException <ul>
7971 * <li>ERROR_NULL_ARGUMENT when the list of ranges is null</li> 8126 * <li>ERROR_INVALID_RANGE when the last of the style ranges is outside the valid range (> getCharCount())</li>
7972 * <li>ERROR_INVALID_RANGE when the last of the style ranges is outside the valid range (> getCharCount())</li> 8127 * </ul>
7973 * </ul> 8128 *
7974 *
7975 * @see #setStyleRanges(int[], StyleRange[]) 8129 * @see #setStyleRanges(int[], StyleRange[])
7976 */ 8130 */
7977 public void setStyleRanges(StyleRange[] ranges) { 8131 public void setStyleRanges(StyleRange[] ranges) {
7978 checkWidget(); 8132 checkWidget();
7979 if (isListening(LineGetStyle)) return; 8133 if (isListening(LineGetStyle)) return;
7980 if (ranges is null) DWT.error(DWT.ERROR_NULL_ARGUMENT); 8134 // DWT extension: allow null for zero length string
8135 //if (ranges is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
7981 setStyleRanges(0, 0, null, ranges, true); 8136 setStyleRanges(0, 0, null, ranges, true);
7982 } 8137 }
7983 /** 8138 /**
7984 * Sets the tab width. 8139 * Sets the tab width.
7985 * 8140 *
7986 * @param tabs tab width measured in characters. 8141 * @param tabs tab width measured in characters.
7987 * @exception DWTException <ul> 8142 * @exception DWTException <ul>
7988 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 8143 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
7989 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 8144 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
7990 * </ul> 8145 * </ul>
7991 */ 8146 */
7992 public void setTabs(int tabs) { 8147 public void setTabs(int tabs) {
7993 checkWidget(); 8148 checkWidget();
7994 tabLength = tabs; 8149 tabLength = tabs;
7995 renderer.setFont(null, tabs); 8150 renderer.setFont(null, tabs);
7996 resetCache(0, content.getLineCount()); 8151 resetCache(0, content.getLineCount());
7997 setCaretLocation(); 8152 setCaretLocation();
7998 super.redraw(); 8153 super.redraw();
7999 } 8154 }
8000 /** 8155 /**
8001 * Sets the widget content. 8156 * Sets the widget content.
8002 * If the widget has the DWT.SINGLE style and "text" contains more than 8157 * If the widget has the DWT.SINGLE style and "text" contains more than
8003 * one line, only the first line is rendered but the text is stored 8158 * one line, only the first line is rendered but the text is stored
8004 * unchanged. A subsequent call to getText will return the same text 8159 * unchanged. A subsequent call to getText will return the same text
8005 * that was set. 8160 * that was set.
8006 * <p> 8161 * <p>
8007 * <b>Note:</b> Only a single line of text should be set when the DWT.SINGLE 8162 * <b>Note:</b> Only a single line of text should be set when the DWT.SINGLE
8008 * style is used. 8163 * style is used.
8009 * </p> 8164 * </p>
8010 * 8165 *
8011 * @param text new widget content. Replaces existing content. Line styles 8166 * @param text new widget content. Replaces existing content. Line styles
8012 * that were set using StyledText API are discarded. The 8167 * that were set using StyledText API are discarded. The
8013 * current selection is also discarded. 8168 * current selection is also discarded.
8014 * @exception DWTException <ul> 8169 * @exception DWTException <ul>
8015 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 8170 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
8016 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 8171 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
8017 * </ul> 8172 * </ul>
8018 * @exception IllegalArgumentException <ul>
8019 * <li>ERROR_NULL_ARGUMENT when String is null</li>
8020 * </ul>
8021 */ 8173 */
8022 public void setText(String text) { 8174 public void setText(String text) {
8023 checkWidget(); 8175 checkWidget();
8024 if (text is null) { 8176 // DWT extension: allow null for zero length string
8025 DWT.error(DWT.ERROR_NULL_ARGUMENT); 8177 // if (text is null) {
8026 } 8178 // DWT.error(DWT.ERROR_NULL_ARGUMENT);
8179 // }
8027 Event event = new Event(); 8180 Event event = new Event();
8028 event.start = 0; 8181 event.start = 0;
8029 event.end = getCharCount(); 8182 event.end = getCharCount();
8030 event.text = text; 8183 event.text = text;
8031 event.doit = true; 8184 event.doit = true;
8032 notifyListeners(DWT.Verify, event); 8185 notifyListeners(DWT.Verify, event);
8033 if (event.doit) { 8186 if (event.doit) {
8034 StyledTextEvent styledTextEvent = null; 8187 StyledTextEvent styledTextEvent = null;
8035 if (isListening(ExtendedModify)) { 8188 if (isListening(ExtendedModify)) {
8036 styledTextEvent = new StyledTextEvent(content); 8189 styledTextEvent = new StyledTextEvent(content);
8037 styledTextEvent.start = event.start; 8190 styledTextEvent.start = event.start;
8038 styledTextEvent.end = event.start + event.text.length(); 8191 styledTextEvent.end = event.start + event.text.length;
8039 styledTextEvent.text = content.getTextRange(event.start, event.end - event.start); 8192 styledTextEvent.text = content.getTextRange(event.start, event.end - event.start);
8040 } 8193 }
8041 content.setText(event.text); 8194 content.setText(event.text);
8042 sendModifyEvent(event); 8195 sendModifyEvent(event);
8043 if (styledTextEvent !is null) { 8196 if (styledTextEvent !is null) {
8044 notifyListeners(ExtendedModify, styledTextEvent); 8197 notifyListeners(ExtendedModify, styledTextEvent);
8045 } 8198 }
8046 } 8199 }
8047 } 8200 }
8069 textLimit = limit; 8222 textLimit = limit;
8070 } 8223 }
8071 /** 8224 /**
8072 * Sets the top index. Do nothing if there is no text set. 8225 * Sets the top index. Do nothing if there is no text set.
8073 * <p> 8226 * <p>
8074 * The top index is the index of the line that is currently at the top 8227 * The top index is the index of the line that is currently at the top
8075 * of the widget. The top index changes when the widget is scrolled. 8228 * of the widget. The top index changes when the widget is scrolled.
8076 * Indexing starts from zero. 8229 * Indexing starts from zero.
8077 * Note: The top index is reset to 0 when new text is set in the widget. 8230 * Note: The top index is reset to 0 when new text is set in the widget.
8078 * </p> 8231 * </p>
8079 * 8232 *
8080 * @param topIndex new top index. Must be between 0 and 8233 * @param topIndex new top index. Must be between 0 and
8081 * getLineCount() - fully visible lines per page. If no lines are fully 8234 * getLineCount() - fully visible lines per page. If no lines are fully
8082 * visible the maximum value is getLineCount() - 1. An out of range 8235 * visible the maximum value is getLineCount() - 1. An out of range
8083 * index will be adjusted accordingly. 8236 * index will be adjusted accordingly.
8084 * @exception DWTException <ul> 8237 * @exception DWTException <ul>
8085 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 8238 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
8086 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 8239 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
8087 * </ul> 8240 * </ul>
8106 if (pixel > 0) { 8259 if (pixel > 0) {
8107 pixel = getAvailableHeightBellow(pixel); 8260 pixel = getAvailableHeightBellow(pixel);
8108 } else { 8261 } else {
8109 pixel = getAvailableHeightAbove(pixel); 8262 pixel = getAvailableHeightAbove(pixel);
8110 } 8263 }
8111 } 8264 }
8112 scrollVertical(pixel, true); 8265 scrollVertical(pixel, true);
8113 } 8266 }
8114 /** 8267 /**
8115 * Sets the top pixel offset. Do nothing if there is no text set. 8268 * Sets the top pixel offset. Do nothing if there is no text set.
8116 * <p> 8269 * <p>
8118 * widget is scrolled so that the given pixel position is at the top. 8271 * widget is scrolled so that the given pixel position is at the top.
8119 * The top index is adjusted to the corresponding top line. 8272 * The top index is adjusted to the corresponding top line.
8120 * Note: The top pixel is reset to 0 when new text is set in the widget. 8273 * Note: The top pixel is reset to 0 when new text is set in the widget.
8121 * </p> 8274 * </p>
8122 * 8275 *
8123 * @param pixel new top pixel offset. Must be between 0 and 8276 * @param pixel new top pixel offset. Must be between 0 and
8124 * (getLineCount() - visible lines per page) / getLineHeight()). An out 8277 * (getLineCount() - visible lines per page) / getLineHeight()). An out
8125 * of range offset will be adjusted accordingly. 8278 * of range offset will be adjusted accordingly.
8126 * @exception DWTException <ul> 8279 * @exception DWTException <ul>
8127 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> 8280 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
8128 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> 8281 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
8131 */ 8284 */
8132 public void setTopPixel(int pixel) { 8285 public void setTopPixel(int pixel) {
8133 checkWidget(); 8286 checkWidget();
8134 if (getCharCount() is 0) { 8287 if (getCharCount() is 0) {
8135 return; 8288 return;
8136 } 8289 }
8137 if (pixel < 0) pixel = 0; 8290 if (pixel < 0) pixel = 0;
8138 int lineCount = content.getLineCount(); 8291 int lineCount = content.getLineCount();
8139 int height = clientAreaHeight - topMargin - bottomMargin; 8292 int height = clientAreaHeight - topMargin - bottomMargin;
8140 int verticalOffset = getVerticalScrollOffset(); 8293 int verticalOffset = getVerticalScrollOffset();
8141 if (isFixedLineHeight()) { 8294 if (isFixedLineHeight()) {
8142 int maxTopPixel = Math.max(0, lineCount * getVerticalIncrement() - height); 8295 int maxTopPixel = Math.max(0, lineCount * getVerticalIncrement() - height);
8143 if (pixel > maxTopPixel) pixel = maxTopPixel; 8296 if (pixel > maxTopPixel) pixel = maxTopPixel;
8144 pixel -= verticalOffset; 8297 pixel -= verticalOffset;
8145 } else { 8298 } else {
8146 pixel -= verticalOffset; 8299 pixel -= verticalOffset;
8147 if (pixel > 0) { 8300 if (pixel > 0) {
8148 pixel = getAvailableHeightBellow(pixel); 8301 pixel = getAvailableHeightBellow(pixel);
8149 } 8302 }
8173 } 8326 }
8174 setScrollBars(true); 8327 setScrollBars(true);
8175 setCaretLocation(); 8328 setCaretLocation();
8176 super.redraw(); 8329 super.redraw();
8177 } 8330 }
8331 // DWT: If necessary, scroll to show the location
8178 bool showLocation(Rectangle rect, bool scrollPage) { 8332 bool showLocation(Rectangle rect, bool scrollPage) {
8179 int clientAreaWidth = this.clientAreaWidth - leftMargin - rightMargin; 8333 int clientAreaWidth = this.clientAreaWidth - leftMargin - rightMargin;
8180 int clientAreaHeight = this.clientAreaHeight - topMargin - bottomMargin; 8334 int clientAreaHeight = this.clientAreaHeight - topMargin - bottomMargin;
8181 bool scrolled = false; 8335 bool scrolled = false;
8182 if (rect.y <= topMargin) { 8336 if (rect.y <= topMargin) {
8234 endOffset = selection.x; 8388 endOffset = selection.x;
8235 } else { 8389 } else {
8236 startOffset = selection.x; 8390 startOffset = selection.x;
8237 endOffset = selection.y; 8391 endOffset = selection.y;
8238 } 8392 }
8239 8393
8240 Rectangle startBounds = getBoundsAtOffset(startOffset); 8394 Rectangle startBounds = getBoundsAtOffset(startOffset);
8241 Rectangle endBounds = getBoundsAtOffset(endOffset); 8395 Rectangle endBounds = getBoundsAtOffset(endOffset);
8242 8396
8243 // can the selection be fully displayed within the widget's visible width? 8397 // can the selection be fully displayed within the widget's visible width?
8244 int w = clientAreaWidth - leftMargin - rightMargin; 8398 int w = clientAreaWidth - leftMargin - rightMargin;
8245 bool selectionFits = rightToLeft ? startBounds.x - endBounds.x <= w : endBounds.x - startBounds.x <= w; 8399 bool selectionFits = rightToLeft ? startBounds.x - endBounds.x <= w : endBounds.x - startBounds.x <= w;
8246 if (selectionFits) { 8400 if (selectionFits) {
8247 // show as much of the selection as possible by first showing 8401 // show as much of the selection as possible by first showing
8252 } 8406 }
8253 // the character at endOffset is not part of the selection 8407 // the character at endOffset is not part of the selection
8254 endBounds.width = 0; 8408 endBounds.width = 0;
8255 showLocation(endBounds, false); 8409 showLocation(endBounds, false);
8256 } else { 8410 } else {
8257 // just show the end of the selection since the selection start 8411 // just show the end of the selection since the selection start
8258 // will not be visible 8412 // will not be visible
8259 showLocation(endBounds, true); 8413 showLocation(endBounds, true);
8260 } 8414 }
8261 } 8415 }
8262 /** 8416 /**
8263 * Updates the selection and caret position depending on the text change. 8417 * Updates the selection and caret position depending on the text change.
8264 * <p> 8418 * <p>
8265 * If the selection intersects with the replaced text, the selection is 8419 * If the selection intersects with the replaced text, the selection is
8266 * reset and the caret moved to the end of the new text. 8420 * reset and the caret moved to the end of the new text.
8267 * If the selection is behind the replaced text it is moved so that the 8421 * If the selection is behind the replaced text it is moved so that the
8268 * same text remains selected. If the selection is before the replaced text 8422 * same text remains selected. If the selection is before the replaced text
8269 * it is left unchanged. 8423 * it is left unchanged.
8270 * </p> 8424 * </p>
8271 * 8425 *
8272 * @param startOffset offset of the text change 8426 * @param startOffset offset of the text change
8273 * @param replacedLength length of text being replaced 8427 * @param replacedLength length of text being replaced
8274 * @param newLength length of new text 8428 * @param newLength length of new text
8275 */ 8429 */
8276 void updateSelection(int startOffset, int replacedLength, int newLength) { 8430 void updateSelection(int startOffset, int replacedLength, int newLength) {
8277 if (selection.y <= startOffset) { 8431 if (selection.y <= startOffset) {
8278 // selection ends before text change 8432 // selection ends before text change
8433 if (wordWrap) setCaretLocation();
8279 return; 8434 return;
8280 } 8435 }
8281 if (selection.x < startOffset) { 8436 if (selection.x < startOffset) {
8282 // clear selection fragment before text change 8437 // clear selection fragment before text change
8283 internalRedrawRange(selection.x, startOffset - selection.x); 8438 internalRedrawRange(selection.x, startOffset - selection.x);
8284 } 8439 }
8285 if (selection.y > startOffset + replacedLength && selection.x < startOffset + replacedLength) { 8440 if (selection.y > startOffset + replacedLength && selection.x < startOffset + replacedLength) {
8286 // clear selection fragment after text change. 8441 // clear selection fragment after text change.
8287 // do this only when the selection is actually affected by the 8442 // do this only when the selection is actually affected by the
8288 // change. Selection is only affected if it intersects the change (1GDY217). 8443 // change. Selection is only affected if it intersects the change (1GDY217).
8289 int netNewLength = newLength - replacedLength; 8444 int netNewLength = newLength - replacedLength;
8290 int redrawStart = startOffset + newLength; 8445 int redrawStart = startOffset + newLength;
8291 internalRedrawRange(redrawStart, selection.y + netNewLength - redrawStart); 8446 internalRedrawRange(redrawStart, selection.y + netNewLength - redrawStart);
8292 } 8447 }