~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/TabPreviewThread.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.image.BufferedImage;
 
34
import java.util.*;
 
35
import java.util.List;
 
36
 
 
37
import javax.swing.JTabbedPane;
 
38
import javax.swing.SwingUtilities;
 
39
 
 
40
import org.pushingpixels.lafwidget.LafWidgetUtilities;
 
41
import org.pushingpixels.lafwidget.LafWidgetUtilities2;
 
42
import org.pushingpixels.lafwidget.utils.DeltaQueue;
 
43
import org.pushingpixels.lafwidget.utils.TrackableThread;
 
44
import org.pushingpixels.lafwidget.utils.DeltaQueue.DeltaMatcher;
 
45
import org.pushingpixels.lafwidget.utils.DeltaQueue.Deltable;
 
46
 
 
47
/**
 
48
 * Thread for running the tab preview requests.
 
49
 * 
 
50
 * @author Kirill Grouchnikov
 
51
 */
 
52
public class TabPreviewThread extends TrackableThread {
 
53
        /**
 
54
         * Indication whether a stop request has been issued on <code>this</code>
 
55
         * thread.
 
56
         */
 
57
        private boolean stopRequested;
 
58
 
 
59
        /**
 
60
         * Queue of preview requests. Contains {@link TabPreviewInfo}s.
 
61
         */
 
62
        protected DeltaQueue previewQueue;
 
63
 
 
64
        /**
 
65
         * Information for previewing a tabbed pane.
 
66
         * 
 
67
         * @author Kirill Grouchnikov
 
68
         */
 
69
        public static class TabPreviewInfo extends DeltaQueue.Deltable {
 
70
                /**
 
71
                 * Tabbed pane.
 
72
                 */
 
73
                public JTabbedPane tabPane;
 
74
 
 
75
                /**
 
76
                 * Callback for passing the preview thumbnail once it is computed.
 
77
                 */
 
78
                public TabPreviewThread.TabPreviewCallback previewCallback;
 
79
 
 
80
                /**
 
81
                 * Width of the preview thumbnail.
 
82
                 */
 
83
                private int previewWidth;
 
84
 
 
85
                /**
 
86
                 * Height of the preview thumbnail.
 
87
                 */
 
88
                private int previewHeight;
 
89
 
 
90
                /**
 
91
                 * Indicates whether all tabs in the {@link #tabPane} should be
 
92
                 * previewed.
 
93
                 */
 
94
                public boolean toPreviewAllTabs;
 
95
 
 
96
                /**
 
97
                 * If {@link #toPreviewAllTabs} is <code>false</code>, contains the
 
98
                 * index of the tab to be previewed.
 
99
                 */
 
100
                public int tabIndexToPreview;
 
101
 
 
102
                /**
 
103
                 * Points to the preview initiator.
 
104
                 */
 
105
                public Object initiator;
 
106
 
 
107
                public void setPreviewWidth(int previewWidth) {
 
108
                        this.previewWidth = previewWidth;
 
109
                }
 
110
 
 
111
                public int getPreviewWidth() {
 
112
                        return previewWidth;
 
113
                }
 
114
 
 
115
                public void setPreviewHeight(int previewHeight) {
 
116
                        this.previewHeight = previewHeight;
 
117
                }
 
118
 
 
119
                public int getPreviewHeight() {
 
120
                        return previewHeight;
 
121
                }
 
122
        }
 
123
 
 
124
        /**
 
125
         * Interface for offering the tab preview image once it has been computed.
 
126
         * 
 
127
         * @author Kirill Grouchnikov
 
128
         */
 
129
        public static interface TabPreviewCallback {
 
130
                /**
 
131
                 * Starts the current cycle of
 
132
                 * {@link #offer(JTabbedPane, int, BufferedImage)} calls. This can be
 
133
                 * used by the implementing class to revalidate itself in case the tab
 
134
                 * count in the specified tabbed pane has changed since the previous
 
135
                 * cycle of {@link #offer(JTabbedPane, int, BufferedImage)} call.
 
136
                 * 
 
137
                 * @param tabPane
 
138
                 *            Tabbed pane.
 
139
                 * @param tabCount
 
140
                 *            Tab count in the tabbed pane.
 
141
                 * @param tabPreviewInfo
 
142
                 *            Tab preview info. Can be changed in the implementation
 
143
                 *            code.
 
144
                 */
 
145
                public void start(JTabbedPane tabPane, int tabCount,
 
146
                                TabPreviewInfo tabPreviewInfo);
 
147
 
 
148
                /**
 
149
                 * Offers the preview image (thumbnail) of a tab in the specified tabbed
 
150
                 * pane.
 
151
                 * 
 
152
                 * @param tabPane
 
153
                 *            Tabbed pane.
 
154
                 * @param tabIndex
 
155
                 *            Tab index.
 
156
                 * @param componentSnap
 
157
                 *            Tab preview image.
 
158
                 */
 
159
                public void offer(JTabbedPane tabPane, int tabIndex,
 
160
                                BufferedImage componentSnap);
 
161
        }
 
162
 
 
163
        /**
 
164
         * Simple constructor. Defined private for singleton.
 
165
         * 
 
166
         * @see #getInstance()
 
167
         */
 
168
        private TabPreviewThread() {
 
169
                super();
 
170
                this.setName("Laf-Widget tab preview");
 
171
                this.stopRequested = false;
 
172
                this.previewQueue = new DeltaQueue();
 
173
        }
 
174
 
 
175
        /*
 
176
         * (non-Javadoc)
 
177
         * 
 
178
         * @see java.lang.Thread#run()
 
179
         */
 
180
        @Override
 
181
        public void run() {
 
182
                while (!this.stopRequested) {
 
183
                        try {
 
184
                                // System.out.println(System.currentTimeMillis() + " Polling");
 
185
                                int delay = 500;
 
186
                                List<Deltable> expired = this.dequeueTabPreviewRequest(delay);
 
187
                                for (Deltable dExpired : expired) {
 
188
                                        final TabPreviewInfo nextPreviewInfo = (TabPreviewInfo) dExpired;
 
189
                                        final JTabbedPane jtp = nextPreviewInfo.tabPane;
 
190
                                        if (jtp == null)
 
191
                                                continue;
 
192
                                        final TabPreviewPainter previewPainter = LafWidgetUtilities2
 
193
                                                        .getTabPreviewPainter(jtp);
 
194
                                        final int tabCount = jtp.getTabCount();
 
195
 
 
196
                                        // SwingUtilities.invokeLater(new Runnable() {
 
197
                                        // public void run() {
 
198
                                        // final TabPreviewInfo copyPreviewInfo = new
 
199
                                        // TabPreviewInfo();
 
200
                                        // copyPreviewInfo.initiator = nextPreviewInfo.initiator;
 
201
                                        // copyPreviewInfo.previewCallback =
 
202
                                        // nextPreviewInfo.previewCallback;
 
203
                                        // copyPreviewInfo.previewHeight =
 
204
                                        // nextPreviewInfo.previewHeight;
 
205
                                        // copyPreviewInfo.previewWidth =
 
206
                                        // nextPreviewInfo.previewWidth;
 
207
                                        // copyPreviewInfo.tabIndexToPreview =
 
208
                                        // nextPreviewInfo.tabIndexToPreview;
 
209
                                        // copyPreviewInfo.tabPane = nextPreviewInfo.tabPane;
 
210
                                        // copyPreviewInfo.toPreviewAllTabs =
 
211
                                        // nextPreviewInfo.toPreviewAllTabs;
 
212
 
 
213
                                        if (nextPreviewInfo.toPreviewAllTabs) {
 
214
                                                SwingUtilities.invokeLater(new Runnable() {
 
215
                                                        @Override
 
216
                                                        public void run() {
 
217
                                                                // The call to start() is only relevant for the
 
218
                                                                // preview of all tabs.
 
219
                                                                nextPreviewInfo.previewCallback.start(jtp, jtp
 
220
                                                                                .getTabCount(), nextPreviewInfo);
 
221
                                                        }
 
222
                                                });
 
223
 
 
224
                                                for (int i = 0; i < tabCount; i++) {
 
225
                                                        final int index = i;
 
226
                                                        SwingUtilities.invokeLater(new Runnable() {
 
227
                                                                @Override
 
228
                                public void run() {
 
229
                                                                        getSingleTabPreviewImage(jtp,
 
230
                                                                                        previewPainter, nextPreviewInfo,
 
231
                                                                                        index);
 
232
                                                                }
 
233
                                                        });
 
234
                                                }
 
235
                                        } else {
 
236
                                                SwingUtilities.invokeLater(new Runnable() {
 
237
                                                        @Override
 
238
                            public void run() {
 
239
                                                                getSingleTabPreviewImage(jtp, previewPainter,
 
240
                                                                                nextPreviewInfo,
 
241
                                                                                nextPreviewInfo.tabIndexToPreview);
 
242
                                                        }
 
243
                                                });
 
244
                                        }
 
245
                                        // }
 
246
                                        // });
 
247
 
 
248
                                        if (previewPainter.toUpdatePeriodically(jtp)) {
 
249
                                                TabPreviewInfo cyclePreviewInfo = new TabPreviewInfo();
 
250
                                                // copy all the fields from the currently processed
 
251
                                                // request
 
252
                                                cyclePreviewInfo.tabPane = nextPreviewInfo.tabPane;
 
253
                                                cyclePreviewInfo.tabIndexToPreview = nextPreviewInfo.tabIndexToPreview;
 
254
                                                cyclePreviewInfo.toPreviewAllTabs = nextPreviewInfo.toPreviewAllTabs;
 
255
                                                cyclePreviewInfo.previewCallback = nextPreviewInfo.previewCallback;
 
256
                                                cyclePreviewInfo.setPreviewWidth(nextPreviewInfo.getPreviewWidth());
 
257
                                                cyclePreviewInfo.setPreviewHeight(nextPreviewInfo.getPreviewHeight());
 
258
                                                cyclePreviewInfo.initiator = nextPreviewInfo.initiator;
 
259
 
 
260
                                                // schedule it to app-specific delay
 
261
                                                cyclePreviewInfo.setDelta(previewPainter
 
262
                                                                .getUpdateCycle(cyclePreviewInfo.tabPane));
 
263
 
 
264
                                                // queue the new request
 
265
                                                this.queueTabPreviewRequest(cyclePreviewInfo);
 
266
                                        }
 
267
                                }
 
268
                                Thread.sleep(delay);
 
269
                        } catch (InterruptedException ie) {
 
270
                                ie.printStackTrace();
 
271
                        }
 
272
                }
 
273
                // System.out.println("Tab preview finished");
 
274
        }
 
275
 
 
276
        /**
 
277
         * Computes and offers the preview thumbnail for a single tab.
 
278
         * 
 
279
         * @param tabPane
 
280
         *            Tabbed pane.
 
281
         * @param previewPainter
 
282
         *            Tab preview painter.
 
283
         * @param previewInfo
 
284
         *            Preview info.
 
285
         * @param tabIndex
 
286
         *            Index of the tab to preview.
 
287
         */
 
288
        protected void getSingleTabPreviewImage(final JTabbedPane tabPane,
 
289
                        final TabPreviewPainter previewPainter,
 
290
                        final TabPreviewInfo previewInfo, final int tabIndex) {
 
291
                int pWidth = previewInfo.getPreviewWidth();
 
292
                int pHeight = previewInfo.getPreviewHeight();
 
293
                final BufferedImage previewImage = new BufferedImage(pWidth, pHeight,
 
294
                                BufferedImage.TYPE_INT_ARGB);
 
295
                Graphics2D gr = previewImage.createGraphics();
 
296
                Component comp = tabPane.getComponentAt(tabIndex);
 
297
 
 
298
                if (previewPainter.hasPreview(tabPane, tabIndex)) {
 
299
                        Map<Component, Boolean> dbSnapshot = new HashMap<Component, Boolean>();
 
300
                        LafWidgetUtilities.makePreviewable(comp, dbSnapshot);
 
301
                        previewPainter.previewTab(tabPane, tabIndex, gr, 0, 0, pWidth,
 
302
                                        pHeight);
 
303
                        LafWidgetUtilities.restorePreviewable(comp, dbSnapshot);
 
304
                } else {
 
305
                        gr.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
 
306
                                        RenderingHints.VALUE_ANTIALIAS_ON);
 
307
                        gr.setColor(Color.red);
 
308
                        gr.setStroke(new BasicStroke(Math.max(5.0f, Math.min(pWidth,
 
309
                                        pHeight) / 10.0f)));
 
310
                        gr.drawLine(0, 0, pWidth, pHeight);
 
311
                        gr.drawLine(0, pHeight, pWidth, 0);
 
312
                }
 
313
                gr.dispose();
 
314
 
 
315
                if (previewInfo.previewCallback != null) {
 
316
                        SwingUtilities.invokeLater(new Runnable() {
 
317
                                @Override
 
318
                public void run() {
 
319
                                        previewInfo.previewCallback.offer(tabPane, tabIndex,
 
320
                                                        previewImage);
 
321
                                }
 
322
                        });
 
323
                }
 
324
        }
 
