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 }