001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: * Chriss Gross (schtoo@schtoo.com) - fix for 61670
011: *******************************************************************************/package org.eclipse.ui.internal.forms.widgets;
012:
013: import com.ibm.icu.text.BreakIterator;
014:
015: import org.eclipse.swt.SWT;
016: import org.eclipse.swt.custom.ScrolledComposite;
017: import org.eclipse.swt.events.MouseEvent;
018: import org.eclipse.swt.graphics.Device;
019: import org.eclipse.swt.graphics.Font;
020: import org.eclipse.swt.graphics.FontData;
021: import org.eclipse.swt.graphics.FontMetrics;
022: import org.eclipse.swt.graphics.GC;
023: import org.eclipse.swt.graphics.Image;
024: import org.eclipse.swt.graphics.ImageData;
025: import org.eclipse.swt.graphics.Point;
026: import org.eclipse.swt.graphics.Rectangle;
027: import org.eclipse.swt.layout.GridData;
028: import org.eclipse.swt.widgets.Combo;
029: import org.eclipse.swt.widgets.Composite;
030: import org.eclipse.swt.widgets.Control;
031: import org.eclipse.swt.widgets.Display;
032: import org.eclipse.swt.widgets.Label;
033: import org.eclipse.swt.widgets.Layout;
034: import org.eclipse.swt.widgets.ScrollBar;
035: import org.eclipse.swt.widgets.Text;
036: import org.eclipse.ui.forms.widgets.ColumnLayout;
037: import org.eclipse.ui.forms.widgets.Form;
038: import org.eclipse.ui.forms.widgets.FormText;
039: import org.eclipse.ui.forms.widgets.FormToolkit;
040: import org.eclipse.ui.forms.widgets.ILayoutExtension;
041:
042: public class FormUtil {
043: public static final String PLUGIN_ID = "org.eclipse.ui.forms"; //$NON-NLS-1$
044:
045: static final int H_SCROLL_INCREMENT = 5;
046:
047: static final int V_SCROLL_INCREMENT = 64;
048:
049: public static final String DEBUG = PLUGIN_ID + "/debug"; //$NON-NLS-1$
050:
051: public static final String DEBUG_TEXT = DEBUG + "/text"; //$NON-NLS-1$
052: public static final String DEBUG_TEXTSIZE = DEBUG + "/textsize"; //$NON-NLS-1$
053:
054: public static final String DEBUG_FOCUS = DEBUG + "/focus"; //$NON-NLS-1$
055:
056: public static final String FOCUS_SCROLLING = "focusScrolling"; //$NON-NLS-1$
057:
058: public static final String IGNORE_BODY = "__ignore_body__"; //$NON-NLS-1$
059:
060: public static Text createText(Composite parent, String label,
061: FormToolkit factory) {
062: return createText(parent, label, factory, 1);
063: }
064:
065: public static Text createText(Composite parent, String label,
066: FormToolkit factory, int span) {
067: factory.createLabel(parent, label);
068: Text text = factory.createText(parent, ""); //$NON-NLS-1$
069: int hfill = span == 1 ? GridData.FILL_HORIZONTAL
070: : GridData.HORIZONTAL_ALIGN_FILL;
071: GridData gd = new GridData(hfill
072: | GridData.VERTICAL_ALIGN_CENTER);
073: gd.horizontalSpan = span;
074: text.setLayoutData(gd);
075: return text;
076: }
077:
078: public static Text createText(Composite parent, String label,
079: FormToolkit factory, int span, int style) {
080: Label l = factory.createLabel(parent, label);
081: if ((style & SWT.MULTI) != 0) {
082: GridData gd = new GridData(
083: GridData.VERTICAL_ALIGN_BEGINNING);
084: l.setLayoutData(gd);
085: }
086: Text text = factory.createText(parent, "", style); //$NON-NLS-1$
087: int hfill = span == 1 ? GridData.FILL_HORIZONTAL
088: : GridData.HORIZONTAL_ALIGN_FILL;
089: GridData gd = new GridData(hfill
090: | GridData.VERTICAL_ALIGN_CENTER);
091: gd.horizontalSpan = span;
092: text.setLayoutData(gd);
093: return text;
094: }
095:
096: public static Text createText(Composite parent,
097: FormToolkit factory, int span) {
098: Text text = factory.createText(parent, ""); //$NON-NLS-1$
099: int hfill = span == 1 ? GridData.FILL_HORIZONTAL
100: : GridData.HORIZONTAL_ALIGN_FILL;
101: GridData gd = new GridData(hfill
102: | GridData.VERTICAL_ALIGN_CENTER);
103: gd.horizontalSpan = span;
104: text.setLayoutData(gd);
105: return text;
106: }
107:
108: public static int computeMinimumWidth(GC gc, String text) {
109: BreakIterator wb = BreakIterator.getWordInstance();
110: wb.setText(text);
111: int last = 0;
112:
113: int width = 0;
114:
115: for (int loc = wb.first(); loc != BreakIterator.DONE; loc = wb
116: .next()) {
117: String word = text.substring(last, loc);
118: Point extent = gc.textExtent(word);
119: width = Math.max(width, extent.x);
120: last = loc;
121: }
122: String lastWord = text.substring(last);
123: Point extent = gc.textExtent(lastWord);
124: width = Math.max(width, extent.x);
125: return width;
126: }
127:
128: public static Point computeWrapSize(GC gc, String text, int wHint) {
129: BreakIterator wb = BreakIterator.getWordInstance();
130: wb.setText(text);
131: FontMetrics fm = gc.getFontMetrics();
132: int lineHeight = fm.getHeight();
133:
134: int saved = 0;
135: int last = 0;
136: int height = lineHeight;
137: int maxWidth = 0;
138: for (int loc = wb.first(); loc != BreakIterator.DONE; loc = wb
139: .next()) {
140: String word = text.substring(saved, loc);
141: Point extent = gc.textExtent(word);
142: if (extent.x > wHint) {
143: // overflow
144: saved = last;
145: height += extent.y;
146: // switch to current word so maxWidth will accommodate very long single words
147: word = text.substring(last, loc);
148: extent = gc.textExtent(word);
149: }
150: maxWidth = Math.max(maxWidth, extent.x);
151: last = loc;
152: }
153: /*
154: * Correct the height attribute in case it was calculated wrong due to wHint being less than maxWidth.
155: * The recursive call proved to be the only thing that worked in all cases. Some attempts can be made
156: * to estimate the height, but the algorithm needs to be run again to be sure.
157: */
158: if (maxWidth > wHint)
159: return computeWrapSize(gc, text, maxWidth);
160: return new Point(maxWidth, height);
161: }
162:
163: public static void paintWrapText(GC gc, String text,
164: Rectangle bounds) {
165: paintWrapText(gc, text, bounds, false);
166: }
167:
168: public static void paintWrapText(GC gc, String text,
169: Rectangle bounds, boolean underline) {
170: BreakIterator wb = BreakIterator.getWordInstance();
171: wb.setText(text);
172: FontMetrics fm = gc.getFontMetrics();
173: int lineHeight = fm.getHeight();
174: int descent = fm.getDescent();
175:
176: int saved = 0;
177: int last = 0;
178: int y = bounds.y;
179: int width = bounds.width;
180:
181: for (int loc = wb.first(); loc != BreakIterator.DONE; loc = wb
182: .next()) {
183: String line = text.substring(saved, loc);
184: Point extent = gc.textExtent(line);
185:
186: if (extent.x > width) {
187: // overflow
188: String prevLine = text.substring(saved, last);
189: gc.drawText(prevLine, bounds.x, y, true);
190: if (underline) {
191: Point prevExtent = gc.textExtent(prevLine);
192: int lineY = y + lineHeight - descent + 1;
193: gc.drawLine(bounds.x, lineY, bounds.x
194: + prevExtent.x, lineY);
195: }
196:
197: saved = last;
198: y += lineHeight;
199: }
200: last = loc;
201: }
202: // paint the last line
203: String lastLine = text.substring(saved, last);
204: gc.drawText(lastLine, bounds.x, y, true);
205: if (underline) {
206: int lineY = y + lineHeight - descent + 1;
207: Point lastExtent = gc.textExtent(lastLine);
208: gc
209: .drawLine(bounds.x, lineY, bounds.x + lastExtent.x,
210: lineY);
211: }
212: }
213:
214: public static ScrolledComposite getScrolledComposite(Control c) {
215: Composite parent = c.getParent();
216:
217: while (parent != null) {
218: if (parent instanceof ScrolledComposite) {
219: return (ScrolledComposite) parent;
220: }
221: parent = parent.getParent();
222: }
223: return null;
224: }
225:
226: public static void ensureVisible(Control c) {
227: ScrolledComposite scomp = getScrolledComposite(c);
228: if (scomp != null) {
229: Object data = scomp.getData(FOCUS_SCROLLING);
230: if (data == null || !data.equals(Boolean.FALSE))
231: FormUtil.ensureVisible(scomp, c);
232: }
233: }
234:
235: public static void ensureVisible(ScrolledComposite scomp,
236: Control control) {
237: // if the control is a FormText we do not need to scroll since it will
238: // ensure visibility of its segments as necessary
239: if (control instanceof FormText)
240: return;
241: Point controlSize = control.getSize();
242: Point controlOrigin = getControlLocation(scomp, control);
243: ensureVisible(scomp, controlOrigin, controlSize);
244: }
245:
246: public static void ensureVisible(ScrolledComposite scomp,
247: Point controlOrigin, Point controlSize) {
248: Rectangle area = scomp.getClientArea();
249: Point scompOrigin = scomp.getOrigin();
250:
251: int x = scompOrigin.x;
252: int y = scompOrigin.y;
253:
254: // horizontal right, but only if the control is smaller
255: // than the client area
256: if (controlSize.x < area.width
257: && (controlOrigin.x + controlSize.x > scompOrigin.x
258: + area.width)) {
259: x = controlOrigin.x + controlSize.x - area.width;
260: }
261: // horizontal left - make sure the left edge of
262: // the control is showing
263: if (controlOrigin.x < x) {
264: if (controlSize.x < area.width)
265: x = controlOrigin.x + controlSize.x - area.width;
266: else
267: x = controlOrigin.x;
268: }
269: // vertical bottom
270: if (controlSize.y < area.height
271: && (controlOrigin.y + controlSize.y > scompOrigin.y
272: + area.height)) {
273: y = controlOrigin.y + controlSize.y - area.height;
274: }
275: // vertical top - make sure the top of
276: // the control is showing
277: if (controlOrigin.y < y) {
278: if (controlSize.y < area.height)
279: y = controlOrigin.y + controlSize.y - area.height;
280: else
281: y = controlOrigin.y;
282: }
283:
284: if (scompOrigin.x != x || scompOrigin.y != y) {
285: // scroll to reveal
286: scomp.setOrigin(x, y);
287: }
288: }
289:
290: public static void ensureVisible(ScrolledComposite scomp,
291: Control control, MouseEvent e) {
292: Point controlOrigin = getControlLocation(scomp, control);
293: int rX = controlOrigin.x + e.x;
294: int rY = controlOrigin.y + e.y;
295: Rectangle area = scomp.getClientArea();
296: Point scompOrigin = scomp.getOrigin();
297:
298: int x = scompOrigin.x;
299: int y = scompOrigin.y;
300: // System.out.println("Ensure: area="+area+", origin="+scompOrigin+",
301: // cloc="+controlOrigin+", csize="+controlSize+", x="+x+", y="+y);
302:
303: // horizontal right
304: if (rX > scompOrigin.x + area.width) {
305: x = rX - area.width;
306: }
307: // horizontal left
308: else if (rX < x) {
309: x = rX;
310: }
311: // vertical bottom
312: if (rY > scompOrigin.y + area.height) {
313: y = rY - area.height;
314: }
315: // vertical top
316: else if (rY < y) {
317: y = rY;
318: }
319:
320: if (scompOrigin.x != x || scompOrigin.y != y) {
321: // scroll to reveal
322: scomp.setOrigin(x, y);
323: }
324: }
325:
326: public static Point getControlLocation(ScrolledComposite scomp,
327: Control control) {
328: int x = 0;
329: int y = 0;
330: Control content = scomp.getContent();
331: Control currentControl = control;
332: for (;;) {
333: if (currentControl == content)
334: break;
335: Point location = currentControl.getLocation();
336: // if (location.x > 0)
337: // x += location.x;
338: // if (location.y > 0)
339: // y += location.y;
340: x += location.x;
341: y += location.y;
342: currentControl = currentControl.getParent();
343: }
344: return new Point(x, y);
345: }
346:
347: static void scrollVertical(ScrolledComposite scomp, boolean up) {
348: scroll(scomp, 0, up ? -V_SCROLL_INCREMENT : V_SCROLL_INCREMENT);
349: }
350:
351: static void scrollHorizontal(ScrolledComposite scomp, boolean left) {
352: scroll(scomp, left ? -H_SCROLL_INCREMENT : H_SCROLL_INCREMENT,
353: 0);
354: }
355:
356: static void scrollPage(ScrolledComposite scomp, boolean up) {
357: Rectangle clientArea = scomp.getClientArea();
358: int increment = up ? -clientArea.height : clientArea.height;
359: scroll(scomp, 0, increment);
360: }
361:
362: static void scroll(ScrolledComposite scomp, int xoffset, int yoffset) {
363: Point origin = scomp.getOrigin();
364: Point contentSize = scomp.getContent().getSize();
365: int xorigin = origin.x + xoffset;
366: int yorigin = origin.y + yoffset;
367: xorigin = Math.max(xorigin, 0);
368: xorigin = Math.min(xorigin, contentSize.x - 1);
369: yorigin = Math.max(yorigin, 0);
370: yorigin = Math.min(yorigin, contentSize.y - 1);
371: scomp.setOrigin(xorigin, yorigin);
372: }
373:
374: public static void updatePageIncrement(ScrolledComposite scomp) {
375: ScrollBar vbar = scomp.getVerticalBar();
376: if (vbar != null) {
377: Rectangle clientArea = scomp.getClientArea();
378: int increment = clientArea.height - 5;
379: vbar.setPageIncrement(increment);
380: }
381: }
382:
383: public static void processKey(int keyCode, Control c) {
384: ScrolledComposite scomp = FormUtil.getScrolledComposite(c);
385: if (scomp != null) {
386: if (c instanceof Combo)
387: return;
388: switch (keyCode) {
389: case SWT.ARROW_DOWN:
390: if (scomp.getData("novarrows") == null) //$NON-NLS-1$
391: FormUtil.scrollVertical(scomp, false);
392: break;
393: case SWT.ARROW_UP:
394: if (scomp.getData("novarrows") == null) //$NON-NLS-1$
395: FormUtil.scrollVertical(scomp, true);
396: break;
397: case SWT.ARROW_LEFT:
398: FormUtil.scrollHorizontal(scomp, true);
399: break;
400: case SWT.ARROW_RIGHT:
401: FormUtil.scrollHorizontal(scomp, false);
402: break;
403: case SWT.PAGE_UP:
404: FormUtil.scrollPage(scomp, true);
405: break;
406: case SWT.PAGE_DOWN:
407: FormUtil.scrollPage(scomp, false);
408: break;
409: }
410: }
411: }
412:
413: public static boolean isWrapControl(Control c) {
414: if ((c.getStyle() & SWT.WRAP) != 0)
415: return true;
416: if (c instanceof Composite) {
417: return ((Composite) c).getLayout() instanceof ILayoutExtension;
418: }
419: return false;
420: }
421:
422: public static int getWidthHint(int wHint, Control c) {
423: boolean wrap = isWrapControl(c);
424: return wrap ? wHint : SWT.DEFAULT;
425: }
426:
427: public static int getHeightHint(int hHint, Control c) {
428: if (c instanceof Composite) {
429: Layout layout = ((Composite) c).getLayout();
430: if (layout instanceof ColumnLayout)
431: return hHint;
432: }
433: return SWT.DEFAULT;
434: }
435:
436: public static int computeMinimumWidth(Control c, boolean changed) {
437: if (c instanceof Composite) {
438: Layout layout = ((Composite) c).getLayout();
439: if (layout instanceof ILayoutExtension)
440: return ((ILayoutExtension) layout).computeMinimumWidth(
441: (Composite) c, changed);
442: }
443: return c.computeSize(FormUtil.getWidthHint(5, c), SWT.DEFAULT,
444: changed).x;
445: }
446:
447: public static int computeMaximumWidth(Control c, boolean changed) {
448: if (c instanceof Composite) {
449: Layout layout = ((Composite) c).getLayout();
450: if (layout instanceof ILayoutExtension)
451: return ((ILayoutExtension) layout).computeMaximumWidth(
452: (Composite) c, changed);
453: }
454: return c.computeSize(SWT.DEFAULT, SWT.DEFAULT, changed).x;
455: }
456:
457: public static Form getForm(Control c) {
458: Composite parent = c.getParent();
459: while (parent != null) {
460: if (parent instanceof Form) {
461: return (Form) parent;
462: }
463: parent = parent.getParent();
464: }
465: return null;
466: }
467:
468: public static Image createAlphaMashImage(Device device,
469: Image srcImage) {
470: Rectangle bounds = srcImage.getBounds();
471: int alpha = 0;
472: int calpha = 0;
473: ImageData data = srcImage.getImageData();
474: // Create a new image with alpha values alternating
475: // between fully transparent (0) and fully opaque (255).
476: // This image will show the background through the
477: // transparent pixels.
478: for (int i = 0; i < bounds.height; i++) {
479: // scan line
480: alpha = calpha;
481: for (int j = 0; j < bounds.width; j++) {
482: // column
483: data.setAlpha(j, i, alpha);
484: alpha = alpha == 255 ? 0 : 255;
485: }
486: calpha = calpha == 255 ? 0 : 255;
487: }
488: return new Image(device, data);
489: }
490:
491: public static Font createBoldFont(Display display, Font regularFont) {
492: FontData[] fontDatas = regularFont.getFontData();
493: for (int i = 0; i < fontDatas.length; i++) {
494: fontDatas[i].setStyle(fontDatas[i].getStyle() | SWT.BOLD);
495: }
496: return new Font(display, fontDatas);
497: }
498:
499: public static boolean mnemonicMatch(String text, char key) {
500: char mnemonic = findMnemonic(text);
501: if (mnemonic == '\0')
502: return false;
503: return Character.toUpperCase(key) == Character
504: .toUpperCase(mnemonic);
505: }
506:
507: private static char findMnemonic(String string) {
508: int index = 0;
509: int length = string.length();
510: do {
511: while (index < length && string.charAt(index) != '&')
512: index++;
513: if (++index >= length)
514: return '\0';
515: if (string.charAt(index) != '&')
516: return string.charAt(index);
517: index++;
518: } while (index < length);
519: return '\0';
520: }
521:
522: public static void setFocusScrollingEnabled(Control c,
523: boolean enabled) {
524: ScrolledComposite scomp = null;
525:
526: if (c instanceof ScrolledComposite)
527: scomp = (ScrolledComposite) c;
528: else
529: scomp = getScrolledComposite(c);
530: if (scomp != null)
531: scomp.setData(FormUtil.FOCUS_SCROLLING, enabled ? null
532: : Boolean.FALSE);
533: }
534:
535: public static void setAntialias(GC gc, int style) {
536: if (!gc.getAdvanced()) {
537: gc.setAdvanced(true);
538: if (!gc.getAdvanced())
539: return;
540: }
541: gc.setAntialias(style);
542: }
543: }
|