325
 
 
326
        /**
 
327
         * Queues the request to preview one or all tabs in the specified tabbed
 
328
         * pane. Once the request is queued, the thread will pick it up from the
 
329
         * queue (in at most 500 milliseconds in the current implementation) and
 
330
         * start processing it. For each tab (if all tabs were requested to be
 
331
         * previewed), the preview thumbnail will be offered to the relevant
 
332
         * callback. This allows to maintain the interactivity of the application
 
333
         * while generating the preview thumbnails for the tab overview dialog (see
 
334
         * {@link TabOverviewDialog}).
 
335
         * 
 
336
         * @param previewInfo
 
337
         *            Tab preview info.
 
338
         */
 
339
        public void queueTabPreviewRequest(TabPreviewInfo previewInfo) {
 
340
                this.previewQueue.queue(previewInfo);
 
341
        }
 
342
 
 
343
        /**
 
344
         * Cancels all tab preview requests that were initiated by the specified
 
345
         * initiator.
 
346
         * 
 
347
         * @param initiator
 
348
         *            Initiator.
 
349
         */
 
350
        public void cancelTabPreviewRequests(final Object initiator) {
 
351
                DeltaMatcher matcher = new DeltaMatcher() {
 
352
                        @Override
 
353
            public boolean matches(Deltable deltable) {
 
354
                                TabPreviewInfo currInfo = (TabPreviewInfo) deltable;
 
355
                                return (currInfo.initiator == initiator);
 
356
                        }
 
357
                };
 
358
                this.previewQueue.removeMatching(matcher);
 
359
        }
 
