~ubuntu-branches/debian/stretch/insubstantial/stretch

« back to all changes in this revision

Viewing changes to substance/src/main/java/org/pushingpixels/substance/internal/contrib/randelshofer/quaqua/QuaquaUtilities.java

  • Committer: Package Import Robot
  • Author(s): Felix Natter
  • Date: 2016-01-18 20:58:45 UTC
  • Revision ID: package-import@ubuntu.com-20160118205845-crbmrkda61qsi5qa
Tags: upstream-7.3+dfsg2
ImportĀ upstreamĀ versionĀ 7.3+dfsg2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * @(#)QuaquaUtilities.java  3.1  2006-09-04
 
3
 *
 
4
 * Copyright (c) 2003-2006 Werner Randelshofer
 
5
 * Staldenmattweg 2, Immensee, CH-6405, Switzerland.
 
6
 * All rights reserved.
 
7
 *
 
8
 * This software is the confidential and proprietary information of
 
9
 * Werner Randelshofer. ("Confidential Information").  You shall not
 
10
 * disclose such Confidential Information and shall use it only in
 
11
 * accordance with the terms of the license agreement you entered into
 
12
 * with Werner Randelshofer.
 
13
 */
 
14
 
 
15
package org.pushingpixels.substance.internal.contrib.randelshofer.quaqua;
 
16
 
 
17
import java.applet.*;
 
18
import java.awt.*;
 
19
import java.awt.event.*;
 
20
import java.awt.font.*;
 
21
import java.awt.image.*;
 
22
import java.awt.peer.*;
 
23
import java.net.*;
 
24
import javax.swing.*;
 
25
import javax.swing.text.*;
 
26
import javax.swing.border.*;
 
27
import javax.swing.plaf.*;
 
28
import javax.swing.plaf.basic.*;
 
29
 
 
30
import org.pushingpixels.substance.internal.contrib.randelshofer.quaqua.util.*;
 
31
 
 
32
/**
 
33
 * Utility class for the Quaqua LAF.
 
34
 *
 
35
 * @author Werner Randelshofer, Staldenmattweg 2, CH-6405 Immensee, Switzerland
 
36
 * @version 3.1 2006-09-04 Added method compositeRequestFocus.
 
37
 * <br>3.0.5 2006-08-20 Method endGraphics must not set
 
38
 * KEY_TEXT_ANTIALIASING to null.
 
39
 * <br>3.0.4 2006-02-19 Catch Throwable in method setWindowAlpha instead
 
40
 * of catching NoSuchMethodException.
 
41
 * <br>3.0.3 2006-01-08 Don't set Window alpha, when running on
 
42
 * Java 1.4.2_05 on Mac OS X 10.3.5. Because this only has the effect of turning
 
43
 * the background color of the Window to white.
 
44
 * <br>3.0.2 2005-12-10 Method isOnActiveWindow() did not reliably
 
45
 * return true.
 
46
 * <br>3.0.1 2005-11-12 Fixed NPE in method repaint border.
 
47
 * <br>3.0 2005-09-24 Removed all reflection helper methods. Moved Sheet
 
48
 * helper methods out into class Sheets.
 
49
 * <br>2.6 2005-09-17 Method isOnFocusedWindow returns true, if
 
50
 * the window returns false on "getFocusableWindowState".
 
51
 * <br>2.5 2005-03-13 Renamed method isFrameActive to isOnActiveFrame.
 
52
 * <br>2.4 2004-12-28 Method createBufferdImage added. Method
 
53
 * isOnActiveWindow() renamed to isFrameActive().
 
54
 * <br>2.3 2004-12-14 Method getUI added.
 
55
 * <br>2.2.1 2004-12-01 Methods setDragEnabled and getDragEnabled never
 
56
 * worked because the attempted to get method objects on the wrong class.
 
57
 * <br>2.2 2004-09-19 Refined algorithm of method isFrameActive.
 
58
 * <br>2.1 2004-07-04 Methods repaintBorder, beginFont, endFont and
 
59
 * isFocused added.
 
60
 * <br>2.0 2004-04-27 Renamed from QuaquaGraphicUtils to QuaquaUtilities.
 
61
 * Added method isFrameActive(Component).
 
62
 * <br>1.1.1 2003-10-08 Diagnostic output to System.out removed.
 
63
 * <br>1.1 2003-10-05 Methods getModifiersText and getModifiersUnicode
 
64
 * added.
 
65
 * <br>1.0 2003-07-19 Created.
 
66
 */
 
67
public class QuaquaUtilities extends BasicGraphicsUtils implements SwingConstants {
 
68
    /** Prevent instance creation. */
 
69
    private QuaquaUtilities() {
 
70
    }
 
71
    
 
72
    /*
 
73
     * Convenience function for determining ComponentOrientation.  Helps us
 
74
     * avoid having Munge directives throughout the code.
 
75
     */
 
76
    public static boolean isLeftToRight( Component c ) {
 
77
        return c.getComponentOrientation().isLeftToRight();
 
78
    }
 
79
    
 
80
    /**
 
81
     * Draw a string with the graphics <code>g</code> at location
 
82
     * (<code>x</code>, <code>y</code>)
 
83
     * just like <code>g.drawString</code> would.
 
84
     * The character at index <code>underlinedIndex</code>
 
85
     * in text will be underlined. If <code>index</code> is beyond the
 
86
     * bounds of <code>text</code> (including < 0), nothing will be
 
87
     * underlined.
 
88
     *
 
89
     * @param g Graphics to draw with
 
90
     * @param text String to draw
 
91
     * @param underlinedIndex Index of character in text to underline
 
92
     * @param x x coordinate to draw at
 
93
     * @param y y coordinate to draw at
 
94
     * @since 1.4
 
95
     */
 
96
    public static void drawStringUnderlineCharAt(Graphics g, String text,
 
97
            int underlinedIndex, int x,int y) {
 
98
        g.drawString(text,x,y);
 
99
        if (underlinedIndex >= 0 && underlinedIndex < text.length() ) {
 
100
            FontMetrics fm = g.getFontMetrics();
 
101
            int underlineRectX = x + fm.stringWidth(text.substring(0,underlinedIndex));
 
102
            int underlineRectY = y;
 
103
            int underlineRectWidth = fm.charWidth(text.charAt(underlinedIndex));
 
104
            int underlineRectHeight = 1;
 
105
            g.fillRect(underlineRectX, underlineRectY + fm.getDescent() - 1,
 
106
                    underlineRectWidth, underlineRectHeight);
 
107
        }
 
108
    }
 
109
    /**
 
110
     * Returns index of the first occurrence of <code>mnemonic</code>
 
111
     * within string <code>text</code>. Matching algorithm is not
 
112
     * case-sensitive.
 
113
     *
 
114
     * @param text The text to search through, may be null
 
115
     * @param mnemonic The mnemonic to find the character for.
 
116
     * @return index into the string if exists, otherwise -1
 
117
     */
 
118
    static int findDisplayedMnemonicIndex(String text, int mnemonic) {
 
119
        if (text == null || mnemonic == '\0') {
 
120
            return -1;
 
121
        }
 
122
        
 
123
        char uc = Character.toUpperCase((char)mnemonic);
 
124
        char lc = Character.toLowerCase((char)mnemonic);
 
125
        
 
126
        int uci = text.indexOf(uc);
 
127
        int lci = text.indexOf(lc);
 
128
        
 
129
        if (uci == -1) {
 
130
            return lci;
 
131
        } else if(lci == -1) {
 
132
            return uci;
 
133
        } else {
 
134
            return (lci < uci) ? lci : uci;
 
135
        }
 
136
    }
 
137
    
 
138
    /**
 
139
     * Returns true if the component is on a Dialog or a Frame, which is active,
 
140
     * or if it is on a Window, which is focused.
 
141
     * Always returns true, if the component has no parent window.
 
142
     */
 
143
    public static boolean isOnActiveWindow(Component c) {
 
144
        // In the RootPaneUI, we set a client property on the whole component
 
145
        // tree, if the ancestor Frame gets activated or deactivated.
 
146
        if (c instanceof JComponent) {
 
147
            Boolean value = (Boolean) ((JComponent) c).getClientProperty("Frame.active");
 
148
            // Unfortunately, the value is not always reliable.
 
149
            // Therefore we can only do a short circuit, if the value is true.
 
150
            if (value != null && value) {
 
151
                return true;
 
152
                //return value.booleanValue();
 
153
            }
 
154
        }
 
155
        /*
 
156
        // This is how I would have implemented the code, if Quaqua would
 
157
        // not be required to work an a Java 1.3 VM.
 
158
        Window window = SwingUtilities.getWindowAncestor(c);
 
159
        if (window == null) {
 
160
            return true;
 
161
        } else if ((window instanceof Frame) || (window instanceof Dialog)) {
 
162
            return window.isActive();
 
163
        } else {
 
164
            if (window.getFocusableWindowState()) {
 
165
                return window.isFocused();
 
166
            } else {
 
167
                return true;
 
168
            }
 
169
        }
 
170
         */
 
171
        
 
172
        // If we missed the client property or if it was false, we have to
 
173
        // figure out the activation state on our own.
 
174
        // The following code works from Java 1.3 onwards.
 
175
        Window window = SwingUtilities.getWindowAncestor(c);
 
176
        boolean isOnActiveWindow;
 
177
        if (window == null) {
 
178
            isOnActiveWindow = true;
 
179
        } else if ((window instanceof Frame) || (window instanceof Dialog)) {
 
180
            isOnActiveWindow = Methods.invokeGetter(window, "isActive", true);
 
181
        } else {
 
182
            if (Methods.invokeGetter(window, "getFocusableWindowState", true)) {
 
183
                isOnActiveWindow = Methods.invokeGetter(window, "isFocused", true);
 
184
            } else {
 
185
                isOnActiveWindow = true;
 
186
            }
 
187
        }
 
188
        
 
189
        // In case the activation property is true, we fix the value of the
 
190
        // client property, so that we can do a short circuit next time.
 
191
        if (isOnActiveWindow && (c instanceof JComponent)) {
 
192
            ((JComponent) c).putClientProperty("Frame.active", isOnActiveWindow);
 
193
        }
 
194
        return isOnActiveWindow;
 
195
    }
 
196
    
 
197
    /**
 
198
     * Returns a Mac OS X specific String describing the modifier key(s),
 
199
     * such as "Shift", or "Ctrl+Shift".
 
200
     *
 
201
     * @return string a text description of the combination of modifier
 
202
     *                keys that were held down during the event
 
203
     */
 
204
    public static String getKeyModifiersText(int modifiers, boolean leftToRight) {
 
205
        return getKeyModifiersUnicode(modifiers, leftToRight);
 
206
    }
 
207
    static String getKeyModifiersUnicode(int modifiers, boolean leftToRight) {
 
208
        char[] cs = new char[4];
 
209
        int count = 0;
 
210
        if (leftToRight) {
 
211
            if ((modifiers & InputEvent.CTRL_MASK) != 0)
 
212
                cs[count++] = '\u2303'; // Unicode: UP ARROWHEAD
 
213
            if ((modifiers & (InputEvent.ALT_MASK | InputEvent.ALT_GRAPH_MASK)) != 0)
 
214
                cs[count++] = '\u2325'; // Unicode: OPTION KEY
 
215
            if ((modifiers & InputEvent.SHIFT_MASK) != 0)
 
216
                cs[count++] = '\u21e7'; // Unicode: UPWARDS WHITE ARROW
 
217
            if ((modifiers & InputEvent.META_MASK) != 0)
 
218
                cs[count++] = '\u2318'; // Unicode: PLACE OF INTEREST SIGN
 
219
        } else {
 
220
            if ((modifiers & InputEvent.META_MASK) != 0)
 
221
                cs[count++] = '\u2318'; // Unicode: PLACE OF INTEREST SIGN
 
222
            if ((modifiers & InputEvent.SHIFT_MASK) != 0)
 
223
                cs[count++] = '\u21e7'; // Unicode: UPWARDS WHITE ARROW
 
224
            if ((modifiers & (InputEvent.ALT_MASK | InputEvent.ALT_GRAPH_MASK)) != 0)
 
225
                cs[count++] = '\u2325'; // Unicode: OPTION KEY
 
226
            if ((modifiers & InputEvent.CTRL_MASK) != 0)
 
227
                cs[count++] = '\u2303'; // Unicode: UP ARROWHEAD
 
228
        }
 
229
        return new String(cs, 0, count);
 
230
    }
 
231
    
 
232
    public static void repaintBorder(JComponent component) {
 
233
        JComponent c = component;
 
234
        Border border = null;
 
235
        Container container = component.getParent();
 
236
        if (container instanceof JViewport) {
 
237
            c = (JComponent) container.getParent();
 
238
            if (c != null) {
 
239
                border = c.getBorder();
 
240
            }
 
241
        }
 
242
        if (border == null) {
 
243
            border = component.getBorder();
 
244
            c = component;
 
245
        }
 
246
        if (border != null && c != null) {
 
247
            int w = c.getWidth();
 
248
            int h = c.getHeight();
 
249
            Insets insets = c.getInsets();
 
250
            c.repaint(0, 0, w, insets.top);
 
251
            c.repaint(0, 0, insets.left, h);
 
252
            c.repaint(0, h - insets.bottom, w, insets.bottom);
 
253
            c.repaint(w - insets.right, 0, insets.right, h);
 
254
        }
 
255
    }
 
256
    public static final Object beginGraphics(Graphics2D graphics2d) {
 
257
        Object object = graphics2d.getRenderingHint(RenderingHints
 
258
                .KEY_TEXT_ANTIALIASING);
 
259
        graphics2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
 
260
                RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
 
261
        return object;
 
262
    }
 
263
    
 
264
    public static final void endGraphics(Graphics2D graphics2d, Object oldHints) {
 
265
        if (oldHints != null) {
 
266
            graphics2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
 
267
                    oldHints);
 
268
        }
 
269
    }
 
270
    public static final boolean isFocused(Component component) {
 
271
        if (QuaquaUtilities.isOnActiveWindow(component)) {
 
272
            Component c = component;
 
273
            if (c instanceof JComponent) {
 
274
                if (c instanceof JScrollPane) {
 
275
                    JViewport viewport = ((JScrollPane) component).getViewport();
 
276
                    if (viewport != null) {
 
277
                        c = viewport.getView();
 
278
                    }
 
279
                }
 
280
                if (c instanceof JTextComponent
 
281
                        && !((JTextComponent) c).isEditable()) {
 
282
                    return false;
 
283
                }
 
284
                return c != null
 
285
                        && (((JComponent) c).hasFocus() || ((JComponent) c).getClientProperty("Quaqua.drawFocusBorder") == Boolean.TRUE);
 
286
            }
 
287
        }
 
288
        return false;
 
289
    }
 
290
    
 
291
    static boolean isHeadless() {
 
292
        return Methods.invokeStaticGetter(GraphicsEnvironment.class, "isHeadless", false);
 
293
    }
 
294
    
 
295
    public static int getLeftSideBearing(Font f, String string) {
 
296
        return (Integer) Methods.invokeStatic(
 
297
                "com.sun.java.swing.SwingUtilities2", "getLeftSideBearing",
 
298
                new Class[]{Font.class, String.class}, new Object[]{f, string},
 
299
                new Integer(0));
 
300
    }
 
301
    
 
302
    /**
 
303
     * Invoked when the user attempts an invalid operation,
 
304
     * such as pasting into an uneditable <code>JTextField</code>
 
305
     * that has focus. The default implementation beeps. Subclasses
 
306
     * that wish different behavior should override this and provide
 
307
     * the additional feedback.
 
308
     *
 
309
     * @param component Component the error occured in, may be null
 
310
     *                  indicating the error condition is not directly
 
311
     *                  associated with a <code>Component</code>.
 
312
     */
 
313
    static void provideErrorFeedback(Component component) {
 
314
        Toolkit toolkit = null;
 
315
        if (component != null) {
 
316
            toolkit = component.getToolkit();
 
317
        } else {
 
318
            toolkit = Toolkit.getDefaultToolkit();
 
319
        }
 
320
        toolkit.beep();
 
321
    } // provideErrorFeedback()
 
322
    
 
323
    public static BufferedImage createBufferedImage(URL location) {
 
324
        Image image = Toolkit.getDefaultToolkit().createImage(location);
 
325
        BufferedImage buf;
 
326
        if (image instanceof BufferedImage) {
 
327
            buf = (BufferedImage) image;
 
328
        } else {
 
329
            loadImage(image);
 
330
            //buf = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
 
331
            buf = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().createCompatibleImage(image.getWidth(null), image.getHeight(null), Transparency.OPAQUE);
 
332
            
 
333
            Graphics g = buf.getGraphics();
 
334
            g.drawImage(image, 0, 0, null);
 
335
            g.dispose();
 
336
            image.flush();
 
337
        }
 
338
        return buf;
 
339
    }
 
340
    public static TexturePaint createTexturePaint(URL location) {
 
341
        BufferedImage texture = createBufferedImage(location);
 
342
        TexturePaint paint = new TexturePaint(texture, new Rectangle(0, 0, texture.getWidth(), texture.getHeight()));
 
343
        return paint;
 
344
    }
 
345
    
 
346
    
 
347
    /**
 
348
     * Loads the image, returning only when the image is loaded.
 
349
     * @param image the image
 
350
     */
 
351
    private static void loadImage(Image image) {
 
352
        Component component = new Component() {};
 
353
        MediaTracker tracker = new MediaTracker(component);
 
354
        synchronized (tracker) {
 
355
            int id = 0;
 
356
            
 
357
            tracker.addImage(image, id);
 
358
            try {
 
359
                tracker.waitForID(id, 0);
 
360
            } catch (InterruptedException e) {
 
361
                System.out.println("INTERRUPTED while loading Image");
 
362
            }
 
363
            int loadStatus = tracker.statusID(id, false);
 
364
            tracker.removeImage(image, id);
 
365
        }
 
366
    }
 
367
    
 
368
    /**
 
369
     * Compute and return the location of the icons origin, the
 
370
     * location of origin of the text baseline, and a possibly clipped
 
371
     * version of the compound labels string.  Locations are computed
 
372
     * relative to the viewR rectangle.
 
373
     * The JComponents orientation (LEADING/TRAILING) will also be taken
 
374
     * into account and translated into LEFT/RIGHT values accordingly.
 
375
     */
 
376
    public static String layoutCompoundLabel(JComponent c,
 
377
            FontMetrics fm,
 
378
            String text,
 
379
            Icon icon,
 
380
            int verticalAlignment,
 
381
            int horizontalAlignment,
 
382
            int verticalTextPosition,
 
383
            int horizontalTextPosition,
 
384
            Rectangle viewR,
 
385
            Rectangle iconR,
 
386
            Rectangle textR,
 
387
            int textIconGap) {
 
388
        boolean orientationIsLeftToRight = true;
 
389
        int     hAlign = horizontalAlignment;
 
390
        int     hTextPos = horizontalTextPosition;
 
391
        
 
392
        if (c != null) {
 
393
            if (!(c.getComponentOrientation().isLeftToRight())) {
 
394
                orientationIsLeftToRight = false;
 
395
            }
 
396
        }
 
397
        
 
398
        // Translate LEADING/TRAILING values in horizontalAlignment
 
399
        // to LEFT/RIGHT values depending on the components orientation
 
400
        switch (horizontalAlignment) {
 
401
            case LEADING:
 
402
                hAlign = (orientationIsLeftToRight) ? LEFT : RIGHT;
 
403
                break;
 
404
            case TRAILING:
 
405
                hAlign = (orientationIsLeftToRight) ? RIGHT : LEFT;
 
406
                break;
 
407
        }
 
408
        
 
409
        // Translate LEADING/TRAILING values in horizontalTextPosition
 
410
        // to LEFT/RIGHT values depending on the components orientation
 
411
        switch (horizontalTextPosition) {
 
412
            case LEADING:
 
413
                hTextPos = (orientationIsLeftToRight) ? LEFT : RIGHT;
 
414
                break;
 
415
            case TRAILING:
 
416
                hTextPos = (orientationIsLeftToRight) ? RIGHT : LEFT;
 
417
                break;
 
418
        }
 
419
        
 
420
        return layoutCompoundLabelImpl(c,
 
421
                fm,
 
422
                text,
 
423
                icon,
 
424
                verticalAlignment,
 
425
                hAlign,
 
426
                verticalTextPosition,
 
427
                hTextPos,
 
428
                viewR,
 
429
                iconR,
 
430
                textR,
 
431
                textIconGap);
 
432
    }
 
433
    
 
434
    /**
 
435
     * Compute and return the location of the icons origin, the
 
436
     * location of origin of the text baseline, and a possibly clipped
 
437
     * version of the compound labels string.  Locations are computed
 
438
     * relative to the viewR rectangle.
 
439
     * This layoutCompoundLabel() does not know how to handle LEADING/TRAILING
 
440
     * values in horizontalTextPosition (they will default to RIGHT) and in
 
441
     * horizontalAlignment (they will default to CENTER).
 
442
     * Use the other version of layoutCompoundLabel() instead.
 
443
     */
 
444
    public static String layoutCompoundLabel(
 
445
            FontMetrics fm,
 
446
            String text,
 
447
            Icon icon,
 
448
            int verticalAlignment,
 
449
            int horizontalAlignment,
 
450
            int verticalTextPosition,
 
451
            int horizontalTextPosition,
 
452
            Rectangle viewR,
 
453
            Rectangle iconR,
 
454
            Rectangle textR,
 
455
            int textIconGap) {
 
456
        return layoutCompoundLabelImpl(null, fm, text, icon,
 
457
                verticalAlignment,
 
458
                horizontalAlignment,
 
459
                verticalTextPosition,
 
460
                horizontalTextPosition,
 
461
                viewR, iconR, textR, textIconGap);
 
462
    }
 
463
    
 
464
    /**
 
465
     * Compute and return the location of the icons origin, the
 
466
     * location of origin of the text baseline, and a possibly clipped
 
467
     * version of the compound labels string.  Locations are computed
 
468
     * relative to the viewR rectangle.
 
469
     * This layoutCompoundLabel() does not know how to handle LEADING/TRAILING
 
470
     * values in horizontalTextPosition (they will default to RIGHT) and in
 
471
     * horizontalAlignment (they will default to CENTER).
 
472
     * Use the other version of layoutCompoundLabel() instead.
 
473
     *
 
474
     * This is the same as SwingUtilities.layoutCompoundLabelImpl, except for
 
475
     * the algorithm for clipping the text. If a text is too long, "..." are
 
476
     * inserted at the middle of the text instead of at the end.
 
477
     */
 
478
    private static String layoutCompoundLabelImpl(
 
479
            JComponent c,
 
480
            FontMetrics fm,
 
481
            String text,
 
482
            Icon icon,
 
483
            int verticalAlignment,
 
484
            int horizontalAlignment,
 
485
            int verticalTextPosition,
 
486
            int horizontalTextPosition,
 
487
            Rectangle viewR,
 
488
            Rectangle iconR,
 
489
            Rectangle textR,
 
490
            int textIconGap) {
 
491
        /* Initialize the icon bounds rectangle iconR.
 
492
         */
 
493
        
 
494
        if (icon != null) {
 
495
            iconR.width = icon.getIconWidth();
 
496
            iconR.height = icon.getIconHeight();
 
497
        } else {
 
498
            iconR.width = iconR.height = 0;
 
499
        }
 
500
        
 
501
        /* Initialize the text bounds rectangle textR.  If a null
 
502
         * or and empty String was specified we substitute "" here
 
503
         * and use 0,0,0,0 for textR.
 
504
         */
 
505
        
 
506
        boolean textIsEmpty = (text == null) || text.equals("");
 
507
        int lsb = 0;
 
508
        
 
509
        View v = null;
 
510
        if (textIsEmpty) {
 
511
            textR.width = textR.height = 0;
 
512
            text = "";
 
513
        } else {
 
514
            v = (c != null) ? (View) c.getClientProperty("html") : null;
 
515
            if (v != null) {
 
516
                textR.width = (int) v.getPreferredSpan(View.X_AXIS);
 
517
                textR.height = (int) v.getPreferredSpan(View.Y_AXIS);
 
518
            } else {
 
519
                textR.width = SwingUtilities.computeStringWidth(fm,text);
 
520
                
 
521
                lsb = getLeftSideBearing(fm.getFont(), text);
 
522
                if (lsb < 0) {
 
523
                    // If lsb is negative, add it to the width, the
 
524
                    // text bounds will later be adjusted accordingly.
 
525
                    textR.width -= lsb;
 
526
                }
 
527
                textR.height = fm.getHeight();
 
528
            }
 
529
        }
 
530
        
 
531
        /* Unless both text and icon are non-null, we effectively ignore
 
532
         * the value of textIconGap.  The code that follows uses the
 
533
         * value of gap instead of textIconGap.
 
534
         */
 
535
        
 
536
        int gap = (textIsEmpty || (icon == null)) ? 0 : textIconGap;
 
537
        
 
538
        if (!textIsEmpty) {
 
539
            
 
540
            /* If the label text string is too wide to fit within the available
 
541
             * space "..." and as many characters as will fit will be
 
542
             * displayed instead.
 
543
             */
 
544
            
 
545
            int availTextWidth;
 
546
            
 
547
            if (horizontalTextPosition == CENTER) {
 
548
                availTextWidth = viewR.width;
 
549
            } else {
 
550
                availTextWidth = viewR.width - (iconR.width + gap);
 
551
            }
 
552
            
 
553
            
 
554
            if (textR.width > availTextWidth) {
 
555
                if (v != null) {
 
556
                    textR.width = availTextWidth;
 
557
                } else {
 
558
                    String clipString = "...";
 
559
                    int totalWidth = SwingUtilities.computeStringWidth(fm,clipString);
 
560
                    int nChars;
 
561
                    int len = text.length();
 
562
                    for(nChars = 0; nChars < len; nChars++) {
 
563
                        int charIndex = (nChars % 2 == 0) ? nChars / 2 : len - 1 - nChars / 2;
 
564
                        totalWidth += fm.charWidth(text.charAt(charIndex));
 
565
                        if (totalWidth > availTextWidth) {
 
566
                            break;
 
567
                        }
 
568
                    }
 
569
                    text = text.substring(0, nChars / 2) + clipString + text.substring(len - nChars / 2);
 
570
                    textR.width = SwingUtilities.computeStringWidth(fm,text);
 
571
                }
 
572
            }
 
573
        }
 
574
        
 
575
        
 
576
        /* Compute textR.x,y given the verticalTextPosition and
 
577
         * horizontalTextPosition properties
 
578
         */
 
579
        
 
580
        if (verticalTextPosition == TOP) {
 
581
            if (horizontalTextPosition != CENTER) {
 
582
                textR.y = 0;
 
583
            } else {
 
584
                textR.y = -(textR.height + gap);
 
585
            }
 
586
        } else if (verticalTextPosition == CENTER) {
 
587
            textR.y = (iconR.height / 2) - (textR.height / 2);
 
588
        } else { // (verticalTextPosition == BOTTOM)
 
589
            if (horizontalTextPosition != CENTER) {
 
590
                textR.y = iconR.height - textR.height;
 
591
            } else {
 
592
                textR.y = (iconR.height + gap);
 
593
            }
 
594
        }
 
595
        
 
596
        if (horizontalTextPosition == LEFT) {
 
597
            textR.x = -(textR.width + gap);
 
598
        } else if (horizontalTextPosition == CENTER) {
 
599
            textR.x = (iconR.width / 2) - (textR.width / 2);
 
600
        } else { // (horizontalTextPosition == RIGHT)
 
601
            textR.x = (iconR.width + gap);
 
602
        }
 
603
        
 
604
        /* labelR is the rectangle that contains iconR and textR.
 
605
         * Move it to its proper position given the labelAlignment
 
606
         * properties.
 
607
         *
 
608
         * To avoid actually allocating a Rectangle, Rectangle.union
 
609
         * has been inlined below.
 
610
         */
 
611
        int labelR_x = Math.min(iconR.x, textR.x);
 
612
        int labelR_width = Math.max(iconR.x + iconR.width,
 
613
                textR.x + textR.width) - labelR_x;
 
614
        int labelR_y = Math.min(iconR.y, textR.y);
 
615
        int labelR_height = Math.max(iconR.y + iconR.height,
 
616
                textR.y + textR.height) - labelR_y;
 
617
        
 
618
        int dx, dy;
 
619
        
 
620
        if (verticalAlignment == TOP) {
 
621
            dy = viewR.y - labelR_y;
 
622
        } else if (verticalAlignment == CENTER) {
 
623
            dy = (viewR.y + (viewR.height / 2)) - (labelR_y + (labelR_height / 2));
 
624
        } else { // (verticalAlignment == BOTTOM)
 
625
            dy = (viewR.y + viewR.height) - (labelR_y + labelR_height);
 
626
        }
 
627
        
 
628
        if (horizontalAlignment == LEFT) {
 
629
            dx = viewR.x - labelR_x;
 
630
        } else if (horizontalAlignment == RIGHT) {
 
631
            dx = (viewR.x + viewR.width) - (labelR_x + labelR_width);
 
632
        } else { // (horizontalAlignment == CENTER)
 
633
            dx = (viewR.x + (viewR.width / 2)) -
 
634
                    (labelR_x + (labelR_width / 2));
 
635
        }
 
636
        
 
637
        /* Translate textR and glypyR by dx,dy.
 
638
         */
 
639
        
 
640
        textR.x += dx;
 
641
        textR.y += dy;
 
642
        
 
643
        iconR.x += dx;
 
644
        iconR.y += dy;
 
645
        
 
646
        if (lsb < 0) {
 
647
            // lsb is negative. We previously adjusted the bounds by lsb,
 
648
            // we now need to shift the x location so that the text is
 
649
            // drawn at the right location. The result is textR does not
 
650
            // line up with the actual bounds (on the left side), but we will
 
651
            // have provided enough space for the text.
 
652
            textR.width += lsb;
 
653
            textR.x -= lsb;
 
654
        }
 
655
        
 
656
        return text;
 
657
    }
 
658
    
 
659
    public static void configureGraphics(Graphics gr) {
 
660
        Graphics2D g = (Graphics2D) gr;
 
661
        g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
 
662
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
 
663
        g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
 
664
    }
 
665
    
 
666
    /** Copied from BasicLookAndFeel.
 
667
     */
 
668
    public static Component compositeRequestFocus(Component component) {
 
669
        try {
 
670
            if (component instanceof Container) {
 
671
                Container container = (Container)component;
 
672
                if (Methods.invokeGetter(container,"isFocusCycleRoot", false)) {
 
673
                    
 
674
                    Object policy = Methods.invokeGetter(container,"getFocusTraversalPolicy", null);
 
675
                    Component comp = (Component) Methods.invoke(policy,"getDefaultComponent", Container.class, container);
 
676
                    if (comp!=null) {
 
677
                        comp.requestFocus();
 
678
                        return comp;
 
679
                    }
 
680
                }
 
681
                Container rootAncestor = (Container) Methods.invokeGetter(container, "getFocusCycleRootAncestor", null);
 
682
                if (rootAncestor!=null) {
 
683
                    Object policy = Methods.invokeGetter(rootAncestor,"getFocusTraversalPolicy", null);
 
684
                    Component comp = (Component) Methods.invoke(policy,"getComponentAfter",
 
685
                            new Class[] {Container.class, Component.class},
 
686
                            new Object[] {rootAncestor, container});
 
687
                    
 
688
                    if (comp!=null && SwingUtilities.isDescendingFrom(comp, container)) {
 
689
                        comp.requestFocus();
 
690
                        return comp;
 
691
                    }
 
692
                }
 
693
            }
 
694
        } catch (NoSuchMethodException e) {
 
695
            // ignore
 
696
        }
 
697
        if (Methods.invokeGetter(component,"isFocusable", true)) {
 
698
            component.requestFocus();
 
699
            return component;
 
700
        }
 
701
        return null;
 
702
    }
 
703
}
 
 
b'\\ No newline at end of file'