001/*
002 * Copyright (c) 2005 Einar Pehrson <einar@pehrson.nu>.
003 *
004 * This file is part of
005 * CleanSheets - a spreadsheet application for the Java platform.
006 *
007 * CleanSheets is free software; you can redistribute it and/or modify
008 * it under the terms of the GNU General Public License as published by
009 * the Free Software Foundation; either version 2 of the License, or
010 * (at your option) any later version.
011 *
012 * CleanSheets is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015 * GNU General Public License for more details.
016 *
017 * You should have received a copy of the GNU General Public License
018 * along with CleanSheets; if not, write to the Free Software
019 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA     02111-1307      USA
020 */
021package csheets.ext.style.ui;
022
023import java.awt.BorderLayout;
024import java.awt.Color;
025import java.awt.Component;
026import java.awt.Dimension;
027import java.awt.GridBagConstraints;
028import java.awt.GridBagLayout;
029import java.awt.Insets;
030import java.awt.event.ActionEvent;
031import java.awt.event.ItemEvent;
032import java.awt.event.ItemListener;
033
034import javax.swing.AbstractAction;
035import javax.swing.BorderFactory;
036import javax.swing.BoxLayout;
037import javax.swing.Icon;
038import javax.swing.ImageIcon;
039import javax.swing.JButton;
040import javax.swing.JColorChooser;
041import javax.swing.JComponent;
042import javax.swing.JLabel;
043import javax.swing.JOptionPane;
044import javax.swing.JPanel;
045import javax.swing.JToggleButton;
046import javax.swing.border.Border;
047import javax.swing.border.MatteBorder;
048
049import csheets.ext.style.StyleExtension;
050
051/**
052 * A component which allows the user to select a border.
053 * @author Einar Pehrson
054 */ 
055@SuppressWarnings("serial")
056public class BorderChooser extends JComponent {
057
058        /** The toggle button for the top border segment */
059        private JToggleButton topButton = new JToggleButton(new ImageIcon(
060                StyleExtension.class.getResource("res/img/border_top.gif")));
061
062        /** The toggle button for the left border segment */
063        private JToggleButton leftButton = new JToggleButton(new ImageIcon(
064                StyleExtension.class.getResource("res/img/border_left.gif")));
065
066        /** The toggle button for the right border segment */
067        private JToggleButton rightButton = new JToggleButton(new ImageIcon(
068                StyleExtension.class.getResource("res/img/border_right.gif")));
069
070        /** The toggle button for the bottom border segment */
071        private JToggleButton bottomButton = new JToggleButton(new ImageIcon(
072                StyleExtension.class.getResource("res/img/border_bottom.gif")));
073
074        /** The preview label */
075        private JLabel previewLabel = new JLabel("");
076
077        /** The currently selected border color */
078        private Color color = Color.black;
079
080        /**
081         * Creates a new border selection panel.
082         */
083        public BorderChooser () {
084                this(null);
085        }
086
087        /**
088         * Creates a new border selection panel with the given initial border
089         * selected.
090         * @param initialBorder the border to select initially
091         */
092        public BorderChooser(Border initialBorder) {
093                // Configures preview label
094                previewLabel.setPreferredSize(new Dimension(100, 80));
095                previewLabel.setBorder(
096                        BorderFactory.createCompoundBorder(
097                                BorderFactory.createTitledBorder("Preview"),
098                                BorderFactory.createEmptyBorder(5, 5, 5, 5)
099                ));
100
101                // Registers listener
102                PreviewLabelUpdater updater = new PreviewLabelUpdater();
103                topButton.addItemListener(updater);
104                leftButton.addItemListener(updater);
105                rightButton.addItemListener(updater);
106                bottomButton.addItemListener(updater);
107
108                // Lays out button panel
109                JPanel buttonPanel = new JPanel(new GridBagLayout());
110                GridBagConstraints gc = new GridBagConstraints();
111                gc.gridwidth = gc.gridheight = 2;
112                gc.gridy = 1;
113                buttonPanel.add(leftButton, gc);
114                gc.gridx = 2;
115                gc.gridy = 0;
116                buttonPanel.add(topButton, gc);
117                gc.gridy = 2;
118                buttonPanel.add(bottomButton, gc);
119                gc.gridx = 4;
120                gc.gridy = 1;
121                buttonPanel.add(rightButton, gc);
122                buttonPanel.setBorder(BorderFactory.createTitledBorder("Border"));
123
124                // Creates color panel
125                JPanel colorPanel = new JPanel();
126                colorPanel.setLayout(new BoxLayout(colorPanel, BoxLayout.X_AXIS));
127                JButton colorButton = new JButton(new ColorAction());
128                colorButton.setAlignmentY(0.5f);
129                colorPanel.add(colorButton);
130                colorPanel.setBorder(BorderFactory.createTitledBorder("Color"));
131
132                // Configures layout and adds components
133                setLayout(new BorderLayout(5, 5));
134                add(buttonPanel, BorderLayout.CENTER);
135                add(colorPanel, BorderLayout.EAST);
136                add(previewLabel, BorderLayout.SOUTH);
137
138                // Sets the initial border
139                setSelectedBorder(initialBorder);
140        }
141
142        /**
143         * Lets the user select a border from a chooser in a standard dialog.
144         * @param parent the parent component of the dialog
145         * @param title the title of the dialog
146         * @param initialBorder the border to select initially
147         * @return the selected border or, if the user did not press OK, null
148         */
149        public static Border showDialog(Component parent, String title,
150                        Border initialBorder) {
151                BorderChooser chooser = new BorderChooser(initialBorder);
152                int returnValue = JOptionPane.showConfirmDialog(
153                        parent,
154                        chooser,
155                        title,
156                        JOptionPane.OK_CANCEL_OPTION,
157                        JOptionPane.PLAIN_MESSAGE,
158                        (Icon)null);
159                if (returnValue == JOptionPane.OK_OPTION)
160                        return chooser.getSelectedBorder();
161                else
162                        return null;
163        }
164
165        /**
166         * Returns the currently selected border in the dialog.
167         * @return the currently selected border
168         */
169        public Border getSelectedBorder() {
170                return BorderFactory.createMatteBorder(
171                        topButton.isSelected() ? 1 : 0,
172                        leftButton.isSelected() ? 1 : 0,
173                        bottomButton.isSelected() ? 1 : 0,
174                        rightButton.isSelected() ? 1 : 0,
175                        color);
176        }
177
178        /**
179         * Sets the currently selected border in the dialog.
180         * @param border the border to select
181         */
182        public void setSelectedBorder(Border border) {
183                if (border instanceof MatteBorder) {
184                        MatteBorder matteBorder = (MatteBorder)border;
185                        color = matteBorder.getMatteColor();
186                        Insets insets = matteBorder.getBorderInsets();
187                        topButton.setSelected(insets.top > 0);
188                        leftButton.setSelected(insets.left > 0);
189                        bottomButton.setSelected(insets.bottom > 0);
190                        rightButton.setSelected(insets.right > 0);
191                }
192        }
193
194        /**
195         * Updates the border of the preview label.
196         */
197        private void updatePreviewBorder() {
198                previewLabel.setBorder(
199                        BorderFactory.createCompoundBorder(
200                                BorderFactory.createTitledBorder("Preview"),
201                                BorderFactory.createCompoundBorder(
202                                        BorderFactory.createEmptyBorder(5, 5, 5, 5),
203                                        getSelectedBorder())));
204        }
205
206        /**
207         * A controller that listens to selection events on the buttons.
208         */
209        private class PreviewLabelUpdater implements ItemListener {
210
211                /**
212                 * Creates a new preview label updater.
213                 */
214                public PreviewLabelUpdater() {}
215
216                /**
217                 * Updates the preview label.
218                 * @param e the event that was fired
219                 */
220                public void itemStateChanged(ItemEvent e) {
221                        updatePreviewBorder();
222                }
223        }
224
225        /**
226         * An action for letting the user select a new border color from a chooser.
227         */
228        private class ColorAction extends AbstractAction {
229
230                public ColorAction() {
231                        putValue(SMALL_ICON, new ImageIcon(
232                                StyleExtension.class.getResource("res/img/color_bg.gif")));
233                }
234
235                public void actionPerformed(ActionEvent e) {
236                        Color c = JColorChooser.showDialog(null, "Choose Border Color",
237                                color);
238                        if (c != null) {
239                                color = c;
240                                updatePreviewBorder();
241                        }
242                }
243        }
244}