jdk

Форк
0
632 строки · 21.8 Кб
1
/*
2
 * Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved.
3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
 *
5
 * This code is free software; you can redistribute it and/or modify it
6
 * under the terms of the GNU General Public License version 2 only, as
7
 * published by the Free Software Foundation.  Oracle designates this
8
 * particular file as subject to the "Classpath" exception as provided
9
 * by Oracle in the LICENSE file that accompanied this code.
10
 *
11
 * This code is distributed in the hope that it will be useful, but WITHOUT
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14
 * version 2 for more details (a copy is included in the LICENSE file that
15
 * accompanied this code).
16
 *
17
 * You should have received a copy of the GNU General Public License version
18
 * 2 along with this work; if not, write to the Free Software Foundation,
19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
 *
21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
 * or visit www.oracle.com if you need additional information or have any
23
 * questions.
24
 */
25

26
package java.awt;
27

28
import java.io.IOException;
29
import java.io.ObjectInputStream;
30
import java.io.ObjectOutputStream;
31
import java.io.ObjectStreamField;
32
import java.io.Serial;
33
import java.io.Serializable;
34
import java.util.Enumeration;
35
import java.util.Hashtable;
36
import java.util.Vector;
37

38
/**
39
 * A {@code CardLayout} object is a layout manager for a
40
 * container. It treats each component in the container as a card.
41
 * Only one card is visible at a time, and the container acts as
42
 * a stack of cards. The first component added to a
43
 * {@code CardLayout} object is the visible component when the
44
 * container is first displayed.
45
 * <p>
46
 * The ordering of cards is determined by the container's own internal
47
 * ordering of its component objects. {@code CardLayout}
48
 * defines a set of methods that allow an application to flip
49
 * through these cards sequentially, or to show a specified card.
50
 * The {@link CardLayout#addLayoutComponent}
51
 * method can be used to associate a string identifier with a given card
52
 * for fast random access.
53
 *
54
 * @author      Arthur van Hoff
55
 * @see         java.awt.Container
56
 * @since       1.0
57
 */
58

