001: /*
002: * Copyright (c) 2004 JETA Software, Inc. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without modification,
005: * are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of JETA Software nor the names of its contributors may
015: * be used to endorse or promote products derived from this software without
016: * specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
021: * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
022: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
023: * INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
024: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
025: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026: * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: */
029:
030: package com.jeta.forms.components.panel;
031:
032: import java.awt.BorderLayout;
033: import java.awt.Component;
034: import java.awt.ComponentOrientation;
035: import java.awt.Container;
036: import java.awt.FocusTraversalPolicy;
037: import java.awt.LayoutManager;
038: import java.io.InputStream;
039: import java.util.HashMap;
040: import java.util.Iterator;
041:
042: import javax.swing.BoxLayout;
043: import javax.swing.JLabel;
044:
045: import com.jeta.forms.gui.common.FormException;
046: import com.jeta.forms.gui.common.FormUtils;
047: import com.jeta.forms.gui.form.FormAccessor;
048: import com.jeta.forms.gui.form.FormComponent;
049: import com.jeta.forms.gui.form.FormIterator;
050: import com.jeta.forms.gui.formmgr.FormManagerUtils;
051: import com.jeta.open.gui.framework.JETAPanel;
052: import com.jeta.open.i18n.I18N;
053: import com.jeta.open.i18n.I18NUtils;
054:
055: /**
056: * This is the main panel class used to load and view a form during runtime.
057: * Usage:
058: *
059: * <pre>
060: * FormPanel panel = new FormPanel("com/mycorp/app/gui/login/loginView.jfrm");
061: * </pre>
062: *
063: * It assumed that all form files are located in your classpath.
064: * <p>
065: *
066: * You should only use the published APIs to programmatically add, remove, or
067: * access Swing Components from a form. If you need to programmatically change a
068: * form, you use a FormAccessor, see {@link #getFormAccessor(String) }. If you
069: * pass a valid form name, this method will return a FormAccessor instance. Use
070: * FormAccessors to access the FormLayout or to add, remove, change, or
071: * enumerate components in the underlying container.
072: * <p>
073: *
074: * <PRE>
075: *
076: * FormPanel myform = new FormPanel( "test.jfrm" ); <i>// where the main form in
077: * test.jfrm is named "settings"</i> FormAccessor form_accessor =
078: * (FormAccessor)myform.getFormAccessor( "settings" ); <i>// adds a component at
079: * column 2 and row 5</i> form_accessor.addBean( new JButton("Test"), new
080: * CellConstraints( 2, 5 ) );
081: *
082: * <i>// or replace the component named 'wizard.view' with a different
083: * component.</i> FormPanel wiz_view = new FormPanel( "pane2.jfrm" );
084: * form_accessor.replaceBean( "wizard.view", wiz_view );
085: *
086: *
087: *
088: * <i>// use FormAccessor to iterate over components in a form as well</i>
089: * Iterator iter = formaccessor.beanIterator(); while( iter.hasNext() ) {
090: * Component comp = (Component)iter.next(); if ( comp instanceof FormAccessor ) {
091: * <i>// found a nested form.</i> <i>// if this iterator is nested, the next
092: * call to next() will</i> <i>// return components in the nested form.</i> }
093: * else { <i>// found a standard Java Bean</i> } }
094: *
095: * </PRE>
096: *
097: * @author Jeff Tassin
098: */
099: public class FormPanel extends JETAPanel {
100:
101: /**
102: * A HashMap<String,Object> of names to Objects. This is a utility for
103: * clients of this class. One example of usage is ButtonGroups. We store
104: * ButtonGroups here according to their name. At runtime buttons can find
105: * their associated group and add themselves accordingly.
106: */
107: private HashMap m_user_objects = new HashMap();
108:
109: /**
110: * The top level form component
111: */
112: private FormComponent m_form_comp;
113:
114: /**
115: * The focus traversal policy.
116: */
117: private FocusTraversalPolicy m_focus_policy;
118: private boolean m_policy_set = false;
119:
120: /**
121: * FormPanel constructor. Loads the form from the given path. This
122: * constructor does not throw an exception if the form resource cannot be
123: * found. Instead, it will display an error message in the panel.
124: *
125: * @param formPath
126: * the path to the form file. This path can be absolute or
127: * relative to the classpath.
128: */
129: public FormPanel(String formPath) {
130: com.jeta.forms.defaults.DefaultInitializer.initialize();
131:
132: boolean designmode = FormUtils.isDesignMode();
133: try {
134: /** always assume design mode is false for FormPanels */
135: FormUtils.setDesignMode(false);
136: FormComponent fc = FormManagerUtils
137: .openPackagedForm(formPath);
138: fc.postInitialize(this );
139: m_form_comp = fc;
140: addForm(fc, new BorderLayout(), BorderLayout.CENTER);
141: } catch (Exception e) {
142: /** show an error message in the panel if we can load the form */
143: BoxLayout layout = new BoxLayout(this , BoxLayout.Y_AXIS);
144: setLayout(layout);
145: JLabel error_label = new JLabel(I18N
146: .getLocalizedMessage("Error:"));
147: error_label.setForeground(java.awt.Color.red);
148: error_label.setAlignmentX(LEFT_ALIGNMENT);
149:
150: JLabel form_label = new JLabel(formPath);
151: form_label.setForeground(java.awt.Color.red);
152: form_label.setAlignmentX(LEFT_ALIGNMENT);
153: form_label.setToolTipText(formPath);
154: add(error_label);
155: add(form_label);
156: add(javax.swing.Box.createVerticalStrut(5));
157: } finally {
158: FormUtils.setDesignMode(designmode);
159: }
160: }
161:
162: /**
163: * FormPanel constructor. Creates a FormPanel using the given InputStream.
164: * The InputStream must reference a valid underlying .jfrm.
165: *
166: * @throws FormException
167: * if any type of I/O error occurs or the input stream is not a
168: * valid form file.
169: */
170: public FormPanel(InputStream istream) throws FormException {
171: try {
172: com.jeta.forms.defaults.DefaultInitializer.initialize();
173:
174: FormComponent fc = FormManagerUtils.openForm(istream);
175: m_form_comp = fc;
176:
177: setLayout(new BorderLayout());
178: add(fc, BorderLayout.CENTER);
179: } catch (Exception e) {
180: if (e instanceof FormException)
181: throw (FormException) e;
182:
183: throw new FormException(
184: "FormPane failed to load form (.jfrm) from InputStream",
185: e);
186: }
187: }
188:
189: /**
190: * FormPanel constructor. Creates a FormPanel using the given FormComponent
191: * as the content.
192: */
193: public FormPanel(FormComponent fc) {
194: com.jeta.forms.defaults.DefaultInitializer.initialize();
195:
196: setLayout(new BorderLayout());
197: add(fc, BorderLayout.CENTER);
198: fc.postInitialize(this );
199: m_form_comp = fc;
200: }
201:
202: /**
203: * Adds the form to this panel using the given layout manager and
204: * constraints
205: */
206: protected void addForm(FormComponent form, LayoutManager layout,
207: Object constraints) {
208: setLayout(layout);
209: add(form, constraints);
210: }
211:
212: /**
213: * Returns an iterator for a collection of Java Beans (java.awt.Component
214: * objects) contained by this form and its nested forms. Only components
215: * that occupy a cell in the grid on the form are returned - not children of
216: * those components. So, if you have a Java Bean that has several child
217: * components, only the Java Bean will be returned and not its children.
218: * This iterator is fail-fast. If any components are added or removed by
219: * invoking the underlying FormAccessors at any time after the Iterator is
220: * created, the iterator will throw a ConcurrentModificationException. If
221: * nested is set to true, then the iterator will fail if components are
222: * added to <i>any</i> FormAccessor in the form hierarchy. If nested if
223: * false, the iterator will fail only if modifications are made to the Form
224: * associated with the current FormAccessor. You may safely call remove on
225: * the iterator if you want to remove the component from the form.
226: *
227: * @return an iterator to a collection of components (java.awt.Component
228: * objects) contained by this form.
229: */
230: public Iterator beanIterator(boolean nested) {
231: return new FormIterator(getFormAccessor(), nested);
232: }
233:
234: /**
235: * Returns the user object associated with the given name. This method does
236: * not return a Swing component (use instead
237: * {@link com.jeta.open.gui.framework.JETAPanel#getComponentByName}).
238: * Rather, this method returns any user object that was associated with this
239: * panel by calling {@link #put(String,Object)}. Null is returned if the
240: * object does not exist.
241: */
242: public Object get(String objName) {
243: if (objName == null)
244: return null;
245: else
246: return m_user_objects.get(objName);
247: }
248:
249: /**
250: * Returns the parent container that contains the top-level form in this
251: * panel. You should rarely have to call this method. Note that a <B>better
252: * and safer solution</B> is to name the form in the builder and call
253: * {@link #getFormAccessor(String)}
254: */
255: public Container getFormContainer() {
256: return m_form_comp.getChildView().getFormContainer();
257: }
258:
259: /**
260: * Return an instance of a FormAccessor that is associated with the top-most
261: * form in this panel (recall that a form can have nested forms). Use
262: * FormAccessors if you want to programmatically change the underlying
263: * FormLayout and/or container.
264: *
265: * @return the FormAccessor associated with the topmost form in this panel.
266: */
267: public FormAccessor getFormAccessor() {
268: return m_form_comp.getChildView().getFormAccessor();
269: }
270:
271: /**
272: * Return an instance of a FormAccessor that has the given name. This is the
273: * same name you gave to the form (either the main form or nested forms) in
274: * the designer. Use FormAccessors if you want to programmatically change
275: * the underlying FormLayout and/or container.
276: *
277: * @param compName
278: * the name of the form to retrieve.
279: * @return the FormAccessor associated with the named form. Null is returned
280: * if component cannot be found with the given name or if the
281: * component is not a FormAccessor object.
282: */
283: public FormAccessor getFormAccessor(String compName) {
284: Component comp = getComponentByName(compName);
285: if (comp instanceof FormAccessor)
286: return (FormAccessor) comp;
287: else
288: return null;
289: }
290:
291: /**
292: * Puts the given object into the user objects map. If an object already
293: * exists for the given name, it is overwritten. Objects can be retrieved
294: * from the map by calling {@link #get( String )}
295: *
296: * @param objName
297: * the name of the object
298: * @param obj
299: * the object
300: */
301: public void put(String objName, Object obj) {
302: if (objName != null) {
303: m_user_objects.put(objName, obj);
304: }
305: }
306:
307: /**
308: * Revalidates this panel.
309: */
310: public void revalidate() {
311: if (m_form_comp != null)
312: m_form_comp.revalidate();
313:
314: super .revalidate();
315: }
316:
317: public void applyComponentOrientation(
318: ComponentOrientation orientation) {
319: I18NUtils.applyComponentOrientation(this , orientation);
320: super .applyComponentOrientation(orientation);
321: }
322:
323: /**
324: * Sets the focus traversal policy for this panel. Only call this if you
325: * wish to override the default handling provided by the form.
326: */
327: public void setFocusTraversalPolicy(FocusTraversalPolicy policy) {
328: super .setFocusTraversalPolicy(policy);
329: // m_focus_policy = null;
330: // m_policy_set = true;
331: }
332:
333: /**
334: * If this form panel contains a form with a custom focus policy, you should
335: * call updateFocusPolicy whenever you programatically add or remove
336: * components from the form or any nested forms. If a custom focus policy
337: * was not assigned in the Form Designer, then this method is not needed.
338: */
339: public void updateFocusPolicy() {
340: // no longer used.
341: }
342:
343: /**
344: * Override so we can update the underlying FormComponent
345: */
346: public void updateUI() {
347: super.updateUI();
348: if (m_form_comp != null)
349: m_form_comp.updateUI();
350: }
351: }
|