001    package org.LiveGraph.gui;
002    
003    import java.util.List;
004    
005    import javax.swing.JFrame;
006    import javax.swing.JMenuBar;
007    import javax.swing.JOptionPane;
008    import javax.swing.JPanel;
009    
010    import org.LiveGraph.LiveGraph;
011    import org.LiveGraph.dataCache.DataCache;
012    import org.LiveGraph.events.Event;
013    import org.LiveGraph.events.EventAnnotation;
014    import org.LiveGraph.events.EventProcessingException;
015    import org.LiveGraph.events.EventProducer;
016    import org.LiveGraph.events.EventType;
017    import org.LiveGraph.gui.dfs.DataFileSettingsPanel;
018    import org.LiveGraph.gui.dfs.DataFileSettingsWindow;
019    import org.LiveGraph.gui.dss.SeriesSettingsPanel;
020    import org.LiveGraph.gui.dss.SeriesSettingsWindow;
021    import org.LiveGraph.gui.gs.GraphSettingsPanel;
022    import org.LiveGraph.gui.gs.GraphSettingsWindow;
023    import org.LiveGraph.gui.msg.MessagePanel;
024    import org.LiveGraph.gui.msg.MessageWindow;
025    import org.LiveGraph.gui.plot.PlotPanel;
026    import org.LiveGraph.gui.plot.PlotWindow;
027    import org.LiveGraph.plot.Plotter;
028    
029    import com.softnetConsult.utils.exceptions.ThrowableTools;
030    
031    import static  org.LiveGraph.gui.GUIEvent.*;
032    
033    
034    public class GUIManager implements EventProducer {
035    
036    /**
037     * The data cache that is used to provide data series information
038     * to new panels and also when constructing new {@code Plotter} objects
039     * required for creating new {@code PlotPanel}s. 
040     */
041    private DataCache dataCache = null;
042    
043    
044    /**
045     * Constructor doesn't do much.
046     */
047    public GUIManager() { }
048    
049    /**
050     * Sets tha data cache that is used to provide data series information
051     * to new panels and also when constructing new {@code Plotter} objects
052     * required for creating new {@code PlotPanel}s. 
053     * @param cache
054     */
055    public void setDataCache(DataCache cache) {
056            dataCache = cache;
057    }
058    
059    /**
060     * Creates a new fully registered instance of a main menu bar.
061     * @return a new main menu bar.
062     */
063    public JMenuBar createMainMenuBar() {
064            MainMenuBar menuBar = new MainMenuBar();
065            LiveGraph.application().eventManager().registerListener(menuBar);
066            return menuBar;
067    }
068    
069    public JPanel createDataFileSettingsPanel() {
070            DataFileSettingsPanel panel = new DataFileSettingsPanel();
071            LiveGraph.application().eventManager().registerListener(panel);
072            return panel;
073    }
074    
075    public JPanel createGraphSettingsPanel() {
076            GraphSettingsPanel panel = new GraphSettingsPanel();
077            if (null != dataCache) {
078                    synchronized(dataCache) {
079                            panel.setSeriesLabels(dataCache.iterateDataSeriesLabels());
080                    }
081            }
082            LiveGraph.application().eventManager().registerListener(panel);
083            return panel;
084    }
085    
086    public JPanel createSeriesSettingsPanel() {
087            SeriesSettingsPanel panel = new SeriesSettingsPanel();
088            if (null != dataCache) {
089                    synchronized(dataCache) {
090                            panel.setSeriesLabels(dataCache.iterateDataSeriesLabels());
091                    }
092            }
093            LiveGraph.application().eventManager().registerListener(panel);
094            return panel;
095    }
096    
097    public JPanel createMessagePanel() {
098            MessagePanel panel = new MessagePanel();
099            LiveGraph.application().eventManager().registerListener(panel);
100            return panel;
101    }
102    
103    public JPanel createPlotPanel() {
104            
105            Plotter plotter = new Plotter(dataCache);
106            LiveGraph.application().eventManager().registerListener(plotter);
107            
108            PlotPanel panel = new PlotPanel(plotter);
109            if (null != dataCache) {
110                    synchronized(dataCache) {
111                            panel.setSeriesLabels(dataCache.iterateDataSeriesLabels());
112                    }
113            }
114            LiveGraph.application().eventManager().registerListener(panel);
115            return panel;
116    }
117    
118    /**
119     * Create a data file settings window and set-up its communication with other objects.
120     * @return data file settings window.
121     */
122    public JFrame createDataFileSettingsWindow() {
123            DataFileSettingsWindow win = new DataFileSettingsWindow();
124            LiveGraph.application().eventManager().registerListener(win);
125            JPanel panel = createDataFileSettingsPanel();
126            win.getContentPane().add(panel);
127            return win;
128    }
129    
130    /**
131     * Create a graph settings window and set-up its communication with other objects.
132     * @return graph settings window.
133     */
134    public JFrame createGraphSettingsWindow() {
135            GraphSettingsWindow win = new GraphSettingsWindow();
136            LiveGraph.application().eventManager().registerListener(win);
137            JPanel panel = createGraphSettingsPanel();
138            win.getContentPane().add(panel);
139            return win;
140    }
141    
142    /**
143     * Create a data series settings window and set-up its communication with other objects.
144     * @return data series settings window.
145     */
146    public JFrame createSeriesSettingsWindow() {
147            SeriesSettingsWindow win = new SeriesSettingsWindow();
148            LiveGraph.application().eventManager().registerListener(win);
149            JPanel panel = createSeriesSettingsPanel();
150            win.getContentPane().add(panel);
151            return win;
152    }
153    
154    /**
155     * Create a message window and set-up its communication with other objects.
156     * @return data series settings window.
157     */
158    public JFrame createMessageWindow() {
159            MessageWindow win = new MessageWindow();
160            LiveGraph.application().eventManager().registerListener(win);
161            JPanel panel = createMessagePanel();
162            win.getContentPane().add(panel);
163            return win;
164    }
165    
166    /**
167     * Create a plot window and set-up its communication with other objects.
168     * 
169     * @return plot window.
170     */
171    public JFrame createPlotWindow() {
172            PlotWindow win = new PlotWindow();
173            win.setJMenuBar(createMainMenuBar());
174            LiveGraph.application().eventManager().registerListener(win);
175            JPanel panel = createPlotPanel();
176            win.getContentPane().add(panel);
177            return win;
178    }
179    
180    
181    /**
182     * Displays or hides the message window.
183     * 
184     * @param state Whether to display ({@code true}) or to hide ({@code false}).
185     */
186    public void setDisplayMessageWindows(boolean state) {   
187            Event<GUIEvent> event = new Event<GUIEvent>(this, GUIEvent.class, GUI_MessagesDisplayStateChanged,
188                                                                                                    state);
189            LiveGraph.application().eventManager().raiseEvent(event);
190    }
191    
192    /**
193     * Displays or hides the data file settings window.
194     * 
195     * @param state Whether to display ({@code true}) or to hide ({@code false}).
196     */
197    public void setDisplayDataFileSettingsWindows(boolean state) {  
198            Event<GUIEvent> event = new Event<GUIEvent>(this, GUIEvent.class, GUI_DataFileSettingsDisplayStateChanged,
199                                                                                                    state);
200            LiveGraph.application().eventManager().raiseEvent(event);
201    }
202    
203    /**
204     * Displays or hides the graph settings window.
205     * 
206     * @param state Whether to display ({@code true}) or to hide ({@code false}).
207     */
208    public void setDisplayGraphSettingsWindows(boolean state) {     
209            Event<GUIEvent> event = new Event<GUIEvent>(this, GUIEvent.class, GUI_GraphSettingsDisplayStateChanged,
210                                                                                                    state);
211            LiveGraph.application().eventManager().raiseEvent(event);
212    }
213    
214    /**
215     * Displays or hides the data series settings window.
216     * 
217     * @param state Whether to display ({@code true}) or to hide ({@code false}).
218     */
219    public void setDisplaySeriesSettingsWindows(boolean state) {    
220            Event<GUIEvent> event = new Event<GUIEvent>(this, GUIEvent.class, GUI_DataSeriesSettingsDisplayStateChanged,
221                                                                                                    state);
222            LiveGraph.application().eventManager().raiseEvent(event);
223    }
224    
225    /**
226     * Displays or hides the plot window.
227     * 
228     * @param state Whether to display ({@code true}) or to hide ({@code false}).
229     */
230    public void setDisplayPlotWindows(boolean state) {      
231            Event<GUIEvent> event = new Event<GUIEvent>(this, GUIEvent.class, GUI_PlotDisplayStateChanged,
232                                                                                                    state);
233            LiveGraph.application().eventManager().raiseEvent(event);
234    }
235    
236    /**
237     * Raises an event to inform listeners that an info message should be displayed.
238     * 
239     * @param o The message.
240     */
241    public void logInfoLn(Object o) {
242            String s = (null == o ? "null" : o.toString());
243            Event<GUIEvent> event = new Event<GUIEvent>(this, GUIEvent.class, GUI_LogMessageInfo, s);
244            LiveGraph.application().eventManager().raiseEvent(event);
245    }
246    
247    /**
248     * Raises an event to inform listeners that an error message should be displayed.
249     * 
250     * @param o The message.
251     */
252    public void logErrorLn(Object o) {
253            try {
254                    String s = (null == o ? "null" : o.toString());
255                    Event<GUIEvent> event = new Event<GUIEvent>(this, GUIEvent.class, GUI_LogMessageError, s);
256                    LiveGraph.application().eventManager().raiseEvent(event);
257            } catch (Throwable ex) {
258                    logErrorLnModal2(o, ex);
259            }
260    }
261    
262    public void logErrorLnModal(Object o) {
263            
264            String msg = (null == o ? "null" : o.toString());
265            System.err.println(msg);
266            JOptionPane.showMessageDialog(null, msg, "LiveGraph error", JOptionPane.ERROR_MESSAGE);
267    }
268    
269    private void logErrorLnModal2(Object o, Throwable ex) {
270            
271            String s = String.format("LiveGraph was going to display an error message,%n" +
272                             "but another error occured during the display process.%n%n" +
273                             "The original error message was:%n" +
274                             "%s%n%n" +
275                             "The error that occured during display is:%n" +
276                             "%s%n",
277                             (null == o ? "null" : o.toString()),
278                             ThrowableTools.stackTraceToString(ex));
279    
280            logErrorLnModal(s);
281    }
282    
283    /**
284     * Raises an event to inform listeners that a success message should be displayed.
285     * 
286     * @param o The message.
287     */
288    public void logSuccessLn(Object o) {
289            String s = (null == o ? "null" : o.toString());
290            Event<GUIEvent> event = new Event<GUIEvent>(this, GUIEvent.class, GUI_LogMessageSuccess, s);
291            LiveGraph.application().eventManager().raiseEvent(event);
292    }
293    
294    /**
295     * Notifies the listeners about the highlighted series.
296     * 
297     * @param hlSeries highlighted series indices.
298     */
299    public void dataSeriesHighlighted(List<Integer> hlSeries) {
300            
301            Event<GUIEvent> event = new Event<GUIEvent>(this, GUIEvent.class, GUIEvent.GUI_DataSeriesHighlighted,
302                                                                                                    hlSeries);
303            LiveGraph.application().eventManager().raiseEvent(event);
304    }
305    
306    /**
307     * Raises an event that requests all listening GUI components to call their {@code dispose()} methods.
308     */
309    public void disposeAllGUI() {
310            Event<GUIEvent> event = new Event<GUIEvent>(this, GUIEvent.class, GUI_DisposeAll);
311            LiveGraph.application().eventManager().raiseEvent(event);
312    }
313    
314    /**
315     * ...
316     * 
317     * @param event ... .
318     */
319    public void eventProcessingFinished(Event<? extends EventType> event) {
320            
321            if (event.getDomain() == GUIEvent.class) {
322                    guiEventProcessingFinished(event.cast(GUIEvent.class));
323                    return;
324            }
325    }
326    
327    /**
328     * ...
329     * 
330     * @param event ... .
331     */
332    public void guiEventProcessingFinished(Event<GUIEvent> event) {
333            
334            switch(event.getType()) {
335                    
336                    // Check whther an error message was actually logged:
337                    case GUI_LogMessageError:
338                            // Look for positive event annotations:
339                            List<EventAnnotation> annotations = event.getAnnotations();
340                            boolean ok = false;
341                            for (EventAnnotation ann : annotations) {
342                                    Object info = ann.getInfo();
343                                    if (null != info && info instanceof Boolean) {
344                                            if (((Boolean) info).booleanValue()) {
345                                                    ok = true;
346                                                    break;
347                                            }
348                                    }
349                            }
350                            // If no positive event annotations found, display without raising an event:
351                            if (!ok) {
352                                    logErrorLnModal(event.getInfoObject());
353                            }
354                            break;
355                    default:
356                            break;
357            }
358    }
359    
360    /**
361     * ...
362     * 
363     * @param event ... 
364     * @param exception ...
365     * @return ...
366     */
367    public boolean eventProcessingException(Event<? extends EventType> event, EventProcessingException exception) {
368            
369            if (event.getDomain() == GUIEvent.class) {
370                    return guiEventProcessingException(event.cast(GUIEvent.class), exception);
371            }
372            
373            return false;
374    }
375    
376    
377    public boolean guiEventProcessingException(Event<GUIEvent> event, EventProcessingException exception) {
378            
379            switch(event.getType()) {
380                    
381                    // If an exception occured while logging an error message, we have to display both, the
382                    // original error message AND the occured exception without raisig further events:
383                    case GUI_LogMessageError:
384                            logErrorLnModal2(event.getInfoObject(), exception);                     
385                            return true;
386                            
387                    default:
388                            return false;
389            }
390    }
391    
392    }   // public class GUIManager