001: /*--------------------------------------------------------------------------*
002: | Copyright (C) 2006 Gereon Fassbender, Christopher Kohlhaas |
003: | |
004: | This program is free software; you can redistribute it and/or modify |
005: | it under the terms of the GNU General Public License as published by the |
006: | Free Software Foundation. A copy of the license has been included with |
007: | these distribution in the COPYING file, if not go to www.fsf.org |
008: | |
009: | As a special exception, you are granted the permissions to link this |
010: | program with every library, which license fulfills the Open Source |
011: | Definition as published by the Open Source Initiative (OSI). |
012: *--------------------------------------------------------------------------*/
013:
014: package org.rapla.plugin.abstractcalendar;
015:
016: import java.awt.Color;
017: import java.awt.Component;
018: import java.awt.Dimension;
019: import java.awt.Font;
020: import java.awt.FontMetrics;
021: import java.awt.Graphics;
022: import java.awt.Graphics2D;
023: import java.awt.Image;
024: import java.awt.MediaTracker;
025: import java.awt.Paint;
026: import java.awt.Point;
027: import java.awt.Rectangle;
028: import java.awt.TexturePaint;
029: import java.awt.event.MouseEvent;
030: import java.awt.image.BufferedImage;
031: import java.util.HashMap;
032: import java.util.Iterator;
033: import java.util.List;
034: import java.util.Map;
035:
036: import javax.swing.JComponent;
037: import javax.swing.event.MouseInputListener;
038:
039: import org.rapla.components.calendarview.swing.SwingBlock;
040: import org.rapla.components.util.SmallIntMap;
041: import org.rapla.entities.Named;
042: import org.rapla.entities.domain.Allocatable;
043: import org.rapla.entities.domain.Repeating;
044: import org.rapla.framework.RaplaContextException;
045: import org.rapla.gui.InfoFactory;
046: import org.rapla.gui.toolkit.RaplaColorList;
047:
048: class SwingRaplaBlock extends AbstractRaplaBlock implements SwingBlock {
049: private static BufferedImage exceptionImage;
050: RaplaBlockView m_view = new RaplaBlockView();
051:
052: private BufferedImage getExceptionImage() {
053: if (exceptionImage != null)
054: return exceptionImage;
055:
056: Image image = getContext().getBuildContext()
057: .getExceptionBackgroundIcon().getImage();
058: MediaTracker m = new MediaTracker(m_view);
059: m.addImage(image, 0);
060: try {
061: m.waitForID(0);
062: } catch (InterruptedException ex) {
063: }
064:
065: exceptionImage = new BufferedImage(image.getWidth(null), image
066: .getHeight(null), BufferedImage.TYPE_INT_ARGB);
067: Graphics g = exceptionImage.getGraphics();
068: g.drawImage(image, 0, 0, null);
069: return exceptionImage;
070: }
071:
072: public Component getView() {
073: return m_view;
074: }
075:
076: public boolean isException() {
077: Repeating repeating = getAppointment().getRepeating();
078: return repeating != null
079: && repeating.isException(getStart().getTime());
080: }
081:
082: static Color TRANS = new Color(100, 100, 100, 100);
083:
084: public void paintDragging(Graphics g, int width, int height) {
085: g.setColor(TRANS);
086: m_view.paint(g, width, height);
087: g.setColor(LINECOLOR_ACTIVE);
088: g.drawRoundRect(0, 0, width, height, 5, 5);
089: }
090:
091: static Font FONT_TITLE = new Font("SansSerif", Font.BOLD, 12);
092: static Font FONT_SMALL_TITLE = new Font("SansSerif", Font.PLAIN, 12);
093: static Font FONT_INVISIBLE = new Font("SansSerif", Font.PLAIN, 9);
094: static Font FONT_RESOURCE = new Font("SansSerif", Font.PLAIN, 12);
095: static Font FONT_PERSON = new Font("SansSerif", Font.ITALIC, 12);
096: static String FOREGROUND_COLOR = RaplaColorList
097: .getHexForColor(Color.black);
098:
099: static SmallIntMap alphaMap = new SmallIntMap();
100:
101: private static Color LINECOLOR_INACTIVE = Color.darkGray;
102: private static Color LINECOLOR_ACTIVE = new Color(255, 90, 10);
103: private static Color LINECOLOR_SAME_RESERVATION = new Color(180,
104: 20, 120);
105:
106: // The Linecolor is not static because it can be changed depending on the mouse move
107: private Color linecolor = LINECOLOR_INACTIVE;
108:
109: class RaplaBlockView extends JComponent implements
110: MouseInputListener {
111: private static final long serialVersionUID = 1L;
112:
113: RaplaBlockView() {
114: javax.swing.ToolTipManager.sharedInstance()
115: .registerComponent(this );
116: addMouseListener(this );
117: }
118:
119: public String getName(Named named) {
120: return SwingRaplaBlock.this .getName(named);
121: }
122:
123: public String getToolTipText(MouseEvent evt) {
124: String text = "";
125: if (getContext().isAnonymous()) {
126: text = getI18n().getString("not_visible.help");
127: } else if (!getContext().isEventSelected()) {
128: text = getI18n().getString("not_selected.help");
129: } else {
130: try {
131: InfoFactory infoFactory = (InfoFactory) getBuildContext()
132: .getServiceManager().lookup(
133: InfoFactory.ROLE);
134: text = infoFactory.getToolTip(getAppointment(),
135: false);
136: } catch (RaplaContextException ex) {
137: }
138: }
139: return "<html>" + text + "</html>";
140: }
141:
142: private Color adjustColor(String org, int alpha) {
143: Map colorMap = (Map) alphaMap.get(alpha);
144: if (colorMap == null) {
145: colorMap = new HashMap();
146: alphaMap.put(alpha, colorMap);
147: }
148: Color color = (Color) colorMap.get(org);
149: if (color == null) {
150: Color or;
151: try {
152: or = RaplaColorList.getColorForHex(org);
153: } catch (NumberFormatException nf) {
154: or = RaplaColorList.getColorForHex("#FFFFFF");
155: }
156: color = new Color(or.getRed(), or.getGreen(), or
157: .getBlue(), alpha);
158: colorMap.put(org, color);
159: }
160:
161: return color;
162: }
163:
164: public void paint(Graphics g) {
165: Dimension dim = getSize();
166: paint(g, dim.width, dim.height);
167: }
168:
169: public void paint(Graphics g, int width, int height) {
170: int alpha = g.getColor().getAlpha();
171:
172: if (!getContext().isEventSelected()) {
173: alpha = 80;
174: paintBackground(g, width, height, alpha);
175: } else {
176: paintBackground(g, width, height, alpha);
177: }
178:
179: //boolean isException = getAppointment().getRepeating().isException(getStart().getTime());
180: Color fg = adjustColor(FOREGROUND_COLOR, alpha); //(isException() ? Color.white : Color.black);
181: g.setColor(fg);
182:
183: if (getAppointment().getRepeating() != null
184: && getBuildContext().isRepeatingVisible()) {
185: if (!getContext().isAnonymous()
186: && getContext().isEventSelected()
187: && !isException()) {
188: getBuildContext().getRepeatingIcon().paintIcon(
189: this , g, width - 17, 0);
190: }
191: /*
192: if ( getBuildContext().isTimeVisible() )
193: g.clipRect(0,0, width -17, height);
194: */
195: }
196: // y will store the y-position of the carret
197: int y = -2;
198: // Draw the Reservationname
199: String timeString = getTimeString();
200: if (timeString != null) {
201: g.setFont(FONT_SMALL_TITLE);
202: y = drawString(g, timeString, y, 2, false) - 1;
203: } else {
204: g.setFont(FONT_TITLE);
205: }
206:
207: if (getContext().isAnonymous()) {
208: y += 4;
209: g.setFont(FONT_INVISIBLE);
210: String label = getI18n().getString("not_visible");
211: y = drawString(g, label, y, 5, true) + 2;
212: return;
213: }
214:
215: String label = getName(getReservation());
216: y = drawString(g, label, y, 2, true) + 2;
217:
218: // If the y reaches the lowerBound "..." will be displayed
219: double lowerBound = height - 11;
220:
221: if (getBuildContext().isPersonVisible()) {
222: g.setFont(FONT_PERSON);
223: g.setColor(fg);
224: Allocatable[] persons = getReservation().getPersons();
225: for (int i = 0; i < persons.length; i++) {
226: if (!getContext().isVisible(persons[i]))
227: continue;
228: String text = getName(persons[i]);
229: if (y > lowerBound) {
230: text = "...";
231: y -= 7;
232: }
233: y = drawString(g, text, y, 7, true);
234: }
235: }
236:
237: if (getBuildContext().isResourceVisible()) {
238: Allocatable[] resources = getReservation()
239: .getResources();
240: g.setFont(FONT_RESOURCE);
241: g.setColor(fg);
242: for (int i = 0; i < resources.length; i++) {
243: if (!getContext().isVisible(resources[i]))
244: continue;
245: String text = getName(resources[i]);
246: if (y > lowerBound) {
247: text = "...";
248: y -= 7;
249: }
250: y = drawString(g, text, y, 7, true);
251: }
252: }
253: }
254:
255: private void setExceptionPaint(Graphics g) {
256: Paint p = new TexturePaint(getExceptionImage(),
257: new Rectangle(14, 14));
258: ((Graphics2D) g).setPaint(p);
259: }
260:
261: private void paintBackground(Graphics g, int width, int height,
262: int alpha) {
263: String[] colors = getColorsAsHex();
264: double colWidth = (double) (width - 2) / colors.length;
265: int x = 0;
266: for (int i = 0; i < colors.length; i++) {
267: g.setColor(adjustColor(colors[i], alpha));
268: g.fillRect((int) Math.ceil(x) + 1, 1, (int) Math
269: .ceil(colWidth), height - 2);
270: if (isException()) {
271: setExceptionPaint(g);
272: g.fillRect((int) Math.ceil(x) + 1, 1, (int) Math
273: .ceil(colWidth), height - 2);
274: }
275: x += colWidth;
276: }
277:
278: //g.setColor( adjustColor( "#000000", alpha ) );
279: g.setColor(linecolor);
280: g.drawRoundRect(0, 0, width - 1, height - 1, 5, 5);
281: }
282:
283: private int findBreakingSpace(char[] c, int offset, int len,
284: int maxWidth, FontMetrics fm) {
285: int index = -1;
286: for (int i = offset; i < offset + len; i++) {
287: if (c[i] == ' '
288: && fm.charsWidth(c, offset, i - offset) < maxWidth)
289: index = i;
290: }
291: return index;
292: }
293:
294: private int findBreaking(char[] c, int offset, int len,
295: int maxWidth, FontMetrics fm) {
296: int index = 0;
297: for (int i = offset; i < offset + len; i++) {
298: if (fm.charsWidth(c, offset, i - offset) < maxWidth)
299: index = i;
300: }
301: return index - 1;
302: }
303:
304: // @return the new y-coordiante below the text
305: private int drawString(Graphics g, String text, int y,
306: int indent, boolean breakLines) {
307: FontMetrics fm = g.getFontMetrics();
308: //g.setFont(new Font("SimSun",Font.PLAIN, 12));
309: char[] c = text.toCharArray();
310: int cWidth = getSize().width - indent;
311: int height = fm.getHeight();
312:
313: int len = c.length;
314: int offset = 0;
315: int x = indent;
316: int maxWidth = (y >= 14
317: || getAppointment().getRepeating() == null || !getBuildContext()
318: .isRepeatingVisible()) ? cWidth : cWidth - 12;
319: if (!breakLines) {
320: maxWidth = maxWidth - 5;
321: } else {
322: while (offset < c.length
323: && fm.charsWidth(c, offset, len) > maxWidth) {
324: int breakingSpace = findBreakingSpace(c, offset,
325: len, maxWidth, fm);
326: //int x = bCenter ? (getSize().width - width)/2 : indent ;
327: y = y + height;
328: if (breakingSpace > 0 && breakLines) {
329: g.drawChars(c, offset, breakingSpace - offset,
330: x, y);
331: // System.out.println("Drawing " + new String(c,offset,breakingSpace-offset));
332: len -= breakingSpace - offset + 1;
333: offset = breakingSpace + 1;
334: } else {
335: int breaking = findBreaking(c, offset, len,
336: maxWidth, fm);
337: if (breaking > 0) {
338: g.drawChars(c, offset, breaking - offset,
339: x, y);
340: g.drawString("\\", fm.charsWidth(c, offset,
341: breaking - offset)
342: + indent, y);
343: // System.out.println("Drawing " + new String(c,offset,breaking-offset) + "\\");
344: len -= breaking - offset;
345: offset = breaking;
346: } else {
347: return y;
348: }
349: }
350: // System.out.println("New len " + len + " new offset " + offset);
351: maxWidth = cWidth;
352: }
353: }
354: y = y + height;
355:
356: g.drawChars(c, offset, len, x, y);
357: // System.out.println("Drawing rest " + new String(c,offset,len));
358: return y;
359: }
360:
361: public void mouseClicked(MouseEvent arg0) {
362:
363: }
364:
365: public void mousePressed(MouseEvent arg0) {
366: }
367:
368: public void mouseReleased(MouseEvent evt) {
369: Point mp = evt.getPoint();
370: boolean inside = mp.x >= 0 && mp.y >= 0
371: && mp.x <= getWidth() && mp.y <= getHeight();
372: changeLineBorder(inside && getContext().isEventSelected());
373: }
374:
375: public void mouseEntered(MouseEvent evt) {
376: if (((evt.getModifiers() & MouseEvent.BUTTON1_MASK) > 0)
377: || !getContext().isEventSelected()) {
378: return;
379: }
380: changeLineBorder(true);
381: }
382:
383: public void mouseExited(MouseEvent evt) {
384: if ((evt.getModifiers() & MouseEvent.BUTTON1_MASK) > 0) {
385: return;
386: }
387: changeLineBorder(false);
388: }
389:
390: public void mouseDragged(MouseEvent arg0) {
391: }
392:
393: public void mouseMoved(MouseEvent arg0) {
394: // TODO Auto-generated method stub
395:
396: }
397:
398: private void changeLineBorder(boolean active) {
399: List blocks = getBuildContext().getBlocks();
400: for (Iterator it = blocks.iterator(); it.hasNext();) {
401: SwingRaplaBlock block = (SwingRaplaBlock) it.next();
402:
403: if (block.getAppointment().equals(getAppointment())) {
404: block.linecolor = active ? LINECOLOR_ACTIVE
405: : LINECOLOR_INACTIVE;
406: block.m_view.repaint();
407: } else if (block.getReservation().equals(
408: getReservation())) {
409: block.linecolor = active ? LINECOLOR_SAME_RESERVATION
410: : LINECOLOR_INACTIVE;
411: block.m_view.repaint();
412: }
413: }
414: }
415:
416: }
417:
418: }
|