001 /** 002 * Created by IntelliJ IDEA. 003 * User: Wei Wang 004 * Date: Nov 27, 2002 005 * Time: 3:50:11 PM 006 */ 007 008 package EVolve.visualization; 009 010 import EVolve.data.*; 011 import EVolve.Scene; 012 import javax.swing.*; 013 import javax.imageio.*; 014 import java.awt.event.*; 015 import java.awt.image.BufferedImage; 016 import java.awt.*; 017 import java.util.*; 018 import java.io.*; 019 020 public abstract class Visualization { 021 public static final int SELECT_TIME_FRAME = 0x0001; 022 public static final int SELECT_OCCURRED_ENTITIES = 0x0010; 023 public static final int SELECT_ALL_ENTITIES = 0x0100; 024 public static final int SELECT_X_AXIS = 0x1000; 025 public static final int SELECT_Y_AXIS = 0x0100; 026 public static final int SELECT_ALL_X_AXIS = 0x0010; 027 public static final int SELECT_ALL_Y_AXIS = 0x0001; 028 029 030 protected String name; // name of the visualization 031 protected EVolve.Window window; // window where the visualization is displayed 032 033 protected VisualizationDefinition definition; // definition of the visualization 034 protected ElementDefinition subjectDefinition; // definition of the subject 035 036 protected Dimension[] dimension; // dimension of the visualization 037 protected JPanel panel; // panel to draw the visualization 038 039 protected JDialog dialog; // configuration dialog 040 protected JPanel panelConfiguration; // configuration panel 041 protected JComboBox comboSubject; // subject selection 042 protected JComboBox[] comboDimension; // dimension selection 043 private JTextField textName; // name input 044 045 protected JPopupMenu popup; // popup menu 046 private JMenu menuSort; 047 private JMenu[] menuDimension; 048 protected JMenuItem[][] itemSort; 049 private JMenuItem itemConfigure; 050 private JMenuItem itemSelect; 051 private JMenuItem itemSave; 052 private ReferenceDimension[] referenceDimension; 053 private static int vizIDPool = 0; 054 private int linkageId; 055 private VisualizationFactory factory = null; 056 057 protected ElementDefinition[] elementDefinition; // definition of elements that can be used as subject 058 protected DataFilter[][][] dataFilter; // data filters that can be used by the dimensions 059 protected int mouseX, mouseY; 060 061 public Visualization() { 062 dimension = createDimension(); 063 panel = createPanel(); 064 panelConfiguration = null; 065 dialog = null; 066 linkageId = vizIDPool++; 067 addPopupTrigger(panel); 068 } 069 070 public String getName() { 071 return name; 072 } 073 074 /** 075 * Sets the name of the visualization. 076 * 077 * @param name name of the visualization 078 */ 079 public void setName(String name) { 080 this.name = name; 081 } 082 083 /** 084 * Sets the window of the visualization. 085 * 086 * @param window window of the visualization 087 */ 088 public void setWindow(EVolve.Window window) { 089 this.window = window; 090 } 091 092 /** 093 * Gets the panel of the visualization. 094 * 095 * @return panel of the visualization 096 */ 097 public JPanel getPanel() { 098 return panel; 099 } 100 101 /** 102 * Gets the additional configuration panel. 103 * 104 * @return the additional configuration panel, null if not necessary 105 */ 106 protected JPanel createConfigurationPanel() { 107 return null; // by default, return null, each visualization can override this 108 } 109 110 protected void createMenu() { 111 popup = new JPopupMenu(); 112 113 itemConfigure = new JMenuItem("Configure..."); 114 itemConfigure.setMnemonic(KeyEvent.VK_C); 115 itemConfigure.addActionListener(new ActionListener() { 116 public void actionPerformed(ActionEvent e) { 117 configure(); 118 } 119 }); 120 popup.add(itemConfigure); 121 122 itemSelect = new JMenuItem("Make Selection"); 123 itemSelect.setMnemonic(KeyEvent.VK_M); 124 itemSelect.addActionListener(new ActionListener() { 125 public void actionPerformed(ActionEvent e) { 126 makeSelection(); 127 } 128 }); 129 popup.add(itemSelect); 130 131 menuSort = new JMenu("Sort"); 132 menuSort.setMnemonic(KeyEvent.VK_S); 133 menuSort.setEnabled(false); 134 popup.add(menuSort); 135 136 ArrayList tempList = new ArrayList(); 137 for (int i = 0; i < dimension.length; i++) { 138 if (dimension[i] instanceof ReferenceDimension) { 139 tempList.add(new Integer(i)); 140 } 141 } 142 143 referenceDimension = new ReferenceDimension[tempList.size()]; 144 menuDimension = new JMenu[tempList.size()]; 145 itemSort = new JMenuItem[tempList.size()][]; 146 for (int i = 0; i < tempList.size(); i++) { 147 int j = ((Integer)(tempList.get(i))).intValue(); 148 referenceDimension[i] = (ReferenceDimension)(dimension[j]); 149 menuDimension[i] = new JMenu(definition.getDimensionDefinition()[j].getName()); 150 menuSort.add(menuDimension[i]); 151 } 152 153 itemSave = new JMenuItem("Save..."); 154 itemSave.setMnemonic(KeyEvent.VK_V); 155 itemSave.addActionListener(new ActionListener() { 156 public void actionPerformed(ActionEvent e) { 157 save(); 158 } 159 }); 160 popup.add(itemSave); 161 } 162 163 private void showPopup(MouseEvent e) { 164 mouseX = e.getX(); 165 mouseY = e.getY(); 166 Rectangle rect = e.getComponent().getBounds(); 167 Rectangle rect2 = popup.getBounds(); 168 int posX= mouseX, posY = mouseY; 169 if (mouseY+rect2.height > rect.height) 170 posY = posY - rect2.height; 171 if (mouseX+rect2.width>rect.width) 172 posX = posX - rect2.width; 173 popup.show(e.getComponent(), posX, posY); 174 } 175 176 /** 177 * Sets the definition of the visualization, called by visualization manager after the visualization is created. 178 * 179 * @param definition definition of the visualization 180 */ 181 public void setDefinition(VisualizationDefinition definition) { 182 panelConfiguration = createConfigurationPanel(); 183 184 this.definition = definition; 185 186 elementDefinition = Scene.getDataManager().getElementDefinition(definition); 187 188 dataFilter = new DataFilter[elementDefinition.length][definition.getDimensionDefinition().length][]; 189 for (int i = 0; i < dataFilter.length; i++) { 190 for (int j = 0; j < dataFilter[i].length; j++) { 191 dataFilter[i][j] = Scene.getDataManager().getDataFilter(elementDefinition[i],definition.getDimensionDefinition()[j].getProperty()); 192 for (int k = 0; k < dataFilter[i][j].length; k++) { 193 assert (((dataFilter[i][j][k].getTargetType() != -1) && (dimension[j] instanceof ReferenceDimension)) || ((dataFilter[i][j][k].getTargetType() == -1) && (dimension[j] instanceof ValueDimension))) : "Incompatible dimension type."; 194 } 195 } 196 } 197 198 subjectDefinition = elementDefinition[0]; 199 for (int i = 0; i < dimension.length; i++) { 200 dimension[i].setDataFilter(dataFilter[0][i][0]); 201 } 202 203 updateConfiguration(); 204 205 createMenu(); 206 } 207 208 /** 209 * Gets the definition of the subject. 210 * 211 * @return definition of the subject 212 */ 213 public ElementDefinition getSubjectDefinition() { 214 return subjectDefinition; 215 } 216 217 /** 218 * Configures the visualization. 219 */ 220 public void configure() { 221 if (dialog == null) { 222 createDialog(); 223 } 224 dialog.pack(); 225 Scene.getUIManager().showDialog(dialog, dialog.getWidth(), dialog.getHeight()); 226 } 227 228 /** 229 * Save visualizations as disk file 230 */ 231 public void save() { 232 BufferedImage image = new BufferedImage(panel.getWidth(), panel.getHeight(), BufferedImage.TYPE_INT_RGB); 233 panel.paint(image.getGraphics()); 234 ImageWriter writer = (ImageWriter)(ImageIO.getImageWritersByFormatName("png").next()); 235 236 JFileChooser fc = new JFileChooser(Scene.getUIManager().getLastResultDir()); 237 fc.setFileFilter(new javax.swing.filechooser.FileFilter() { 238 public String getDescription() { 239 return "PNG Files"; 240 } 241 242 public boolean accept(File f) { 243 return f.getName().substring(f.getName().lastIndexOf('.') + 1).toLowerCase().equals("png"); 244 } 245 }); 246 247 if (fc.showSaveDialog(Scene.getFrame()) == JFileChooser.APPROVE_OPTION) { 248 File file = fc.getSelectedFile(); 249 Scene.getUIManager().setLastResultDir(file.getPath()); 250 try { 251 writer.setOutput(ImageIO.createImageOutputStream(file)); 252 writer.write(image); 253 } catch (IOException e) {} 254 } 255 } 256 257 /** 258 * Creates the configuration dialog. 259 */ 260 protected void createDialog() { 261 dialog = new JDialog(Scene.getFrame(), "Configure", true); 262 263 JPanel panelTitle = new JPanel(new FlowLayout()); 264 dialog.getContentPane().add(panelTitle, BorderLayout.NORTH); 265 266 panelTitle.add(new JLabel("Title: ")); 267 268 textName = new JTextField(name, 12); 269 panelTitle.add(textName); 270 271 JPanel panelMain = new JPanel(new BorderLayout()); 272 panelMain.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Choose subject & dimensions")); 273 dialog.getContentPane().add(panelMain, BorderLayout.CENTER); 274 275 JPanel panelName = new JPanel(new GridLayout(definition.getDimensionDefinition().length + 1, 1, 5, 5)); 276 panelMain.add(panelName, BorderLayout.WEST); 277 278 panelName.add(new JLabel(" Subject: ")); 279 for (int i = 0; i < definition.getDimensionDefinition().length; i++) { 280 panelName.add(new JLabel(" " + definition.getDimensionDefinition()[i].getName() + ": ")); 281 } 282 283 JPanel panelCombo = new JPanel(new GridLayout(definition.getDimensionDefinition().length + 1, 1, 5, 5)); 284 panelMain.add(panelCombo, BorderLayout.CENTER); 285 286 comboSubject = new JComboBox(); 287 for (int i = 0; i < elementDefinition.length; i++) { 288 comboSubject.addItem(elementDefinition[i].getName()); 289 } 290 comboSubject.addActionListener(new ActionListener() { 291 public void actionPerformed(ActionEvent e) { 292 updateComboSubject(); 293 } 294 }); 295 panelCombo.add(comboSubject); 296 297 comboDimension = new JComboBox[definition.getDimensionDefinition().length]; 298 for (int i = 0; i < comboDimension.length; i++) { 299 comboDimension[i] = new JComboBox(); 300 comboDimension[i].addActionListener(new ActionListener() { 301 public void actionPerformed(ActionEvent e) { 302 updateComboDimension(); 303 } 304 }); 305 panelCombo.add(comboDimension[i]); 306 } 307 308 updateComboSubject(); 309 310 if (panelConfiguration != null) { 311 panelMain.add(panelConfiguration, BorderLayout.SOUTH); 312 } 313 314 JPanel panelButton = new JPanel(new FlowLayout()); 315 dialog.getContentPane().add(panelButton, BorderLayout.SOUTH); 316 317 JButton buttonApply = new JButton("Apply"); 318 buttonApply.addActionListener(new ActionListener() { 319 public void actionPerformed(ActionEvent e) { 320 dialogApply(); 321 } 322 }); 323 panelButton.add(buttonApply); 324 325 JButton buttonCancel = new JButton("Cancel"); 326 buttonCancel.addActionListener(new ActionListener() { 327 public void actionPerformed(ActionEvent e) { 328 dialogCancel(); 329 } 330 }); 331 panelButton.add(buttonCancel); 332 333 //************* 334 for (int i=0; i<comboSubject.getItemCount(); i++) { 335 if ((comboSubject.getItemAt(i)).equals(subjectDefinition.getName())) { 336 comboSubject.setSelectedIndex(i); 337 break; 338 } 339 } 340 for (int i=0;i<comboDimension.length;i++) { 341 for (int j =0 ; j<comboDimension[i].getItemCount();j++) { 342 if (comboDimension[i].getItemAt(j).equals(dimension[i].getDataFilter().getName())) { 343 comboDimension[i].setSelectedIndex(j); 344 break; 345 } 346 } 347 } 348 } 349 350 /** 351 * Updates the subject combo-box. 352 */ 353 private void updateComboSubject() { 354 comboSubject.setToolTipText(elementDefinition[comboSubject.getSelectedIndex()].getDescription()); 355 for (int i = 0; i < comboDimension.length; i++) { 356 comboDimension[i].removeAllItems(); 357 for (int j = 0; j < dataFilter[comboSubject.getSelectedIndex()][i].length; j++) { 358 comboDimension[i].addItem(dataFilter[comboSubject.getSelectedIndex()][i][j].getName()); 359 } 360 } 361 updateComboDimension(); 362 } 363 364 /** 365 * Updates the dimension combo-boxes. 366 */ 367 private void updateComboDimension() { 368 for (int i = 0; i < comboDimension.length; i++) { 369 if (comboDimension[i].getSelectedIndex() != -1) { 370 comboDimension[i].setToolTipText(dataFilter[comboSubject.getSelectedIndex()][i][comboDimension[i].getSelectedIndex()].getDescription()); 371 } 372 } 373 } 374 375 /** 376 * Button "Apply" is clicked. 377 */ 378 private void dialogApply() { 379 dialog.setVisible(false); 380 subjectDefinition = elementDefinition[comboSubject.getSelectedIndex()]; 381 name = textName.getText(); 382 if (name.indexOf(subjectDefinition.getName()) == -1) 383 window.setTitle(name + " - " + subjectDefinition.getName()); 384 else 385 window.setTitle(name); 386 for (int i = 0; i < dimension.length; i++) { 387 dimension[i].setDataFilter(dataFilter[comboSubject.getSelectedIndex()][i][comboDimension[i].getSelectedIndex()]); 388 if (dimension[i] instanceof ReferenceDimension) ((ReferenceDimension)dimension[i]).clearEntityMap(); 389 } 390 updateConfiguration(); 391 menuSort.setEnabled(false); 392 } 393 394 /** 395 * Button "Cancel" is clicked. 396 */ 397 private void dialogCancel() { 398 dialog.setVisible(false); 399 } 400 401 public void updateMenu() { 402 for (int i = 0; i < referenceDimension.length; i++) { 403 ArrayList comparatorList = referenceDimension[i].getComparator(); 404 itemSort[i] = new JMenuItem[comparatorList.size()]; 405 menuDimension[i].removeAll(); 406 for (int j = 0; j < itemSort[i].length; j++) { 407 itemSort[i][j] = new JMenuItem(((EntityComparator)(comparatorList.get(j))).getName()); 408 itemSort[i][j].addActionListener(new ActionListener() { 409 public void actionPerformed(ActionEvent e) { 410 selectComparator(e); 411 } 412 }); 413 menuDimension[i].add(itemSort[i][j]); 414 } 415 } 416 417 ArrayList menuOptional = createOptionalMenu(); 418 if (menuOptional == null ) return; 419 for (int i=0; i<menuOptional.size(); i++) 420 popup.add((JMenuItem)menuOptional.get(i)); 421 } 422 423 protected ArrayList createOptionalMenu() { 424 return null; 425 } 426 427 public void selectComparator(ActionEvent e) { 428 for (int i = 0; i < itemSort.length; i++) { 429 for (int j = 0; j < itemSort[i].length; j++) { 430 if (itemSort[i][j] == e.getSource()) { 431 referenceDimension[i].selectComparator(j); 432 sort(); 433 return; 434 } 435 } 436 } 437 } 438 439 protected void addPopupTrigger(Component component) { 440 component.addMouseListener(new MouseAdapter() { 441 public void mouseReleased(MouseEvent e) { 442 if (e.isPopupTrigger()) { 443 showPopup(e); 444 } 445 } 446 447 public void mousePressed(MouseEvent e) { 448 if (e.isPopupTrigger()) { 449 showPopup(e); 450 } 451 } 452 }); 453 } 454 455 public void enableSortMenu() { 456 menuSort.setEnabled(true); 457 } 458 459 /** 460 * Creates the dimensions. 461 * 462 * @return the dimensions 463 */ 464 public abstract Dimension[] createDimension(); 465 466 /** 467 * Creates available selection menu items. 468 * 469 * @return the array of menu items 470 */ 471 public abstract JMenuItem[] createSelectionMenuItem(); 472 473 /** 474 * Creates the panel. 475 * 476 * @return the panel 477 */ 478 protected abstract JPanel createPanel(); 479 480 /** 481 * Updates the configuration. 482 */ 483 protected abstract void updateConfiguration(); 484 485 /** 486 * Gets ready for receiving data. 487 */ 488 public abstract void preVisualize(); 489 490 /** 491 * Receives data. 492 * 493 * @param data the data 494 */ 495 protected abstract void receiveElement(Element element); 496 497 /** 498 * Visualizes after receiving data. 499 */ 500 public abstract void visualize(); 501 502 /** 503 * sorting the visualization with selected comparator 504 */ 505 public abstract void sort(); 506 507 /** 508 * according to user selectiong, get a data subset 509 */ 510 public abstract void makeSelection(); 511 512 /** 513 * 514 * @return a Hash map contains all current visualization's configure 515 */ 516 public HashMap getCurrentConfigure() { 517 HashMap configure = new HashMap(); 518 519 configure.put("Factory",getFactory()); 520 configure.put("Subject",subjectDefinition); 521 configure.put("Name",name); 522 configure.put("Interval", new Integer(-1)); 523 configure.put("Options", ";not using any options"); 524 525 return configure; 526 } 527 528 /** 529 * following are all interfaces needed for predefined viz 530 */ 531 public void autoUpdateConfiguration(HashMap config) { 532 533 int selectedSubjectId = -1; 534 Dimension [] predefinedDimension; 535 536 for (int i=0; i< elementDefinition.length; i++) { 537 if (elementDefinition[i].getName().equals(((ElementDefinition)config.get("Subject")).getName())) { 538 subjectDefinition = elementDefinition[i]; 539 selectedSubjectId = i; 540 break; 541 } 542 } 543 544 predefinedDimension = (Dimension[])config.get("Dimension"); 545 for (int i=0; i<dimension.length; i++) { 546 for (int j=0; j< dataFilter[selectedSubjectId][i].length;j++) { 547 if (dataFilter[selectedSubjectId][i][j].getName().equals(predefinedDimension[i].getDataFilter().getName())) { 548 dimension[i].setDataFilter(dataFilter[selectedSubjectId][i][j]); 549 break; 550 } 551 } 552 } 553 554 updateConfiguration(); 555 window.setTitle(name); 556 menuSort.setEnabled(false); 557 } 558 559 public EVolve.Window getWindow() { 560 return window; 561 } 562 563 public void setFactory(VisualizationFactory factory) { 564 this.factory = factory; 565 } 566 567 public VisualizationFactory getFactory() { 568 return factory; 569 } 570 571 public void autoSave(String path, String dataFn) { 572 BufferedImage image = new BufferedImage(panel.getWidth(), panel.getHeight(), BufferedImage.TYPE_INT_RGB); 573 panel.paint(image.getGraphics()); 574 ImageWriter writer = (ImageWriter)(ImageIO.getImageWritersByFormatName("png").next()); 575 576 try { 577 RandomAccessFile file = new RandomAccessFile((path+File.separator+ 578 dataFn.substring(dataFn.lastIndexOf(File.separator)+1,dataFn.length()-4)+".png"),"rw"); 579 writer.setOutput(ImageIO.createImageOutputStream(file)); 580 writer.write(image); 581 } catch (IOException e) { 582 System.out.println("writing file error."); 583 } 584 585 } 586 587 /** 588 * following methods are used in unify/overlap viz 589 */ 590 public abstract ReferenceDimension getLinkableDimension(int dim); 591 592 public int getVisualizationID() { 593 return linkageId; 594 } 595 596 public Dimension[] getDimension() { 597 return dimension; 598 } 599 600 public VisualizationDefinition getDefinition() { 601 return definition; 602 } 603 604 public int getxMax() { 605 return -1; 606 } 607 608 public AutoImage getImage() { 609 return null; 610 } 611 612 public void setImage(AutoImage image) { 613 return; 614 } 615 616 public void cleanup() { 617 dimension = null; 618 comboDimension = null; 619 menuDimension = null; 620 itemSort = null; 621 referenceDimension = null; 622 elementDefinition = null; 623 dataFilter = null; 624 } 625 626 protected int switchOption(boolean turn_on, int option, int add_on_option) { 627 int returnVal; 628 if (turn_on) 629 returnVal = option | add_on_option; 630 else 631 returnVal = option & ~add_on_option; 632 return returnVal; 633 } 634 }