View Javadoc

1   /*
2    * Copyright (c) 2003-2008 by Cosylab d. d.
3    *
4    * This file is part of CosyBeans.
5    *
6    * CosyBeans is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation, either version 3 of the License, or
9    * (at your option) any later version.
10   *
11   * CosyBeans is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with CosyBeans.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  
20  package com.cosylab.gui.plugins;
21  
22  import java.awt.AWTEvent;
23  import java.awt.Component;
24  import java.awt.Container;
25  import java.awt.Graphics;
26  import java.awt.Point;
27  import java.awt.Rectangle;
28  import java.awt.Toolkit;
29  import java.awt.event.AWTEventListener;
30  import java.awt.event.ComponentEvent;
31  import java.awt.event.ComponentListener;
32  import java.awt.event.MouseEvent;
33  import java.beans.PropertyChangeEvent;
34  import java.beans.PropertyChangeListener;
35  import java.util.ArrayList;
36  import java.util.Date;
37  import java.util.List;
38  import java.util.logging.Level;
39  import java.util.logging.Logger;
40  
41  import javax.swing.JComponent;
42  import javax.swing.JRootPane;
43  import javax.swing.SwingUtilities;
44  
45  import com.cosylab.application.PlugIn;
46  import com.cosylab.application.PlugInException;
47  import com.cosylab.application.PlugInManager;
48  import com.cosylab.gui.components.util.ColorHelper;
49  import com.cosylab.gui.components.util.PaintHelper;
50  import com.cosylab.gui.displayers.DataState;
51  import com.cosylab.gui.displayers.DataStateProvider;
52  import com.cosylab.logging.DebugLogger;
53  
54  
55  /**
56   * A plugin class that listens for all Displayer and data state changes within
57   * a CosyPanel and paints various warning and timeout simbols over affected
58   * Displayers.
59   *
60   * @author Jernej Kamenik
61   * @version 1.1, 10.7.2002
62   *
63   * @see com.cosybeans.gui.core.CosyPanel
64   * @see com.cosybeans.gui.core.PlugIn
65   * @see com.cosybeans.gui.displayers.Displayer
66   */
67  public class VitragePlugIn extends JComponent implements PlugIn,
68  	PropertyChangeListener, ComponentListener
69  {
70  
71  	private static final long serialVersionUID = 1L;
72  	/**
73  	 * Property name for antialiasing boolean flag. Witrage plugin checks for
74  	 * this properti in configuration of parent application panel and use it
75  	 * when painting simbols.
76  	 */
77  	public final static String ENHANCED = "vitrageplugin.antialiasing";
78  	private final static Logger logger = DebugLogger.getLogger("VP", Level.OFF);
79  
80  	//private PlugInManager manager = null;
81  	private Container contentPane = null;
82  	private List<DataStateProvider> displayers = null;
83  	private boolean isEnabled;
84  	private boolean isInHierarchy;
85  
86  	/**
87  	 * Constructor for VitragePlugin
88  	 */
89  	public VitragePlugIn()
90  	{
91  		super();
92  		setOpaque(false);
93  		displayers = new ArrayList<DataStateProvider>();
94  	}
95  
96  	/**
97  	 * Creates vitrage plugin, which directly hooks up to parent without Cosy
98  	 * framework.
99  	 *
100 	 * @param comp thecomponent, which subcomponents will be examined for
101 	 *        Displayer instances
102 	 */
103 	public VitragePlugIn(JComponent comp)
104 	{
105 		this();
106 		installToRoot(comp.getRootPane());
107 
108 		hookAWT(comp);
109 	}
110 
111 	private void hookAWT(Container comp)
112 	{
113 		Component[] components = comp.getComponents();
114 
115 		if (components == null) {
116 			return;
117 		}
118 
119 		for (int i = 0; i < components.length; i++) {
120 			if (components[i] instanceof DataStateProvider) {
121 				hookDisplayer((DataStateProvider)components[i]);
122 			}
123 
124 			if (components[i] instanceof Container) {
125 				hookAWT((Container)components[i]);
126 			}
127 		}
128 	}
129 
130 	/*
131 	 * (non-Javadoc)
132 	 * @see com.cosylab.application.PlugIn#installPlugIn(com.cosylab.application.PlugInManager)
133 	 */
134 	public void installPlugIn(PlugInManager manager) throws PlugInException
135 	{
136 		if (manager == null) {
137 			throw new NullPointerException("manager");
138 		}
139 
140 		logger.info("Installing to " + manager);
141 
142 /*		PaintHelper.setEnhanced(Boolean.getBoolean(
143 		        panel.getApplication().getConfiguration().getProperty(ENHANCED,
144 		            Boolean.TRUE.toString())));
145 */
146 
147 		JRootPane root = SwingUtilities.getRootPane(manager.getOwnerPanel().getContentPane());
148 
149 		if (root != null) {
150 			installToRoot(root);
151 		}
152 
153 	}
154 
155 	private void installToRoot(JRootPane root)
156 	{
157 		contentPane = root.getContentPane();
158 
159 		if (!isInHierarchy) {
160 			if (root != null) {
161 				root.getLayeredPane().add(this, new Integer(1), -1);
162 				setLocation(SwingUtilities.convertPoint(contentPane, 0, 0,
163 				        getParent()));
164 				setSize(contentPane.getSize());
165 				root.addComponentListener(this);
166 				isInHierarchy = true;
167 				root.getLayeredPane().validate();
168 
169 				// Set the proper cursor (workaround)
170 				// ike: not working for applets, security restriction
171 				try {
172 					Toolkit.getDefaultToolkit().addAWTEventListener(new CursorListener(
173 					        contentPane), AWTEvent.MOUSE_EVENT_MASK);
174 				} catch (SecurityException e) {
175 					System.out.println(
176 					    "No permission to access AWT, Vitrage my not function property: "
177 					    + e.getMessage());
178 				}
179 			}
180 		}
181 	}
182 
183 	private void hookDisplayer(DataStateProvider disp)
184 	{
185 		logger.fine("disp " + disp);
186 		disp.addPropertyChangeListener(this);
187 
188 		if (disp.getDataState().type != DataState.NORMAL
189 		    && disp.getDataState().type != DataState.CONNECTED) {
190 			addPaintedDisplayer(disp);
191 		}
192 	}
193 
194 	@SuppressWarnings("unused")
195 	private void unhookDisplayer(DataStateProvider disp)
196 	{
197 		logger.fine("disp " + disp);
198 		disp.removePropertyChangeListener(this);
199 		removePaintedDisplayer(disp);
200 	}
201 
202 	/**
203 	 * 
204 	 * @param source
205 	 */
206 	public void displayerStateChanged(DataStateProvider source)
207 	{
208 		if (source.getDataState().type == DataState.NORMAL // connected is not neccessary normal
209 		//|| source.getDataState().type == DataState.CONNECTED
210 		) {
211 			removePaintedDisplayer(source);
212 		} else {
213 			addPaintedDisplayer(source);
214 		}
215 	}
216 
217 	/*
218 	 * (non-Javadoc)
219 	 * @see com.cosylab.application.PlugIn#destroy()
220 	 */
221 	public void destroy()
222 	{
223 	}
224 
225 	/**
226 	 * Method for painting the vitrage over displayers.
227 	 *
228 	 * @param g Graphics object to be painted.
229 	 *
230 	 * @see PaintHelper
231 	 */
232 	public void paintComponent(Graphics g)
233 	{
234 		super.paintComponent(g);
235 
236 		if (isEnabled) {
237 			logger.fine("Painting");
238 
239 			DataStateProvider displayer = null;
240 			Component component = null;
241 			long timeoutTime;
242 			String state;
243 			Rectangle r;
244 
245 			for (int i = 0; i < displayers.size(); i++) {
246 				displayer = (DataStateProvider)displayers.get(i);
247 				component = (Component)displayer;
248 
249 				if (!component.isShowing()) {
250 					continue;
251 				}
252 
253 				if (!component.isDisplayable()) {
254 					continue;
255 				}
256 
257 				r = SwingUtilities.convertRectangle(component.getParent(),
258 					    component.getBounds(), this);
259 
260 				/*if (true) {
261 				    g.setColor(Color.RED);
262 				    g.drawOval(r.x,r.y,r.width,r.height);
263 				    continue;
264 				}*/
265 				state = displayer.getDataState().type;
266 				timeoutTime = displayer.getDataState().timestamp;
267 
268 				if (state == DataState.NOT_INITIALIZED
269 				    || state == DataState.DISCONNECTED
270 				    || state == DataState.UNDEFINED) {
271 					logger.fine("Painting DISABLED " + displayer);
272 					PaintHelper.paintDisabled(g.create(r.x, r.y, r.width,
273 					        r.height), 0, 0, r.width, r.height);
274 				} else {
275 					int timeSize = (int)(Math.min(r.width, r.height) * 8.8 / 10);
276 					int stateSize = (int)(Math.min(r.width, r.height) * 9. / 10);
277 
278 					if (stateSize < 1) {
279 						stateSize = 1;
280 					}
281 
282 					if (timeSize < 1) {
283 						timeSize = 1;
284 					}
285 
286 					int timeX = (r.width - timeSize) / 2;
287 					int timeY = (r.height - timeSize) / 2;
288 					int stateX = (r.width - stateSize) / 2;
289 					int stateY = (r.height - stateSize) / 2;
290 
291 					if (state == DataState.WARNING) {
292 						logger.fine("Painting WARNING " + displayer);
293 						PaintHelper.paintWarning(g.create(r.x, r.y, r.width,
294 						        r.height), stateX, stateY, stateSize);
295 					} else if (state == DataState.ALARM) {
296 						String severity= displayer.getDataState().description;
297 						logger.fine("Painting ALARM " + displayer+ " "+severity);
298 						if ("INVALID_ALARM".equals(severity)) {
299 							PaintHelper.paintAlarmInvalid(g.create(r.x, r.y, r.width,
300 					        r.height), stateX, stateY, stateSize);
301 						} else if ("MAJOR_ALARM".equals(severity)) {
302 							PaintHelper.paintAlarmMajor(g.create(r.x, r.y, r.width,
303 					        r.height), stateX, stateY, stateSize);
304 						} else if ("MINOR_ALARM".equals(severity)) {
305 							PaintHelper.paintAlarmMinor(g.create(r.x, r.y, r.width,
306 					        r.height), stateX, stateY, stateSize);
307 						}
308 					} else if (state == DataState.ERROR) {
309 						logger.fine("Painting ERROR " + displayer);
310 						PaintHelper.paintEmergency(g.create(r.x, r.y, r.width,
311 						        r.height), stateX, stateY, stateSize);
312 						PaintHelper.paintRectangle(g.create(r.x, r.y, r.width,
313 						        r.height), 0, 0, r.width, r.height,
314 						    ColorHelper.getEmergencyOutline(),
315 						    Math.max(stateSize / 50,2));
316 					} else if (state == DataState.TIMEOUT) {
317 						logger.fine("Painting TIMEOUT " + displayer);
318 						PaintHelper.paintTimeout(g.create(r.x, r.y, r.width,
319 						        r.height), timeX, timeY, timeSize,
320 						    new Date(timeoutTime));
321 						PaintHelper.paintRectangle(g.create(r.x, r.y, r.width,
322 						        r.height), 0, 0, r.width, r.height,
323 						    ColorHelper.getTimeOutOutline(), Math.max(stateSize / 50,2));
324 					}
325 				}
326 			}
327 		}
328 	}
329 
330 	private void addPaintedDisplayer(DataStateProvider displayer)
331 	{
332 		synchronized (displayers) {
333 			if (!displayers.contains(displayer)) {
334 				logger.fine("disp " + displayer);
335 				displayers.add(displayer);
336 
337 				if (!isEnabled) {
338 					setVitrageEnabled(true);
339 				}
340 			}
341 		}
342 
343 		repaint();
344 	}
345 
346 	private void removePaintedDisplayer(DataStateProvider displayer)
347 	{
348 		synchronized (displayers) {
349 			if (displayers.contains(displayer)) {
350 				logger.fine("disp " + displayer);
351 				displayers.remove(displayer);
352 
353 				if (displayers.size() == 0) {
354 					setVitrageEnabled(false);
355 				}
356 			}
357 		}
358 
359 		repaint();
360 	}
361 
362 	/**
363 	 * Enables/disable the vitrage.
364 	 * 
365 	 * @param enabled
366 	 */
367 	public void setVitrageEnabled(boolean enabled)
368 	{
369 		isEnabled = enabled;
370 	}
371 	
372 	/**
373 	 * Returns true if vitrage is enabled
374 	 * 
375 	 * @return
376 	 */
377 	public boolean isVitrageEnabled() {
378 		return isEnabled;
379 	}
380 
381 	/*
382 	 * (non-Javadoc)
383 	 * @see java.awt.event.ComponentListener#componentHidden(java.awt.event.ComponentEvent)
384 	 */
385 	public void componentHidden(ComponentEvent e)
386 	{
387 		isEnabled = false;
388 	}
389 	
390 	/*
391 	 * (non-Javadoc)
392 	 * @see java.awt.event.ComponentListener#componentMoved(java.awt.event.ComponentEvent)
393 	 */
394 	public void componentMoved(ComponentEvent e)
395 	{
396 		if (getParent() == null) {
397 			return;
398 		}
399 	}
400 
401 	/*
402 	 * (non-Javadoc)
403 	 * @see java.awt.event.ComponentListener#componentResized(java.awt.event.ComponentEvent)
404 	 */
405 	public void componentResized(ComponentEvent e)
406 	{
407 		setSize(contentPane.getSize());
408 	}
409 
410 	/*
411 	 * (non-Javadoc)
412 	 * @see java.awt.event.ComponentListener#componentShown(java.awt.event.ComponentEvent)
413 	 */
414 	public void componentShown(ComponentEvent e)
415 	{
416 		isEnabled = true;
417 	}
418 
419 	/*
420 	 * (non-Javadoc)
421 	 *
422 	 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
423 	 */
424 	public void propertyChange(PropertyChangeEvent evt)
425 	{
426 		if (evt.getSource() instanceof DataStateProvider
427 		    && ("dataState").equals(evt.getPropertyName())) {
428 		    //bugfix RT#11580 by jkamenik
429 		    DataState nds = (DataState)evt.getNewValue();
430 		    DataState ods = (DataState)evt.getOldValue();
431 		    if (nds == null || ods == null
432 			    || nds.type != ods.type 
433 			    || nds.description!=ods.description) {
434 				displayerStateChanged((DataStateProvider)evt.getSource());
435 			}
436 		    //end bugfix
437 		}
438 	}
439 
440 	/**
441 	 * Listen for all events that our check box is likely to be interested in.
442 	 * Redispatch them to the check box.
443 	 */
444 	private class CursorListener implements AWTEventListener
445 	{
446 		Container contentPane;
447 
448 		/**
449 		 * Creates a new CursorListener object.
450 		 *
451 		 * @param contentPane DOCUMENT ME!
452 		 */
453 		public CursorListener(Container contentPane)
454 		{
455 			this.contentPane = contentPane;
456 		}
457 		
458 		/*
459 		 * (non-Javadoc)
460 		 * @see java.awt.event.AWTEventListener#eventDispatched(java.awt.AWTEvent)
461 		 */
462 		public void eventDispatched(AWTEvent event)
463 		{
464 			if (event instanceof MouseEvent) {
465 				MouseEvent evt = (MouseEvent)event;
466 				Point ePt = evt.getPoint();
467 				Point pt = SwingUtilities.convertPoint(evt.getComponent(),
468 					    ePt.x, ePt.y, contentPane);
469 				Component topC = SwingUtilities.getDeepestComponentAt(contentPane,
470 					    pt.x, pt.y);
471 
472 				if (topC != null) {
473 					setCursor(topC.getCursor());
474 				}
475 			}
476 		}
477 	}
478 }
479 
480 /* __oOo__ */