1/*
2 * Copyright (c) 2007, 2016, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23package com.sun.swingset3.demos.list;
24
25import java.awt.*;
26import java.awt.event.ActionEvent;
27import java.awt.event.FocusAdapter;
28import java.awt.event.FocusEvent;
29import java.awt.event.FocusListener;
30import java.util.Vector;
31import javax.swing.*;
32
33import com.sun.swingset3.DemoProperties;
34import com.sun.swingset3.demos.ResourceManager;
35
36/**
37 * List Demo. This demo shows that it is not always necessary to have an array
38 * of objects as big as the size of the list stored.
39 *
40 * Indeed, in this example, there is no array kept for the list data, rather it
41 * is generated on the fly as only those elements are needed.
42 *
43 * @version 1.17 11/17/05
44 * @author Jeff Dinkins
45 */
46@DemoProperties(
47        value = "JList Demo",
48        category = "Data",
49        description = "Demonstrates JList, a component which supports display/editing of a data list",
50        sourceFiles = {
51            "com/sun/swingset3/demos/list/ListDemo.java",
52            "com/sun/swingset3/demos/list/Permuter.java",
53            "com/sun/swingset3/demos/ResourceManager.java",
54            "com/sun/swingset3/demos/list/resources/ListDemo.properties",
55            "com/sun/swingset3/demos/list/resources/images/blue.gif",
56            "com/sun/swingset3/demos/list/resources/images/cyan.gif",
57            "com/sun/swingset3/demos/list/resources/images/gray.gif",
58            "com/sun/swingset3/demos/list/resources/images/green.gif",
59            "com/sun/swingset3/demos/list/resources/images/ListDemo.gif",
60            "com/sun/swingset3/demos/list/resources/images/magenta.gif",
61            "com/sun/swingset3/demos/list/resources/images/red.gif",
62            "com/sun/swingset3/demos/list/resources/images/yellow.gif"
63        }
64)
65public final class ListDemo extends JPanel {
66
67    private static final Dimension HGAP10 = new Dimension(10, 1);
68    private static final Dimension VGAP10 = new Dimension(1, 10);
69    private static final Dimension HGAP15 = new Dimension(15, 1);
70    private static final Dimension HGAP30 = new Dimension(30, 1);
71
72    private final ResourceManager resourceManager = new ResourceManager(this.getClass());
73    public static final String DEMO_TITLE = ListDemo.class.getAnnotation(DemoProperties.class).value();
74
75    private final JList<String> list;
76
77    private JPanel prefixList;
78    private JPanel suffixList;
79
80    private Action prefixAction;
81    private Action suffixAction;
82
83    private final GeneratedListModel listModel;
84
85    /**
86     * main method allows us to run as a standalone demo.
87     *
88     * @param args
89     */
90    public static void main(String[] args) {
91        JFrame frame = new JFrame(DEMO_TITLE);
92
93        frame.getContentPane().add(new ListDemo());
94        frame.setPreferredSize(new Dimension(800, 600));
95        frame.pack();
96        frame.setLocationRelativeTo(null);
97        frame.setVisible(true);
98    }
99
100    /**
101     * ListDemo Constructor
102     */
103    public ListDemo() {
104        setLayout(new BorderLayout());
105
106        loadImages();
107
108        JLabel description = new JLabel(resourceManager.getString("ListDemo.description"));
109        add(description, BorderLayout.NORTH);
110
111        JPanel centerPanel = new JPanel();
112        centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.X_AXIS));
113        centerPanel.add(Box.createRigidArea(HGAP10));
114        add(centerPanel, BorderLayout.CENTER);
115
116        JPanel listPanel = new JPanel();
117        listPanel.setLayout(new BoxLayout(listPanel, BoxLayout.Y_AXIS));
118        listPanel.add(Box.createRigidArea(VGAP10));
119
120        centerPanel.add(listPanel);
121        centerPanel.add(Box.createRigidArea(HGAP30));
122
123        // Create the list
124        list = new JList<>();
125        list.setCellRenderer(new CompanyLogoListCellRenderer());
126        listModel = new GeneratedListModel();
127        list.setModel(listModel);
128
129        // Set the preferred row count. This affects the preferredSize
130        // of the JList when it's in a scrollpane.
131        list.setVisibleRowCount(22);
132
133        // Add list to a scrollpane
134        JScrollPane scrollPane = new JScrollPane(list);
135        listPanel.add(scrollPane);
136        listPanel.add(Box.createRigidArea(VGAP10));
137
138        // Add the control panel (holds the prefix/suffix list and prefix/suffix checkboxes)
139        centerPanel.add(createControlPanel());
140
141        // create prefixes and suffixes
142        addPrefix("Tera", true);
143        addPrefix("Micro", false);
144        addPrefix("Southern", false);
145        addPrefix("Net", true);
146        addPrefix("YoYo", true);
147        addPrefix("Northern", false);
148        addPrefix("Tele", false);
149        addPrefix("Eastern", false);
150        addPrefix("Neo", false);
151        addPrefix("Digi", false);
152        addPrefix("National", false);
153        addPrefix("Compu", true);
154        addPrefix("Meta", true);
155        addPrefix("Info", false);
156        addPrefix("Western", false);
157        addPrefix("Data", false);
158        addPrefix("Atlantic", false);
159        addPrefix("Advanced", false);
160        addPrefix("Euro", false);
161        addPrefix("Pacific", false);
162        addPrefix("Mobile", false);
163        addPrefix("In", false);
164        addPrefix("Computa", false);
165        addPrefix("Digital", false);
166        addPrefix("Analog", false);
167
168        addSuffix("Tech", true);
169        addSuffix("Soft", true);
170        addSuffix("Telecom", true);
171        addSuffix("Solutions", false);
172        addSuffix("Works", true);
173        addSuffix("Dyne", false);
174        addSuffix("Services", false);
175        addSuffix("Vers", false);
176        addSuffix("Devices", false);
177        addSuffix("Software", false);
178        addSuffix("Serv", false);
179        addSuffix("Systems", true);
180        addSuffix("Dynamics", true);
181        addSuffix("Net", false);
182        addSuffix("Sys", false);
183        addSuffix("Computing", false);
184        addSuffix("Scape", false);
185        addSuffix("Com", false);
186        addSuffix("Ware", false);
187        addSuffix("Widgets", false);
188        addSuffix("Media", false);
189        addSuffix("Computer", false);
190        addSuffix("Hardware", false);
191        addSuffix("Gizmos", false);
192        addSuffix("Concepts", false);
193    }
194
195    private JPanel createControlPanel() {
196        JPanel controlPanel = new JPanel() {
197            private final Insets insets = new Insets(0, 4, 10, 10);
198
199            @Override
200            public Insets getInsets() {
201                return insets;
202            }
203        };
204        controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.X_AXIS));
205
206        JPanel prefixPanel = new JPanel();
207        prefixPanel.setLayout(new BoxLayout(prefixPanel, BoxLayout.Y_AXIS));
208        prefixPanel.add(new JLabel(resourceManager.getString("ListDemo.prefixes")));
209
210        JPanel suffixPanel = new JPanel();
211        suffixPanel.setLayout(new BoxLayout(suffixPanel, BoxLayout.Y_AXIS));
212        suffixPanel.add(new JLabel(resourceManager.getString("ListDemo.suffixes")));
213
214        prefixList = new JPanel() {
215            private final Insets insets = new Insets(0, 4, 0, 0);
216
217            @Override
218            public Insets getInsets() {
219                return insets;
220            }
221        };
222        prefixList.setLayout(new BoxLayout(prefixList, BoxLayout.Y_AXIS));
223        JScrollPane scrollPane = new JScrollPane(prefixList);
224        scrollPane.getVerticalScrollBar().setUnitIncrement(10);
225        prefixPanel.add(scrollPane);
226        prefixPanel.add(Box.createRigidArea(HGAP10));
227
228        suffixList = new JPanel() {
229            private final Insets insets = new Insets(0, 4, 0, 0);
230
231            @Override
232            public Insets getInsets() {
233                return insets;
234            }
235        };
236        suffixList.setLayout(new BoxLayout(suffixList, BoxLayout.Y_AXIS));
237        scrollPane = new JScrollPane(suffixList);
238        scrollPane.getVerticalScrollBar().setUnitIncrement(10);
239        suffixPanel.add(scrollPane);
240        suffixPanel.add(Box.createRigidArea(HGAP10));
241
242        controlPanel.add(prefixPanel);
243        controlPanel.add(Box.createRigidArea(HGAP15));
244        controlPanel.add(suffixPanel);
245        return controlPanel;
246    }
247
248    private final FocusListener listFocusListener = new FocusAdapter() {
249        @Override
250        public void focusGained(FocusEvent e) {
251            JComponent c = (JComponent) e.getComponent();
252            c.scrollRectToVisible(new Rectangle(0, 0, c.getWidth(), c.getHeight()));
253        }
254    };
255
256    private void addPrefix(String prefix, boolean selected) {
257        if (prefixAction == null) {
258            prefixAction = new UpdatePrefixListAction(listModel);
259        }
260        final JCheckBox cb = (JCheckBox) prefixList.add(new JCheckBox(prefix));
261        cb.setSelected(selected);
262        cb.addActionListener(prefixAction);
263        if (selected) {
264            listModel.addPrefix(prefix);
265        }
266        cb.addFocusListener(listFocusListener);
267    }
268
269    private void addSuffix(String suffix, boolean selected) {
270        if (suffixAction == null) {
271            suffixAction = new UpdateSuffixListAction(listModel);
272        }
273        final JCheckBox cb = (JCheckBox) suffixList.add(new JCheckBox(suffix));
274        cb.setSelected(selected);
275        cb.addActionListener(suffixAction);
276        if (selected) {
277            listModel.addSuffix(suffix);
278        }
279        cb.addFocusListener(listFocusListener);
280    }
281
282    private static class UpdatePrefixListAction extends AbstractAction {
283
284        private final GeneratedListModel listModel;
285
286        protected UpdatePrefixListAction(GeneratedListModel listModel) {
287            this.listModel = listModel;
288        }
289
290        @Override
291        public void actionPerformed(ActionEvent e) {
292            JCheckBox cb = (JCheckBox) e.getSource();
293            if (cb.isSelected()) {
294                listModel.addPrefix(cb.getText());
295            } else {
296                listModel.removePrefix(cb.getText());
297            }
298        }
299    }
300
301    private static class UpdateSuffixListAction extends AbstractAction {
302
303        private final GeneratedListModel listModel;
304
305        protected UpdateSuffixListAction(GeneratedListModel listModel) {
306            this.listModel = listModel;
307        }
308
309        @Override
310        public void actionPerformed(ActionEvent e) {
311            JCheckBox cb = (JCheckBox) e.getSource();
312            if (cb.isSelected()) {
313                listModel.addSuffix(cb.getText());
314            } else {
315                listModel.removeSuffix(cb.getText());
316            }
317        }
318    }
319
320    private static class GeneratedListModel extends AbstractListModel<String> {
321
322        private Permuter permuter;
323
324        private final Vector<String> prefix = new Vector<>();
325        private final Vector<String> suffix = new Vector<>();
326
327        private void update() {
328            permuter = new Permuter(getSize());
329            fireContentsChanged(this, 0, getSize());
330        }
331
332        public void addPrefix(String s) {
333            if (!prefix.contains(s)) {
334                prefix.addElement(s);
335                update();
336            }
337        }
338
339        public void removePrefix(String s) {
340            prefix.removeElement(s);
341            update();
342        }
343
344        public void addSuffix(String s) {
345            if (!suffix.contains(s)) {
346                suffix.addElement(s);
347                update();
348            }
349        }
350
351        public void removeSuffix(String s) {
352            suffix.removeElement(s);
353            update();
354        }
355
356        @Override
357        public int getSize() {
358            return prefix.size() * suffix.size();
359        }
360
361        @Override
362        public String getElementAt(int index) {
363            if (permuter == null) {
364                update();
365            }
366            // morph the index to another int -- this has the benefit of
367            // causing the list to look random.
368            int j = permuter.map(index);
369            int ps = prefix.size();
370            int ss = suffix.size();
371            return prefix.elementAt(j % ps) + suffix.elementAt((j / ps) % ss);
372        }
373    }
374
375    private final ImageIcon[] images = new ImageIcon[7];
376
377    void loadImages() {
378        images[0] = resourceManager.createImageIcon("red.gif", resourceManager.getString("ListDemo.red"));
379        images[1] = resourceManager.createImageIcon("blue.gif", resourceManager.getString("ListDemo.blue"));
380        images[2] = resourceManager.createImageIcon("yellow.gif", resourceManager.getString("ListDemo.yellow"));
381        images[3] = resourceManager.createImageIcon("green.gif", resourceManager.getString("ListDemo.green"));
382        images[4] = resourceManager.createImageIcon("gray.gif", resourceManager.getString("ListDemo.gray"));
383        images[5] = resourceManager.createImageIcon("cyan.gif", resourceManager.getString("ListDemo.cyan"));
384        images[6] = resourceManager.createImageIcon("magenta.gif", resourceManager.getString("ListDemo.magenta"));
385    }
386
387    private class CompanyLogoListCellRenderer extends DefaultListCellRenderer {
388
389        @Override
390        public Component getListCellRendererComponent(
391                JList<?> list,
392                Object value,
393                int index,
394                boolean isSelected,
395                boolean cellHasFocus) {
396            Component retValue = super.getListCellRendererComponent(
397                    list, value, index, isSelected, cellHasFocus
398            );
399            setIcon(images[index % 7]);
400            return retValue;
401        }
402    }
403}
404