]> git.argeo.org Git - lgpl/argeo-commons.git/blob - forms/FormUtil.java
Prepare next development cycle
[lgpl/argeo-commons.git] / forms / FormUtil.java
1 package org.argeo.eclipse.ui.forms;
2
3 import org.eclipse.swt.SWT;
4 import org.eclipse.swt.custom.ScrolledComposite;
5 import org.eclipse.swt.events.MouseEvent;
6 //import org.eclipse.swt.graphics.Device;
7 import org.eclipse.swt.graphics.FontMetrics;
8 import org.eclipse.swt.graphics.GC;
9 //import org.eclipse.swt.graphics.Image;
10 //import org.eclipse.swt.graphics.ImageData;
11 import org.eclipse.swt.graphics.Point;
12 import org.eclipse.swt.graphics.Rectangle;
13 import org.eclipse.swt.layout.GridData;
14 import org.eclipse.swt.widgets.Combo;
15 import org.eclipse.swt.widgets.Composite;
16 import org.eclipse.swt.widgets.Control;
17 import org.eclipse.swt.widgets.Label;
18 import org.eclipse.swt.widgets.Layout;
19 //import org.eclipse.swt.widgets.ScrollBar;
20 import org.eclipse.swt.widgets.Text;
21 //import org.eclipse.ui.forms.widgets.ColumnLayout;
22 //import org.eclipse.ui.forms.widgets.Form;
23 //import org.eclipse.ui.forms.widgets.FormText;
24 //import org.eclipse.ui.forms.widgets.FormToolkit;
25 //import org.eclipse.ui.forms.widgets.ILayoutExtension;
26 //
27 import com.ibm.icu.text.BreakIterator;
28
29 public class FormUtil {
30 public static final String PLUGIN_ID = "org.eclipse.ui.forms"; //$NON-NLS-1$
31
32 static final int H_SCROLL_INCREMENT = 5;
33
34 static final int V_SCROLL_INCREMENT = 64;
35
36 public static final String DEBUG = PLUGIN_ID + "/debug"; //$NON-NLS-1$
37
38 public static final String DEBUG_TEXT = DEBUG + "/text"; //$NON-NLS-1$
39 public static final String DEBUG_TEXTSIZE = DEBUG + "/textsize"; //$NON-NLS-1$
40
41 public static final String DEBUG_FOCUS = DEBUG + "/focus"; //$NON-NLS-1$
42
43 public static final String FOCUS_SCROLLING = "focusScrolling"; //$NON-NLS-1$
44
45 public static final String IGNORE_BODY = "__ignore_body__"; //$NON-NLS-1$
46
47 public static Text createText(Composite parent, String label,
48 FormToolkit factory) {
49 return createText(parent, label, factory, 1);
50 }
51
52 public static Text createText(Composite parent, String label,
53 FormToolkit factory, int span) {
54 factory.createLabel(parent, label);
55 Text text = factory.createText(parent, ""); //$NON-NLS-1$
56 int hfill = span == 1 ? GridData.FILL_HORIZONTAL
57 : GridData.HORIZONTAL_ALIGN_FILL;
58 GridData gd = new GridData(hfill | GridData.VERTICAL_ALIGN_CENTER);
59 gd.horizontalSpan = span;
60 text.setLayoutData(gd);
61 return text;
62 }
63
64 public static Text createText(Composite parent, String label,
65 FormToolkit factory, int span, int style) {
66 Label l = factory.createLabel(parent, label);
67 if ((style & SWT.MULTI) != 0) {
68 GridData gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
69 l.setLayoutData(gd);
70 }
71 Text text = factory.createText(parent, "", style); //$NON-NLS-1$
72 int hfill = span == 1 ? GridData.FILL_HORIZONTAL
73 : GridData.HORIZONTAL_ALIGN_FILL;
74 GridData gd = new GridData(hfill | GridData.VERTICAL_ALIGN_CENTER);
75 gd.horizontalSpan = span;
76 text.setLayoutData(gd);
77 return text;
78 }
79
80 public static Text createText(Composite parent, FormToolkit factory,
81 int span) {
82 Text text = factory.createText(parent, ""); //$NON-NLS-1$
83 int hfill = span == 1 ? GridData.FILL_HORIZONTAL
84 : GridData.HORIZONTAL_ALIGN_FILL;
85 GridData gd = new GridData(hfill | GridData.VERTICAL_ALIGN_CENTER);
86 gd.horizontalSpan = span;
87 text.setLayoutData(gd);
88 return text;
89 }
90
91 public static int computeMinimumWidth(GC gc, String text) {
92 BreakIterator wb = BreakIterator.getWordInstance();
93 wb.setText(text);
94 int last = 0;
95
96 int width = 0;
97
98 for (int loc = wb.first(); loc != BreakIterator.DONE; loc = wb.next()) {
99 String word = text.substring(last, loc);
100 Point extent = gc.textExtent(word);
101 width = Math.max(width, extent.x);
102 last = loc;
103 }
104 String lastWord = text.substring(last);
105 Point extent = gc.textExtent(lastWord);
106 width = Math.max(width, extent.x);
107 return width;
108 }
109
110 public static Point computeWrapSize(GC gc, String text, int wHint) {
111 BreakIterator wb = BreakIterator.getWordInstance();
112 wb.setText(text);
113 FontMetrics fm = gc.getFontMetrics();
114 int lineHeight = fm.getHeight();
115
116 int saved = 0;
117 int last = 0;
118 int height = lineHeight;
119 int maxWidth = 0;
120 for (int loc = wb.first(); loc != BreakIterator.DONE; loc = wb.next()) {
121 String word = text.substring(saved, loc);
122 Point extent = gc.textExtent(word);
123 if (extent.x > wHint) {
124 // overflow
125 saved = last;
126 height += extent.y;
127 // switch to current word so maxWidth will accommodate very long single words
128 word = text.substring(last, loc);
129 extent = gc.textExtent(word);
130 }
131 maxWidth = Math.max(maxWidth, extent.x);
132 last = loc;
133 }
134 /*
135 * Correct the height attribute in case it was calculated wrong due to wHint being less than maxWidth.
136 * The recursive call proved to be the only thing that worked in all cases. Some attempts can be made
137 * to estimate the height, but the algorithm needs to be run again to be sure.
138 */
139 if (maxWidth > wHint)
140 return computeWrapSize(gc, text, maxWidth);
141 return new Point(maxWidth, height);
142 }
143
144 // RAP [rh] paintWrapText unnecessary
145 // public static void paintWrapText(GC gc, String text, Rectangle bounds) {
146 // paintWrapText(gc, text, bounds, false);
147 // }
148
149 // RAP [rh] paintWrapText unnecessary
150 // public static void paintWrapText(GC gc, String text, Rectangle bounds,
151 // boolean underline) {
152 // BreakIterator wb = BreakIterator.getWordInstance();
153 // wb.setText(text);
154 // FontMetrics fm = gc.getFontMetrics();
155 // int lineHeight = fm.getHeight();
156 // int descent = fm.getDescent();
157 //
158 // int saved = 0;
159 // int last = 0;
160 // int y = bounds.y;
161 // int width = bounds.width;
162 //
163 // for (int loc = wb.first(); loc != BreakIterator.DONE; loc = wb.next()) {
164 // String line = text.substring(saved, loc);
165 // Point extent = gc.textExtent(line);
166 //
167 // if (extent.x > width) {
168 // // overflow
169 // String prevLine = text.substring(saved, last);
170 // gc.drawText(prevLine, bounds.x, y, true);
171 // if (underline) {
172 // Point prevExtent = gc.textExtent(prevLine);
173 // int lineY = y + lineHeight - descent + 1;
174 // gc
175 // .drawLine(bounds.x, lineY, bounds.x + prevExtent.x,
176 // lineY);
177 // }
178 //
179 // saved = last;
180 // y += lineHeight;
181 // }
182 // last = loc;
183 // }
184 // // paint the last line
185 // String lastLine = text.substring(saved, last);
186 // gc.drawText(lastLine, bounds.x, y, true);
187 // if (underline) {
188 // int lineY = y + lineHeight - descent + 1;
189 // Point lastExtent = gc.textExtent(lastLine);
190 // gc.drawLine(bounds.x, lineY, bounds.x + lastExtent.x, lineY);
191 // }
192 // }
193
194 public static ScrolledComposite getScrolledComposite(Control c) {
195 Composite parent = c.getParent();
196
197 while (parent != null) {
198 if (parent instanceof ScrolledComposite) {
199 return (ScrolledComposite) parent;
200 }
201 parent = parent.getParent();
202 }
203 return null;
204 }
205
206 public static void ensureVisible(Control c) {
207 ScrolledComposite scomp = getScrolledComposite(c);
208 if (scomp != null) {
209 Object data = scomp.getData(FOCUS_SCROLLING);
210 if (data == null || !data.equals(Boolean.FALSE))
211 FormUtil.ensureVisible(scomp, c);
212 }
213 }
214
215 public static void ensureVisible(ScrolledComposite scomp, Control control) {
216 // if the control is a FormText we do not need to scroll since it will
217 // ensure visibility of its segments as necessary
218 // if (control instanceof FormText)
219 // return;
220 Point controlSize = control.getSize();
221 Point controlOrigin = getControlLocation(scomp, control);
222 ensureVisible(scomp, controlOrigin, controlSize);
223 }
224
225 public static void ensureVisible(ScrolledComposite scomp,
226 Point controlOrigin, Point controlSize) {
227 Rectangle area = scomp.getClientArea();
228 Point scompOrigin = scomp.getOrigin();
229
230 int x = scompOrigin.x;
231 int y = scompOrigin.y;
232
233 // horizontal right, but only if the control is smaller
234 // than the client area
235 if (controlSize.x < area.width
236 && (controlOrigin.x + controlSize.x > scompOrigin.x
237 + area.width)) {
238 x = controlOrigin.x + controlSize.x - area.width;
239 }
240 // horizontal left - make sure the left edge of
241 // the control is showing
242 if (controlOrigin.x < x) {
243 if (controlSize.x < area.width)
244 x = controlOrigin.x + controlSize.x - area.width;
245 else
246 x = controlOrigin.x;
247 }
248 // vertical bottom
249 if (controlSize.y < area.height
250 && (controlOrigin.y + controlSize.y > scompOrigin.y
251 + area.height)) {
252 y = controlOrigin.y + controlSize.y - area.height;
253 }
254 // vertical top - make sure the top of
255 // the control is showing
256 if (controlOrigin.y < y) {
257 if (controlSize.y < area.height)
258 y = controlOrigin.y + controlSize.y - area.height;
259 else
260 y = controlOrigin.y;
261 }
262
263 if (scompOrigin.x != x || scompOrigin.y != y) {
264 // scroll to reveal
265 scomp.setOrigin(x, y);
266 }
267 }
268
269 public static void ensureVisible(ScrolledComposite scomp, Control control,
270 MouseEvent e) {
271 Point controlOrigin = getControlLocation(scomp, control);
272 int rX = controlOrigin.x + e.x;
273 int rY = controlOrigin.y + e.y;
274 Rectangle area = scomp.getClientArea();
275 Point scompOrigin = scomp.getOrigin();
276
277 int x = scompOrigin.x;
278 int y = scompOrigin.y;
279 // System.out.println("Ensure: area="+area+", origin="+scompOrigin+",
280 // cloc="+controlOrigin+", csize="+controlSize+", x="+x+", y="+y);
281
282 // horizontal right
283 if (rX > scompOrigin.x + area.width) {
284 x = rX - area.width;
285 }
286 // horizontal left
287 else if (rX < x) {
288 x = rX;
289 }
290 // vertical bottom
291 if (rY > scompOrigin.y + area.height) {
292 y = rY - area.height;
293 }
294 // vertical top
295 else if (rY < y) {
296 y = rY;
297 }
298
299 if (scompOrigin.x != x || scompOrigin.y != y) {
300 // scroll to reveal
301 scomp.setOrigin(x, y);
302 }
303 }
304
305 public static Point getControlLocation(ScrolledComposite scomp,
306 Control control) {
307 int x = 0;
308 int y = 0;
309 Control content = scomp.getContent();
310 Control currentControl = control;
311 for (;;) {
312 if (currentControl == content)
313 break;
314 Point location = currentControl.getLocation();
315 // if (location.x > 0)
316 // x += location.x;
317 // if (location.y > 0)
318 // y += location.y;
319 x += location.x;
320 y += location.y;
321 currentControl = currentControl.getParent();
322 }
323 return new Point(x, y);
324 }
325
326 static void scrollVertical(ScrolledComposite scomp, boolean up) {
327 scroll(scomp, 0, up ? -V_SCROLL_INCREMENT : V_SCROLL_INCREMENT);
328 }
329
330 static void scrollHorizontal(ScrolledComposite scomp, boolean left) {
331 scroll(scomp, left ? -H_SCROLL_INCREMENT : H_SCROLL_INCREMENT, 0);
332 }
333
334 static void scrollPage(ScrolledComposite scomp, boolean up) {
335 Rectangle clientArea = scomp.getClientArea();
336 int increment = up ? -clientArea.height : clientArea.height;
337 scroll(scomp, 0, increment);
338 }
339
340 static void scroll(ScrolledComposite scomp, int xoffset, int yoffset) {
341 Point origin = scomp.getOrigin();
342 Point contentSize = scomp.getContent().getSize();
343 int xorigin = origin.x + xoffset;
344 int yorigin = origin.y + yoffset;
345 xorigin = Math.max(xorigin, 0);
346 xorigin = Math.min(xorigin, contentSize.x - 1);
347 yorigin = Math.max(yorigin, 0);
348 yorigin = Math.min(yorigin, contentSize.y - 1);
349 scomp.setOrigin(xorigin, yorigin);
350 }
351
352 // RAP [rh] FormUtil#updatePageIncrement: empty implementation
353 public static void updatePageIncrement(ScrolledComposite scomp) {
354 // ScrollBar vbar = scomp.getVerticalBar();
355 // if (vbar != null) {
356 // Rectangle clientArea = scomp.getClientArea();
357 // int increment = clientArea.height - 5;
358 // vbar.setPageIncrement(increment);
359 // }
360 // ScrollBar hbar = scomp.getHorizontalBar();
361 // if (hbar != null) {
362 // Rectangle clientArea = scomp.getClientArea();
363 // int increment = clientArea.width - 5;
364 // hbar.setPageIncrement(increment);
365 // }
366 }
367
368 public static void processKey(int keyCode, Control c) {
369 if (c.isDisposed()) {
370 return;
371 }
372 ScrolledComposite scomp = FormUtil.getScrolledComposite(c);
373 if (scomp != null) {
374 if (c instanceof Combo)
375 return;
376 switch (keyCode) {
377 case SWT.ARROW_DOWN:
378 if (scomp.getData("novarrows") == null) //$NON-NLS-1$
379 FormUtil.scrollVertical(scomp, false);
380 break;
381 case SWT.ARROW_UP:
382 if (scomp.getData("novarrows") == null) //$NON-NLS-1$
383 FormUtil.scrollVertical(scomp, true);
384 break;
385 case SWT.ARROW_LEFT:
386 FormUtil.scrollHorizontal(scomp, true);
387 break;
388 case SWT.ARROW_RIGHT:
389 FormUtil.scrollHorizontal(scomp, false);
390 break;
391 case SWT.PAGE_UP:
392 FormUtil.scrollPage(scomp, true);
393 break;
394 case SWT.PAGE_DOWN:
395 FormUtil.scrollPage(scomp, false);
396 break;
397 }
398 }
399 }
400
401 public static boolean isWrapControl(Control c) {
402 if ((c.getStyle() & SWT.WRAP) != 0)
403 return true;
404 if (c instanceof Composite) {
405 return false;
406 // return ((Composite) c).getLayout() instanceof ILayoutExtension;
407 }
408 return false;
409 }
410
411 public static int getWidthHint(int wHint, Control c) {
412 boolean wrap = isWrapControl(c);
413 return wrap ? wHint : SWT.DEFAULT;
414 }
415
416 public static int getHeightHint(int hHint, Control c) {
417 if (c instanceof Composite) {
418 Layout layout = ((Composite) c).getLayout();
419 // if (layout instanceof ColumnLayout)
420 // return hHint;
421 }
422 return SWT.DEFAULT;
423 }
424
425 public static int computeMinimumWidth(Control c, boolean changed) {
426 if (c instanceof Composite) {
427 Layout layout = ((Composite) c).getLayout();
428 // if (layout instanceof ILayoutExtension)
429 // return ((ILayoutExtension) layout).computeMinimumWidth(
430 // (Composite) c, changed);
431 }
432 return c.computeSize(FormUtil.getWidthHint(5, c), SWT.DEFAULT, changed).x;
433 }
434
435 public static int computeMaximumWidth(Control c, boolean changed) {
436 if (c instanceof Composite) {
437 Layout layout = ((Composite) c).getLayout();
438 // if (layout instanceof ILayoutExtension)
439 // return ((ILayoutExtension) layout).computeMaximumWidth(
440 // (Composite) c, changed);
441 }
442 return c.computeSize(SWT.DEFAULT, SWT.DEFAULT, changed).x;
443 }
444
445 // public static Form getForm(Control c) {
446 // Composite parent = c.getParent();
447 // while (parent != null) {
448 // if (parent instanceof Form) {
449 // return (Form) parent;
450 // }
451 // parent = parent.getParent();
452 // }
453 // return null;
454 // }
455
456 // RAP [rh] FormUtil#createAlphaMashImage unnecessary
457 // public static Image createAlphaMashImage(Device device, Image srcImage) {
458 // Rectangle bounds = srcImage.getBounds();
459 // int alpha = 0;
460 // int calpha = 0;
461 // ImageData data = srcImage.getImageData();
462 // // Create a new image with alpha values alternating
463 // // between fully transparent (0) and fully opaque (255).
464 // // This image will show the background through the
465 // // transparent pixels.
466 // for (int i = 0; i < bounds.height; i++) {
467 // // scan line
468 // alpha = calpha;
469 // for (int j = 0; j < bounds.width; j++) {
470 // // column
471 // data.setAlpha(j, i, alpha);
472 // alpha = alpha == 255 ? 0 : 255;
473 // }
474 // calpha = calpha == 255 ? 0 : 255;
475 // }
476 // return new Image(device, data);
477 // }
478
479 public static boolean mnemonicMatch(String text, char key) {
480 char mnemonic = findMnemonic(text);
481 if (mnemonic == '\0')
482 return false;
483 return Character.toUpperCase(key) == Character.toUpperCase(mnemonic);
484 }
485
486 private static char findMnemonic(String string) {
487 int index = 0;
488 int length = string.length();
489 do {
490 while (index < length && string.charAt(index) != '&')
491 index++;
492 if (++index >= length)
493 return '\0';
494 if (string.charAt(index) != '&')
495 return string.charAt(index);
496 index++;
497 } while (index < length);
498 return '\0';
499 }
500
501 public static void setFocusScrollingEnabled(Control c, boolean enabled) {
502 ScrolledComposite scomp = null;
503
504 if (c instanceof ScrolledComposite)
505 scomp = (ScrolledComposite)c;
506 else
507 scomp = getScrolledComposite(c);
508 if (scomp!=null)
509 scomp.setData(FormUtil.FOCUS_SCROLLING, enabled?null:Boolean.FALSE);
510 }
511
512 // RAP [rh] FormUtil#setAntialias unnecessary
513 // public static void setAntialias(GC gc, int style) {
514 // if (!gc.getAdvanced()) {
515 // gc.setAdvanced(true);
516 // if (!gc.getAdvanced())
517 // return;
518 // }
519 // gc.setAntialias(style);
520 // }
521 }