1// BEGIN LICENSE BLOCK 2// Version: CMPL 1.1 3// 4// The contents of this file are subject to the Cisco-style Mozilla Public 5// License Version 1.1 (the "License"); you may not use this file except 6// in compliance with the License. You may obtain a copy of the License 7// at www.eclipse-clp.org/license. 8// 9// Software distributed under the License is distributed on an "AS IS" 10// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 11// the License for the specific language governing rights and limitations 12// under the License. 13// 14// The Original Code is The ECLiPSe Constraint Logic Programming System. 15// The Initial Developer of the Original Code is Cisco Systems, Inc. 16// Portions created by the Initial Developer are 17// Copyright (C) 2006 Cisco Systems, Inc. All Rights Reserved. 18// 19// Contributor(s): 20// 21// END LICENSE BLOCK 22 23package com.parctechnologies.eclipse.visualisation; 24import com.parctechnologies.eclipse.*; 25 26import java.util.*; 27import javax.swing.*; 28import java.awt.BorderLayout; 29import java.awt.Dimension; 30import java.awt.GridBagLayout; 31import java.awt.GridBagConstraints; 32import java.awt.Insets; 33import java.awt.Toolkit; 34import java.awt.event.ActionEvent; 35import javax.swing.event.*; 36 37/** 38 * The ViewerManager is the delegatee of the VisClient. 39 40 41 * The responsibilities of this class are all viewer-related and are grouped 42 * around each of the methods which are invoked by VisClient's processEvent 43 * method during the course of an event.<p> 44 * The graphical 45 * management of the viewers as well as the top level buttons and menus is 46 * delegated to ViewerManagerFrame.<p> 47 * The responsibilities are: 48 * <ul> 49 * <li> When setViewerBuildingPolicy is called for a create event, the 50 * ViewerManager must ask the user which viewers should be created OR if 51 * a suitable scenario already exists it should ask the user if they wish to 52 * use the viewerBuildingPolicy stored in the scenario. 53 * <li> When prepareForEvent is called for a create event, the ViewerManager must 54 * build and configure any viewers which are going to monitor the new viewable, 55 * according to its ViewerBuildingPolicy. 56 * <li> When prepareForEvent is called for any event, the ViewerManager must 57 * determine which viewers are participating in the event and then invoke the 58 * prepareForEvent method of each of those viewers. 59 * <li> For collectPreEventGoals, the viewerManager should collect the pre event 60 * goals of each of the participating viewers into a batch goal and return it. 61 * <li> For startEvent in the case of a createEvent, the viewerManager should 62 * add the new viewers to the ViewerManagerFrame. 63 * <li> For startEvent generally, the viewerManager should invoke the startEvent 64 * method of all participating viewers, distributing the results of each one's 65 * pre-event goals. 66 * <li> For shouldHold, the viewer should return true if any one of the 67 * participating viewers wants to hold. 68 * <li> For stopEvent, in the case of a DestroyEvent, the viewerManager should 69 * remove the viewers whose viewable has ceased to exist from the 70 * viewerManagerFrame. 71 * <li> For stopEvent generally, the viewerManager should invoke the stopEvent 72 * method of all participating viewers. 73 * <li> The ViewerManager must also provide access to the collection of current 74 * interest specs for any existent viewable. 75 * </ul> 76 * 77 * <p> 78 */ 79class ViewerManager 80{ 81 // in order to be able to efficiently determine which viewers are 82 // participating in each event, the ViewerManager maintains several map 83 // data structures. 84 85 // this allows us to work out the viewable which the event refers to, from its 86 // name. 87 private Map viewableNameToViewable; 88 89 // This is for update events, where we may need to determine which of several 90 // viewers monitoring the viewable is participating. 91 // we have exactly one interest per viewer 92 private Map interestSpecNameToViewer; 93 94 // maps viewable to all viewers monitoring it. 95 private Map viewableToViewers; 96 97 // required for implementation of getInterestSpecs() 98 private Map viewableToInterestSpecs; 99 100 private ViewerBuildingPolicy viewerBuildingPolicy; 101 // List of viewers which are participating in the current event 102 private List participatingViewers; 103 private Atom vcSupportAtom = new Atom("vc_support"); 104 private ViewerManagerFrame viewerManagerFrame; 105 private VisEvent currentEvent; 106 private VisClientStateModel stateModel; 107 108 109 ViewerManager(VisClientStateModel stateModel) 110 { 111 this.stateModel = stateModel; 112 initialise(); 113 } 114 115 private void initialise() 116 { 117 viewableNameToViewable = new HashMap(); 118 interestSpecNameToViewer = new HashMap(); 119 viewableToViewers = new HashMap(); 120 viewableToInterestSpecs = new HashMap(); 121 initialiseViewerBuildingPolicy(); 122 initialiseViewerManagerFrame(); 123 } 124 125 private void initialiseViewerManagerFrame() 126 { 127 viewerManagerFrame = new ViewerManagerFrame(stateModel); 128 if(DebuggingSupport.useGraphics) 129 { 130 viewerManagerFrame.setVisible(true); 131 } 132 viewerManagerFrame.pack(); 133 134 } 135 136 public void initialiseViewerBuildingPolicy() 137 { 138 viewerBuildingPolicy = new DefaultViewerBuildingPolicy(stateModel); 139 } 140 141 public ViewerBuildingPolicy getViewerBuildingPolicy() { 142 return viewerBuildingPolicy; 143 } 144 145 public void configureViewerBuildingPolicy(String viewableName, 146 ViewableType viewableType) 147 { 148 if (!stateModel.getViewerBuildingPolicySelected()) { 149 // The user wishes to select new viewers 150 JDialog dialog = new SelectViewersDialog(viewableName, 151 viewableType); 152 dialog.show(); 153 } 154 } 155 156 private Viewable initialiseViewable(String viewableName, 157 ViewableType type) 158 { 159 Viewable viewable = new Viewable(viewableName, type); 160 viewableNameToViewable.put(viewableName, viewable); 161 return(viewable); 162 } 163 164 165 private java.util.List buildViewers(Viewable viewable) 166 { 167 java.util.List newViewers = viewerBuildingPolicy.buildViewers(viewable); 168 Iterator newViewersIterator = newViewers.iterator(); 169 Viewer newViewer; 170 171 while(newViewersIterator.hasNext()) 172 { 173 newViewer = (Viewer) newViewersIterator.next(); 174 newViewer.setViewerManager(this); 175 if (DebuggingSupport.logMessages) { 176 DebuggingSupport.logMessage(this, 177 "built viewer=" + newViewer + 178 " interestSpec=" + 179 newViewer.getInterestSpec().getName() ); 180 } 181 interestSpecNameToViewer.put(newViewer.getInterestSpec().getName(), 182 newViewer); 183 } 184 return(newViewers); 185 } 186 187 void closeViewer(Viewer viewer) 188 { 189 viewerManagerFrame.removeViewer(viewer); 190 Collection oldViewers = 191 (Collection) viewableToViewers.remove(viewer.getViewable()); 192 Collection newViewers = new LinkedList(oldViewers); 193 newViewers.remove(viewer); 194 viewableToViewers.put(viewer.getViewable(), newViewers); 195 interestSpecNameToViewer.remove(viewer.getInterestSpec().getName()); 196 DebuggingSupport. 197 logMessage(this, "viewer "+viewer.getDescription()+" removed"); 198 // clean up memory used by the viewer 199 System.gc(); 200 } 201 202 void prepareForEvent(VisEvent visEvent) 203 { 204 String viewableName = visEvent.getViewableName(); 205 Viewable viewable; 206 Viewer currentViewer; 207 208 if(visEvent instanceof CreateEvent) 209 { 210 CreateEvent createEvent = (CreateEvent) visEvent; 211 viewable = 212 initialiseViewable(viewableName, 213 createEvent.getViewableType()); 214 java.util.List newViewers = buildViewers(viewable); 215 viewableToViewers.put(viewable, newViewers); 216 Collection interestSpecs = getAllInterestSpecs(newViewers); 217 viewableToInterestSpecs.put(viewable, interestSpecs); 218 } 219 else 220 { 221 viewable = 222 (Viewable) viewableNameToViewable.get(viewableName); 223 } 224 225 participatingViewers = 226 (java.util.List) determineParticipatingViewers(visEvent, viewable); 227 228 Iterator viewersIterator 229 = participatingViewers.iterator(); 230 while(viewersIterator.hasNext()) 231 { 232 currentViewer = (Viewer) viewersIterator.next(); 233 currentViewer.prepareForEvent(visEvent); 234 } 235 } 236 237 private List determineParticipatingViewers(VisEvent event, 238 Viewable viewable) 239 { 240 if(event instanceof UpdateEvent) 241 { 242 UpdateEvent updateEvent = (UpdateEvent) event; 243 String interestSpecName = updateEvent.getInterestSpecName(); 244 LinkedList result = new LinkedList(); 245 Object viewer = interestSpecNameToViewer.get(interestSpecName); 246 if (DebuggingSupport.logMessages) { 247 DebuggingSupport.logMessage(this, 248 "interestSpecName=" + 249 interestSpecName + " viewer=" + 250 viewer); 251 } 252 if(viewer != null) 253 { 254 result.add(viewer); 255 } 256 return(result); 257 } 258 else 259 { 260 return((List) viewableToViewers.get(viewable)); 261 } 262 } 263 264 BatchGoal collectPreEventGoals(VisEvent visEvent) 265 { 266 BatchGoal preEventGoals = new BatchGoal(); 267 Viewer currentViewer; 268 269 Iterator viewersIterator 270 = participatingViewers.iterator(); 271 while(viewersIterator.hasNext()) 272 { 273 currentViewer = (Viewer) viewersIterator.next(); 274 preEventGoals.add(currentViewer.collectPreEventGoals(visEvent)); 275 } 276 return(preEventGoals); 277 } 278 279 void holdingEvent(VisEvent visEvent) 280 { 281 viewerManagerFrame.setLastEventString(visEvent.getDescription()); 282 } 283 284 void startEvent(VisEvent visEvent, java.util.List goalResults) 285 { 286 viewerManagerFrame.setLastEventString(""); 287 288 Viewer currentViewer; 289 Viewable viewable = 290 (Viewable) viewableNameToViewable.get(visEvent.getViewableName()); 291 java.util.List currentGoalResults; 292 293 currentEvent = visEvent; 294 295 Iterator viewersIterator 296 = participatingViewers.iterator(); 297 Iterator goalResultsIterator 298 = goalResults.iterator(); 299 300 String viewableNameString = viewable.getNameString(); 301 302 303 while(viewersIterator.hasNext()) 304 { 305 currentViewer = (Viewer) viewersIterator.next(); 306 currentGoalResults = (java.util.List) goalResultsIterator.next(); 307 currentViewer.startEvent(visEvent, currentGoalResults); 308 if(visEvent instanceof CreateEvent) 309 { 310 viewerManagerFrame.addViewer(currentViewer, viewableNameString); 311 } 312 } 313 } 314 315 316 317 boolean shouldHold() 318 { 319 Viewer currentViewer; 320 Iterator viewersIterator 321 = participatingViewers.iterator(); 322 while(viewersIterator.hasNext()) 323 { 324 currentViewer = (Viewer) viewersIterator.next(); 325 if(currentViewer.shouldHold()) 326 { 327 return(true); 328 } 329 } 330 return(false); 331 } 332 333 void stopEvent() 334 { 335 Viewer currentViewer; 336 Iterator viewersIterator 337 = participatingViewers.iterator(); 338 String viewableName = currentEvent.getViewableName(); 339 Viewable viewable = 340 (Viewable) viewableNameToViewable.get(viewableName); 341 342 343 while(viewersIterator.hasNext()) 344 { 345 currentViewer = (Viewer) viewersIterator.next(); 346 currentViewer.stopEvent(); 347 if(currentEvent instanceof DestroyEvent) 348 { 349 try 350 { 351 SwingUtilities.invokeAndWait(new ViewerCloser(currentViewer)); 352 } 353 catch(Exception e) 354 { 355 throw new RuntimeException("Exception "+e+ 356 " thrown during ViewerCloser.run()"); 357 } 358 } 359 } 360 if(currentEvent instanceof DestroyEvent) 361 { 362 viewableToViewers.remove(viewable); 363 viewableToInterestSpecs.remove(viewable); 364 viewableNameToViewable.remove(viewableName); 365 } 366 currentEvent = null; 367 participatingViewers = null; 368 } 369 370 private class ViewerCloser implements Runnable { 371 private Viewer viewer; 372 ViewerCloser(Viewer viewer) { 373 this.viewer = viewer; 374 } 375 public void run() { 376 // closes the internal frame window and updates all book-keeping 377 viewerManagerFrame.removeViewer(viewer); 378 } 379 } 380 381 Collection getAllInterestSpecs(Collection viewers) 382 { 383 Collection interestSpecs = new LinkedList(); 384 Viewer currentViewer; 385 Iterator viewersIterator 386 = viewers.iterator(); 387 while(viewersIterator.hasNext()) 388 { 389 currentViewer = (Viewer) viewersIterator.next(); 390 interestSpecs.add(currentViewer.getInterestSpec()); 391 } 392 return(interestSpecs); 393 } 394 395 Collection getInterestSpecs(String viewableName) 396 { 397 Viewable viewable = (Viewable) viewableNameToViewable.get(viewableName); 398 return((Collection) viewableToInterestSpecs.get(viewable)); 399 } 400 401 402 void errorDialog(String message) 403 { 404 JOptionPane.showConfirmDialog(viewerManagerFrame, message, 405 "Error in visualisation client", 406 JOptionPane.DEFAULT_OPTION); 407 } 408 409 /** 410 * Dialog from which the user will select the viewers they wish to be 411 * created 412 */ 413 private class SelectViewersDialog extends JDialog { 414 String viewableName; 415 ViewableType viewableType; 416 417 List buttons; 418 Set keys; 419 420 public SelectViewersDialog(String viewableName, 421 ViewableType viewableType) { 422 super(); 423 this.buttons = new LinkedList(); 424 this.viewableName = viewableName ; 425 this.viewableType = viewableType ; 426 setModal(true); 427 this.setTitle("Select viewers for "+viewableName); 428 getContentPane().setLayout(new BorderLayout()); 429 getContentPane().add(new JLabel("Which viewers would you like to create for viewable \""+viewableName+"\"?"), 430 BorderLayout.NORTH); 431 432 getContentPane().add(viewerFactorySelectorPanel(), 433 BorderLayout.CENTER); 434 JPanel buttonPanel = new JPanel(); 435 buttonPanel.add(new ActionButton(new OkayAction())); 436 getContentPane().add(buttonPanel, BorderLayout.SOUTH); 437 pack(); 438 // locate the window in the center for the screen 439 Dimension screenSize = 440 Toolkit.getDefaultToolkit().getScreenSize(); 441 Dimension windowSize = getPreferredSize(); 442 setLocation(screenSize.width/2 - (windowSize.width/2), 443 screenSize.height/2 - (windowSize.height/2)); 444 } 445 446 private JPanel viewerFactorySelectorPanel() { 447 JPanel panel = new JPanel(); 448 BoxLayout layout = new BoxLayout(panel, BoxLayout.Y_AXIS); 449 panel.setLayout(layout); 450 keys = ((DefaultViewerBuildingPolicy)viewerBuildingPolicy).availableViewerFactories(viewableType); 451 Iterator it = keys.iterator(); 452 for(int i = 0; it.hasNext(); i++) 453 { 454 Object name = it.next(); 455 JCheckBox button = new JCheckBox(name.toString()); 456 buttons.add(button); 457 panel.add(button); 458 } 459 return(panel); 460 } 461 462 private class OkayAction extends AbstractAction 463 { 464 OkayAction() 465 { 466 super("Okay"); 467 } 468 public void actionPerformed(ActionEvent event) 469 { 470 List selected = new LinkedList(); 471 Iterator keyIt = keys.iterator(); 472 for(Iterator it = buttons.iterator(); it.hasNext(); ) { 473 Object key = keyIt.next(); 474 if (((AbstractButton)it.next()).isSelected()) { 475 selected.add(key); 476 } 477 } 478 (new PolicySelectedCommand(viewableName, selected)).issue(); 479 dispose(); 480 } 481 } 482 483 } 484} 485