001: package com.xoetrope.awt.survey;
002:
003: import java.awt.Color;
004: import java.awt.Dimension;
005: import java.awt.Font;
006: import java.awt.FontMetrics;
007: import java.awt.Graphics;
008: import java.awt.Image;
009:
010: import net.xoetrope.xui.XProjectManager;
011: import net.xoetrope.xui.style.XStyle;
012: import net.xoetrope.xui.style.XStyleManager;
013: import com.xoetrope.event.*;
014: import com.xoetrope.util.*;
015:
016: /**
017: * <p>Extends XQuestion by rendering text as a single strip wrapped
018: * over multiple lines and without using a header</p>
019: * <p> Copyright (c) Xoetrope Ltd., 2001-2006, This software is licensed under
020: * the GNU Public License (GPL), please see license.txt for more details. If
021: * you make commercial use of this software you must purchase a commercial
022: * license from Xoetrope.</p>
023: * <p>$Revision: 1.4 $</p>
024: */
025: public class XWrapQuestion extends XQuestion {
026: int woffset = 20;
027: int bandHeight = 5;
028: int qWidth;
029:
030: private Image offscreen;
031: protected static Color shadowColor, selectedColor, shadeColor;
032:
033: public XWrapQuestion() {
034: super ();
035: if (shadowColor == null) {
036: XStyle shadeStyle = currentProject.getStyleManager()
037: .getStyle("Question/Shade");
038: XStyle threeDStyle = currentProject.getStyleManager()
039: .getStyle("Question/ThreeD");
040: shadowColor = threeDStyle
041: .getStyleAsColor(XStyle.COLOR_BACK);
042: selectedColor = threeDStyle
043: .getStyleAsColor(XStyle.COLOR_FORE);
044: shadeColor = shadeStyle.getStyleAsColor(XStyle.COLOR_FORE);
045: }
046: }
047:
048: /**
049: * Sets the scale for question layout
050: * @param newScale the new scale
051: */
052: public void setScale(int newScale) {
053: setBackground(null);//frame.getColor( 2, classId ));
054:
055: scale = newScale;
056: Dimension d = getSize();
057: qWidth = d.width / 3;
058: xScale = (d.width - qWidth - woffset * 2) / scale;
059:
060: clickListener.setOffset(woffset);
061: }
062:
063: /**
064: * Renders the question. Renders question text as a single strip wrapped
065: * over multiple lines and without using a header. The responses/options are
066: * then spaced horizontally with a block/shadow behind the check marks.
067: * @param g
068: */
069: public void paint(Graphics g) {
070: int xOffset = woffset;
071:
072: Font f;
073: FontMetrics fm;
074: Graphics og;
075:
076: Dimension d = getSize();
077: // if ( offscreen == null ) {
078: offscreen = createImage(d.width, d.height);
079:
080: og = offscreen.getGraphics();
081: og.setClip(0, 0, d.width, d.height);
082: XStyle questionStyle = styleManager.getStyle("Question");
083: f = styleManager.getFont(questionStyle);
084: og.setFont(f);
085: fm = og.getFontMetrics(f);
086:
087: // Draw light bands across the top and bottom.
088: og.setColor(cueColor);
089: og.fillRect(0, 0, d.width + 1, bandHeight);
090: og.fillRect(0, d.height - 2, d.width + 1, 2);
091:
092: // Fill in the background
093: og.setColor(questionBkColor);
094: og.fillRect(0, bandHeight, d.width, d.height - bandHeight - 2);
095:
096: // Draw the question text over multiple lines
097: og.setColor(questionTextColor);
098: int start = 0;
099: int end = 0;
100: String line;
101: int lineNum = 1;
102: String questionText = question.getText();
103: do {
104: boolean drawLine = false;
105:
106: // Extend the string by a word (to the next space, if any)
107: end = questionText.indexOf(' ', end + 1);
108: String ss;
109: if (end > 0)
110: ss = questionText.substring(start, end);
111: else {
112: ss = questionText.substring(start);
113: drawLine = true;
114: }
115:
116: // Does the next word fit in?
117: if (fm.getStringBounds(ss, g).getWidth() < (qWidth - 30))
118: line = ss;
119: else
120: drawLine = true;
121:
122: if (drawLine) {
123: og.drawString(ss, woffset, lineNum * fm.getAscent()
124: + 10 + bandHeight);
125: lineNum++;
126: start = end + 1;
127: }
128: } while (end >= 0);
129:
130: // If no text drawn, then do it now
131: if ((start == 0) && (lineNum == 1))
132: og.drawString(questionText, woffset, fm.getAscent()
133: + bandHeight);
134: // }
135: // else {
136: // og = offscreen.getGraphics();
137: // og.setClip( 0, 0, d.width, d.height );
138: // }
139:
140: XStyle responseStyle = styleManager
141: .getStyle("Question/Response");
142: f = styleManager.getFont(responseStyle);
143: og.setFont(f);
144: fm = og.getFontMetrics(f);
145:
146: xOffset = qWidth + woffset + woffset / 2;
147: int responses = question.getNumOptions();
148: int ctop = d.height / 2 - 10;
149:
150: for (int i = 0; i < responses; i++) {
151: // Draw the surround
152: og.setColor(shadeColor);
153: og.fillRect(xOffset - 10, bandHeight, 30, d.height
154: - bandHeight - 2);
155:
156: // Draw the check background
157: XGraphicUtils.draw3dObject(og, false, xOffset, ctop, 12,
158: 12, checkBkColor, responseTextBkColor, checkColor,
159: shadowColor, responseTextBkColor);
160:
161: // Draw the text
162: og.setColor(responseTextColor);
163: og.drawString(question.getOptionText(i), xOffset + 22, fm
164: .getAscent()
165: + ctop);
166:
167: xOffset += xScale;
168: }
169:
170: xOffset = qWidth + woffset + woffset / 2;
171: if (clickListener.getIsEntered()) {
172: // highlight the question with a frame
173: og.setColor(responseTextBkColor);
174: og.drawRect(0, bandHeight, d.width - 2, d.height - 3
175: - bandHeight);
176:
177: int activeResponse = clickListener.getActiveResponse();
178: if (activeResponse >= 0) {
179: // Draw a button like object
180: XGraphicUtils.draw3dObject(og, true, xOffset
181: + activeResponse * xScale, ctop, 12, 12,
182: checkBkColor, responseTextBkColor, checkColor,
183: shadowColor, responseTextBkColor);
184: og.fillRect(xOffset + activeResponse * xScale + 2,
185: ctop + 2, 9, 9);
186: }
187: }
188: if (clickListener.getSelectedResponse() >= 0) {
189: og.setColor(selectedColor);
190: og.fillRect(xOffset + clickListener.getSelectedResponse()
191: * xScale + 2, ctop + 2, 8, 8);
192: }
193:
194: g.drawImage(offscreen, 0, 0, null);
195: og.dispose();
196: }
197:
198: /**
199: * Find a response
200: * @param x the x coordinate of the mouse click
201: * @param y the y coordinate of the mouse click
202: * @param defResponse the default response
203: * @return true if a response was found
204: */
205: public boolean setState(int x, int y, int defResponse) {
206: int oldResponse = defResponse;
207: int activeResponse = (x - qWidth) / xScale;
208: if ((activeResponse == 0) && (x < 0))
209: activeResponse = oldResponse;
210: else if (activeResponse >= numResponses)
211: activeResponse = oldResponse;
212:
213: clickListener.setActiveResponse(activeResponse);
214: return (defResponse != activeResponse);
215: }
216:
217: /**
218: * Called by XClickListener to check if a response event should be sent to the
219: * parent form. The control can also use this event to do post click processing
220: * @return true if the parent is to be notified
221: */
222: public boolean respond() {
223: return true;
224: }
225:
226: /**
227: * Repaint the responses
228: */
229: public void paintStates() {
230: repaint();// 0, 10, d.width+1, d.height -20 );
231: }
232:
233: /**
234: * Clear the screen
235: */
236: public void invalidate() {
237: super .invalidate();
238: offscreen = null;
239: }
240:
241: /**
242: * Update the screen
243: * @param g
244: */
245: public void update(Graphics g) {
246: paint(g);
247: }
248:
249: /**
250: * Is the prepared image drawn off screen?
251: * @return The double buffered flag
252: */
253: public boolean isDoubleBuffered() {
254: return true;
255: }
256: }
|