360
 
 
361
        /**
 
362
         * Removes the tab preview requests that have at most specified delay left.
 
363
         * 
 
364
         * @param delay
 
365
         *            Delay.
 
366
         * @return The list of all tab preview requests that have at most specified
 
367
         *         delay left.
 
368
         */
 
369
        private List<Deltable> dequeueTabPreviewRequest(int delay) {
 
370
                return this.previewQueue.dequeue(delay);
 
371
        }
 
372
 
 
373
        /*
 
374
         * (non-Javadoc)
 
375
         * 
 
376
         * @see org.pushingpixels.lafwidget.utils.TrackableThread#requestStop()
 
377
         */
 
378
        @Override
 
379
        protected void requestStop() {
 
380
                this.stopRequested = true;
 
381
                TabPreviewThread.tabPreviewThread = null;
 
382
        }
 
383
 
 
384
        /**
 
385
         * The preview thread.
 
386
         */
 
387
        private static TabPreviewThread tabPreviewThread;
 
388
 
 
389
        /**
 
390
         * Returns the singleton instance of the tab preview thread.
 
391
         * 
 
392
         * @return The singleton instance of the tab preview thread.
 
393
         */
 
394
        public static synchronized TabPreviewThread getInstance() {
 
395
                if (TabPreviewThread.tabPreviewThread == null) {
 
396
                        // System.err.println("Allocating ");
 
397
                        // Thread.dumpStack();
 
398
                        TabPreviewThread.tabPreviewThread = new TabPreviewThread();
 
399
                        TabPreviewThread.tabPreviewThread.start();
 
400
                }
 
401
                return TabPreviewThread.tabPreviewThread;
 
402
        }
 
