001    /* EVolve - an Extensible Software Visualization Framework
002     * Copyright (C) 2001-2002 Qin Wang
003     *
004     * This library is free software; you can redistribute it and/or
005     * modify it under the terms of the GNU Library General Public
006     * License as published by the Free Software Foundation; either
007     * version 2 of the License, or (at your option) any later version.
008     *
009     * This library is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
012     * Library General Public License for more details.
013     *
014     * You should have received a copy of the GNU Library General Public
015     * License along with this library; if not, write to the
016     * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
017     * Boston, MA 02111-1307, USA.
018     */
019    
020    /*
021     * EVolve is distributed at http://www.sable.mcgill.ca/EVolve/
022     */
023    
024    package EVolve;
025    
026    import java.awt.*;
027    import java.awt.event.*;
028    import java.util.*;
029    import javax.swing.*;
030    import EVolve.data.Entity;
031    import EVolve.data.ReferenceLink;
032    import EVolve.data.Selection;
033    import EVolve.exceptions.EVolveException;
034    import EVolve.visualization.Visualization;
035    import EVolve.util.xmlutils.datastructures.SerializedSelection;
036    
037    public class Filter {
038        private ArrayList selection;
039        private ArrayList field;
040    
041        private final JDialog dialog;
042        private JDialog timeFrameChangeDialog;
043        private JSplitPane splitMain, splitLeft, splitLeftLower;
044        private JList listSelection, listField, listEntity;
045        private DefaultListModel modelSelection, modelField, modelEntity;
046        private JTextArea timeframeArea;
047        private JTextField textStartTime, textEndTime;
048    
049        private JPopupMenu popup;
050        private JMenuItem itemRename, itemCloneSelection, itemChangeTimeFrame;
051        private JMenuItem itemRemoveItems, itemKeepItems;
052        private int activateFieldIndex;
053    
054        public Filter() {
055            selection = new ArrayList();
056            field = new ArrayList();
057    
058            dialog = new JDialog(Scene.getFrame(), "Filter", false);
059    
060            final CardLayout cardButton = new CardLayout();
061            final JPanel panelButton = new JPanel(cardButton);
062            dialog.getContentPane().add(panelButton, BorderLayout.SOUTH);
063    
064            // selection
065            modelSelection = new DefaultListModel();
066            listSelection = new JList(modelSelection);
067            listSelection.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
068            listSelection.addMouseListener(new MouseAdapter() {
069                public void mousePressed(MouseEvent e) {
070                    updateSelection();
071                    cardButton.show(panelButton, "Selection");
072                }
073            });
074    
075            JScrollPane scrollSelection = new JScrollPane(listSelection, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
076            scrollSelection.setBackground(Color.white);
077            scrollSelection.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Selections"));
078    
079            JPanel panelSelection = new JPanel(new FlowLayout());
080            panelButton.add(panelSelection, "Selection");
081    
082            JButton buttonDeselect = new JButton("Deselect");
083            buttonDeselect.addActionListener(new ActionListener() {
084                public void actionPerformed(ActionEvent e) {
085                    listSelection.clearSelection();
086                }
087            });
088            panelSelection.add(buttonDeselect);
089    
090            JButton buttonColor = new JButton("Coloring");
091            buttonColor.addActionListener(new ActionListener() {
092                public void actionPerformed(ActionEvent e) {
093                    color();
094                }
095            });
096            panelSelection.add(buttonColor);
097    
098            JButton buttonApplyNow = new JButton("Visualize Now");
099            buttonApplyNow.addActionListener(new ActionListener() {
100                public void actionPerformed(ActionEvent e) {
101                    dialog.setVisible(false);
102                    Scene.getVisualizationManager().visualizeNow();
103                }
104            });
105            panelSelection.add(buttonApplyNow);
106    
107            JButton buttonFilter = new JButton("Decoloring");
108            buttonFilter.addActionListener(new ActionListener() {
109                public void actionPerformed(ActionEvent e) {
110                    filter();
111                }
112            });
113            panelSelection.add(buttonFilter);
114    
115            JButton buttonRemove = new JButton("Remove");
116            buttonRemove.addActionListener(new ActionListener() {
117                public void actionPerformed(ActionEvent e) {
118                    remove();
119                }
120            });
121            panelSelection.add(buttonRemove);
122    
123            JButton buttonSelectionClose = new JButton("Close");
124            buttonSelectionClose.addActionListener(new ActionListener() {
125                public void actionPerformed(ActionEvent e) {
126                    dialog.setVisible(false);
127                }
128            });
129            panelSelection.add(buttonSelectionClose);
130    
131            // field
132            modelField = new DefaultListModel();
133            listField = new JList(modelField);
134            listField.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
135            listField.addMouseListener(new MouseAdapter() {
136                public void mousePressed(MouseEvent e) {
137                    updateField();
138                    cardButton.show(panelButton, "Field");
139                }
140            });
141            listField.setEnabled(false);
142    
143            JScrollPane scrollField = new JScrollPane(listField, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
144            scrollField.setBackground(Color.white);
145            scrollField.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Fields"));
146    
147            JPanel panelField = new JPanel(new FlowLayout());
148            panelButton.add(panelField, "Field");
149    
150            JButton buttonSelectAll = new JButton("Select All");
151            buttonSelectAll.addActionListener(new ActionListener() {
152                public void actionPerformed(ActionEvent e) {
153                    selectAll();
154                }
155            });
156            panelField.add(buttonSelectAll);
157    
158            JButton buttonClearAll = new JButton("Clear All");
159            buttonClearAll.addActionListener(new ActionListener() {
160                public void actionPerformed(ActionEvent e) {
161                    clearAll();
162                }
163            });
164            panelField.add(buttonClearAll);
165    
166            JButton buttonFieldClose = new JButton("Close");
167            buttonFieldClose.addActionListener(new ActionListener() {
168                public void actionPerformed(ActionEvent e) {
169                    dialog.setVisible(false);
170                }
171            });
172            panelField.add(buttonFieldClose);
173    
174            // entity
175            modelEntity = new DefaultListModel();
176            listEntity = new JList(modelEntity);
177            listEntity.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
178            listEntity.addMouseListener(new MouseAdapter() {
179                public void mousePressed(MouseEvent e) {
180                    cardButton.show(panelButton, "Entity");
181                }
182            });
183    
184            JScrollPane scrollEntity = new JScrollPane(listEntity, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
185            scrollEntity.setBackground(Color.white);
186            scrollEntity.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Selected Entities"));
187    
188            timeframeArea = new JTextArea();
189            timeframeArea.setBackground(Color.white);
190            timeframeArea.append("   ");
191            timeframeArea.setEditable(false);
192    
193            JScrollPane scrollTimeFrame = new JScrollPane(timeframeArea,ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
194            scrollTimeFrame.setBackground(Color.white);
195            scrollTimeFrame.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "Selected Time Frame"));
196    
197            JPanel panelEntity = new JPanel(new FlowLayout());
198            panelButton.add(panelEntity, "Entity");
199    
200            JButton buttonRemoveSelected = new JButton("Remove Selected");
201            buttonRemoveSelected.addActionListener(new ActionListener() {
202                public void actionPerformed(ActionEvent e) {
203                    removeSelected();
204                }
205            });
206            panelEntity.add(buttonRemoveSelected);
207    
208            JButton buttonRemoveUnselected = new JButton("Remove Unselected");
209            buttonRemoveUnselected.addActionListener(new ActionListener() {
210                public void actionPerformed(ActionEvent e) {
211                    removeUnselected();
212                }
213            });
214            panelEntity.add(buttonRemoveUnselected);
215    
216            JButton buttonEntityClose = new JButton("Close");
217            buttonEntityClose.addActionListener(new ActionListener() {
218                public void actionPerformed(ActionEvent e) {
219    
220                    dialog.setVisible(false);
221                }
222            });
223            panelEntity.add(buttonEntityClose);
224    
225            splitLeftLower = new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollField, scrollTimeFrame);
226            splitLeftLower.setDividerSize(2);
227            splitLeft = new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollSelection, splitLeftLower);
228            splitLeft.setDividerSize(2);
229    
230            splitMain = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, splitLeft, scrollEntity);
231            splitMain.setDividerSize(2);
232            dialog.getContentPane().add(splitMain, BorderLayout.CENTER);
233    
234            createMenu();
235            addPopupTrigger(listSelection);
236        }
237    
238        public void load() {
239            dialog.pack();
240            Scene.getUIManager().showDialog(dialog, Toolkit.getDefaultToolkit().getScreenSize().width / 2, Toolkit.getDefaultToolkit().getScreenSize().height * 3 / 4);
241            splitMain.setDividerLocation(0.5);
242            splitLeft.setDividerLocation(0.5);
243            splitLeftLower.setDividerLocation(0.5);
244            updateSelection();
245        }
246    
247        public void addSelection(Selection selection) {
248            this.selection.add(selection);
249            update();
250    
251            listSelection.setSelectedIndex(this.selection.size() - 1);
252            updateSelection();
253    
254            if (!dialog.isVisible()) {
255                load();
256            }
257        }
258    
259        private void update() {
260            modelSelection.removeAllElements();
261            for (int i = 0; i < selection.size(); i++) {
262                Selection s = (Selection)(selection.get(i));
263                if (s.getColor() == null) {
264                    modelSelection.addElement("* " + s.getName() + " (" + Scene.getDataManager().getElementDefinition()[((Selection)(selection.get(i))).getEntityType()].getName() + ")");
265                } else {
266                    modelSelection.addElement("<html><font color=#" + getColorHex(s.getColor()) + ">" + s.getName() + " (" + Scene.getDataManager().getElementDefinition()[((Selection)(selection.get(i))).getEntityType()].getName() + ")</font></html>");
267                }
268            }
269        }
270    
271        private void updateTimeFrameInfo() {
272            timeframeArea.replaceRange(null,0,timeframeArea.getText().length());
273            Selection selected = getActiveSelection();
274            if (selected != null) {
275                String info = "Start Event no.(overall): " + selected.getStart() + "\n";
276                info = info + "End Event no.(overall): " + selected.getEnd() + "\n";
277                //String info = "";
278                if (selected.getStartTime() != -1) {
279                    info = info + "Start Time: " + selected.getStartTime() + "\n";
280                    info = info + "End Time: " + selected.getEndTime() + "\n";
281                } else {
282                    info = info + "Start Time: begin of the trace\n";
283                    info = info + "End Time: end of the trace\n";
284                }
285                timeframeArea.append(info);
286            }
287    
288        }
289    
290        private String getColorHex(Color color) {
291            String returnVal = Integer.toHexString(color.getBlue());
292            if (returnVal.length() < 2) {
293                returnVal = "0" + returnVal;
294            }
295            returnVal = Integer.toHexString(color.getGreen()) + returnVal;
296            if (returnVal.length() < 4) {
297                returnVal = "0" + returnVal;
298            }
299            returnVal = Integer.toHexString(color.getRed()) + returnVal;
300            if (returnVal.length() < 6) {
301                returnVal = "0" + returnVal;
302            }
303    
304            return returnVal;
305        }
306    
307        public void updateSelection() {
308            if (listSelection.getSelectedIndex() != -1) {
309                modelField.removeAllElements();
310                modelEntity.removeAllElements();
311    
312                Selection s = (Selection)(selection.get(listSelection.getSelectedIndex()));
313    
314                for (int i = 0; i < s.getSelected().length; i++) {
315                    modelEntity.addElement(s.getSelected()[i].getName());
316                }
317    
318                ArrayList vizType = Scene.getVisualizationManager().getVisualizationType();
319                field.clear();
320                ReferenceLink[] link = Scene.getDataManager().getReferenceLink();
321    
322                activateFieldIndex = -1;
323                Selection selection = getActiveSelection();
324                for (int i = 0; i < link.length; i++) {
325                    /*if ((vizType.indexOf("" + link[i].getSourceType() + "") != -1) && (link[i].getTargetType() == s.getEntityType())) {
326                        field.add(link[i]);
327                    }*/
328                    if (vizType.indexOf("" + link[i].getSourceType() + "") != -1) {
329                        if (Scene.getDataManager().getElementDefinition()[link[i].getSourceType()].getType()==selection.getSourceType()) {
330                            /*if ((link[i].getTargetType() == s.getEntityType())&&(activateFieldIndex == -1))
331                                activateFieldIndex = field.size();*/
332                            if (link[i].getName().equals(s.getEntityCategory()))
333                                activateFieldIndex = field.size();
334                            field.add(link[i]);
335                        }
336                    }
337                }
338    
339                for (int i = 0; i < field.size(); i++) {
340                    modelField.addElement(((ReferenceLink)(field.get(i))).getName() + " (" + Scene.getDataManager().getElementDefinition()[((ReferenceLink)(field.get(i))).getSourceType()].getName() + ")");
341                }
342    
343                /*ArrayList selected = new ArrayList();
344                for (int i = 0; i < s.getLink().length; i++) {
345                    if (field.indexOf(s.getLink()[i]) != -1) {
346                        selected.add(new Integer(field.indexOf(s.getLink()[i])));
347                    }
348                }
349                selected.add(new Integer(activateFieldIndex));
350    
351                int[] selectedLink = new int[selected.size()];
352                for (int i = 0; i < selectedLink.length; i++) {
353                    selectedLink[i] = ((Integer)(selected.get(i))).intValue();
354                }
355                listField.setSelectedIndices(selectedLink);*/
356                listField.setSelectedIndex(activateFieldIndex);
357    
358                updateTimeFrameInfo();
359                updateField();
360            }
361        }
362    
363        private void updateField() {
364            if (listSelection.getSelectedIndex() != -1) {
365                ReferenceLink[] newLink = new ReferenceLink[listField.getSelectedIndices().length];
366                for (int i = 0; i < newLink.length; i++) {
367                    newLink[i] = (ReferenceLink)(field.get(listField.getSelectedIndices()[i]));
368                }
369    
370                Selection s = (Selection)(selection.get(listSelection.getSelectedIndex()));
371                s.setLink(newLink);
372            }
373        }
374    
375        private void updateEntity() {
376            if (listSelection.getSelectedIndex() != -1) {
377                modelEntity.removeAllElements();
378    
379                Selection s = (Selection)(selection.get(listSelection.getSelectedIndex()));
380                for (int i = 0; i < s.getSelected().length; i++) {
381                    modelEntity.addElement(s.getSelected()[i].getName());
382                }
383            }
384        }
385    
386        private void color() {
387            if (listSelection.getSelectedIndex() != -1) {
388                Color newColor = JColorChooser.showDialog(Scene.getFrame(), "Choose a color", Color.black);
389                if (newColor != null) {
390                    int selected = listSelection.getSelectedIndex();
391                    ((Selection)(selection.get(selected))).setColor(newColor);
392                    update();
393    
394                    listSelection.setSelectedIndex(selected);
395                    updateSelection();
396                }
397            }
398        }
399    
400        private void filter() {
401            if (listSelection.getSelectedIndex() != -1) {
402                int selected = listSelection.getSelectedIndex();
403                ((Selection)(selection.get(selected))).setColor(null);
404                update();
405    
406                listSelection.setSelectedIndex(selected);
407                updateSelection();
408            }
409        }
410    
411        private void remove() {
412            if (listSelection.getSelectedIndex() != -1) {
413                selection.remove(listSelection.getSelectedIndex());
414                update();
415            }
416        }
417    
418        private void selectAll() {
419            /*if (listSelection.getSelectedIndex() != -1) {
420                int[] all = new int[modelField.size()];
421                for (int i = 0; i < all.length; i++) {
422                    all[i] = i;
423                }
424                listField.setSelectedIndices(all);
425                updateField();
426            }*/
427        }
428    
429        private void clearAll() {
430            if (listSelection.getSelectedIndex() != -1) {
431                listField.setSelectedIndices(new int[0]);
432                updateField();
433            }
434        }
435    
436        private void removeSelected() {
437            if (listSelection.getSelectedIndex() != -1) {
438                Selection s = (Selection)(selection.get(listSelection.getSelectedIndex()));
439                int[] index = listEntity.getSelectedIndices();
440                Entity[] newEntity = new Entity[s.getSelected().length - index.length];
441    
442                int j = 0;
443                int k = 0;
444                for (int i = 0; i < newEntity.length; i++) {
445                    while ((j < index.length) && (index[j] == k)) {
446                        j++;
447                        k++;
448                    }
449                    newEntity[i] = s.getSelected()[k];
450                    k++;
451                }
452                s.setSelected(newEntity);
453                updateEntity();
454            }
455        }
456    
457        private void removeUnselected() {
458            if (listSelection.getSelectedIndex() != -1) {
459                Selection s = (Selection)(selection.get(listSelection.getSelectedIndex()));
460                int[] index = listEntity.getSelectedIndices();
461                Entity[] newEntity = new Entity[index.length];
462    
463                for (int i = 0; i < newEntity.length; i++) {
464                    newEntity[i] = s.getSelected()[index[i]];
465                }
466                s.setSelected(newEntity);
467                updateEntity();
468            }
469        }
470    
471        public Selection[] getSelection() {
472            Selection[] returnVal = new Selection[selection.size()];
473            for (int i = 0; i < returnVal.length; i++) {
474                returnVal[i] = (Selection)(selection.get(i));
475            }
476    
477            return returnVal;
478        }
479    
480        public Selection getActiveSelection() {
481            int selectedIndex = listSelection.getSelectedIndex();
482    
483            if (selectedIndex == -1) return null;
484    
485            return (Selection)selection.get(selectedIndex);
486        }
487    
488        public int getSelectedIndex() {
489            return listSelection.getSelectedIndex();
490        }
491    
492        public void loadSelection(ArrayList selections, int selectedIndex) throws EVolveException{
493            Selection newSelection = null;
494            long start, end, startTime, endTime;
495            int sourceType, entityType;
496            String entityCategory;
497            long selected[];
498            ArrayList IDs,timeMap;
499            String currentName;
500            StringTokenizer token;
501            Color color;
502    
503            this.selection.clear();
504    
505            try {
506                for (int i=0; i<selections.size(); i++) {
507                    SerializedSelection data = (SerializedSelection)selections.get(i);
508                    timeMap = null;
509    
510                    currentName = data.CurrentSelectionName;
511                    start = Long.parseLong(data.StartEventNo);
512                    end = Long.parseLong(data.EndEventNo);
513                    startTime = Long.parseLong(data.StartTime);
514                    endTime = Long.parseLong(data.EndTime);
515    
516                    token = new StringTokenizer(data.TimeMap,",");
517                    while (token.hasMoreTokens()) {
518                        if (timeMap == null) timeMap = new ArrayList();
519                        long[] value = new long[2];
520                        value[0] = Long.parseLong(token.nextToken());
521                        value[1] = Long.parseLong(token.nextToken());
522                        timeMap.add(value);
523                    }
524                    sourceType = Integer.parseInt(data.SourceType);
525                    entityType = Integer.parseInt(data.EntityType);
526                    entityCategory = data.EntityCategory;
527                    color = null;
528                    if ((data.Color != null)&&(data.Color.length() > 0))
529                        color = new Color(Integer.parseInt(data.Color));
530                    token = new StringTokenizer(data.SelectedEntities,",");
531    
532                    IDs = new ArrayList();
533                    while (token.hasMoreTokens()) {
534                        IDs.add(token.nextToken());
535                    }
536                    selected = new long[IDs.size()];
537                    for (int k=0; k<selected.length; k++)
538                        selected[k] = Long.parseLong((String)IDs.get(k));
539    
540                    newSelection = new Selection(currentName,sourceType,entityType,entityCategory,selected,start,end,timeMap);
541                    newSelection.setStartTime(startTime);
542                    newSelection.setEndTime(endTime);
543                    newSelection.setColor(color);
544    
545                    this.selection.add(newSelection);
546                    update();
547                }
548                if (selectedIndex != -1)
549                    listSelection.setSelectedIndex(selectedIndex);
550                updateSelection();
551            } catch (NumberFormatException e) {
552                throw new EVolveException("Selection data is invalid, expect:numerical, found:string.");
553            }
554        }
555    
556        public ArrayList getSelections() {
557            ArrayList list = new ArrayList();
558            Selection currentSelection;
559            Entity[] entities;
560            ArrayList timeMap;
561    
562            for (int i=0; i<selection.size(); i++) {
563                SerializedSelection data = new SerializedSelection();
564                timeMap = null;
565                currentSelection = (Selection)selection.get(i);
566    
567                data.CurrentSelectionName = currentSelection.getName();
568                data.StartEventNo = String.valueOf(currentSelection.getStart());
569                data.EndEventNo = String.valueOf(currentSelection.getEnd());
570                data.StartTime = String.valueOf(currentSelection.getStartTime());
571                data.EndTime = String.valueOf(currentSelection.getEndTime());
572    
573                timeMap = currentSelection.getTimeMap();
574                if (timeMap != null) {
575                    data.TimeMap = new String();
576                    for (int j=0; j<timeMap.size(); j++) {
577                        long[] value = (long[])timeMap.get(j);
578                        data.TimeMap = data.TimeMap + String.valueOf(value[0])+","+String.valueOf(value[1])+",";
579                    }
580                }
581                data.SourceType = String.valueOf(currentSelection.getSourceType());
582                data.EntityType = String.valueOf(currentSelection.getEntityType());
583                data.EntityCategory = currentSelection.getEntityCategory();
584                if (currentSelection.getColor() != null)
585                    data.Color = String.valueOf(currentSelection.getColor().getRGB());
586                entities = currentSelection.getSelected();
587                data.SelectedEntities = new String();
588                for (int j=0; j<entities.length; j++) {
589                    data.SelectedEntities = data.SelectedEntities + String.valueOf(entities[j].getId())+",";
590                }
591                list.add(data);
592            }
593    
594            return list;
595        }
596    
597        public Selection getNewestSelection() {
598            return (Selection)selection.get(selection.size()-1);
599        }
600    
601        public void selectWithRegExp() {
602            int selectionNumber = selection.size();
603    
604            Visualization viz = Scene.getVisualizationManager().getActiveVisualization();
605    
606            if (viz == null) return;
607    
608            viz.makeSelection();
609    
610            if (selection.size() > selectionNumber) {
611                for (int i=selectionNumber; i<selection.size(); i++) {
612                    String patterns = JOptionPane.showInputDialog(Scene.getFrame(),
613                                      "Input pattern expression(s).\n(seperated with \";\")");
614                    if (patterns != null) {
615                        patterns = generateRegExp(patterns);
616                        Selection added = (Selection)selection.get(i);
617                        added.filterEntities(patterns,true);
618                    }
619                }
620                updateSelection();
621            }
622        }
623    
624        private String generateRegExp(String inputs) {
625            String returnVal = "";
626            StringTokenizer token = new StringTokenizer(inputs+";",";");
627            while (token.hasMoreTokens()) {
628                String input = token.nextToken();
629                for (int i=0; i<input.length(); i++) {
630                    char aChar = input.charAt(i);
631                    switch (aChar) {
632                        case '*':
633                            returnVal = returnVal + ".{1,}";
634                            break;
635                        case '.':
636                            returnVal += "/{1}";
637                            break;
638                        case '?':
639                            returnVal += '.';
640                            break;
641                        default:
642                            returnVal += aChar;
643                            break;
644                    }
645                }
646                returnVal += ';';
647            }
648            return returnVal;
649        }
650    
651        private void createMenu() {
652            popup = new JPopupMenu();
653    
654            itemRename = new JMenuItem("Rename Selection ...");
655            itemRename.setMnemonic(KeyEvent.VK_R);
656            itemRename.addActionListener(new ActionListener() {
657                public void actionPerformed(ActionEvent e) {
658                    Selection selected = getActiveSelection();
659                    if (selected != null) {
660                        String newName = JOptionPane.showInputDialog(selected.getName());
661                        selected.setName(newName);
662                        update();
663                    }
664                }
665            });
666            popup.add(itemRename);
667    
668            itemCloneSelection = new JMenuItem("Clone Current Selection");
669            itemCloneSelection.setMnemonic(KeyEvent.VK_C);
670            itemCloneSelection.addActionListener(new ActionListener() {
671                public void actionPerformed(ActionEvent e) {
672                    Selection selected = getActiveSelection();
673                    if (selected != null) {
674                        Selection newSelection = (Selection)selected.clone();
675                        addSelection(newSelection);
676                    }
677                }
678            });
679            popup.add(itemCloneSelection);
680    
681            itemChangeTimeFrame = new JMenuItem("Change Time Frame");
682            itemChangeTimeFrame.setMnemonic(KeyEvent.VK_C);
683            itemChangeTimeFrame.addActionListener(new ActionListener() {
684                public void actionPerformed(ActionEvent e) {
685                    Selection selected = getActiveSelection();
686                    if (selected != null) {
687                        createChangeTimeDialog(selected);
688                    }
689                }
690            });
691            popup.add(itemChangeTimeFrame);
692    
693            itemRemoveItems = new JMenuItem("Remove Entities ...");
694            itemRemoveItems.setMnemonic(KeyEvent.VK_R);
695            itemRemoveItems.addActionListener(new ActionListener() {
696                public void actionPerformed(ActionEvent e) {
697                    filterEntities(false);
698                }
699            });
700            popup.add(itemRemoveItems);
701    
702            itemKeepItems = new JMenuItem("Remove All Entities Except ...");
703            itemKeepItems.setMnemonic(KeyEvent.VK_E);
704            itemKeepItems.addActionListener(new ActionListener() {
705                public void actionPerformed(ActionEvent e) {
706                    filterEntities(true);
707                }
708            });
709            popup.add(itemKeepItems);
710        }
711    
712        private void addPopupTrigger(Component component) {
713    
714            component.addMouseListener(new MouseAdapter() {
715                public void mouseReleased(MouseEvent e) {
716                    if (e.isPopupTrigger()) {
717                        showPopup(e);
718                    }
719                }
720    
721                public void mousePressed(MouseEvent e) {
722                    if (e.isPopupTrigger()) {
723                        showPopup(e);
724                    }
725                }
726            });
727        }
728    
729        private void showPopup(MouseEvent e) {
730            int mouseX = e.getX();
731            int mouseY = e.getY();
732            Rectangle rect = e.getComponent().getBounds();
733            Rectangle rect2 = popup.getBounds();
734            int posX= mouseX, posY = mouseY;
735            if (mouseY+rect2.height > rect.height)
736                posY = posY - rect2.height;
737            if (mouseX+rect2.width>rect.width)
738                posX = posX - rect2.width;
739                popup.show(e.getComponent(), posX, posY);
740        }
741    
742        private void createChangeTimeDialog(Selection selected) {
743    
744            if (timeFrameChangeDialog == null) {
745                textStartTime = new JTextField(String.valueOf(selected.getStartTime()));
746                textEndTime = new JTextField(String.valueOf(selected.getEndTime()));
747                timeFrameChangeDialog = new JDialog(dialog,"Change Time Frame",true);
748    
749                Box boxMain = new Box(BoxLayout.Y_AXIS);
750                boxMain.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(),
751                        "Choose range"));
752                timeFrameChangeDialog.getContentPane().add(boxMain,BorderLayout.CENTER);
753    
754                boxMain.add(new JLabel("Start time:"));
755                boxMain.add(textStartTime);
756                boxMain.add(new JLabel("End time:"));
757                boxMain.add(textEndTime);
758    
759                timeFrameChangeDialog.getContentPane().add(boxMain, BorderLayout.CENTER);
760    
761                JPanel panelButton = new JPanel(new FlowLayout());
762                timeFrameChangeDialog.getContentPane().add(panelButton, BorderLayout.SOUTH);
763    
764                JButton buttonApply = new JButton("Ok");
765                buttonApply.addActionListener(new ActionListener() {
766                    public void actionPerformed(ActionEvent e) {
767                        Selection selected = getActiveSelection();
768                        if (selected != null) {
769                            try {
770                                long start = Long.parseLong(textStartTime.getText());
771                                long end = Long.parseLong(textEndTime.getText());
772                                selected.changeTimeFrame(start,end);
773                                updateTimeFrameInfo();
774                                timeFrameChangeDialog.setVisible(false);
775                            } catch (NumberFormatException e1) {
776                                Scene.showErrorMessage("Only numbers are allowed.");
777                            }
778                        }
779                    }
780                });
781                panelButton.add(buttonApply);
782    
783                JButton buttonCancel = new JButton("Cancel");
784                buttonCancel.addActionListener(new ActionListener() {
785                    public void actionPerformed(ActionEvent e) {
786                        timeFrameChangeDialog.setVisible(false);
787                    }
788                });
789                panelButton.add(buttonCancel);
790                timeFrameChangeDialog.pack();
791            } else {
792                textStartTime.setText(String.valueOf(selected.getStartTime()));
793                textEndTime.setText(String.valueOf(selected.getEndTime()));
794            }
795    
796            Scene.getUIManager().showDialog(timeFrameChangeDialog, timeFrameChangeDialog.getWidth(), timeFrameChangeDialog.getHeight());
797        }
798    
799        private void filterEntities(boolean keepMatched) {
800            int selected = listSelection.getSelectedIndex();
801            if (selected == -1) return;
802            String patterns = JOptionPane.showInputDialog(Scene.getFrame(),
803                              "Input pattern expression(s).\n(seperated with \";\")");
804            if (patterns != null) {
805                patterns = generateRegExp(patterns);
806                Selection tobeChanged = (Selection)selection.get(selected);
807                tobeChanged.filterEntities(patterns, keepMatched);
808            }
809            updateSelection();
810        }
811    
812    }