001    package nl.cwi.sen1.visbase.factbrowser;
002    
003    import java.awt.event.MouseEvent;
004    import java.util.Iterator;
005    
006    import javax.swing.tree.DefaultMutableTreeNode;
007    
008    import nl.cwi.sen1.configapi.Factory;
009    import nl.cwi.sen1.configapi.types.ActionDescriptionList;
010    import nl.cwi.sen1.configapi.types.Event;
011    import nl.cwi.sen1.gui.CloseAbortedException;
012    import nl.cwi.sen1.gui.Studio;
013    import nl.cwi.sen1.gui.StudioImplWithPredefinedLayout;
014    import nl.cwi.sen1.gui.StudioWithPredefinedLayout;
015    import nl.cwi.sen1.gui.component.StudioComponent;
016    import nl.cwi.sen1.gui.component.StudioComponentImpl;
017    import nl.cwi.sen1.gui.plugin.DefaultStudioPlugin;
018    import nl.cwi.sen1.relationstores.types.RType;
019    import nl.cwi.sen1.util.DefaultPopupImpl;
020    import nl.cwi.sen1.util.MouseAdapter;
021    import nl.cwi.sen1.visbase.factbrowser.data.FactBrowserDataManager;
022    import nl.cwi.sen1.visbase.factbrowser.data.RStore;
023    import nl.cwi.sen1.visbase.factbrowser.data.RStoreFact;
024    import nl.cwi.sen1.visbase.factbrowser.data.VisualisationPlugin;
025    import nl.cwi.sen1.visbase.rstorecontainer.datatypes.ATermParseException;
026    import nl.cwi.sen1.visbase.rstorecontainer.datatypes.FactInfo;
027    import nl.cwi.sen1.visbase.rstorecontainer.datatypes.FactInfoList;
028    
029    import org.apache.commons.logging.Log;
030    import org.apache.commons.logging.LogFactory;
031    
032    import aterm.ATerm;
033    import aterm.ATermList;
034    import aterm.pure.PureFactory;
035    
036    /**
037     * This class is the main entry point for the toolbus FactBrowserInterface
038     * script. It also listens to event from the FactBrowserWindow with the visual
039     * tree containing the RStores
040     * 
041     * <b>DataManager</b> This method has a dataManager which takes care of the
042     * registration of new Rstores/Facts/FactTypes and VisualisationPlugins.
043     * 
044     * <b>RTypes decoding</b> For the decoding of the given Facts with Rtypes, the
045     * rstore-container FactInfoList()is used. This will get a container class with
046     * all the nessecary information about the Facts.
047     * 
048     * @extends DefaultStudioPlungin This class makes it possible to add this class
049     *          as a plugin in the Meta-Environment.
050     * 
051     * @implemented FactBrowserTif This is the interface containing the methods
052     *              responsible for the communication with the toolbus
053     * 
054     * @author Renze de Vries
055     * @Date 12-02-2007
056     */
057    public class FactBrowser extends DefaultStudioPlugin implements FactbrowserTif {
058            private static final int DOUBLE_CLICK = 2;
059    
060            private FactBrowserDataManager dataManager;
061    
062            private static final String TOOL_NAME = "factbrowser";
063    
064            private static final Log log = LogFactory.getLog(FactBrowser.class);
065    
066            private Factory configFactory;
067    
068            private Studio studio;
069    
070            private StudioComponent component;
071    
072            private FactbrowserBridge bridge;
073    
074            private FactBrowserWindow factBrowserWindow;
075    
076            private DefaultPopupImpl popup;
077    
078            /**
079             * This is the default constructor it creates the dataManager and the
080             * visualisationClass
081             * 
082             * @author Renze de Vries
083             * @date 22-02-2007
084             */
085            public FactBrowser() {
086                    dataManager = FactBrowserDataManager.getInstance();
087                    factBrowserWindow = new FactBrowserWindow();
088            }
089    
090            /**
091             * <b>ToolbusInterface</b> This method is a toolBus interface required
092             * implementation. It gets as parameters the type of the visualisation, name
093             * and the identifier for the plugin. It passes the visualisation to the
094             * dataManager and signals the visualisationWindow to redraw.
095             * 
096             * 
097             * @param pluginType
098             * @param pluginIdentifier
099             * @param pluginName1
100             * 
101             * @author Renze de Vries
102             * @date 20-02-2007
103             */
104            public void fbAddVisualizationPlugin(ATerm pluginType,
105                            int pluginIdentifier, String pluginName) {
106                    log.debug("Incoming Visualisation plugin with name: " + pluginName
107                                    + " and identifier: " + pluginIdentifier);
108                    log.debug("Incoming Visualisation plugin with type: "
109                                    + pluginType.toString());
110    
111                    VisualisationPlugin visPlugin = new VisualisationPlugin(pluginName,
112                                    pluginIdentifier);
113                    dataManager.createVisualisation(visPlugin, dataManager
114                                    .addFactType(pluginType.toString()));
115    
116                    factBrowserWindow.redrawTree();
117            }
118    
119            /**
120             * <b>ToolbusInterface</b> This method is an interface for the toolbus
121             * communications. It's task is to add a passed Rstore with all it's
122             * children facts to the dataStore which is managed by the (caching)
123             * dataManager.
124             * 
125             * @param rstoreName
126             * @param rstoreIdentifier
127             * @param rstoreFacts
128             * 
129             * @author Renze de Vries
130             * @date 20-02-2007
131             */
132            public void fbShowRstoreFacts(String rstoreName, int rstoreIdentifier,
133                            ATerm rstoreFacts) {
134    
135                    // Create the RStoreNode and set the parameters Name and Identifier
136                    RStore rstoreNode = new RStore(rstoreName, rstoreIdentifier);
137    
138                    // We want to create all children FactNodes so Create a FactInfoList
139                    FactInfoList factInfoList = null;
140                    try {
141                            // Put the ATerm containing the RStore facts in the List
142                            factInfoList = new FactInfoList((ATermList) rstoreFacts);
143    
144                            // Iterate through FactInfo list
145                            for (FactInfo factInfo : factInfoList.getFactInfos()) {
146                                    // Create a new factNode so we can add them to the in memory
147                                    // tree
148                                    RStoreFact factNode = new RStoreFact(factInfo.getName(),
149                                                    factInfo.getId(), dataManager.addFactType(factInfo
150                                                                    .getType()));
151    
152                                    factNode.setRType(factInfo.getRType());
153    
154                                    // add them to the parent RStore
155                                    rstoreNode.addFactNode(factNode);
156                            }
157    
158                    } catch (ATermParseException e) {
159                            e.printStackTrace();
160                    }
161    
162                    // Finally add the Rstore to the visual tree
163                    factBrowserWindow.addRStore(rstoreNode);
164    
165                    Iterator<RStoreFact> iterator = rstoreNode.getFactNodes().iterator();
166                    while (iterator.hasNext()) {
167                            RType rtype = iterator.next().getRType();
168    
169                            ATerm term = studio.getATermFactory().make(
170                                            "fb-type-selected(<term>)", rtype.toTerm());
171                            bridge.sendEvent(term);
172                    }
173    
174                    studio.makeVisible(component);
175            }
176    
177            /**
178             * Removes the rstore with the specified rstoreIdentifier from the tree.
179             * 
180             * @author Bas Basten
181             * @author Anton Lycklama a Nijeholt
182             * @date 19-03-2007
183             * 
184             * @param rstoreIdentifier
185             */
186            public void fbRstoreUnloaded(int rstoreIdentifier) {
187                    factBrowserWindow.removeRStoreTreeNode(rstoreIdentifier);
188            }
189    
190            /**
191             * Method must be implemented as part of toolbus compliance
192             */
193            public void recAckEvent(ATerm t0) {
194            }
195    
196            /**
197             * Method will be called when the connection with the toolbus is terminated
198             */
199            public void recTerminate(ATerm t0) {
200                    fireStudioPluginClosed();
201            }
202    
203            /**
204             * This method returns the name of this Tool for the metaStudio.
205             */
206            public String getName() {
207                    return TOOL_NAME;
208            }
209    
210            private ATerm createEventId(ATerm moduleId) {
211                    return studio.getATermFactory().make(TOOL_NAME + "(<term>)", moduleId);
212            }
213    
214            /**
215             * This is the entry method for the FactBrowser. When the meta-environment
216             * is started this will be called to add the factBrowser to the studio. It
217             * calls a method which will load the layout with the menu's.
218             * 
219             * @param metaStudio
220             *            This is the instance of the metaStudio
221             * 
222             * @author Renze de Vries
223             * @date 20-02-2007
224             */
225            public void initStudioPlugin(Studio metaStudio) {
226                    this.studio = metaStudio;
227                    this.configFactory = Factory.getInstance((PureFactory) metaStudio
228                                    .getATermFactory());
229                    bridge = new FactbrowserBridge(metaStudio.getATermFactory(), this);
230                    popup = new DefaultPopupImpl(bridge);
231                    metaStudio.connect(getName(), bridge);
232    
233                    addFactBrowserComponent();
234            }
235    
236            /**
237             * This method will initialize the layout and add it to the MetaStudio
238             * environment
239             * 
240             * @author Renze de Vries
241             * @date 20-02-2007
242             */
243            private void addFactBrowserComponent() {
244                    final ATerm id = configFactory.getPureFactory().parse(TOOL_NAME);
245                    final Event popupAction = configFactory.makeEvent_Popup();
246    
247                    factBrowserWindow.addMouseListener(new MouseAdapter(id, bridge,
248                                    popupAction) {
249                            @Override
250                            public void mousePressed(MouseEvent e) {
251                                    factBrowserWindow.selectNodeAtPosition(e.getX(), e.getY());
252    
253                                    ATerm rStoreId = getSelectedRStoreId();
254                                    if (rStoreId != null) {
255                                            setId(createEventId(rStoreId));
256                                            super.mousePressed(e);
257                                    }
258                            }
259    
260                            @Override
261                            public void mouseClicked(MouseEvent e) {
262                                    if (e.getButton() == MouseEvent.BUTTON1) {
263                                            if (e.getClickCount() == DOUBLE_CLICK) {
264                                                    mouseDoubleClick(e);
265                                            }
266                                    }
267                            }
268                    });
269    
270                    component = new StudioComponentImpl("Facts", factBrowserWindow) {
271                            @Override
272                            public void requestClose() throws CloseAbortedException {
273                                    throw new CloseAbortedException();
274                            }
275                    };
276                    ((StudioWithPredefinedLayout) studio).addComponent(component,
277                                    StudioImplWithPredefinedLayout.TOP_LEFT);
278    
279            }
280    
281            /**
282             * Handles the double click actions on a rstore tree node and a
283             * visualization treenode. Only the messages will be send, the data itself
284             * will not be handled here.
285             * 
286             * Scenario 1: If the user double clicks on a rstore tree node a message
287             * will be send to the toolbus and requests all the facts within the rstore.
288             * 
289             * Scenario 2: If the user double clicks on a fact tree node a message will
290             * be send to the toolbus to request all the possible visualizations for the
291             * given fact.
292             * 
293             * @author Renze de Vries
294             * @author Bas Basten
295             * @author Anton Lycklama a Nijeholt
296             * @date 19-03-2007
297             */
298            private void mouseDoubleClick(MouseEvent mouseEvent) {
299                    DefaultMutableTreeNode selectedNode = factBrowserWindow
300                                    .getSelectedNode();
301    
302                    if (selectedNode != null) {
303                            // This is to check if the selection was on a
304                            // VisualisationPlugin
305                            if (dataManager.checkValidVisualisationPlugin(selectedNode)) {
306                                    int visPluginID = dataManager.getVisPluginID(selectedNode);
307                                    int factID = dataManager.getFactID(selectedNode);
308                                    int rstoreID = dataManager.getRStoreID(selectedNode);
309    
310                                    // build the Aterm with the given identifiers and send it
311                                    ATerm term = studio.getATermFactory().make(
312                                                    "fb-visualization-selected(<int>, <int>, <int>)",
313                                                    rstoreID, factID, visPluginID);
314                                    bridge.sendEvent(term);
315                            } else if (dataManager.checkValidRStoreFact(selectedNode)) {
316                            } else if (dataManager.checkValidRStore(selectedNode)) {
317                            } else {
318                                    log.warn("A node was selected which was an invalid type");
319                            }
320                    } else {
321                            log.warn("Double clicked but there was no node selected");
322                    }
323            }
324    
325            /**
326             * @author Taeke Kooiker
327             * @date 14-08-2007
328             */
329            public void showPopup(int RStoreId, ATerm menuList) {
330                    ActionDescriptionList l = configFactory
331                                    .ActionDescriptionListFromTerm(menuList);
332                    popup.showPopup(menuList.getFactory().makeInt(RStoreId), l);
333            }
334    
335            /**
336             * @author Taeke Kooiker
337             * @date 14-08-2007
338             */
339            public ATerm getSelectedRstoreid() {
340                    ATerm rStoreId = getSelectedRStoreId();
341    
342                    if (rStoreId != null) {
343                            ATerm term = studio.getATermFactory().make(
344                                            "snd-value(selected-rstoreid(<term>))", rStoreId);
345                            return term;
346                    }
347    
348                    ATerm term = studio.getATermFactory().make(
349                                    "snd-value(no-rstore-selected)");
350                    return term;
351            }
352    
353            /**
354             * @author Taeke Kooiker
355             * @date 15-08-2007
356             */
357            private ATerm getSelectedRStoreId() {
358                    DefaultMutableTreeNode selectedNode = factBrowserWindow
359                                    .getSelectedNode();
360    
361                    if (selectedNode != null) {
362                            while (!(selectedNode.getUserObject() instanceof RStore)
363                                            || selectedNode.getParent() == null) {
364                                    selectedNode = (DefaultMutableTreeNode) selectedNode
365                                                    .getParent();
366                            }
367    
368                            if (selectedNode.getUserObject() instanceof RStore) {
369                                    int id = FactBrowserDataManager.getInstance().getRStoreID(
370                                                    selectedNode);
371                                    return studio.getATermFactory().makeInt(id);
372                            }
373                    }
374    
375                    return null;
376            }
377    }