59
public class CardLayout implements LayoutManager2,
60
                                   Serializable {
61
    /**
62
     * Use serialVersionUID from JDK 1.4 for interoperability.
63
     */
64
    @Serial
65
    private static final long serialVersionUID = -4328196481005934313L;
66

67
    /*
68
     * This creates a Vector to store associated
69
     * pairs of components and their names.
70
     * @see java.util.Vector
71
     */
72
    Vector<Card> vector = new Vector<>();
73

74
    /**
75
     * A pair of component and string that represents its name.
76
     */
77
    static class Card implements Serializable {
78

79
        /**
80
         * Use serialVersionUID from JDK 1.4 for interoperability.
81
         */
82
        @Serial
83
        private static final long serialVersionUID = 6640330810709497518L;
84
        public String name;
85
        public Component comp;
86
        public Card(String cardName, Component cardComponent) {
87
            name = cardName;
88
            comp = cardComponent;
89
        }
90
    }
91

92
    /*
93
     * Index of Component currently displayed by CardLayout.
94
     */
95
    int currentCard = 0;
96

97

98
    /*
99
    * A cards horizontal Layout gap (inset). It specifies
100
    * the space between the left and right edges of a
101
    * container and the current component.
102
    * This should be a non negative Integer.
103
    * @see getHgap()
104
    * @see setHgap()
105
    */
106
    int hgap;
107

108
    /*
109
    * A cards vertical Layout gap (inset). It specifies
110
    * the space between the top and bottom edges of a
111
    * container and the current component.
112
    * This should be a non negative Integer.
113
    * @see getVgap()
114
    * @see setVgap()
115
    */
116
    int vgap;
117

118
    /**
119
     * @serialField tab         Hashtable
120
     *      deprecated, for forward compatibility only
121
     * @serialField hgap        int the horizontal Layout gap
122
     * @serialField vgap        int the vertical Layout gap
123
     * @serialField vector      Vector the pairs of components and their names
124
     * @serialField currentCard int the index of Component currently displayed
125
     */
126
    @Serial
127
    private static final ObjectStreamField[] serialPersistentFields = {
128
        new ObjectStreamField("tab", Hashtable.class),
129
        new ObjectStreamField("hgap", Integer.TYPE),
130
        new ObjectStreamField("vgap", Integer.TYPE),
131
        new ObjectStreamField("vector", Vector.class),
132
        new ObjectStreamField("currentCard", Integer.TYPE)
133
    };
134

135
    /**
136
     * Creates a new card layout with gaps of size zero.
137
     */
138
    public CardLayout() {
139
        this(0, 0);
140
    }
141

142
    /**
143
     * Creates a new card layout with the specified horizontal and
144
     * vertical gaps. The horizontal gaps are placed at the left and
145
     * right edges. The vertical gaps are placed at the top and bottom
146
     * edges.
147
     * @param     hgap   the horizontal gap.
148
     * @param     vgap   the vertical gap.
149
     */
150
    public CardLayout(int hgap, int vgap) {
151
        this.hgap = hgap;
152
        this.vgap = vgap;
153
    }
154

155
    /**
156
     * Gets the horizontal gap between components.
157
     * @return    the horizontal gap between components.
158
     * @see       java.awt.CardLayout#setHgap(int)
159
     * @see       java.awt.CardLayout#getVgap()
160
     * @since     1.1
161
     */
162
    public int getHgap() {
163
        return hgap;
164
    }
165

166
    /**
167
     * Sets the horizontal gap between components.
168
     * @param hgap the horizontal gap between components.
169
     * @see       java.awt.CardLayout#getHgap()
170
     * @see       java.awt.CardLayout#setVgap(int)
171
     * @since     1.1
172
     */
173
    public void setHgap(int hgap) {
174
        this.hgap = hgap;
175
    }
176

177
    /**
178
     * Gets the vertical gap between components.
179
     * @return the vertical gap between components.
180
     * @see       java.awt.CardLayout#setVgap(int)
181
     * @see       java.awt.CardLayout#getHgap()
182
     */
183
    public int getVgap() {
184
        return vgap;
185
    }
186

187
    /**
188
     * Sets the vertical gap between components.
189
     * @param     vgap the vertical gap between components.
190
     * @see       java.awt.CardLayout#getVgap()
191
     * @see       java.awt.CardLayout#setHgap(int)
192
     * @since     1.1
193
     */
194
    public void setVgap(int vgap) {
195
        this.vgap = vgap;
196
    }
197

198
    /**
199
     * Adds the specified component to this card layout's internal
200
     * table of names. The object specified by {@code constraints}
201
     * must be a string. The card layout stores this string as a key-value
202
     * pair that can be used for random access to a particular card.
203
     * By calling the {@code show} method, an application can
204
     * display the component with the specified name.
205
     * @param     comp          the component to be added.
206
     * @param     constraints   a tag that identifies a particular
207
     *                                        card in the layout.
208
     * @see       java.awt.CardLayout#show(java.awt.Container, java.lang.String)
209
     * @throws  IllegalArgumentException  if the constraint is not a string.
210
     */
211
    public void addLayoutComponent(Component comp, Object constraints) {
212
      synchronized (comp.getTreeLock()) {
213
          if (constraints == null){
214
              constraints = "";
215
          }
216
        if (constraints instanceof String) {
217
            addLayoutComponent((String)constraints, comp);
218
        } else {
219
            throw new IllegalArgumentException("cannot add to layout: constraint must be a string");
220
        }
221
      }
222
    }
223

224
    /**
225
     * @deprecated   replaced by
226
     *      {@code addLayoutComponent(Component, Object)}.
227
     */
228
    @Deprecated
229
    public void addLayoutComponent(String name, Component comp) {
230
        synchronized (comp.getTreeLock()) {
231
            if (!vector.isEmpty()) {
232
                comp.setVisible(false);
233
            }
234
            for (int i=0; i < vector.size(); i++) {
235
                if ((vector.get(i)).name.equals(name)) {
236
                    (vector.get(i)).comp = comp;
237
                    return;
238
                }
239
            }
240
            vector.add(new Card(name, comp));
241
        }
242
    }
243

244
    /**
245
     * Removes the specified component from the layout.
246
     * If the card was visible on top, the next card underneath it is shown.
247
     * @param   comp   the component to be removed.
248
     * @see     java.awt.Container#remove(java.awt.Component)
249
     * @see     java.awt.Container#removeAll()
250
     */
251
    public void removeLayoutComponent(Component comp) {
252
        synchronized (comp.getTreeLock()) {
253
            for (int i = 0; i < vector.size(); i++) {
254
                if ((vector.get(i)).comp == comp) {
255
                    // if we remove current component we should show next one
256
                    if (comp.isVisible() && (comp.getParent() != null)) {
257
                        next(comp.getParent());
258
                    }
259

260
                    vector.remove(i);
261

262
                    // correct currentCard if this is necessary
263
                    if (currentCard > i) {
264
                        currentCard--;
265
                    }
266
                    break;
267
                }
268
            }
269
        }
270
    }
271

272
    /**
273
     * Determines the preferred size of the container argument using
274
     * this card layout.
275
     * @param   parent the parent container in which to do the layout
276
     * @return  the preferred dimensions to lay out the subcomponents
277
     *                of the specified container
278
     * @see     java.awt.Container#getPreferredSize
279
     * @see     java.awt.CardLayout#minimumLayoutSize
280
     */
281
    public Dimension preferredLayoutSize(Container parent) {
282
        synchronized (parent.getTreeLock()) {
283
            Insets insets = parent.getInsets();
284
            int ncomponents = parent.getComponentCount();
285
            int w = 0;
286
            int h = 0;
287

288
            for (int i = 0 ; i < ncomponents ; i++) {
289
                Component comp = parent.getComponent(i);
290
                Dimension d = comp.getPreferredSize();
291
                if (d.width > w) {
292
                    w = d.width;
293
                }
294
                if (d.height > h) {
295
                    h = d.height;
296
                }
297
            }
298
            return new Dimension(insets.left + insets.right + w + hgap*2,
299
                                 insets.top + insets.bottom + h + vgap*2);
300
        }
301
    }
302

303
    /**
304
     * Calculates the minimum size for the specified panel.
305
     * @param     parent the parent container in which to do the layout
306
     * @return    the minimum dimensions required to lay out the
307
     *                subcomponents of the specified container
308
     * @see       java.awt.Container#doLayout
309
     * @see       java.awt.CardLayout#preferredLayoutSize
310
     */
311
    public Dimension minimumLayoutSize(Container parent) {
312
        synchronized (parent.getTreeLock()) {
313
            Insets insets = parent.getInsets();
314
            int ncomponents = parent.getComponentCount();
315
            int w = 0;
316
            int h = 0;
317

318
            for (int i = 0 ; i < ncomponents ; i++) {
319
                Component comp = parent.getComponent(i);
320
                Dimension d = comp.getMinimumSize();
321
                if (d.width > w) {
322
                    w = d.width;
323
                }
324
                if (d.height > h) {
325
                    h = d.height;
326
                }
327
            }
328
            return new Dimension(insets.left + insets.right + w + hgap*2,
329
                                 insets.top + insets.bottom + h + vgap*2);
330
        }
331
    }
332

333
    /**
334
     * Returns the maximum dimensions for this layout given the components
335
     * in the specified target container.
336
     * @param target the component which needs to be laid out
337
     * @see Container
338
     * @see #minimumLayoutSize
339
     * @see #preferredLayoutSize
340
     */
341
    public Dimension maximumLayoutSize(Container target) {
342
        return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
343
    }
344

345
    /**
346
     * Returns the alignment along the x axis.  This specifies how
347
     * the component would like to be aligned relative to other
348
     * components.  The value should be a number between 0 and 1
349
     * where 0 represents alignment along the origin, 1 is aligned
350
     * the furthest away from the origin, 0.5 is centered, etc.
351
     */
352
    public float getLayoutAlignmentX(Container parent) {
353
        return 0.5f;
354
    }
355

356
    /**
357
     * Returns the alignment along the y axis.  This specifies how
358
     * the component would like to be aligned relative to other
359
     * components.  The value should be a number between 0 and 1
360
     * where 0 represents alignment along the origin, 1 is aligned
361
     * the furthest away from the origin, 0.5 is centered, etc.
362
     */
363
    public float getLayoutAlignmentY(Container parent) {
364
        return 0.5f;
365
    }
366

367
    /**
368
     * Invalidates the layout, indicating that if the layout manager
369
     * has cached information it should be discarded.
370
     */
371
    public void invalidateLayout(Container target) {
372
    }
373

374
    /**
375
     * Lays out the specified container using this card layout.
376
     * <p>
377
     * Each component in the {@code parent} container is reshaped
378
     * to be the size of the container, minus space for surrounding
379
     * insets, horizontal gaps, and vertical gaps.
380
     *
381
     * @param     parent the parent container in which to do the layout
382
     * @see       java.awt.Container#doLayout
383
     */
384
    public void layoutContainer(Container parent) {
385
        synchronized (parent.getTreeLock()) {
386
            Insets insets = parent.getInsets();
387
            int ncomponents = parent.getComponentCount();
388
            Component comp = null;
389
            boolean currentFound = false;
390

391
            for (int i = 0 ; i < ncomponents ; i++) {
392
                comp = parent.getComponent(i);
393
                comp.setBounds(hgap + insets.left, vgap + insets.top,
394
                               parent.width - (hgap*2 + insets.left + insets.right),
395
                               parent.height - (vgap*2 + insets.top + insets.bottom));
396
                if (comp.isVisible()) {
397
                    currentFound = true;
398
                }
399
            }
400

401
            if (!currentFound && ncomponents > 0) {
402
                parent.getComponent(0).setVisible(true);
403
            }
404
        }
405
    }
406

407
    /**
408
     * Make sure that the Container really has a CardLayout installed.
409
     * Otherwise havoc can ensue!
410
     */
411
    void checkLayout(Container parent) {
412
        if (parent.getLayout() != this) {
413
            throw new IllegalArgumentException("wrong parent for CardLayout");
414
        }
415
    }
416

417
    /**
418
     * Flips to the first card of the container.
419
     * @param     parent   the parent container in which to do the layout
420
     * @see       java.awt.CardLayout#last
421
     */
422
    public void first(Container parent) {
423
        synchronized (parent.getTreeLock()) {
424
            checkLayout(parent);
425
            int ncomponents = parent.getComponentCount();
426
            for (int i = 0 ; i < ncomponents ; i++) {
427
                Component comp = parent.getComponent(i);
428
                if (comp.isVisible()) {
429
                    comp.setVisible(false);
430
                    break;
431
                }
432
            }
433
            if (ncomponents > 0) {
434
                currentCard = 0;
435
                parent.getComponent(0).setVisible(true);
436
                parent.validate();
437
            }
438
        }
439
    }
440

441
    /**
442
     * Flips to the next card of the specified container. If the
443
     * currently visible card is the last one, this method flips to the
444
     * first card in the layout.
445
     * @param     parent   the parent container in which to do the layout
446
     * @see       java.awt.CardLayout#previous
447
     */
448
    public void next(Container parent) {
449
        synchronized (parent.getTreeLock()) {
450
            checkLayout(parent);
451
            int ncomponents = parent.getComponentCount();
452
            for (int i = 0 ; i < ncomponents ; i++) {
453
                Component comp = parent.getComponent(i);
454
                if (comp.isVisible()) {
455
                    comp.setVisible(false);
456
                    currentCard = (i + 1) % ncomponents;
457
                    comp = parent.getComponent(currentCard);
458
                    comp.setVisible(true);
459
                    parent.validate();
460
                    return;
461
                }
462
            }
463
            showDefaultComponent(parent);
464
        }
465
    }
466

467
    /**
468
     * Flips to the previous card of the specified container. If the
469
     * currently visible card is the first one, this method flips to the
470
     * last card in the layout.
471
     * @param     parent   the parent container in which to do the layout
472
     * @see       java.awt.CardLayout#next
473
     */
474
    public void previous(Container parent) {
475
        synchronized (parent.getTreeLock()) {
476
            checkLayout(parent);
477
            int ncomponents = parent.getComponentCount();
478
            for (int i = 0 ; i < ncomponents ; i++) {
479
                Component comp = parent.getComponent(i);
480
                if (comp.isVisible()) {
481
                    comp.setVisible(false);
482
                    currentCard = ((i > 0) ? i-1 : ncomponents-1);
483
                    comp = parent.getComponent(currentCard);
484
                    comp.setVisible(true);
485
                    parent.validate();
486
                    return;
487
                }
488
            }
489
            showDefaultComponent(parent);
490
        }
491
    }
492

493
    void showDefaultComponent(Container parent) {
494
        if (parent.getComponentCount() > 0) {
495
            currentCard = 0;
496
            parent.getComponent(0).setVisible(true);
497
            parent.validate();
498
        }
499
    }
500

501
    /**
502
     * Flips to the last card of the container.
503
     * @param     parent   the parent container in which to do the layout
504
     * @see       java.awt.CardLayout#first
505
     */
506
    public void last(Container parent) {
507
        synchronized (parent.getTreeLock()) {
508
            checkLayout(parent);
509
            int ncomponents = parent.getComponentCount();
510
            for (int i = 0 ; i < ncomponents ; i++) {
511
                Component comp = parent.getComponent(i);
512
                if (comp.isVisible()) {
513
                    comp.setVisible(false);
514
                    break;
515
                }
516
            }
517
            if (ncomponents > 0) {
518
                currentCard = ncomponents - 1;
519
                parent.getComponent(currentCard).setVisible(true);
520
                parent.validate();
521
            }
522
        }
523
    }
524

525
    /**
526
     * Flips to the component that was added to this layout with the
527
     * specified {@code name}, using {@code addLayoutComponent}.
528
     * If no such component exists, then nothing happens.
529
     * @param     parent   the parent container in which to do the layout
530
     * @param     name     the component name
531
     * @see       java.awt.CardLayout#addLayoutComponent(java.awt.Component, java.lang.Object)
532
     */
533
    public void show(Container parent, String name) {
534
        synchronized (parent.getTreeLock()) {
535
            checkLayout(parent);
536
            Component next = null;
537
            int ncomponents = vector.size();
538
            for (int i = 0; i < ncomponents; i++) {
539
                Card card = vector.get(i);
540
                if (card.name.equals(name)) {
541
                    next = card.comp;
542
                    currentCard = i;
543
                    break;
544
                }
545
            }
546
            if ((next != null) && !next.isVisible()) {
547
                ncomponents = parent.getComponentCount();
548
                for (int i = 0; i < ncomponents; i++) {
549
                    Component comp = parent.getComponent(i);
550
                    if (comp.isVisible()) {
551
                        comp.setVisible(false);
552
                        break;
553
                    }
554
                }
555
                next.setVisible(true);
556
                parent.validate();
557
            }
558
        }
559
    }
560

561
    /**
562
     * Returns a string representation of the state of this card layout.
563
     * @return    a string representation of this card layout.
564
     */
565
    public String toString() {
566
        return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + "]";
567
    }
568

569
    /**
570
     * Reads serializable fields from stream.
571
     *
572
     * @param  s the {@code ObjectInputStream} to read
573
     * @throws ClassNotFoundException if the class of a serialized object could
574
     *         not be found
575
     * @throws IOException if an I/O error occurs
576
     */
577
    @Serial
578
    @SuppressWarnings("unchecked")
579
    private void readObject(ObjectInputStream s)
580
        throws ClassNotFoundException, IOException
581
    {
582
        ObjectInputStream.GetField f = s.readFields();
583

584
        hgap = f.get("hgap", 0);
585
        vgap = f.get("vgap", 0);
586

587
        if (f.defaulted("vector")) {
588
            //  pre-1.4 stream
589
            Hashtable<String, Component> tab = (Hashtable)f.get("tab", null);
590
            vector = new Vector<>();
591
            if (tab != null && !tab.isEmpty()) {
592
                for (Enumeration<String> e = tab.keys() ; e.hasMoreElements() ; ) {
593
                    String key = e.nextElement();
594
                    Component comp = tab.get(key);
595
                    vector.add(new Card(key, comp));
596
                    if (comp.isVisible()) {
597
                        currentCard = vector.size() - 1;
598
                    }
599
                }
600
            }
601
        } else {
602
            vector = (Vector)f.get("vector", null);
603
            currentCard = f.get("currentCard", 0);
604
        }
605
    }
606

607
    /**
608
     * Writes serializable fields to stream.
609
     *
610
     * @param  s the {@code ObjectOutputStream} to write
611
     * @throws IOException if an I/O error occurs
612
     */
613
    @Serial
614
    private void writeObject(ObjectOutputStream s)
615
        throws IOException
616
    {
617
        Hashtable<String, Component> tab = new Hashtable<>();
618
        int ncomponents = vector.size();
619
        for (int i = 0; i < ncomponents; i++) {
620
            Card card = vector.get(i);
621
            tab.put(card.name, card.comp);
622
        }
623

624
        ObjectOutputStream.PutField f = s.putFields();
625
        f.put("hgap", hgap);
626
        f.put("vgap", vgap);
627
        f.put("vector", vector);
628
        f.put("currentCard", currentCard);
629
        f.put("tab", tab);
630
        s.writeFields();
631
    }
632
}
633

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.