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

« back to all changes in this revision

Viewing changes to laf-widget/src/main/java/org/pushingpixels/lafwidget/tabbed/TabOverviewDialog.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
 * Copyright (c) 2005-2010 Laf-Widget Kirill Grouchnikov. All Rights Reserved.
 
3
 *
 
4
 * Redistribution and use in source and binary forms, with or without
 
5
 * modification, are permitted provided that the following conditions are met:
 
6
 *
 
7
 *  o Redistributions of source code must retain the above copyright notice,
 
8
 *    this list of conditions and the following disclaimer.
 
9
 *
 
10
 *  o Redistributions in binary form must reproduce the above copyright notice,
 
11
 *    this list of conditions and the following disclaimer in the documentation
 
12
 *    and/or other materials provided with the distribution.
 
13
 *
 
14
 *  o Neither the name of Laf-Widget Kirill Grouchnikov nor the names of
 
15
 *    its contributors may be used to endorse or promote products derived
 
16
 *    from this software without specific prior written permission.
 
17
 *
 
18
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 
19
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 
20
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
21
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 
22
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
23
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
24
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 
25
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 
26
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 
27
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 
28
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
29
 */
 
30
package org.pushingpixels.lafwidget.tabbed;
 
31
 
 
32
import java.awt.*;
 
33
import java.awt.event.*;
 
34
import java.awt.image.BufferedImage;
 
35
import java.beans.PropertyChangeEvent;
 
36
import java.beans.PropertyChangeListener;
 
37
import java.text.MessageFormat;
 
38
 
 
39
import javax.swing.*;
 
40
import javax.swing.border.*;
 
41
 
 
42
import org.pushingpixels.lafwidget.*;
 
43
import org.pushingpixels.lafwidget.animation.AnimationConfigurationManager;
 
44
import org.pushingpixels.lafwidget.contrib.blogofbug.swing.components.*;
 
45
import org.pushingpixels.lafwidget.tabbed.TabPreviewThread.TabPreviewInfo;
 
46
import org.pushingpixels.lafwidget.utils.ShadowPopupBorder;
 
47
import org.pushingpixels.lafwidget.utils.LafConstants.TabOverviewKind;
 
48
import org.pushingpixels.trident.Timeline;
 
49
import org.pushingpixels.trident.Timeline.TimelineState;
 
50
import org.pushingpixels.trident.callback.UIThreadTimelineCallbackAdapter;
 
51
import org.pushingpixels.trident.swing.SwingRepaintCallback;
 
52
 
 
53
/**
 
54
 * Tab overview dialog.
 
55
 * 
 
56
 * @author Kirill Grouchnikov
 
57
 */
 
