001    /*
002     * Copyright 2002-2006 the original author or authors.
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005     * use this file except in compliance with the License. You may obtain a copy of
006     * the License at
007     * 
008     * http://www.apache.org/licenses/LICENSE-2.0
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012     * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013     * License for the specific language governing permissions and limitations under
014     * the License.
015     */
016    package org.springframework.richclient.dialog.support;
017    
018    import java.awt.BorderLayout;
019    import java.beans.PropertyChangeEvent;
020    import java.beans.PropertyChangeListener;
021    
022    import javax.swing.JComponent;
023    import javax.swing.JPanel;
024    import javax.swing.JSeparator;
025    
026    import org.springframework.richclient.command.ActionCommand;
027    import org.springframework.richclient.command.CommandGroup;
028    import org.springframework.richclient.core.Guarded;
029    import org.springframework.richclient.core.Message;
030    import org.springframework.richclient.dialog.DialogPage;
031    import org.springframework.richclient.dialog.Messagable;
032    import org.springframework.richclient.dialog.TitlePane;
033    import org.springframework.richclient.dialog.TitledPageApplicationDialog;
034    import org.springframework.richclient.util.GuiStandardUtils;
035    
036    /**
037     * Useful methods for working with {@link DialogPage}s. These methods make it easier to
038     * place dialog pages in arbitrary containers, wire in message listeners, wire actions
039     * to the page complete status, etc.
040     * <p>
041     * These helpers can be used to quickly construct a standard layout (like that found in
042     * the {@link TitledPageApplicationDialog}, or you can use these methods to construct the
043     * various components (title area and button bar) and then lay things out as you like.
044     * <p>
045     * The standard layout is obtained using the
046     * {@link #createStandardView(DialogPage, ActionCommand, ActionCommand)} or
047     * {@link #createStandardView(DialogPage, Object[])} methods. To create the pieces and do
048     * the layout independently, use {@link #createTitlePane(DialogPage)} to get the title
049     * pane and wire your OK command into the page complete status using
050     * {@link #adaptPageCompletetoGuarded(DialogPage, Guarded)}. If you don't want to use the
051     * standard title pane, you can easily arrange for the messages coming from the dialog
052     * page to be sent to a {@link Messagable} of your choice using
053     * {@link #addMessageMonitor(DialogPage, Messagable)}.
054     * 
055     * @author Larry Streepy
056     * 
057     */
058    public class DialogPageUtils {
059    
060        /**
061         * Create a standard {@link TitlePane} wired to receive messages from the given dialog
062         * page. The title pane will also be configured from the dialog page's title and icon.
063         * 
064         * @param dialogPage to process
065         */
066        public static TitlePane createTitlePane( DialogPage dialogPage ) {
067            TitlePane titlePane = new TitlePane();
068            titlePane.setTitle(dialogPage.getTitle());
069            titlePane.setImage(dialogPage.getImage());
070            addMessageMonitor(dialogPage, titlePane);
071    
072            return titlePane;
073        }
074    
075        /**
076         * Construct a complete standard layout for a dialog page. This is a panel with the
077         * title/message area at the top, the dialog page control in the center, and the
078         * command button bar (using the provided ok and cancel commands) on the bottom. The
079         * finishCommand provided will automatically be wired into the page complete status of
080         * the dialog page.
081         * 
082         * @param dialogPage to process
083         * @param okCommand Action command to wire into dialogPage's page complete status
084         * @param cancelCommand to add to the command button bar
085         * @return created component
086         * @see #createTitlePane(DialogPage)
087         * @see #adaptPageCompletetoGuarded(DialogPage, Guarded)
088         */
089        public static JComponent createStandardView( DialogPage dialogPage, ActionCommand okCommand,
090                ActionCommand cancelCommand ) {
091            adaptPageCompletetoGuarded(dialogPage, okCommand);
092            return createStandardView(dialogPage, new Object[] { okCommand, cancelCommand });
093        }
094    
095        /**
096         * Construct a complete standard layout for a dialog page. This is a panel with the
097         * title/message area at the top, the dialog page control in the center, and the
098         * command button bar (using the provided group of commands) on the bottom. You should
099         * have already wired any commands to the page complete status as needed.
100         * 
101         * @param dialogPage to process
102         * @param commandGroupMembers Array of commands to place in the button bar
103         * @return created component
104         * @see #createTitlePane(DialogPage)
105         * @see #adaptPageCompletetoGuarded(DialogPage, Guarded)
106         */
107        public static JComponent createStandardView( DialogPage dialogPage, Object[] commandGroupMembers ) {
108            JPanel viewPanel = new JPanel(new BorderLayout());
109    
110            JPanel titlePaneContainer = new JPanel(new BorderLayout());
111            titlePaneContainer.add(createTitlePane(dialogPage).getControl());
112            titlePaneContainer.add(new JSeparator(), BorderLayout.SOUTH);
113            viewPanel.add(titlePaneContainer, BorderLayout.NORTH);
114    
115            JComponent pageControl = dialogPage.getControl();
116            GuiStandardUtils.attachDialogBorder(pageControl);
117            viewPanel.add(pageControl);
118    
119            viewPanel.add(createButtonBar(commandGroupMembers), BorderLayout.SOUTH);
120    
121            return viewPanel;
122        }
123    
124        /**
125         * Return a standardized row of command buttons.
126         * 
127         * @param groupMembers
128         * @return button bar
129         */
130        public static JComponent createButtonBar( Object[] groupMembers ) {
131            CommandGroup dialogCommandGroup = CommandGroup.createCommandGroup(null, groupMembers);
132            JComponent buttonBar = dialogCommandGroup.createButtonBar();
133            GuiStandardUtils.attachDialogBorder(buttonBar);
134            return buttonBar;
135        }
136    
137        /**
138         * Add a message monitor. Each monitor will have its
139         * {@link Messagable#setMessage(Message)} method called whenever the MESSAGE property
140         * on the dialog page changes.
141         * 
142         * @param dialogPage to monitor
143         * @param monitor to add
144         */
145        public static void addMessageMonitor( DialogPage dialogPage, Messagable monitor ) {
146            dialogPage.addPropertyChangeListener(Messagable.MESSAGE_PROPERTY, new MessageHandler(monitor));
147        }
148    
149        /**
150         * Create an adapter that will monitor the page complete status of the dialog page and
151         * adapt it to operations on the provided Guarded object. If the page is complete,
152         * then the guarded object will be enabled. If this page is not complete, then the
153         * guarded object will be disabled.
154         * 
155         * @param dialogPage to monitor
156         * @param guarded object to adapt
157         */
158        public static void adaptPageCompletetoGuarded( DialogPage dialogPage, Guarded guarded ) {
159            dialogPage.addPropertyChangeListener(DialogPage.PAGE_COMPLETE_PROPERTY, new PageCompleteAdapter(guarded));
160        }
161    
162        /**
163         * Internal class to handle the PAGE_COMPLETE property changes in the dialog page and
164         * adapt them to operations on a Guarded object.
165         */
166        protected static class PageCompleteAdapter implements PropertyChangeListener {
167            private Guarded guarded;
168    
169            /**
170             * Construct a handler on the given guarded object.
171             * 
172             * @param guarded object to manage
173             */
174            protected PageCompleteAdapter( Guarded guarded ) {
175                this.guarded = guarded;
176            }
177    
178            /**
179             * Handle a change in the page complete state of the dialog page
180             * 
181             * @param e
182             */
183            public void propertyChange( PropertyChangeEvent e ) {
184                if( DialogPage.PAGE_COMPLETE_PROPERTY.equals(e.getPropertyName()) ) {
185                    guarded.setEnabled(((Boolean) e.getNewValue()).booleanValue());
186                }
187            }
188        }
189    
190        /**
191         * Internal class to handle the MESSAGE_PROPERTY property changes in a dialog page.
192         */
193        private static class MessageHandler implements PropertyChangeListener {
194            private Messagable monitor;
195    
196            /**
197             * Construct a handler on the given message monitor.
198             * 
199             * @param monitor to send messages to
200             */
201            public MessageHandler( Messagable monitor ) {
202                this.monitor = monitor;
203            }
204    
205            /**
206             * Handle a change in the message or page complete state of the dialog page.
207             * 
208             * @param e
209             */
210            public void propertyChange( PropertyChangeEvent e ) {
211                if( Messagable.MESSAGE_PROPERTY.equals(e.getPropertyName()) ) {
212                    monitor.setMessage((Message) e.getNewValue());
213                }
214            }
215        }
216    }