403
 
 
404
        /**
 
405
         * Returns indication whether tab preview thread is running.
 
406
         * 
 
407
         * @return <code>true</code> if the tab preview thread is running,
 
408
         *         <code>false</code> otherwise.
 
409
         */
 
410
        public static synchronized boolean instanceRunning() {
 
411
                return (TabPreviewThread.tabPreviewThread != null);
 
412
        }
 
413
 
 
414
        // public void dump() {
 
415
        // System.out.println("Dump");
 
416
        // for (int i = 0; i < this.previewRequests.size(); i++) {
 
417
        // TabPreviewInfo tpi = (TabPreviewInfo) this.previewRequests.get(i);
 
418
        // System.out.println("\t" + tpi.tabIndexToPreview + " -> "
 
419
        // + tpi.timeToExpire);
 
420
        // }
 
421
        // }
 
422
        //
 
423
        // public static void main(String[] args) {
 
424
        // TabPreviewThread tpt = new TabPreviewThread();
 
425
        // TabPreviewInfo tpi11 = new TabPreviewInfo();
 
426
        // tpi11.tabIndexToPreview = 11;
 
427
        // tpi11.timeToExpire = 100;
 
428
        // tpt.queueTabPreviewRequest(tpi11);
 
429
        // tpt.dump();
 