58
public class TabOverviewDialog extends JDialog {
 
59
        /**
 
60
         * The associated tabbed pane.
 
61
         */
 
62
        protected JTabbedPane tabPane;
 
63
 
 
64
        // /**
 
65
        // * The grid overview panel (with all thumbnails).
 
66
        // */
 
67
        // protected JPanel gridOverviewPanel;
 
68
 
 
69
        /**
 
70
         * The associated preview callback.
 
71
         */
 
72
        protected TabPreviewThread.TabPreviewCallback previewCallback;
 
73
 
 
74
        /**
 
75
         * Listener on LAF switches.
 
76
         */
 
77
        protected PropertyChangeListener lafSwitchListener;
 
78
 
 
79
        /**
 
80
         * Handles mouse events on the tab overview dialog (such as highlighting the
 
81
         * currently rolled-over tab preview, closing the overview when a tab
 
82
         * preview is clicked, tooltips etc.)
 
83
         * 
 
84
         * @author Kirill Grouchnikov
 
85
         */
 
86
        protected class TabPreviewMouseHandler extends MouseAdapter {
 
87
                /**
 
88
                 * Tab index.
 
89
                 */
 
90
                private int index;
 
91
 
 
92
                /**
 
93
                 * Tab preview control.
 
94
                 */
 
95
                private JComponent previewControl;
 
96
 
 
97
                /**
 
98
                 * If <code>true</code>, the preview uses double click to select the tab
 
99
                 * and dismiss the tab overview dialog.
 
100
                 */
 
101
                private boolean useDoubleClick;
 
102
 
 
103
                /**
 
104
                 * If <code>true</code>, the tab preview controls have rollover effects
 
105
                 * on borders.
 
106
                 */
 
107
                private boolean hasRolloverBorderEffect;
 
108
 
 
109
                /**
 
110
                 * Creates the mouse handler for a single tab preview control.
 
111
                 * 
 
112
                 * @param index
 
113
                 *            Tab index.
 
114
                 * @param previewControl
 
115
                 *            Tab preview control.
 
116
                 * @param hasRolloverBorderEffect
 
117
                 *            If <code>true</code>, the preview uses double click to
 
118
                 *            select the tab and dismiss the tab overview dialog.
 
119
                 * @param useDoubleClick
 
120
                 *            If <code>true</code>, the tab preview controls have
 
121
                 *            rollover effects on borders.
 
122
                 */
 
123
                public TabPreviewMouseHandler(int index, JComponent previewControl,
 
124
                                boolean hasRolloverBorderEffect, boolean useDoubleClick) {
 
125
                        this.index = index;
 
126
                        this.previewControl = previewControl;
 
127
                        this.useDoubleClick = useDoubleClick;
 
128
                        this.hasRolloverBorderEffect = hasRolloverBorderEffect;
 
129
                }
 
130
 
 
131
                @Override
 
132
                public void mouseClicked(MouseEvent e) {
 
133
                        if (this.useDoubleClick) {
 
134
                                if (e.getClickCount() < 2)
 
135
                                        return;
 
136
                        }
 
137
 
 
138
                        SwingUtilities.invokeLater(new Runnable() {
 
139
                                @Override
 
140
                public void run() {
 
141
                                        TabOverviewDialog.this.dispose();
 
142
                                        TabOverviewDialog.this.tabPane
 
143
                                                        .setSelectedIndex(TabPreviewMouseHandler.this.index);
 
144
                                }
 
145
                        });
 
146
                }
 
147
 
 
148
                @Override
 
149
                public void mouseEntered(MouseEvent e) {
 
150
                        if (!this.hasRolloverBorderEffect)
 
151
                                return;
 
152
                        boolean isSelected = (TabOverviewDialog.this.tabPane
 
153
                                        .getSelectedIndex() == this.index);
 
154
                        Border innerBorder = isSelected ? new LineBorder(Color.blue, 2)
 
155
                                        : new LineBorder(Color.black, 1);
 
156
                        this.previewControl.setBorder(new CompoundBorder(
 
157
                                        new ShadowPopupBorder(), innerBorder));
 
158
                        // if (isSelected)
 
159
                        // this.previewControl.setBorder(new LineBorder(Color.blue, 2));
 
160
                        // else
 
161
                        // this.previewControl.setBorder(new CompoundBorder(
 
162
                        // new EmptyBorder(1, 1, 1, 1), new LineBorder(
 
163
                        // Color.black, 1)));
 
164
                }
 
165
 
 
166
                @Override
 
167
                public void mouseExited(MouseEvent e) {
 
168
                        if (!this.hasRolloverBorderEffect)
 
169
                                return;
 
170
                        boolean isSelected = (TabOverviewDialog.this.tabPane
 
171
                                        .getSelectedIndex() == this.index);
 
172
                        Border innerBorder = isSelected ? new LineBorder(Color.black, 2)
 
173
                                        : new LineBorder(Color.black, 1);
 
174
                        this.previewControl.setBorder(new CompoundBorder(
 
175
                                        new ShadowPopupBorder(), innerBorder));
 
176
                        // if (isSelected)
 
177
                        // this.previewControl.setBorder(new LineBorder(Color.black, 2));
 
178
                        // else
 
179
                        // this.previewControl.setBorder(new CompoundBorder(
 
180
                        // new EmptyBorder(1, 1, 1, 1), new LineBorder(
 
181
                        // Color.black, 1)));
 
182
                }
 
183
        }
 
184
 
 
185
        /**
 
186
         * Tab round carousel overview panel. Contains a round carousel of tab
 
187
         * preview widgets. The widgets are created in a separate thread (
 
188
         * {@link TabPreviewThread}) and offered to the tab overview dialog via the
 
189
         * registered implementation of {@link TabPreviewThread.TabPreviewCallback}.
 
190
         * This way the application stays interactive while the tab overview dialog
 
191
         * is being populated.
 
192
         * 
 
193
         * @author Kirill Grouchnikov
 
194
         */
 
195
        protected class TabRoundCarouselOverviewPanel extends JPanel {
 
196
                /**
 
197
                 * Tab preview controls.
 
198
                 */
 
199
                protected ReflectedImageLabel[] previewControls;
 
200
 
 
201
                /**
 
202
                 * Width of a single tab preview control.
 
203
                 */
 
204
                protected int pWidth;
 
205
 
 
206
                /**
 
207
                 * Height of a single tab preview control.
 
208
                 */
 
209
                protected int pHeight;
 
210
 
 
211
                /**
 
212
                 * Associated carousel.
 
213
                 */
 
214
                protected JCarosel carosel;
 
215
 
 
216
                /**
 
217
                 * Creates a tab overview panel.
 
218
                 * 
 
219
                 * @param dialogWidth
 
220
                 *            The width of the parent dialog.
 
221
                 * @param dialogHeight
 
222
                 *            The height of the parent dialog.
 
223
                 */
 
224
                public TabRoundCarouselOverviewPanel(final int dialogWidth,
 
225
                                final int dialogHeight) {
 
226
                        // int tabCount = TabOverviewDialog.this.tabPane.getTabCount();
 
227
 
 
228
                        // this.previewControls = new HashSet<Component>();
 
229
                        TabPreviewThread.TabPreviewCallback previewCallback = new TabPreviewThread.TabPreviewCallback() {
 
230
                                /*
 
231
                                 * (non-Javadoc)
 
232
                                 * 
 
233
                                 * @seeorg.pushingpixels.lafwidget.tabbed.TabPreviewThread.
 
234
                                 * TabPreviewCallback#start(javax.swing.JTabbedPane, int,
 
235
                                 * org.pushingpixels
 
236
                                 * .lafwidget.tabbed.TabPreviewThread.TabPreviewInfo)
 
237
                                 */
 
238
                                @Override
 
239
                public void start(JTabbedPane tabPane, int tabCount,
 
240
                                                TabPreviewInfo tabPreviewInfo) {
 
241
                                        // Check if need to reallocate the preview controls.
 
242
                                        boolean isSame = (previewControls != null)
 
243
                                                        && (previewControls.length == tabCount);
 
244
                                        if (isSame)
 
245
                                                return;
 
246
 
 
247
                                        if (previewControls != null) {
 
248
                                                for (int i = 0; i < previewControls.length; i++) {
 
249
                                                        carosel.remove(previewControls[i]);
 
250
                                                }
 
251
                                        }
 
252
 
 
253
                                        double coef = Math.min(3.5, tabCount / 1.5);
 
254
                                        coef = Math.max(coef, 4.5);
 
255
                                        pWidth = (int) (dialogWidth / coef);
 
256
                                        pHeight = (int) (dialogHeight / coef);
 
257
 
 
258
                                        tabPreviewInfo.setPreviewWidth(pWidth - 4);
 
259
                                        tabPreviewInfo.setPreviewHeight(pHeight - 4);
 
260
 
 
261
                                        previewControls = new ReflectedImageLabel[tabCount];
 
262
                                        TabPreviewPainter tpp = LafWidgetUtilities2
 
263
                                                        .getTabPreviewPainter(TabOverviewDialog.this.tabPane);
 
264
                                        for (int i = 0; i < tabCount; i++) {
 
265
                                                BufferedImage placeHolder = new BufferedImage(pWidth,
 
266
                                                                pHeight, BufferedImage.TYPE_INT_ARGB);
 
267
                                                Graphics2D g2d = (Graphics2D) placeHolder.getGraphics();
 
268
                                                g2d.setColor(UIManager.getColor("Label.background"));
 
269
                                                g2d.fillRect(0, 0, pWidth, pHeight);
 
270
                                                ReflectedImageLabel ril = (ReflectedImageLabel) carosel
 
271
                                                                .add(placeHolder, tabPane.getTitleAt(i));
 
272
                                                ril.setForeground(UIManager
 
273
                                                                .getColor("Label.foreground"));
 
274
                                                ril.setBackground(UIManager
 
275
                                                                .getColor("Label.background"));
 
276
                                                // TabPreviewControl previewControl = new
 
277
                                                // TabPreviewControl(
 
278
                                                // TabOverviewDialog.this.tabPane, i);
 
279
                                                ril.setPreferredSize(new Dimension(pWidth, pHeight));
 
280
                                                // fix for issue 177 in Substance (disallowing
 
281
                                                // selection
 
282
                                                // of disabled tabs).
 
283
                                                if (tpp.isSensitiveToEvents(
 
284
                                                                TabOverviewDialog.this.tabPane, i)) {
 
285
                                                        ril.addMouseListener(new TabPreviewMouseHandler(i,
 
286
                                                                        ril, false, true));
 
287
                                                        ril
 
288
                                                                        .setToolTipText(LafWidgetUtilities
 
289
                                                                                        .getResourceBundle(tabPane)
 
290
                                                                                        .getString(
 
291
                                                                                                        "TabbedPane.overviewWidgetTooltip"));
 
292
                                                }
 
293
                                                previewControls[i] = ril;
 
294
                                                // carosel.add(previewControl);
 
295
                                        }
 
296
                                        carosel.bringToFront(previewControls[tabPane
 
297
                                                        .getSelectedIndex()]);
 
298
                                        // System.err.println("Added " + previewControls.length
 
299
                                        // + " labels");
 
300
                                        // doLayout();
 
301
                                        // for (int i = 0; i < tabCount; i++) {
 
302
                                        // previewControls[i].revalidate();
 
303
                                        // }
 
304
                                        // repaint();
 
305
                                }
 
306
 
 
307
                                /*
 
308
                                 * (non-Javadoc)
 
309
                                 * 
 
310
                                 * @seeorg.pushingpixels.lafwidget.tabbed.TabPreviewThread.
 
311
                                 * TabPreviewCallback#offer(javax.swing.JTabbedPane, int,
 
312
                                 * java.awt.image.BufferedImage)
 
313
                                 */
 
314
                                @Override
 
315
                public void offer(JTabbedPane tabPane, int tabIndex,
 
316
                                                BufferedImage componentSnap) {
 
317
                                        int width = componentSnap.getWidth() + 4;
 
318
                                        int height = componentSnap.getHeight() + 4;
 
319
                                        BufferedImage result = new BufferedImage(width, height,
 
320
                                                        BufferedImage.TYPE_INT_ARGB);
 
321
                                        Graphics2D g2d = (Graphics2D) result.getGraphics();
 
322
                                        g2d.setColor(UIManager.getColor("Label.background"));
 
323
                                        g2d.fillRect(0, 0, width, height);
 
324
                                        g2d.setColor(UIManager.getColor("Label.foreground"));
 
325
                                        g2d.drawRect(0, 0, width - 1, height - 1);
 
326
                                        g2d.drawImage(componentSnap, 2, 2, null);
 
327
 
 
328
                                        Icon tabIcon = tabPane.getIconAt(tabIndex);
 
329
                                        if (tabIcon != null) {
 
330
                                                tabIcon.paintIcon(tabPane, g2d, 2, 2);
 
331
                                        }
 
332
 
 
333
                                        // Component caroselComponent = carosel.add(result, tabPane
 
334
                                        // .getTitleAt(tabIndex));
 
335
                                        // caroselComponent.setForeground(UIManager
 
336
                                        // .getColor("Label.foreground"));
 
337
 
 
338
                                        // System.err.println("Setting image on " + tabIndex);
 
339
                                        previewControls[tabIndex].setRichImage(result);
 
340
                                        // System.err.println("Set image on " + tabIndex);
 
341
                                        previewControls[tabIndex].repaint();
 
342
                                        // previewControls.add(caroselComponent);
 
343
                                        // TabRoundCarouselOverviewPanel.this.previewControls[tabIndex]
 
344
                                        // .setPreviewImage(componentSnap);
 
345
                                }
 
346
                        };
 
347
 
 
348
                        this.carosel = new JCarosel();
 
349
                        this.carosel.setDepthBasedAlpha(true);
 
350
                        // // carosel.setBackground(Color.BLACK, Color.DARK_GRAY);
 
351
                        // carosel
 
352
                        // .add(
 
353
                        // TabOverviewDialog.class
 
354
                        // .getResource(
 
355
                        // "/contrib/com/blogofbug/examples/images/Acknowledgements.png")
 
356
                        // .toString(), "You Rock", 128, 128);
 
357
                        // carosel.add(TabOverviewDialog.class.getResource(
 
358
                        // "/contrib/com/blogofbug/examples/images/Dock.png")
 
359
                        // .toString(), "Docks Rock", 128, 128);
 
360
                        // carosel.add(TabOverviewDialog.class.getResource(
 
361
                        // "/contrib/com/blogofbug/examples/images/Cascade.png")
 
362
                        // .toString(), "Cascade Icon", 128, 128);
 
363
                        // carosel.add(TabOverviewDialog.class.getResource(
 
364
                        // "/contrib/com/blogofbug/examples/images/Quit.png")
 
365
                        // .toString(), "Quit Bugging", 128, 128);
 
366
                        this.setLayout(new BorderLayout());
 
367
                        this.add(carosel, BorderLayout.CENTER);
 
368
 
 
369
                        TabPreviewInfo previewInfo = new TabPreviewInfo();
 
370
                        previewInfo.tabPane = TabOverviewDialog.this.tabPane;
 
371
                        previewInfo.previewCallback = previewCallback;
 
372
                        // previewInfo.previewWidth = this.pWidth - 4;
 
373
                        // previewInfo.previewHeight = this.pHeight - 20;
 
374
                        previewInfo.toPreviewAllTabs = true;
 
375
                        previewInfo.initiator = TabOverviewDialog.this;
 
376
 
 
377
                        TabPreviewThread.getInstance().queueTabPreviewRequest(previewInfo);
 
378
                }
 
379
        }
 
380
 
 
381
        /**
 
382
         * Tab menu carousel overview panel. Contains a menu carousel of tab preview
 
383
         * widgets. The widgets are created in a separate thread (
 
384
         * {@link TabPreviewThread}) and offered to the tab overview dialog via the
 
385
         * registered implementation of {@link TabPreviewThread.TabPreviewCallback}.
 
386
         * This way the application stays interactive while the tab overview dialog
 
387
         * is being populated.
 
388
         * 
 
389
         * @author Kirill Grouchnikov
 
390
         */
 
391
        protected class TabMenuCarouselOverviewPanel extends JPanel {
 
392
                /**
 
393
                 * Tab preview controls.
 
394
                 */
 
395
                protected ReflectedImageLabel[] previewControls;
 
396
 
 
397
                /**
 
398
                 * Width of a single tab preview control.
 
399
                 */
 
400
                protected int pWidth;
 
401
 
 
402
                /**
 
403
                 * Height of a single tab preview control.
 
404
                 */
 
405
                protected int pHeight;
 
406
 
 
407
                /**
 
408
                 * The associated carousel menu.
 
409
                 */
 
410
                protected JCarouselMenu caroselMenu;
 
411
 
 
412
                /**
 
413
                 * Cell renderer for the carosel menu. Employs a little trick to provide
 
414
                 * LAF-consistent painting of the cells.
 
415
                 * 
 
416
                 * @author Kirill Grouchnikov
 
417
                 */
 
418
                protected class MenuCarouselListCellRenderer extends JLabel implements
 
419
                                ListCellRenderer {
 
420
                        /**
 
421
                         * The cell renderer from the currently installed LAF.
 
422
                         */
 
423
                        protected ListCellRenderer lafDefaultCellRenderer;
 
424
 
 
425
                        /**
 
426
                         * Creates the cell renderer for the carosel menu.
 
427
                         * 
 
428
                         * @param lafDefaultCellRenderer
 
429
                         *            The cell renderer from the currently installed LAF.
 
430
                         */
 
431
                        public MenuCarouselListCellRenderer(
 
432
                                        ListCellRenderer lafDefaultCellRenderer) {
 
433
                                this.lafDefaultCellRenderer = lafDefaultCellRenderer;
 
434
                                // if (lafDefaultCellRenderer instanceof Component) {
 
435
                                // JComponent jc = (JComponent) lafDefaultCellRenderer;
 
436
                                // jc.setBorder(new EmptyBorder(5, 5, 5, 5));
 
437
                                // jc.setFont(super.getFont().deriveFont(Font.BOLD, 14.0f));
 
438
                                // }
 
439
                        }
 
440
 
 
441
                        /**
 
442
                         * Sets up the component for stamping
 
443
                         */
 
444
                        @Override
 
445
            public Component getListCellRendererComponent(JList jList,
 
446
                                        Object object, int i, boolean isSelected,
 
447
                                        boolean cellHasFocus) {
 
448
                                JCarouselMenu.MenuItem item = (JCarouselMenu.MenuItem) object;
 
449
                                Component result = this.lafDefaultCellRenderer
 
450
                                                .getListCellRendererComponent(jList, item.getLabel(),
 
451
                                                                i, isSelected, cellHasFocus);
 
452
 
 
453
                                if (result instanceof Component) {
 
454
                                        JComponent jc = (JComponent) result;
 
455
                                        jc.setBorder(new EmptyBorder(5, 5, 5, 5));
 
456
                                        jc.setFont(super.getFont().deriveFont(Font.BOLD, 14.0f));
 
457
                                }
 
458
 
 
459
                                return result;
 
460
                        }
 
461
                }
 
462
 
 
463
                /**
 
464
                 * Creates a tab overview panel.
 
465
                 * 
 
466
                 * @param dialogWidth
 
467
                 *            The width of the parent dialog.
 
468
                 * @param dialogHeight
 
469
                 *            The height of the parent dialog.
 
470
                 */
 
471
                public TabMenuCarouselOverviewPanel(final int dialogWidth,
 
472
                                final int dialogHeight) {
 
473
                        // int tabCount = TabOverviewDialog.this.tabPane.getTabCount();
 
474
 
 
475
                        // this.previewControls = new HashSet<Component>();
 
476
                        TabPreviewThread.TabPreviewCallback previewCallback = new TabPreviewThread.TabPreviewCallback() {
 
477
                                /*
 
478
                                 * (non-Javadoc)
 
479
                                 * 
 
480
                                 * @seeorg.pushingpixels.lafwidget.tabbed.TabPreviewThread.
 
481
                                 * TabPreviewCallback#start(javax.swing.JTabbedPane, int,
 
482
                                 * org.pushingpixels
 
483
                                 * .lafwidget.tabbed.TabPreviewThread.TabPreviewInfo)
 
484
                                 */
 
485
                                @Override
 
486
                public void start(JTabbedPane tabPane, int tabCount,
 
487
                                                TabPreviewInfo tabPreviewInfo) {
 
488
                                        // Check if need to reallocate the preview controls.
 
489
                                        boolean isSame = (previewControls != null)
 
490
                                                        && (previewControls.length == tabCount);
 
491
                                        if (isSame)
 
492
                                                return;
 
493
 
 
494
                                        if (previewControls != null) {
 
495
                                                for (int i = 0; i < previewControls.length; i++) {
 
496
                                                        caroselMenu.remove(previewControls[i]);
 
497
                                                }
 
498
                                        }
 
499
 
 
500
                                        double coef = Math.min(2.8, tabCount / 1.8);
 
501
                                        coef = Math.max(2.5, coef);
 
502
                                        pWidth = (int) (dialogWidth / coef);
 
503
                                        pHeight = (int) (dialogHeight / coef);
 
504
 
 
505
                                        tabPreviewInfo.setPreviewWidth(pWidth - 4);
 
506
                                        tabPreviewInfo.setPreviewHeight(pHeight - 4);
 
507
 
 
508
                                        previewControls = new ReflectedImageLabel[tabCount];
 
509
                                        TabPreviewPainter tpp = LafWidgetUtilities2
 
510
                                                        .getTabPreviewPainter(TabOverviewDialog.this.tabPane);
 
511
                                        for (int i = 0; i < tabCount; i++) {
 
512
                                                BufferedImage placeHolder = new BufferedImage(pWidth,
 
513
                                                                pHeight, BufferedImage.TYPE_INT_ARGB);
 
514
                                                Graphics2D g2d = (Graphics2D) placeHolder.getGraphics();
 
515
                                                g2d.setColor(UIManager.getColor("Label.background"));
 
516
                                                g2d.fillRect(0, 0, pWidth, pHeight);
 
517
                                                ReflectedImageLabel ril = (ReflectedImageLabel) caroselMenu
 
518
                                                                .add(placeHolder, tabPane.getTitleAt(i));
 
519
                                                ril.setForeground(UIManager
 
520
                                                                .getColor("Label.foreground"));
 
521
                                                ril.setBackground(UIManager
 
522
                                                                .getColor("Label.background"));
 
523
                                                // TabPreviewControl previewControl = new
 
524
                                                // TabPreviewControl(
 
525
                                                // TabOverviewDialog.this.tabPane, i);
 
526
                                                ril.setPreferredSize(new Dimension(pWidth, pHeight));
 
527
                                                // fix for issue 177 in Substance (disallowing
 
528
                                                // selection
 
529
                                                // of disabled tabs).
 
530
                                                if (tpp.isSensitiveToEvents(
 
531
                                                                TabOverviewDialog.this.tabPane, i)) {
 
532
                                                        ril.addMouseListener(new TabPreviewMouseHandler(i,
 
533
                                                                        ril, false, true));
 
534
                                                        ril
 
535
                                                                        .setToolTipText(LafWidgetUtilities
 
536
                                                                                        .getResourceBundle(tabPane)
 
537
                                                                                        .getString(
 
538
                                                                                                        "TabbedPane.overviewWidgetTooltip"));
 
539
                                                }
 
540
                                                previewControls[i] = ril;
 
541
                                                // carosel.add(previewControl);
 
542
                                        }
 
543
                                        caroselMenu.setSelectedIndex(tabPane.getSelectedIndex());
 
544
                                        // System.err.println("Added " + previewControls.length
 
545
                                        // + " labels");
 
546
                                        // doLayout();
 
547
                                        // for (int i = 0; i < tabCount; i++) {
 
548
                                        // previewControls[i].revalidate();
 
549
                                        // }
 
550
                                        // repaint();
 
551
                                }
 
552
 
 
553
                                /*
 
554
                                 * (non-Javadoc)
 
555
                                 * 
 
556
                                 * @seeorg.pushingpixels.lafwidget.tabbed.TabPreviewThread.
 
557
                                 * TabPreviewCallback#offer(javax.swing.JTabbedPane, int,
 
558
                                 * java.awt.image.BufferedImage)
 
559
                                 */
 
560
                                @Override
 
561
                public void offer(JTabbedPane tabPane, int tabIndex,
 
562
                                                BufferedImage componentSnap) {
 
563
                                        int width = componentSnap.getWidth() + 4;
 
564
                                        int height = componentSnap.getHeight() + 4;
 
565
                                        BufferedImage result = new BufferedImage(width, height,
 
566
                                                        BufferedImage.TYPE_INT_ARGB);
 
567
                                        Graphics2D g2d = (Graphics2D) result.getGraphics();
 
568
                                        g2d.setColor(UIManager.getColor("Label.background"));
 
569
                                        g2d.fillRect(0, 0, width, height);
 
570
                                        g2d.setColor(UIManager.getColor("Label.foreground"));
 
571
                                        g2d.drawRect(0, 0, width - 1, height - 1);
 
572
                                        g2d.drawImage(componentSnap, 2, 2, null);
 
573
 
 
574
                                        Icon tabIcon = tabPane.getIconAt(tabIndex);
 
575
                                        if (tabIcon != null) {
 
576
                                                tabIcon.paintIcon(tabPane, g2d, 2, 2);
 
577
                                        }
 
578
                                        // Component caroselComponent = carosel.add(result, tabPane
 
579
                                        // .getTitleAt(tabIndex));
 
580
                                        // caroselComponent.setForeground(UIManager
 
581
                                        // .getColor("Label.foreground"));
 
582
 
 
583
                                        // System.err.println("Setting image on " + tabIndex);
 
584
                                        previewControls[tabIndex].setRichImage(result);
 
585
                                        // System.err.println("Set image on " + tabIndex);
 
586
                                        previewControls[tabIndex].repaint();
 
587
                                        // previewControls.add(caroselComponent);
 
588
                                        // TabRoundCarouselOverviewPanel.this.previewControls[tabIndex]
 
589
                                        // .setPreviewImage(componentSnap);
 
590
                                }
 
591
                        };
 
592
 
 
593
                        this.caroselMenu = new JCarouselMenu(null);
 
594
                        JList dummyList = new JList();
 
595
                        ListCellRenderer lcr = dummyList.getCellRenderer();
 
596
                        this.caroselMenu.setCellRenderer(new MenuCarouselListCellRenderer(
 
597
                                        lcr));
 
598
                        this.caroselMenu.setMenuScrollColor(UIManager
 
599
                                        .getColor("Panel.background"));
 
600
                        this.caroselMenu.setUpDownColor(UIManager
 
601
                                        .getColor("Label.foreground"));
 
602
                        LafWidgetSupport support = LafWidgetRepository.getRepository()
 
603
                                        .getLafSupport();
 
604
                        if (support != null) {
 
605
                                this.caroselMenu.setUpDownIcons(support
 
606
                                                .getArrowIcon(SwingConstants.NORTH), support
 
607
                                                .getArrowIcon(SwingConstants.SOUTH));
 
608
                        }
 
609
 
 
610
                        // this.carosel.setDepthBasedAlpha(true);
 
611
                        // // carosel.setBackground(Color.BLACK, Color.DARK_GRAY);
 
612
                        // carosel
 
613
                        // .add(
 
614
                        // TabOverviewDialog.class
 
615
                        // .getResource(
 
616
                        // "/contrib/com/blogofbug/examples/images/Acknowledgements.png")
 
617
                        // .toString(), "You Rock", 128, 128);
 
618
                        // carosel.add(TabOverviewDialog.class.getResource(
 
619
                        // "/contrib/com/blogofbug/examples/images/Dock.png")
 
620
                        // .toString(), "Docks Rock", 128, 128);
 
621
                        // carosel.add(TabOverviewDialog.class.getResource(
 
622
                        // "/contrib/com/blogofbug/examples/images/Cascade.png")
 
623
                        // .toString(), "Cascade Icon", 128, 128);
 
624
                        // carosel.add(TabOverviewDialog.class.getResource(
 
625
                        // "/contrib/com/blogofbug/examples/images/Quit.png")
 
626
                        // .toString(), "Quit Bugging", 128, 128);
 
627
                        this.setLayout(new BorderLayout());
 
628
                        this.add(caroselMenu, BorderLayout.CENTER);
 
629
 
 
630
                        TabPreviewInfo previewInfo = new TabPreviewInfo();
 
631
                        previewInfo.tabPane = TabOverviewDialog.this.tabPane;
 
632
                        previewInfo.previewCallback = previewCallback;
 
633
                        previewInfo.setPreviewWidth(this.pWidth - 4);
 
634
                        previewInfo.setPreviewHeight(this.pHeight - 4);
 
635
                        previewInfo.toPreviewAllTabs = true;
 
636
                        previewInfo.initiator = TabOverviewDialog.this;
 
637
 
 
638
                        TabPreviewThread.getInstance().queueTabPreviewRequest(previewInfo);
 
639
                }
 
640
 
 
641
                /*
 
642
                 * (non-Javadoc)
 
643
                 * 
 
644
                 * @see javax.swing.JPanel#updateUI()
 
645
                 */
 
646
                @Override
 
647
                public void updateUI() {
 
648
                        super.updateUI();
 
649
                        if (this.caroselMenu != null) {
 
650
                                JList dummyList = new JList();
 
651
                                ListCellRenderer lcr = dummyList.getCellRenderer();
 
652
                                this.caroselMenu
 
653
                                                .setCellRenderer(new MenuCarouselListCellRenderer(lcr));
 
654
                                this.caroselMenu.setMenuScrollColor(UIManager
 
655
                                                .getColor("Panel.background"));
 
656
                                this.caroselMenu.setUpDownColor(UIManager
 
657
                                                .getColor("Label.foreground"));
 
658
                                this.caroselMenu.setBackground(UIManager
 
659
                                                .getColor("Panel.background"));
 
660
                                LafWidgetSupport support = LafWidgetRepository.getRepository()
 
661
                                                .getLafSupport();
 
662
                                if (support != null) {
 
663
                                        this.caroselMenu.setUpDownIcons(support
 
664
                                                        .getArrowIcon(SwingConstants.NORTH), support
 
665
                                                        .getArrowIcon(SwingConstants.SOUTH));
 
666
                                }
 
667
                        }
 
668
                }
 
669
        }
 
670
 
 
671
        /**
 
672
         * Tab grid overview panel. Contains a grid of tab preview widgets. The
 
673
         * widgets are created in a separate thread ({@link TabPreviewThread}) and
 
674
         * offered to the tab overview dialog via the registered implementation of
 
675
         * {@link TabPreviewThread.TabPreviewCallback}. This way the application
 
676
         * stays interactive while the tab overview dialog is being populated.
 
677
         * 
 
678
         * @author Kirill Grouchnikov
 
679
         */
 
680
        protected class TabGridOverviewPanel extends JPanel {
 
681
                /**
 
682
                 * Tab preview controls.
 
683
                 */
 
684
                protected TabPreviewControl[] previewControls;
 
685
 
 
686
                /**
 
687
                 * Width of a single tab preview control.
 
688
                 */
 
689
                protected int pWidth;
 
690
 
 
691
                /**
 
692
                 * Height of a single tab preview control.
 
693
                 */
 
694
                protected int pHeight;
 
695
 
 
696
                /**
 
697
                 * Number of overview grid columns.
 
698
                 */
 
699
                protected int colCount;
 
700
 
 
701
                /**
 
702
                 * Glass pane for rollover effects.
 
703
                 */
 
704
                protected TabGridOverviewGlassPane glassPane;
 
705
 
 
706
                /**
 
707
                 * Creates a tab overview panel.
 
708
                 * 
 
709
                 * @param dialogWidth
 
710
                 *            The width of the parent dialog.
 
711
                 * @param dialogHeight
 
712
                 *            The height of the parent dialog.
 
713
                 */
 
714
                public TabGridOverviewPanel(final int dialogWidth,
 
715
                                final int dialogHeight) {
 
716
                        // int tabCount = TabOverviewDialog.this.tabPane.getTabCount();
 
717
 
 
718
                        TabPreviewThread.TabPreviewCallback previewCallback = new TabPreviewThread.TabPreviewCallback() {
 
719
                                /*
 
720
                                 * (non-Javadoc)
 
721
                                 * 
 
722
                                 * @seeorg.pushingpixels.lafwidget.tabbed.TabPreviewThread.
 
723
                                 * TabPreviewCallback#start(javax.swing.JTabbedPane, int,
 
724
                                 * org.pushingpixels
 
725
                                 * .lafwidget.tabbed.TabPreviewThread.TabPreviewInfo)
 
726
                                 */
 
727
                                @Override
 
728
                public void start(JTabbedPane tabPane, int tabCount,
 
729
                                                TabPreviewInfo tabPreviewInfo) {
 
730
                                        colCount = (int) Math.sqrt(tabCount);
 
731
                                        if (colCount * colCount < tabCount)
 
732
                                                colCount++;
 
733
 
 
734
                                        pWidth = (dialogWidth - 8) / colCount;
 
735
                                        pHeight = (dialogHeight - 32) / colCount;
 
736
 
 
737
                                        tabPreviewInfo.setPreviewWidth(pWidth - 4);
 
738
                                        tabPreviewInfo.setPreviewHeight(pHeight - 20);
 
739
 
 
740
                                        // Check if need to reallocate the preview controls.
 
741
                                        boolean isSame = (previewControls != null)
 
742
                                                        && (previewControls.length == tabCount);
 
743
                                        if (isSame)
 
744
                                                return;
 
745
 
 
746
                                        if (previewControls != null) {
 
747
                                                for (int i = 0; i < previewControls.length; i++) {
 
748
                                                        remove(previewControls[i]);
 
749
                                                }
 
750
                                        }
 
751
 
 
752
                                        previewControls = new TabPreviewControl[tabCount];
 
753
                                        TabPreviewPainter tpp = LafWidgetUtilities2
 
754
                                                        .getTabPreviewPainter(TabOverviewDialog.this.tabPane);
 
755
                                        for (int i = 0; i < tabCount; i++) {
 
756
                                                TabPreviewControl previewControl = new TabPreviewControl(
 
757
                                                                TabOverviewDialog.this.tabPane, i);
 
758
                                                // fix for issue 177 in Substance (disallowing selection
 
759
                                                // of disabled tabs).
 
760
                                                if (tpp.isSensitiveToEvents(
 
761
                                                                TabOverviewDialog.this.tabPane, i)) {
 
762
                                                        previewControl
 
763
                                                                        .addMouseListener(new TabPreviewMouseHandler(
 
764
                                                                                        i, previewControl, true, false));
 
765
                                                }
 
766
                                                previewControls[i] = previewControl;
 
767
                                                add(previewControl);
 
768
                                        }
 
769
 
 
770
                                        doLayout();
 
771
                                        for (int i = 0; i < tabCount; i++) {
 
772
                                                previewControls[i].revalidate();
 
773
                                        }
 
774
                                        repaint();
 
775
 
 
776
                                        JRootPane rp = SwingUtilities
 
777
                                                        .getRootPane(TabGridOverviewPanel.this);
 
778
                                        glassPane = new TabGridOverviewGlassPane(
 
779
                                                        TabGridOverviewPanel.this);
 
780
                                        rp.setGlassPane(glassPane);
 
781
                                        glassPane.setVisible(true);
 
782
                                }
 
783
 
 
784
                                /*
 
785
                                 * (non-Javadoc)
 
786
                                 * 
 
787
                                 * @seeorg.pushingpixels.lafwidget.tabbed.TabPreviewThread.
 
788
                                 * TabPreviewCallback#offer(javax.swing.JTabbedPane, int,
 
789
                                 * java.awt.image.BufferedImage)
 
790
                                 */
 
791
                                @Override
 
792
                public void offer(JTabbedPane tabPane, int tabIndex,
 
793
                                                BufferedImage componentSnap) {
 
794
                                        TabGridOverviewPanel.this.previewControls[tabIndex]
 
795
                                                        .setPreviewImage(componentSnap, true);
 
796
                                }
 
797
                        };
 
798
 
 
799
                        this.setLayout(new TabGridOverviewPanelLayout());
 
800
 
 
801
                        TabPreviewInfo previewInfo = new TabPreviewInfo();
 
802
                        previewInfo.tabPane = TabOverviewDialog.this.tabPane;
 
803
                        previewInfo.previewCallback = previewCallback;
 
804
                        //previewInfo.setPreviewWidth(this.pWidth - 4);
 
805
                        //previewInfo.setPreviewHeight(this.pHeight - 20);
 
806
                        previewInfo.toPreviewAllTabs = true;
 
807
                        previewInfo.initiator = TabOverviewDialog.this;
 
808
 
 
809
                        TabPreviewThread.getInstance().queueTabPreviewRequest(previewInfo);
 
810
                }
 
811
 
 
812
                /**
 
813
                 * Layout manager for the tab overview panel.
 
814
                 * 
 
815
                 * @author Kirill Grouchnikov
 
816
                 */
 
817
                private class TabGridOverviewPanelLayout implements LayoutManager {
 
818
                        /*
 
819
                         * (non-Javadoc)
 
820
                         * 
 
821
                         * @see java.awt.LayoutManager#addLayoutComponent(java.lang.String,
 
822
                         * java.awt.Component)
 
823
                         */
 
824
                        @Override
 
825
            public void addLayoutComponent(String name, Component comp) {
 
826
                        }
 
827
 
 
828
                        /*
 
829
                         * (non-Javadoc)
 
830
                         * 
 
831
                         * @see
 
832
                         * java.awt.LayoutManager#removeLayoutComponent(java.awt.Component)
 
833
                         */
 
834
                        @Override
 
835
            public void removeLayoutComponent(Component comp) {
 
836
                        }
 
837
 
 
838
                        /*
 
839
                         * (non-Javadoc)
 
840
                         * 
 
841
                         * @see java.awt.LayoutManager#layoutContainer(java.awt.Container)
 
842
                         */
 
843
                        @Override
 
844
            public void layoutContainer(Container parent) {
 
845
                                // int width = parent.getWidth();
 
846
                                // int height = parent.getHeight();
 
847
                                //
 
848
                                if (TabGridOverviewPanel.this.previewControls == null)
 
849
                                        return;
 
850
 
 
851
                                for (int i = 0; i < TabGridOverviewPanel.this.previewControls.length; i++) {
 
852
                                        TabPreviewControl previewControl = TabGridOverviewPanel.this.previewControls[i];
 
853
                                        if (previewControl == null)
 
854
                                                continue;
 
855
                                        int rowIndex = i / TabGridOverviewPanel.this.colCount;
 
856
                                        int colIndex = i % TabGridOverviewPanel.this.colCount;
 
857
 
 
858
                                        previewControl.setBounds(colIndex
 
859
                                                        * TabGridOverviewPanel.this.pWidth, rowIndex
 
860
                                                        * TabGridOverviewPanel.this.pHeight,
 
861
                                                        TabGridOverviewPanel.this.pWidth,
 
862
                                                        TabGridOverviewPanel.this.pHeight);
 
863
                                }
 
864
                        }
 
865
 
 
866
                        /*
 
867
                         * (non-Javadoc)
 
868
                         * 
 
869
                         * @see java.awt.LayoutManager#minimumLayoutSize(java.awt.Container)
 
870
                         */
 
871
                        @Override
 
872
            public Dimension minimumLayoutSize(Container parent) {
 
873
                                return parent.getSize();
 
874
                        }
 
875
 
 
876
                        /*
 
877
                         * (non-Javadoc)
 
878
                         * 
 
879
                         * @see
 
880
                         * java.awt.LayoutManager#preferredLayoutSize(java.awt.Container)
 
881
                         */
 
882
                        @Override
 
883
            public Dimension preferredLayoutSize(Container parent) {
 
884
                                return this.minimumLayoutSize(parent);
 
885
                        }
 
886
                }
 
887
        }
 
888
 
 
889
        /**
 
890
         * Glass pane for the tab grid overview panel. Provides rollover effects,
 
891
         * showing zoomed version of the tab thumbnails.
 
892
         * 
 
893
         * @author Kirill Grouchnikov
 
894
         */
 
895
        public class TabGridOverviewGlassPane extends JPanel {
 
896
                private final class RolloverMouseListener extends MouseAdapter {
 
897
                        private final int index;
 
898
                        private final TabGridOverviewPanel overviewPanel;
 
899
 
 
900
                        private Timeline rolloverTimeline;
 
901
 
 
902
                        private RolloverMouseListener(final int index,
 
903
                                        final TabGridOverviewPanel overviewPanel) {
 
904
                                this.index = index;
 
905
                                this.overviewPanel = overviewPanel;
 
906
                                this.rolloverTimeline = new Timeline(
 
907
                                                overviewPanel.previewControls[index]);
 
908
                                AnimationConfigurationManager.getInstance().configureTimeline(
 
909
                                                this.rolloverTimeline);
 
910
                                this.rolloverTimeline.addPropertyToInterpolate("zoom", 1.0f,
 
911
                                                1.2f);
 
912
                                this.rolloverTimeline.addCallback(new SwingRepaintCallback(
 
913
                                                SwingUtilities.getRootPane(overviewPanel)));
 
914
                                this.rolloverTimeline
 
915
                                                .addCallback(new UIThreadTimelineCallbackAdapter() {
 
916
                                                        @Override
 
917
                                                        public void onTimelineStateChanged(
 
918
                                                                        TimelineState oldState,
 
919
                                                                        TimelineState newState,
 
920
                                                                        float durationFraction,
 
921
                                                                        float timelinePosition) {
 
922
                                                                if ((oldState == TimelineState.DONE)
 
923
                                                                                && (newState == TimelineState.IDLE)) {
 
924
                                                                        overviewPanel.previewControls[index]
 
925
                                                                                        .setToolTipText(LafWidgetUtilities
 
926
                                                                                                        .getResourceBundle(tabPane)
 
927
                                                                                                        .getString(
 
928
                                                                                                                        "TabbedPane.overviewWidgetTooltip"));
 
929
                                                                }
 
930
                                                        }
 
931
                                                });
 
932
                        }
 
933
 
 
934
                        @Override
 
935
                        public void mouseEntered(MouseEvent e) {
 
936
                                currHoverIndex = index;
 
937
                                overviewPanel.previewControls[index].setToolTipText(null);
 
938
                                this.rolloverTimeline.play();
 
939
                        }
 
940
 
 
941
                        @Override
 
942
                        public void mouseExited(MouseEvent e) {
 
943
                                if (currHoverIndex == index)
 
944
                                        currHoverIndex = -1;
 
945
                                overviewPanel.previewControls[index].setToolTipText(null);
 
946
                                this.rolloverTimeline.playReverse();
 
947
                        }
 
948
                }
 
949
 
 
950
                /**
 
951
                 * Index of the tab thumbnail currently under the mouse pointer.
 
952
                 */
 
953
                private int currHoverIndex;
 
954
 
 
955
                /**
 
956
                 * Mouse listeneres (one for each tab thumbnail).
 
957
                 */
 
958
                private MouseListener[] mouseListeners;
 
959
 
 
960
                /**
 
961
                 * The associated overview panel.
 
962
                 */
 
963
                private TabGridOverviewPanel overviewPanel;
 
964
 
 
965
                /**
 
966
                 * Creates the glass pane.
 
967
                 * 
 
968
                 * @param overviewPanel
 
969
                 *            The associated overview panel.
 
970
                 */
 
971
                public TabGridOverviewGlassPane(final TabGridOverviewPanel overviewPanel) {
 
972
                        this.setOpaque(false);
 
973
                        this.overviewPanel = overviewPanel;
 
974
 
 
975
                        int size = this.overviewPanel.previewControls.length;
 
976
                        this.mouseListeners = new MouseListener[size];
 
977
                        this.currHoverIndex = -1;
 
978
                        for (int i = 0; i < size; i++) {
 
979
                                final int index = i;
 
980
                                this.mouseListeners[i] = new RolloverMouseListener(index,
 
981
                                                overviewPanel);
 
982
                                this.overviewPanel.previewControls[i]
 
983
                                                .addMouseListener(this.mouseListeners[i]);
 
984
                        }
 
985
                }
 
986
 
 
987
                /*
 
988
                 * (non-Javadoc)
 
989
                 * 
 
990
                 * @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
 
991
                 */
 
992
                @Override
 
993
                protected void paintComponent(Graphics g) {
 
994
                        Graphics2D graphics = (Graphics2D) g.create();
 
995
                        for (int i = 0; i < tabPane.getTabCount(); i++) {
 
996
                                TabPreviewControl child = overviewPanel.previewControls[i];
 
997
                                if (child.getZoom() > 1.0f) {
 
998
                                        paintSingleTabComponent(graphics, i);
 
999
                                }
 
1000
                        }
 
1001
                        if (currHoverIndex >= 0) {
 
1002
                                // paint the currently hovered once again (so it'll be on top)
 
1003
                                paintSingleTabComponent(graphics, currHoverIndex);
 
1004
                        }
 
1005
                        graphics.dispose();
 
1006
                }
 
1007
 
 
1008
                /**
 
1009
                 * Paints a single tab component.
 
1010
                 * 
 
1011
                 * @param graphics
 
1012
                 *            Graphics context.
 
1013
                 * @param index
 
1014
                 *            Tab component index.
 
1015
                 */
 
1016
                private void paintSingleTabComponent(Graphics2D graphics, int index) {
 
1017
                        TabPreviewControl child = overviewPanel.previewControls[index];
 
1018
                        Rectangle cBounds = child.getBounds();
 
1019
                        int dx = child.getLocationOnScreen().x
 
1020
                                        - this.getLocationOnScreen().x;
 
1021
                        int dy = child.getLocationOnScreen().y
 
1022
                                        - this.getLocationOnScreen().y;
 
1023
                        double factor = child.getZoom();
 
1024
                        int bw = (int) (cBounds.width * factor);
 
1025
                        int bh = (int) (cBounds.height * factor);
 
1026
                        BufferedImage bi = new BufferedImage(bw, bh,
 
1027
                                        BufferedImage.TYPE_INT_ARGB);
 
1028
                        Graphics2D bGraphics = (Graphics2D) bi.getGraphics().create();
 
1029
                        bGraphics.scale(factor, factor);
 
1030
 
 
1031
                        TabPreviewControl tChild = child;
 
1032
 
 
1033
                        bGraphics.setColor(tChild.getBackground());
 
1034
                        bGraphics.fillRect(0, 0, tChild.getWidth(), tChild.getHeight());
 
1035
 
 
1036
                        Icon icon = tabPane.getIconAt(index);
 
1037
                        int iy = (icon == null) ? 16 : icon.getIconHeight();
 
1038
                        if (icon != null) {
 
1039
                                icon.paintIcon(this, bGraphics, 1, 1);
 
1040
                        }
 
1041
                        String title = tabPane.getTitleAt(index);
 
1042
                        JLabel tempLabel = new JLabel(title);
 
1043
                        tempLabel.setBounds(tChild.titleLabel.getBounds());
 
1044
                        tempLabel.setFont(tChild.titleLabel.getFont());
 
1045
                        int bdx = tempLabel.getX();
 
1046
                        int bdy = tempLabel.getY();
 
1047
                        bGraphics.translate(bdx, bdy);
 
1048
                        tempLabel.paint(bGraphics);
 
1049
                        bGraphics.translate(-bdx, -bdy);
 
1050
                        bdx = 1;
 
1051
                        bdy = iy + 3;
 
1052
                        bGraphics.translate(bdx, bdy);
 
1053
                        (child).paintTabThumbnail(bGraphics);
 
1054
                        bGraphics.translate(-bdx, -bdy);
 
1055
                        bGraphics.setColor(Color.black);
 
1056
                        bGraphics.drawRect(0, 0, child.getWidth() - 1,
 
1057
                                        child.getHeight() - 1);
 
1058
                        bGraphics.dispose();
 
1059
 
 
1060
                        dx -= (bw - cBounds.width) / 2;
 
1061
                        dy -= (bh - cBounds.height) / 2;
 
1062
                        // make sure that the enlarged thumbnail stays inbounds
 
1063
                        dx = Math.max(dx, 0);
 
1064
                        dy = Math.max(dy, 0);
 
1065
                        if (dx + bi.getWidth() > getWidth()) {
 
1066
                                dx -= (dx + bi.getWidth() - getWidth());
 
1067
                        }
 
1068
                        if (dy + bi.getHeight() > getHeight()) {
 
1069
                                dy -= (dy + bi.getHeight() - getHeight());
 
1070
                        }
 
1071
                        graphics.drawImage(bi, dx, dy, null);
 
1072
                }
 
1073
        }
 
1074
 
 
1075
        /**
 
1076
         * Creates a new tab overview dialog. Declared private to enforce usage of
 
1077
         * {@link #getOverviewDialog(JTabbedPane)}.
 
1078
         * 
 
1079
         * @param tabPane
 
1080
         *            Tabbed pane.
 
1081
         * @param overviewKind
 
1082
         *            Overview kind.
 
1083
         * @param owner
 
1084
         *            Optional owner for the tab overview dialog.
 
1085
         * @param modal
 
1086
         *            Modality indication.
 
1087
         * @param dialogWidth
 
1088
         *            Tab overview dialog width.
 
1089
         * @param dialogHeight
 
1090
         *            Tab overview dialog height.
 
1091
         * @throws HeadlessException
 
1092
         * @see #getOverviewDialog(JTabbedPane)
 
1093
         */
 
1094
        private TabOverviewDialog(final JTabbedPane tabPane,
 
1095
                        TabOverviewKind overviewKind, Frame owner, boolean modal,
 
1096
                        int dialogWidth, int dialogHeight) throws HeadlessException {
 
1097
                super(owner, modal);
 
1098
                this.tabPane = tabPane;
 
1099
                this.setLayout(new BorderLayout());
 
1100
                if (overviewKind == TabOverviewKind.GRID) {
 
1101
                        TabGridOverviewPanel gridOverviewPanel = new TabGridOverviewPanel(
 
1102
                                        dialogWidth, dialogHeight);
 
1103
                        this.add(gridOverviewPanel, BorderLayout.CENTER);
 
1104
                        //
 
1105
                        // TabGridOverviewGlassPane glassPane = new
 
1106
                        // TabGridOverviewGlassPane(
 
1107
                        // gridOverviewPanel);
 
1108
                        // this.setGlassPane(glassPane);
 
1109
                        // glassPane.setVisible(true);
 
1110
                }
 
1111
                if (overviewKind == TabOverviewKind.ROUND_CAROUSEL) {
 
1112
                        this.add(new TabRoundCarouselOverviewPanel(dialogWidth,
 
1113
                                        dialogHeight), BorderLayout.CENTER);
 
1114
                }
 
1115
                if (overviewKind == TabOverviewKind.MENU_CAROUSEL) {
 
1116
                        this
 
1117
                                        .add(new TabMenuCarouselOverviewPanel(dialogWidth,
 
1118
                                                        dialogHeight), BorderLayout.CENTER);
 
1119
                }
 
1120
 
 
1121
                this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
 
1122
                this.setResizable(false);
 
1123
 
 
1124
                this.lafSwitchListener = new PropertyChangeListener() {
 
1125
                        @Override
 
1126
            public void propertyChange(PropertyChangeEvent evt) {
 
1127
                                if ("lookAndFeel".equals(evt.getPropertyName())) {
 
1128
                                        SwingUtilities.invokeLater(new Runnable() {
 
1129
                                                @Override
 
1130
                        public void run() {
 
1131
                                                        SwingUtilities
 
1132
                                                                        .updateComponentTreeUI(TabOverviewDialog.this);
 
1133
                                                }
 
1134
                                        });
 
1135
                                }
 
1136
                        }
 
1137
                };
 
1138
 
 
1139
                UIManager.addPropertyChangeListener(this.lafSwitchListener);
 
1140
 
 
1141
                // Cancel all pending preview requests issued by this overview
 
1142
                // dialog when it closes.
 
1143
                this.addWindowListener(new WindowAdapter() {
 
1144
                        /*
 
1145
                         * (non-Javadoc)
 
1146
                         * 
 
1147
                         * @see
 
1148
                         * java.awt.event.WindowAdapter#windowClosing(java.awt.event.WindowEvent
 
1149
                         * )
 
1150
                         */
 
1151
                        @Override
 
1152
                        public void windowClosing(WindowEvent e) {
 
1153
                                this.cancelRequests();
 
1154
                                UIManager.removePropertyChangeListener(lafSwitchListener);
 
1155
                        }
 
1156
 
 
1157
                        /*
 
1158
                         * (non-Javadoc)
 
1159
                         * 
 
1160
                         * @see
 
1161
                         * java.awt.event.WindowAdapter#windowClosed(java.awt.event.WindowEvent
 
1162
                         * )
 
1163
                         */
 
1164
                        @Override
 
1165
                        public void windowClosed(WindowEvent e) {
 
1166
                                this.cancelRequests();
 
1167
                                UIManager.removePropertyChangeListener(lafSwitchListener);
 
1168
                        }
 
1169
 
 
1170
                        /**
 
1171
                         * Cancels preview requests issued by <code>this</code> overview
 
1172
                         * dialog.
 
1173
                         */
 
1174
                        private void cancelRequests() {
 
1175
                                if (TabPreviewThread.instanceRunning()) {
 
1176
                                        TabPreviewThread.getInstance().cancelTabPreviewRequests(
 
1177
                                                        TabOverviewDialog.this);
 
1178
                                }
 
1179
                        }
 
1180
                });
 
1181
        }
 
1182
 
 
1183
        /**
 
1184
         * Returns a new instance of a tab overview dialog.
 
1185
         * 
 
1186
         * @param tabPane
 
1187
         *            Tabbed pane.
 
1188
         * @return Tab overview dialog for the specified tabbed pane.
 
1189
         */
 
1190
        public static TabOverviewDialog getOverviewDialog(JTabbedPane tabPane) {
 
1191
                final TabPreviewPainter previewPainter = LafWidgetUtilities2
 
1192
                                .getTabPreviewPainter(tabPane);
 
1193
                String title = previewPainter.toUpdatePeriodically(tabPane) ? MessageFormat
 
1194
                                .format(LafWidgetUtilities.getResourceBundle(tabPane)
 
1195
                                                .getString("TabbedPane.overviewDialogTitleRefresh"),
 
1196
                                                new Object[] {previewPainter
 
1197
                                .getUpdateCycle(tabPane) / 1000})
 
1198
                                : LafWidgetUtilities.getResourceBundle(tabPane).getString(
 
1199
                                                "TabbedPane.overviewDialogTitle");
 
1200
                JFrame frameForModality = previewPainter.getModalOwner(tabPane);
 
1201
                boolean isModal = (frameForModality != null);
 
1202
                Rectangle dialogScreenBounds = previewPainter
 
1203
                                .getPreviewDialogScreenBounds(tabPane);
 
1204
                TabOverviewKind overviewKind = previewPainter.getOverviewKind(tabPane);
 
1205
                final TabOverviewDialog overviewDialog = new TabOverviewDialog(tabPane,
 
1206
                                overviewKind, frameForModality, isModal,
 
1207
                                dialogScreenBounds.width, dialogScreenBounds.height);
 
1208
                overviewDialog.setTitle(title);
 
1209
 
 
1210
                overviewDialog.setLocation(dialogScreenBounds.x, dialogScreenBounds.y);
 
1211
                overviewDialog.setSize(dialogScreenBounds.width,
 
1212
                                dialogScreenBounds.height);
 
1213
 
 
1214
                // make sure that the tab overview dialog is disposed when
 
1215
                // it loses focus
 
1216
                final PropertyChangeListener activeWindowListener = new PropertyChangeListener() {
 
1217
                        @Override
 
1218
            public void propertyChange(PropertyChangeEvent evt) {
 
1219
                                if ("activeWindow".equals(evt.getPropertyName())) {
 
1220
                                        if (overviewDialog == evt.getOldValue()) {
 
1221
                                                if (previewPainter.toDisposeOverviewOnFocusLoss()) {
 
1222
                                                        overviewDialog.dispose();
 
1223
                                                }
 
1224
                                        }
 
1225
                                }
 
1226
                        }
 
1227
                };
 
1228
                KeyboardFocusManager.getCurrentKeyboardFocusManager()
 
1229
                                .addPropertyChangeListener(activeWindowListener);
 
1230
 
 
1231
                // make sure that when the window with the tabbed pane is
 
1232
                // closed, the tab overview dialog is disposed.
 
1233
                final Window tabWindow = SwingUtilities.getWindowAncestor(tabPane);
 
1234
                final WindowListener tabWindowListener = new WindowAdapter() {
 
1235
                        @Override
 
1236
                        public void windowClosed(WindowEvent e) {
 
1237
                                overviewDialog.dispose();
 
1238
                        }
 
1239
                };
 
1240
                tabWindow.addWindowListener(tabWindowListener);
 
1241
                overviewDialog.addWindowListener(new WindowAdapter() {
 
1242
                        @Override
 
1243
                        public void windowClosed(WindowEvent e) {
 
1244
                                tabWindow.removeWindowListener(tabWindowListener);
 
1245
                                KeyboardFocusManager.getCurrentKeyboardFocusManager()
 
1246
                                                .removePropertyChangeListener(activeWindowListener);
 
1247
                        }
 
1248
                });
 
1249
 
 
1250
                return overviewDialog;
 
1251
        }
 
1252
}