001: /*
002: * $Id: TreeMenuCommand.java,v 1.1 2002/04/19 06:10:34 skavish Exp $
003: *
004: * ===========================================================================
005: *
006: * The JGenerator Software License, Version 1.0
007: *
008: * Copyright (c) 2000 Dmitry Skavish (skavish@usa.net). All rights reserved.
009: *
010: * Redistribution and use in source and binary forms, with or without
011: * modification, are permitted provided that the following conditions are met:
012: *
013: * 1. Redistributions of source code must retain the above copyright
014: * notice, this list of conditions and the following disclaimer.
015: *
016: * 2. Redistributions in binary form must reproduce the above copyright
017: * notice, this list of conditions and the following disclaimer in
018: * the documentation and/or other materials provided with the
019: * distribution.
020: *
021: * 3. The end-user documentation included with the redistribution, if
022: * any, must include the following acknowlegement:
023: * "This product includes software developed by Dmitry Skavish
024: * (skavish@usa.net, http://www.flashgap.com/)."
025: * Alternately, this acknowlegement may appear in the software itself,
026: * if and wherever such third-party acknowlegements normally appear.
027: *
028: * 4. The name "The JGenerator" must not be used to endorse or promote
029: * products derived from this software without prior written permission.
030: * For written permission, please contact skavish@usa.net.
031: *
032: * 5. Products derived from this software may not be called "The JGenerator"
033: * nor may "The JGenerator" appear in their names without prior written
034: * permission of Dmitry Skavish.
035: *
036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: * DISCLAIMED. IN NO EVENT SHALL DMITRY SKAVISH OR THE OTHER
040: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: * SUCH DAMAGE.
048: *
049: */
050:
051: package org.openlaszlo.iv.flash.commands;
052:
053: import java.awt.geom.*;
054: import java.io.*;
055: import java.util.*;
056: import org.openlaszlo.iv.flash.api.*;
057: import org.openlaszlo.iv.flash.api.action.*;
058: import org.openlaszlo.iv.flash.api.button.*;
059: import org.openlaszlo.iv.flash.api.shape.*;
060: import org.openlaszlo.iv.flash.commands.*;
061: import org.openlaszlo.iv.flash.context.*;
062: import org.openlaszlo.iv.flash.util.*;
063:
064: /**
065: * TreeMenuCommand JGenerator Object
066: *
067: * @author William L. Thomson Jr.
068: * @company Obsidian-Studios Inc.
069: * @version 1.0
070: * @date April 16, 2002
071: */
072: public class TreeMenuCommand extends GenericCommand {
073:
074: protected int itemPad;
075: protected int upClipColumn, overClipColumn, numColumn,
076: parentColumn, directionColumn, titleColumn, urlColumn,
077: windowColumn, goToColumn, goToLabelColumn = -1;
078: protected Script headerSymbol, footerSymbol;
079: protected String dataSource, headerSymbolName, footerSymbolName,
080: instanceName, closeLevel;
081:
082: protected void initColumnIndexes(String[][] data) {
083: upClipColumn = findColumn("upClip", data);
084: overClipColumn = findColumn("overClip", data);
085: numColumn = findColumn("Num", data);
086: parentColumn = findColumn("Parent", data);
087: directionColumn = findColumn("Direction", data);
088: titleColumn = findColumn("Title", data);
089: urlColumn = findColumn("Url", data);
090: windowColumn = findColumn("Window", data);
091: goToColumn = findColumn("goto", data);
092: goToLabelColumn = findColumn("gotoLabel", data);
093: if (upClipColumn == -1)
094: Log
095: .error("TreeMenuCommand Error\nA upClip column was not specified in the data source.");
096: if (overClipColumn == -1)
097: Log
098: .error("TreeMenuCommand Error\nA overClip column was not specified in the data source.");
099: if (numColumn == -1)
100: Log
101: .error("TreeMenuCommand Error\nA num column was not specified in the data source.");
102: if (parentColumn == -1)
103: Log
104: .error("TreeMenuCommand Error\nA parent column was not specified in the data source.");
105: if (directionColumn == -1)
106: Log
107: .error("TreeMenuCommand Error\nA direction column was not specified in the data source.");
108: if (titleColumn == -1)
109: Log
110: .error("TreeMenuCommand Error\nA title column was not specified in the data source.");
111: if (urlColumn == -1 && goToColumn == -1 && goToColumn == -1)
112: Log
113: .error("TreeMenuCommand Error\nNeither a url or goto or gotoLabel column was not specified in the data source.");
114: }
115:
116: protected void initParams(Context context) {
117: dataSource = getParameter(context, "dataSource", "");
118: headerSymbolName = getParameter(context, "headerSymbol", "");
119: footerSymbolName = getParameter(context, "footerSymbol", "");
120: instanceName = getParameter(context, "instanceName", "");
121: closeLevel = getParameter(context, "closeLevel", "All");
122: itemPad = getIntParameter(context, "itemPad", 10);
123: if (dataSource.equals(""))
124: Log
125: .error("TreeMenuCommand Error\nA data source was not specified in authoring environment.");
126: if (headerSymbolName.equals(""))
127: Log
128: .error("TreeMenuCommand Error\nA header symbol was not specified in authoring environment.");
129: if (footerSymbolName.equals(""))
130: Log
131: .error("TreeMenuCommand Error\nA footer symbol was not specified in authoring environment.");
132: if (instanceName.equals(""))
133: Log
134: .error("TreeMenuCommand Error\nA instance name was not specified in authoring environment.");
135: }
136:
137: protected void initSymbols(FlashFile flashFile) {
138: headerSymbol = flashFile.getScript(headerSymbolName);
139: footerSymbol = flashFile.getScript(footerSymbolName);
140: if (headerSymbol == null)
141: Log
142: .error("TreeMenuCommand Error\nCould not get the header script from the flash file.");
143: if (footerSymbol == null)
144: Log
145: .error("TreeMenuCommand Error\nCould not get the footer script from the flash file.");
146: }
147:
148: public void doCommand(FlashFile flashFile, Context context,
149: Script parentScript, int frameNum) {
150: initParams(context);
151: initSymbols(flashFile);
152: String[][] data = null;
153: try {
154: UrlDataSource urlDataSource = new UrlDataSource(dataSource,
155: flashFile);
156: data = urlDataSource.getData();
157: } catch (IVException ive) {
158: Log
159: .error("TreeMenuCommand Error\nCould not Parse the datasource into a multi-dimensional array because :\n"
160: + ive);
161: } catch (IOException ioe) {
162: Log
163: .error("TreeMenuCommand Error\nCould not Parse the datasource into a multi-dimensional array because :\n"
164: + ioe);
165: }
166: if (data != null) {
167: initColumnIndexes(data);
168: makeMenu(flashFile, data);
169: } else {
170: Log
171: .error("TreeMenuCommand Error\nThe datasource it empty.");
172: }
173: }
174:
175: protected void makeMenu(FlashFile flashFile, String[][] data) {
176: Instance instance = getInstance(); // get an instance of the template
177: instance.name = instanceName; // set the name of the instance
178: Script script = instance.copyScript(); // copy the instance's script
179: Frame frame = null;
180: if (closeLevel.equalsIgnoreCase("All")) { // Check to see if we should close all menus
181: script.getFrameAt(0).addStopAction(); // add a stop action to frame 1
182: script.newFrame(); // create a new frame so we now have two
183: frame = script.getFrameAt(1); // frame 2 will represent menu open this and all sub menus
184: } else
185: frame = script.getFrameAt(0); // get the first frame and show the first main menu
186: frame.addStopAction(); // and add a stop action to it
187: String direction = "up"; // direction used for footer and header placement
188: double buttonWidth = 0;
189: double buttonHeight = 0;
190: double y = 0; // y (vertical) to space out each button
191: double x = 0; // x for later
192: int row = 0; // row of data represents row in table
193: int menuItem = 0; // number of items, buttons or menus in this menu
194: if (flashFile.getMainScript().getBounds().getY() < flashFile
195: .getMainScript().getBounds().getHeight() / 2)
196: direction = "down";
197: for (row = 1; row < data.length; row++) {
198: if (data[row][parentColumn].equals("0")) { // get the main menu data and create the main buttons and sub menus
199: Script buttonScript = createButton(flashFile, data,
200: row, menuItem);
201: buttonWidth = buttonScript.getBounds().getWidth(); // get the width before creating and adding a sub menu
202: buttonHeight = buttonScript.getBounds().getHeight(); // get the height before creating and adding a sub menu
203: makeSubMenu(flashFile, data, row, buttonScript,
204: buttonWidth, buttonHeight);
205: frame.addInstance(buttonScript, row + 1,
206: AffineTransform.getTranslateInstance(x, y),
207: null, "item" + menuItem);
208: if (data[row][directionColumn].equalsIgnoreCase("down")) {
209: direction = "down";
210: y += buttonHeight - itemPad;
211: } else {
212: direction = "up";
213: y -= buttonHeight - itemPad;
214: }
215: menuItem++;
216: }
217: }
218: Button2 invisibleButton = createInvisibleButton(script
219: .getBounds());
220: if (direction.equals("down")) {
221: frame.addInstance(invisibleButton, 0, AffineTransform
222: .getTranslateInstance(x, 0), null); // add the invisible button that will close the whole menu
223: addHeader(frame, row, x, itemPad);
224: addFooter(frame, row, x, y - itemPad);
225: } else {
226: frame
227: .addInstance(invisibleButton, 0, AffineTransform
228: .getTranslateInstance(x,
229: -(y + buttonHeight)), null); // add the invisible button that will close the whole menu
230: addFooter(frame, row, x, buttonHeight - itemPad);
231: addHeader(frame, row, x, y + buttonHeight - itemPad);
232: }
233: }
234:
235: protected void makeSubMenu(FlashFile flashFile, String[][] data,
236: int row, Script buttonScript, double buttonWidth,
237: double buttonHeight) {
238: String direction = "up";
239: double subButtonWidth = 0;
240: double subButtonHeight = 0;
241: double subX = buttonWidth;
242: double subY = 0;
243: int subRow = 0;
244: int subMenuItem = 0;
245: Frame innerFrame = null;
246: for (subRow = 1; subRow < data.length; subRow++) {
247: if (Integer.parseInt(data[subRow][parentColumn]) == row) {
248: if (innerFrame == null) {
249: buttonScript.getFrameAt(0).addStopAction();
250: innerFrame = buttonScript.newFrame();
251: innerFrame.addStopAction();
252: }
253: Script subButtonScript = createButton(flashFile, data,
254: subRow, subMenuItem);
255: subButtonWidth = subButtonScript.getBounds().getWidth(); // get the width before creating and adding a sub menu
256: subButtonHeight = subButtonScript.getBounds()
257: .getHeight(); // get the height before creating and adding a sub menu
258: makeSubMenu(flashFile, data, subRow, subButtonScript,
259: subButtonWidth, subButtonHeight);
260: innerFrame.addInstance(subButtonScript, 1,
261: AffineTransform
262: .getTranslateInstance(subX, subY),
263: null, "item" + subMenuItem);
264: if (data[subRow][directionColumn]
265: .equalsIgnoreCase("down")) {
266: direction = "down";
267: subY += subButtonHeight - itemPad;
268: } else {
269: direction = "up";
270: subY -= subButtonHeight - itemPad;
271: }
272: subMenuItem++;
273: }
274: }
275: if (innerFrame != null) {
276: if (direction.equals("down")) {
277: addHeader(innerFrame, subRow, subX, itemPad);
278: addFooter(innerFrame, subRow, subX, subY - itemPad);
279: } else {
280: addFooter(innerFrame, subRow, subX, subButtonHeight
281: - itemPad);
282: addHeader(innerFrame, subRow, subX, subY
283: + subButtonHeight - itemPad);
284: }
285: }
286: }
287:
288: protected void addFooter(Frame frame, int level, double x, double y) {
289: frame.addInstance(footerSymbol, level, AffineTransform
290: .getTranslateInstance(x, y), null);
291: }
292:
293: protected void addHeader(Frame frame, int level, double x, double y) {
294: frame.addInstance(headerSymbol, level, AffineTransform
295: .getTranslateInstance(x, y), null);
296: }
297:
298: protected Script createButton(FlashFile flashFile, String[][] data,
299: int row, int itemNumber) {
300: String name = data[row][titleColumn];
301: Script script = new Script(1);
302: Frame frame = script.getFrameAt(0);
303: Context buttonContext = null;
304: try {
305: buttonContext = ContextFactory.createContext(data, row); // create a new context
306: } catch (IVException ive) {
307: Log
308: .error("TreeMenuCommand Error\nCould not make new button context because :\n"
309: + ive);
310: }
311: Script upClipScript = flashFile.getScript(
312: data[row][upClipColumn]).copyScript(); // get a copy of the upClip script
313: Script overClipScript = flashFile.getScript(
314: data[row][overClipColumn]).copyScript(); // get a copy of the overClip script
315: try {
316: flashFile.processScript(upClipScript, buttonContext);
317: flashFile.processScript(overClipScript, buttonContext);
318: } catch (IVException ive) {
319: Log
320: .error("TreeMenuCommand Error\nCould not process new button context because :\n"
321: + ive);
322: }
323: Button2 button2 = new Button2();
324: button2.addActionCondition(onRollOver(itemNumber));
325: button2.addActionCondition(onRelease(data, row));
326: button2.addButtonRecord(new ButtonRecord(ButtonRecord.Up,
327: upClipScript, 1, AffineTransform.getTranslateInstance(
328: 0, 0), CXForm.newIdentity(true)));
329: button2.addButtonRecord(new ButtonRecord(ButtonRecord.Over
330: | ButtonRecord.Down, overClipScript, 2, AffineTransform
331: .getTranslateInstance(0, 0), CXForm.newIdentity(true)));
332: Shape shape = new Shape();
333: shape.setBounds(upClipScript.getBounds());
334: shape.setFillStyle0(FillStyle.newSolid(new Color(0, 0, 0)));
335: shape.drawRectangle(upClipScript.getBounds());
336: button2.addButtonRecord(new ButtonRecord(ButtonRecord.HitTest,
337: shape, 3, AffineTransform.getTranslateInstance(0, 0),
338: CXForm.newIdentity(true)));
339: button2.setTrackAs(Button2.TrackAsMenu);
340: frame.addInstance(button2, 1, AffineTransform
341: .getTranslateInstance(0, 0), null, name);
342: return (script);
343: }
344:
345: protected Button2 createInvisibleButton(Rectangle2D rectangle2D) {
346: Button2 button2 = new Button2();
347: Program program = new Program();
348: program.gotoFrame(0);
349: button2.addActionCondition(ActionCondition.onRollOver(program));
350: Shape shape = new Shape();
351: shape.setBounds(rectangle2D);
352: shape.setFillStyle0(FillStyle.newSolid(new Color(0, 0, 0)));
353: shape.drawRectangle(rectangle2D);
354: button2.addButtonRecord(new ButtonRecord(ButtonRecord.HitTest,
355: shape, 1, AffineTransform.getTranslateInstance(0, 0),
356: CXForm.newIdentity(true)));
357: button2.setTrackAs(Button2.TrackAsButton);
358: return (button2);
359: }
360:
361: protected ActionCondition onRollOver(int itemNumber) {
362: Program program = new Program();
363: program.setTarget("../item" + (itemNumber - 1)); // tell the menu item just before this one to go to frame 1 menu closed
364: program.gotoFrame(0); //to go to frame 1 menu closed
365: program.setTarget("../item" + (itemNumber + 1)); // tell the menu item just after this one
366: program.gotoFrame(0); // to go to frame 1 menu closed
367: program.setTarget(""); // go back to the timeline this button is on
368: program.gotoFrame(1); // go to frame 2 menu open
369: return (ActionCondition.onRollOver(program));
370: }
371:
372: protected ActionCondition onRelease(String[][] data, int row) {
373: Program program = new Program();
374: if (urlColumn != -1)
375: program.getURL(data[row][urlColumn],
376: data[row][windowColumn]);
377: else if (goToColumn != -1)
378: program.gotoFrame(Integer.parseInt(data[row][goToColumn]));
379: else if (goToLabelColumn != -1)
380: program.gotoLabel(data[row][goToLabelColumn]);
381: return (ActionCondition.onRelease(program));
382: }
383: }
|