430
        //
 
431
        // TabPreviewInfo tpi12 = new TabPreviewInfo();
 
432
        // tpi12.tabIndexToPreview = 12;
 
433
        // tpi12.timeToExpire = 100;
 
434
        // tpt.queueTabPreviewRequest(tpi12);
 
435
        // tpt.dump();
 
436
        //
 
437
        // TabPreviewInfo tpi21 = new TabPreviewInfo();
 
438
        // tpi21.tabIndexToPreview = 21;
 
439
        // tpi21.timeToExpire = 200;
 
440
        // tpt.queueTabPreviewRequest(tpi21);
 
441
        // tpt.dump();
 
442
        //
 
443
        // TabPreviewInfo tpi31 = new TabPreviewInfo();
 
444
        // tpi31.tabIndexToPreview = 31;
 
445
        // tpi31.timeToExpire = 300;
 
446
        // tpt.queueTabPreviewRequest(tpi31);
 
447
        // tpt.dump();
 
448
        //
 
449
        // TabPreviewInfo tpi13 = new TabPreviewInfo();
 
450
        // tpi13.tabIndexToPreview = 13;
 
451
        // tpi13.timeToExpire = 100;
 
452
        // tpt.queueTabPreviewRequest(tpi13);
 
453
        // tpt.dump();
 
454
        //
 
455
        // TabPreviewInfo tpi22 = new TabPreviewInfo();
 
456
        // tpi22.tabIndexToPreview = 22;
 
457
        // tpi22.timeToExpire = 200;
 
458
        // tpt.queueTabPreviewRequest(tpi22);
 
459
        // tpt.dump();
 
460
        //
 
461
        // TabPreviewInfo tpi25 = new TabPreviewInfo();
 
462
        // tpi25.tabIndexToPreview = 25;
 
463
        // tpi25.timeToExpire = 250;
 
464
        // tpt.queueTabPreviewRequest(tpi25);
 
465
        // tpt.dump();
 
466
        //
 
467
        // TabPreviewInfo tpi51 = new TabPreviewInfo();
 
468
        // tpi51.tabIndexToPreview = 51;
 
469
        // tpi51.timeToExpire = 500;
 
470
        // tpt.queueTabPreviewRequest(tpi51);
 
471
        // tpt.dump();
 
472
        //
 
473
        // List gr150 = tpt.dequeueTabPreviewRequest(2500);
 
474
        // System.out.println("Dump 150");
 
475
        // for (int i = 0; i < gr150.size(); i++) {
 
476
        // TabPreviewInfo tpi = (TabPreviewInfo) gr150.get(i);
 
477
        // System.out.println("\t" + tpi.tabIndexToPreview);
 
478
        // }
 
479
        // tpt.dump();
 
480
        //
 
481
        // TrackableThread.requestStopAllThreads();
 
482
        // }
 
483
}
 
 
b'\\ No newline at end of file'