001: package jimm.datavision.layout.swing;
002:
003: import jimm.datavision.ErrorHandler;
004: import jimm.datavision.field.Field;
005: import jimm.datavision.field.ImageField;
006: import java.awt.Dimension;
007: import java.awt.CardLayout;
008: import javax.swing.JPanel;
009: import java.util.ArrayList;
010: import java.util.Iterator;
011:
012: // This file also contains the SwingPageField class.
013:
014: /**
015: * Holds report page contents and creates {@link SwingPage} instances
016: * when requested.
017: *
018: * @author Jim Menard, <a href="mailto:jimm@io.com">jimm@io.com</a>
019: * @see SwingLE
020: * @see SwingPageField
021: */
022: class SwingPageContents {
023:
024: ArrayList pageFields;
025: SwingPage page;
026: int pageNumber;
027: JPanel parent;
028: Dimension pageDim;
029: Thread buildThread;
030:
031: /**
032: * Constructor.
033: *
034: * @param parent the panel in which this page will be displayed; its
035: * layout must be a <code>CardLayout</code>
036: * @param pageNumber the page number, starting at 1
037: * @param dim the page dimensions
038: */
039: SwingPageContents(JPanel parent, int pageNumber, Dimension dim) {
040: pageFields = new ArrayList();
041: this .pageNumber = pageNumber;
042: this .parent = parent;
043: pageDim = dim;
044: }
045:
046: /**
047: * Adds a new field, its display value, and its position on the page.
048: *
049: * @param f a report field
050: * @param v the field's display value (retrieved from the database or
051: * otherwise calculated)
052: * @param r the display position and size
053: */
054: void add(Field f, String v, java.awt.Rectangle r) {
055: pageFields.add(new SwingPageField(f, v, r));
056: }
057:
058: /**
059: * Returns <code>true</code> if the swing page has been built.
060: */
061: boolean isPageBuilt() {
062: return page != null;
063: }
064:
065: /**
066: * Returns the swing page. If the page is being built, wait for the page
067: * building to complete before returning the page. If page construction
068: * has not started, build the page and return it.
069: *
070: * @return a <code>SwingPage</code>
071: */
072: SwingPage getPage() {
073: if (page == null) {
074: if (buildThread != null) { // Wait for page build to finish
075: try {
076: // One more check because the thread may have finished
077: if (buildThread != null) {
078: synchronized (buildThread) {
079: buildThread.join();
080: }
081: }
082: } catch (InterruptedException e) {
083: ErrorHandler.error(e);
084: // page may be null
085: }
086: } else
087: buildPage();
088: }
089: return page;
090: }
091:
092: /**
093: * Displays the swing page, building it first if necessary.
094: */
095: void showPage() {
096: getPage(); // Make sure page completely built
097: CardLayout cardLayout = (CardLayout) parent.getLayout();
098: cardLayout.show(parent, "page " + pageNumber);
099: }
100:
101: /**
102: * Builds the swing page and adds it to the parent, all in a separate
103: * thread. Calls {@link #buildPage}.
104: * <p>
105: * This isn't entirely thread safe, but it's close enough for our purposes.
106: */
107: void prebuildPage() {
108: if (page != null || buildThread != null)
109: return;
110:
111: buildThread = new Thread(new Runnable() {
112: public void run() {
113: buildPage();
114: buildThread = null;
115: }
116: });
117: buildThread.start();
118: }
119:
120: /**
121: * Builds the swing page and adds it to the parent.
122: */
123: void buildPage() {
124: SwingPage newPage = new SwingPage();
125: newPage.setPreferredSize(pageDim);
126:
127: for (Iterator iter = pageFields.iterator(); iter.hasNext();) {
128: SwingPageField spf = (SwingPageField) iter.next();
129:
130: // Create field and add to page.
131: SwingField sf;
132: if (spf.field instanceof ImageField)
133: sf = new SwingImageField((ImageField) spf.field);
134: else
135: sf = new SwingTextField(spf.field, spf.value);
136:
137: sf.getComponent().setBounds(spf.rect);
138: newPage.add(sf.getComponent());
139: }
140:
141: // Add page to parent
142: parent.add(newPage, "page " + pageNumber);
143:
144: page = newPage;
145: }
146:
147: /**
148: * Forgets the page we have built, removes it from its parent, and restores
149: * the field information so we can build the page later.
150: */
151: void forgetPage() {
152: if (!isPageBuilt())
153: return;
154:
155: CardLayout cardLayout = (CardLayout) parent.getLayout();
156: cardLayout.removeLayoutComponent(page);
157: parent.remove(page);
158:
159: page = null;
160: }
161: }
162:
163: /**
164: * Holds a report field, its value when this instance is created, and
165: * a rectangle for page placement.
166: *
167: * @author Jim Menard, <a href="mailto:jimm@io.com">jimm@io.com</a>
168: * @see SwingPage
169: * @see SwingLE
170: * @see SwingPageContents
171: */
172: class SwingPageField {
173:
174: Field field;
175: String value;
176: java.awt.Rectangle rect;
177:
178: /**
179: * Constructor.
180: *
181: * @param f a report field
182: * @param v the field's display value (retrieved from the database or
183: * otherwise calculated)
184: * @param r the display position and size
185: */
186: SwingPageField(Field f, String v, java.awt.Rectangle r) {
187: field = f;
188: value = v;
189: rect = r;
190: }
191: }
|