001    package hep.aida.ref.sql.JAS3Plugin;
002    
003    import hep.aida.ref.sql.SQLTupleFactory;
004    
005    // FreeHEP
006    import org.freehep.application.studio.Studio;
007    import org.freehep.application.studio.PluginInfo;
008    import org.freehep.application.RecentItemTextField;
009    import org.freehep.util.commanddispatcher.CommandProcessor;
010    import org.freehep.util.commanddispatcher.CommandSourceAdapter;
011    import org.freehep.util.commanddispatcher.CommandState;
012    import org.freehep.util.commanddispatcher.BooleanCommandState;
013    
014    // AIDA
015    import hep.aida.IAnalysisFactory;
016    import hep.aida.ITupleFactory;
017    import hep.aida.IHistogramFactory;
018    import hep.aida.IBaseHistogram;
019    import hep.aida.IHistogram;
020    import hep.aida.IHistogram1D;
021    import hep.aida.IHistogram2D;
022    import hep.aida.ICloud;
023    import hep.aida.ICloud1D;
024    import hep.aida.ICloud2D;
025    import hep.aida.IProfile;
026    import hep.aida.IProfile1D;
027    import hep.aida.IEvaluator;
028    import hep.aida.ITree;
029    import hep.aida.ITuple;
030    import hep.aida.ref.tuple.FTupleColumn;
031    
032    // SQLTuple
033    import hep.aida.ref.sql.SQLTuple;
034    import hep.aida.ref.sql.SQLTupleException;
035    
036    // JAS
037    import org.freehep.jas.plugin.console.ConsoleService;
038    import org.freehep.jas.services.TextEditorService;
039    import org.freehep.jas.services.PlotFactory;
040    import org.freehep.jas.services.PlotPage;
041    import org.freehep.jas.services.PlotRegion;
042    import org.freehep.jas.services.Plotter;
043    import org.freehep.jas.plugin.tree.FTreeNodeAddedNotification;
044    import org.freehep.jas.plugin.tree.FTreeProvider;
045    import org.freehep.jas.plugin.tree.FTree;
046    import org.freehep.jas.plugin.tree.FTreeNode;
047    import org.freehep.jas.services.WebBrowser;
048    import org.freehep.jas.plugin.web.SimpleWebBrowser;
049    
050    // Swing
051    import javax.swing.JOptionPane;
052    import javax.swing.ImageIcon;
053    
054    // Java
055    import java.util.List;
056    import java.io.PrintWriter;
057    import java.io.IOException;
058    import java.net.URL;
059    import java.net.MalformedURLException;
060    
061    /** <code>SQLTupleCommands</code> contains SQLTuple commands for JAS3 plugin of SQLTuple.
062      * It uses directly AIDA {@link ITuple} calls so it profits from {@link hep.aida.ref.sql.SQLTuple}
063      * optimisation.
064      * <p><font color="#880088">
065      * $Id: SQLTupleCommands.java,v 1.10 2007/09/26 07:58:51 hrivnac Exp $
066      * <pre>
067      * $Log: SQLTupleCommands.java,v $
068      * Revision 1.10  2007/09/26 07:58:51  hrivnac
069      * cache savable fromjas menu
070      *
071      * Revision 1.9  2007/05/23 16:38:44  hrivnac
072      * logical connections for Plotter; better UML
073      *
074      * Revision 1.8  2006/12/19 14:31:08  hrivnac
075      * news added into WS
076      *
077      * Revision 1.7  2006/04/22 12:05:27  hrivnac
078      * help included in  JAS plugin
079      *
080      * Revision 1.6  2005/10/10 10:05:33  hrivnac
081      * prepared for 1.0.2
082      *
083      * Revision 1.5  2005/09/29 16:08:38  hrivnac
084      * javadoc fixed
085      *
086      * Revision 1.4  2005/09/29 14:31:32  hrivnac
087      * clouds and profiles added
088      *
089      * Revision 1.3  2005/09/29 13:02:39  hrivnac
090      * histograms can be plotted in a different way in JAS3
091      *
092      * Revision 1.2  2005/09/29 09:22:59  hrivnac
093      * jas3 plugin improved
094      *
095      * Revision 1.1  2005/09/28 22:49:55  hrivnac
096      * added SQLTuple-aware projections
097      *
098      * </pre>
099      * </font></p>
100      * @opt attributes
101      * @opt operations
102      * @opt types
103      * @opt visibility
104      * @version $Id: SQLTupleCommands.java,v 1.10 2007/09/26 07:58:51 hrivnac Exp $
105      * @author <a href="mailto:Julius.Hrivnac@cern.ch">J.Hrivnac</a> */
106    public class SQLTupleCommands extends CommandProcessor {
107    
108      /** Initialise and connect to JAS3.
109        * @param plugin The connected {@link SQLTuplePlugin}. */
110      public SQLTupleCommands(SQLTuplePlugin plugin) {
111        // Register environment
112        _plugin = plugin;
113        _app = ((Studio)plugin.getApplication());
114        TextEditorService textEditor   = (TextEditorService)_app.getLookup().lookup(TextEditorService.class);
115        FTreeProvider     treeProvider = (FTreeProvider    )_app.getLookup().lookup(FTreeProvider.class);
116                          _plotFactory = (PlotFactory      )_app.getLookup().lookup(PlotFactory.class);
117        _tree = treeProvider.tree();
118        // Register Adaptors
119        treeProvider.treeNodeAdapterRegistry().registerNodeAdapter(new SQLTupleColumnAdapter(_app, this), FTupleColumn.class);
120        // Create Console
121        ConsoleService cs = (ConsoleService)_app.getLookup().lookup(ConsoleService.class);
122        if (cs != null) {
123          try {
124            _log = new PrintWriter(cs.getConsoleOutputStream("SQLTuple", null), true);
125            }
126          catch (IOException e) {
127            JOptionPane.showMessageDialog(_app, "Can't open SQLTuple Console: " + e, "SQLTuple Projector Warning", JOptionPane.WARNING_MESSAGE);
128            }
129          }
130        }
131    
132      /** Project {@link IHistogram} in Current Region. */
133      public void onProjectHistogramInCurrentRegion() {
134        histogram(false, false, false);
135        setChanged();
136        }
137    
138      /** Project {@link IHistogram} in New Region. */
139      public void onProjectHistogramInNewRegion() {
140        histogram(false, false, true);
141        setChanged();
142        }
143    
144      /** Project {@link IHistogram} in New Page. */
145      public void onProjectHistogramInNewPage() {
146        histogram(true, false, false);
147        setChanged();
148        }
149    
150      /** Project {@link IHistogram} Overlay. */
151      public void onProjectHistogramOverlay() {
152        histogram(false, true, false);
153        setChanged();
154        }
155    
156      /** Project {@link ICloud} in Current Region. */
157      public void onProjectCloudInCurrentRegion() {
158        cloud(false, false, false);
159        setChanged();
160        }
161    
162      /** Project {@link ICloud} in New Region. */
163      public void onProjectCloudInNewRegion() {
164        cloud(false, false, true);
165        setChanged();
166        }
167    
168      /** Project {@link ICloud} in New Page. */
169      public void onProjectCloudInNewPage() {
170        cloud(true, false, false);
171        setChanged();
172        }
173    
174      /** Project {@link ICloud} Overlay. */
175      public void onProjectCloudOverlay() {
176        cloud(false, true, false);
177        setChanged();
178        }
179    
180      /** Project {@link IProfile} in Current Region. */
181      public void onProjectProfileInCurrentRegion() {
182        profile(false, false, false);
183        setChanged();
184        }
185    
186      /** Project {@link IProfile} in New Region. */
187      public void onProjectProfileInNewRegion() {
188        profile(false, false, true);
189        setChanged();
190        }
191    
192      /** Project {@link IProfile} in New Page. */
193      public void onProjectProfileInNewPage() {
194        profile(true, false, false);
195        setChanged();
196        }
197    
198      /** Project {@link IProfile} Overlay. */
199      public void onProjectProfileOverlay() {
200        profile(false, true, false);
201        setChanged();
202        }
203    
204      /** Act on Save Cache click. Saves database schema cache into a file. */
205      public void onSaveCache() {
206        SQLTupleFactory.saveCache();
207              setChanged();
208        }
209        
210      /** Enable Save Cache. Always enabled.
211        * @param state Ignored. */
212      public void enableSaveCache(CommandState state) {
213        state.setEnabled(true);
214        }
215    
216      /** Act on Help click. Open a window with a help page. */
217      public void onHelpSQLTuple() {
218        if (_webBrowser == null) {
219          _webBrowser = (SimpleWebBrowser)_app.getLookup().lookup(WebBrowser.class);
220          }
221        try {
222          URL homePage = new URL(_homePageString);
223          _webBrowser.showURL(homePage);
224          }
225        catch (MalformedURLException e) {
226          JOptionPane.showMessageDialog(_app, "Can't show help: " + e, "SQLTuple Error", JOptionPane.ERROR_MESSAGE);
227          }
228              setChanged();
229        }
230        
231      /** Enable Help. Always enabled.
232        * @param state Ignored. */
233      public void enableHelpSQLTuple(CommandState state) {
234        state.setEnabled(true);
235        }
236    
237      /** Project {@link ITuple} into {@link IHistogram}. 
238        * Depending on number of selected columns, following
239        * {@link IHistogram}s are produced:
240        * <ol>
241        * <li>{@link IHistogram1D}</li>
242        * <li>{@link IHistogram2D}</li>
243        * <li>{@link IHistogram2D} with weight</li>
244        * </ol>
245        * @param newPage Whether plot on a new page.
246        * @param overlay Whether overlay current plot.
247        * @param newPlot Whether create new plot.
248        * @return        The created {@link IHistogram}. */
249      private IHistogram histogram(boolean newPage, 
250                                   boolean overlay, 
251                                   boolean newPlot) {
252        ITree tree = (ITree)(_app.getLookup().lookup(ITree.class));
253        IAnalysisFactory af = IAnalysisFactory.create();
254        ITupleFactory tf = af.createTupleFactory(tree);
255        IHistogramFactory hf = af.createHistogramFactory(tree);
256        FTreeNode[] nodes = _tree.selectedNodes();
257        FTreeNode parent = nodes[0].parent();
258        ITuple tuple = (ITuple)(parent.objectForClass(ITuple.class));
259        IHistogram histogram = null;
260        tree.mkdirs(parent.path() + "-histograms");
261        if (nodes.length == 1) {
262          String columnX = nodes[0].toString();
263          int indexX = tuple.findColumn(columnX);
264          IEvaluator evaluatorX = tf.createEvaluator(columnX);
265          histogram = hf.createHistogram1D(parent.path() + "-histograms/" + columnX, 
266                                           50, 
267                                           tuple.columnMin(indexX),
268                                           tuple.columnMax(indexX));
269          plot(histogram, newPage, overlay, newPlot);
270          tuple.project((IHistogram1D)histogram, evaluatorX);
271          }
272        else if (nodes.length == 2) {
273          String columnX = nodes[0].toString();   
274          String columnY = nodes[1].toString();   
275          int indexX= tuple.findColumn(columnX);   
276          int indexY= tuple.findColumn(columnY);   
277          IEvaluator evaluatorX = tf.createEvaluator(columnX);
278          IEvaluator evaluatorY = tf.createEvaluator(columnY);
279          histogram = hf.createHistogram2D(parent.path() + "-histograms/" + columnX + " x " + columnY,
280                                           50,
281                                           tuple.columnMin(indexX),
282                                           tuple.columnMax(indexX),
283                                           50,
284                                           tuple.columnMin(indexY),
285                                           tuple.columnMax(indexY));
286          plot(histogram, newPage, overlay, newPlot);
287          tuple.project((IHistogram2D)histogram, evaluatorX, evaluatorY);
288          }
289        else if (nodes.length == 3) {
290          String columnX = nodes[0].toString();   
291          String columnY = nodes[1].toString();   
292          String columnW = nodes[2].toString();   
293          int indexX = tuple.findColumn(columnX);   
294          int indexY = tuple.findColumn(columnY);   
295          int indexW = tuple.findColumn(columnW);   
296          IEvaluator evaluatorX = tf.createEvaluator(columnX);
297          IEvaluator evaluatorY = tf.createEvaluator(columnY);
298          IEvaluator weight     = tf.createEvaluator(columnW);
299          histogram = hf.createHistogram2D(parent.path() + "-histograms/" + columnX + " x " + columnY + " x " + columnW,
300                                           50,
301                                           tuple.columnMin(indexX),
302                                           tuple.columnMax(indexX),
303                                           50,
304                                           tuple.columnMin(indexY),
305                                           tuple.columnMax(indexY));
306          plot(histogram, newPage, overlay, newPlot);
307          tuple.project((IHistogram2D)histogram, evaluatorX, evaluatorY, weight);
308          }
309        else {
310          JOptionPane.showMessageDialog(_app, "Can't project IHistogram from " + nodes.length + " columns", "SQLTuple Projector Warning", JOptionPane.WARNING_MESSAGE);
311          }
312        return histogram;
313        }
314    
315      /** Project {@link ITuple} into {@link ICloud}. 
316        * Depending on number of selected columns, following
317        * {@link IHistogram}s are produced:
318        * <ol>
319        * <li>{@link ICloud1D}</li>
320        * <li>{@link ICloud2D}</li>
321        * <li>{@link ICloud2D} with weight</li>
322        * </ol>
323        * @param newPage Whether plot on a new page.
324        * @param overlay Whether overlay current plot.
325        * @param newPlot Whether create new plot.
326        * @return        The created {@link ICloud}. */
327      private ICloud cloud(boolean newPage, 
328                           boolean overlay, 
329                           boolean newPlot) {
330        ITree tree = (ITree)(_app.getLookup().lookup(ITree.class));
331        IAnalysisFactory af = IAnalysisFactory.create();
332        ITupleFactory tf = af.createTupleFactory(tree);
333        IHistogramFactory hf = af.createHistogramFactory(tree);
334        FTreeNode[] nodes = _tree.selectedNodes();
335        FTreeNode parent = nodes[0].parent();
336        ITuple tuple = (ITuple)(parent.objectForClass(ITuple.class));
337        ICloud cloud = null;
338        tree.mkdirs(parent.path() + "-clouds");
339        if (nodes.length == 1) {
340          String columnX = nodes[0].toString();
341          int indexX = tuple.findColumn(columnX);   
342          IEvaluator evaluatorX = tf.createEvaluator(columnX);
343          cloud = hf.createCloud1D(parent.path() + "-clouds/" + columnX);
344          plot(cloud, newPage, overlay, newPlot);
345          tuple.project((ICloud1D)cloud, evaluatorX);
346          }
347        else if (nodes.length == 2) {
348          String columnX = nodes[0].toString();   
349          String columnY = nodes[1].toString();   
350          int indexX= tuple.findColumn(columnX);   
351          int indexY= tuple.findColumn(columnY);   
352          IEvaluator evaluatorX = tf.createEvaluator(columnX);
353          IEvaluator evaluatorY = tf.createEvaluator(columnY);
354          cloud = hf.createCloud2D(parent.path() + "-clouds/" + columnX + " x " + columnY);
355          tuple.project((ICloud2D)cloud, evaluatorX, evaluatorY);
356          }
357        else if (nodes.length == 3) {
358          String columnX = nodes[0].toString();   
359          String columnY = nodes[1].toString();   
360          String columnW = nodes[2].toString();   
361          int indexX = tuple.findColumn(columnX);   
362          int indexY = tuple.findColumn(columnY);   
363          int indexW = tuple.findColumn(columnW);   
364          IEvaluator evaluatorX = tf.createEvaluator(columnX);
365          IEvaluator evaluatorY = tf.createEvaluator(columnY);
366          IEvaluator weight     = tf.createEvaluator(columnW);
367          cloud = hf.createCloud2D(parent.path() + "-clouds/" + columnX + " x " + columnY + " x " + columnW);
368          plot(cloud, newPage, overlay, newPlot);
369          tuple.project((ICloud2D)cloud, evaluatorX, evaluatorY, weight);
370          }
371        else {
372          JOptionPane.showMessageDialog(_app, "Can't project ICloud from " + nodes.length + " columns", "SQLTuple Projector Warning", JOptionPane.WARNING_MESSAGE);
373          }
374        return cloud;
375        }
376    
377      /** Project {@link ITuple} into {@link IProfile}. 
378        * Depending on number of selected columns, following
379        * {@link IProfile}s are produced:
380        * <ol>
381        * <li></li>
382        * <li>{@link IProfile1D}</li>
383        * <li>{@link IProfile1D} with weight</li>
384        * </ol>
385        * @param newPage Whether plot on a new page.
386        * @param overlay Whether overlay current plot.
387        * @param newPlot Whether create new plot.
388        * @return        The created {@link IProfile}. */
389      private IProfile profile(boolean newPage, 
390                               boolean overlay, 
391                               boolean newPlot) {
392        ITree tree = (ITree)(_app.getLookup().lookup(ITree.class));
393        IAnalysisFactory af = IAnalysisFactory.create();
394        ITupleFactory tf = af.createTupleFactory(tree);
395        IHistogramFactory hf = af.createHistogramFactory(tree);
396        FTreeNode[] nodes = _tree.selectedNodes();
397        FTreeNode parent = nodes[0].parent();
398        ITuple tuple = (ITuple)(parent.objectForClass(ITuple.class));
399        IProfile profile = null;
400        tree.mkdirs(parent.path() + "-profiles");
401        if (nodes.length == 2) {
402          String columnX = nodes[0].toString();   
403          String columnY = nodes[1].toString();   
404          int indexX= tuple.findColumn(columnX);   
405          int indexY= tuple.findColumn(columnY);   
406          IEvaluator evaluatorX = tf.createEvaluator(columnX);
407          IEvaluator evaluatorY = tf.createEvaluator(columnY);
408          profile = hf.createProfile1D(parent.path() + "-profiles/" + columnX + " x " + columnY,
409                                       50,
410                                       tuple.columnMin(indexX),
411                                       tuple.columnMax(indexX),
412                                       tuple.columnMin(indexY),
413                                       tuple.columnMax(indexY));
414          plot(profile, newPage, overlay, newPlot);
415          tuple.project((IProfile1D)profile, evaluatorX, evaluatorY);
416          }
417        else if (nodes.length == 3) {
418          String columnX = nodes[0].toString();   
419          String columnY = nodes[1].toString();   
420          String columnW = nodes[2].toString();   
421          int indexX = tuple.findColumn(columnX);   
422          int indexY = tuple.findColumn(columnY);   
423          int indexW = tuple.findColumn(columnW);   
424          IEvaluator evaluatorX = tf.createEvaluator(columnX);
425          IEvaluator evaluatorY = tf.createEvaluator(columnY);
426          IEvaluator weight     = tf.createEvaluator(columnW);
427          profile = hf.createProfile1D(parent.path() + "-profiles/" + columnX + " x " + columnY + " x " + columnW,
428                                       50,
429                                       tuple.columnMin(indexX),
430                                       tuple.columnMax(indexX),
431                                       tuple.columnMin(indexY),
432                                       tuple.columnMax(indexY));
433    
434          plot(profile, newPage, overlay, newPlot);
435          tuple.project((IProfile1D)profile, evaluatorX, evaluatorY, weight);
436          }
437        else {
438          JOptionPane.showMessageDialog(_app, "Can't project IProfile from " + nodes.length + " columns", "SQLTuple Projector Warning", JOptionPane.WARNING_MESSAGE);
439          }
440        return profile;
441        }
442    
443      /** Enable EventSelector. Always enbabled.
444        * @param state Ignored. */
445      public void enableProjector(CommandState state) {
446        state.setEnabled(true);
447        }
448        
449      /** Plot {@link IBaseHistogram} according to selected options.
450        * @param histogram The {@link IBaseHistogram} to plot.
451        * @param newPage   Whether plot on a new page.
452        * @param overlay   Whether overlay current plot.
453        * @param newPlot   Whether create new plot. */
454      private void plot(IBaseHistogram histogram, 
455                        boolean newPage, 
456                        boolean overlay, 
457                        boolean newPlot) {        
458        PlotPage plotPage = newPage ? null : _plotFactory.currentPage();
459        boolean justCreated = false;
460        if (plotPage == null) {
461          plotPage = _plotFactory.createPage(null);
462          plotPage.showPage();
463          justCreated = true;
464          }
465        PlotRegion region = plotPage.currentRegion();
466        if (region == null) {
467          region = plotPage.createRegion(0, 0, 1, 1);
468          }
469        else if (newPlot && !justCreated) {
470          region = plotPage.addRegion();
471          }
472        Plotter plotter = region.currentPlot();
473        if (plotter == null) {
474          plotter = _plotFactory.createPlotterFor(histogram.getClass());
475          }
476        plotter.plot(histogram, overlay ? plotter.OVERLAY : plotter.NORMAL);
477        region.showPlot(plotter);
478        }
479    
480      private SQLTuplePlugin _plugin;
481    
482      private Studio _app;
483    
484      private FTree _tree;
485      
486      private PlotFactory _plotFactory;
487    
488      private PrintWriter _log;
489    
490      private SimpleWebBrowser _webBrowser;
491    
492      private static String _homePageString = "classpath:/hep/aida/ref/sql/JAS3Plugin/doc-files/JAS3.html";
493    
494      }