001    /*
002     * CRIMSON
003     * Copyright (c) 2006, Stephen Fisher, Susan Davidson, and Junhyong Kim, 
004     * University of Pennsylvania.
005     *
006     * This program is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU General Public License as
008     * published by the Free Software Foundation; either version 2 of the
009     * License, or (at your option) any later version.
010     *
011     * This program is distributed in the hope that it will be useful, but
012     * WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * General Public License for more details.
015     *
016     * You should have received a copy of the GNU General Public License
017     * along with this program; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019     * 02110-1301 USA.
020     *
021     * @(#)QueryEditor.java
022     */
023    
024    package edu.upenn.crimson.gui;
025    
026    import edu.upenn.crimson.*;
027    import edu.upenn.crimson.io.*;
028    import java.awt.*;
029    import java.awt.event.*;
030    import javax.swing.*;
031    import javax.swing.event.*;
032    import javax.swing.border.Border;
033    import javax.swing.text.*;
034    import java.util.StringTokenizer;
035    import java.util.HashSet;
036    import java.util.ArrayList;
037    import java.util.Arrays;
038    import java.util.Iterator;
039    import java.util.Collection;
040    import java.sql.*;
041    
042    /**
043     * This is a graphical query editor.
044     *
045     * @author  Stephen Fisher
046     * @version $Id: QueryEditor.java,v 1.41 2007/05/18 20:49:22 fisher Exp $
047     */
048    
049    
050    public class QueryEditor extends JFrame {
051             /** 
052              * This is the total number of leaves that will be displayed in
053              * the leaf list for the user to manually select.
054              */
055             private final long MAX_LEAVES = 100000;
056    
057             /** 
058              * This is a determined by the random number generator used in
059              * randomselect. 
060              */
061             private final long MAX_SEED = 900000000L;
062    
063             private String[] LEAF_SELECTION = { "Select All", "Random Selection", 
064                                                                                                             "Select by Temp Depth (dist)", "Select by Temp Depth (weighted)", 
065                                                                                                             "Select by Level (dist)", "Select by Level (weighted)", "Manual Selection" };
066             private String[] SEQUENCE_SELECTION = { "Select All", "Random Codon Selection", "Random Base Pair Selection", 
067                                                                                                                      "Manual Codon Selection", "Manual Base Pair Selection", "Select None" };
068             
069             private QueryEditor thisFrame;
070             
071             private Query query = null;
072             private Tree tree = null;
073             private JComboBox treeCB;
074             private JLabel treePartitionsL = new JLabel();
075             private JLabel treeLeavesL = new JLabel();
076             private JLabel treeMaxTempDepthL = new JLabel();
077             private JButton treeTempDepthB;
078             private JLabel treeMaxLevelL = new JLabel();
079             private JButton treeLevelB;
080             private JLabel treeLengthL = new JLabel();
081             
082             private JComboBox leafCB;
083             private JComboBox sequenceCB;
084             
085             private JSpinner numLeavesS;
086             private SpinnerNumberModel numLeavesSM;
087             private JSpinner tempDepthS;
088             private SpinnerNumberModel tempDepthSM;
089             private JSpinner levelS;
090             private SpinnerNumberModel levelSM;
091             public JList leafL = new JList();
092    
093             private JSpinner numPositionsS;
094             private SpinnerNumberModel numPositionsSM;
095             private int maxPositions;  // this will change for bp or codon selections
096             private JTextField positionTF = new JTextField();
097             private JList partitionsL = new JList();
098             private JButton selectAllB;
099             private JButton unselectAllB;
100             private JButton selectModelB;
101             private JButton unselectModelB;
102             
103             private JTextField seedTF = new JTextField(10);
104    
105             // default values for running query
106             private String file;
107             private boolean incSequence;
108             private int repeat;
109    
110             public QueryEditor(Query queryObj) {
111                      this(queryObj, "", false, 1);
112             }
113    
114             public QueryEditor(Query queryObj, String default_file, 
115                                                              boolean default_incSequence, int default_repeat) {
116                      super("Query Editor");
117                      
118                      // keep pointer to self so can 'dispose' Frame below
119                      thisFrame = this;
120                      
121                      setDefaultCloseOperation(DISPOSE_ON_CLOSE);
122                      
123                      if (queryObj == null) {
124                                    CrimsonUtils.printError("Can not edit null query.");
125                                    thisFrame.dispose();
126                                    return;
127                      }
128                      this.query = queryObj;
129    
130                      // *************************************************
131                      // STORE QUERYDIALOG DEFAULTS
132                      this.file = default_file;
133                      this.incSequence = default_incSequence;
134                      this.repeat = default_repeat;
135                      // END STORE QUERYDIALOG DEFAULTS
136                      // *************************************************
137    
138                      Border emptyBorder = BorderFactory.createEmptyBorder(5,5,5,5);
139                      Border loweredBorder = BorderFactory.createLoweredBevelBorder();
140                      Border etchedBorder = BorderFactory.createEtchedBorder();
141                      Border etchedPadBorder5 = 
142                                    BorderFactory.createCompoundBorder(etchedBorder, emptyBorder);
143                      //              Border loweredPadBorder5 = BorderFactory.createCompoundBorder(loweredBorder, emptyBorder);
144                      
145                      // *************************************************
146                      // TREE INFO SETUP
147                      JPanel treeP = new JPanel(new BorderLayout());
148                      JPanel treeCtrlP = new JPanel(new GridLayout(0,1,0,5));
149                      treeP.setBorder(BorderFactory.createTitledBorder(etchedPadBorder5, 
150                                                                                                                                                            " Tree Selection "));
151                      
152                      treeCB = new JComboBox(ObjectHandles.getTreeList());
153                      treeCB.setBorder(loweredBorder);
154                      treeCB.setEditable(false);
155                      treeCB.addActionListener(new ActionListener() {
156                                             public void actionPerformed(ActionEvent e) {
157                                                      String treeID = (String) ((JComboBox) e.getSource()).getSelectedItem();
158                                                      if (CrimsonUtils.isEmpty(treeID)) {
159                                                                    tree = null;
160                                                                    
161                                                                    treePartitionsL.setText("");
162                                                                    treeLeavesL.setText("");
163                                                                    treeMaxTempDepthL.setText("");
164                                                                    treeMaxLevelL.setText("");
165                                                                    treeLengthL.setText("");
166                                                                    
167                                                                    Object[] blank = { };
168                                                                    leafL.setListData(blank);
169                                                                    partitionsL.setListData(blank);
170                                                                    maxPositions = 0;
171    
172                                                                    // disable selection buttons
173                                                                    selectAllB.setEnabled(false);
174                                                                    unselectAllB.setEnabled(false);
175                                                                    selectModelB.setEnabled(false);
176                                                                    unselectModelB.setEnabled(false);
177    
178                                                      } else {
179                                                                    tree = ObjectHandles.getTree(treeID);
180    
181                                                                    treePartitionsL.setText(" " + tree.getNumPartitions());
182                                                                    treeLeavesL.setText(" " + tree.getNumLeaves());
183                                                                    treeMaxTempDepthL.setText(" " + tree.getMaxTempDepth());
184                                                                    treeMaxLevelL.setText(" " + tree.getMaxLevel());
185                                                                    treeLengthL.setText(" " + tree.getLength());
186                                                                    
187                                                                    // update numLeaves spinner bounds, bounded by tree.getNumLeaves
188                                                                    Object savedVal = numLeavesS.getValue();
189                                                                    int inc = tree.getNumLeaves() / 20;
190                                                                    numLeavesSM = new SpinnerNumberModel(0, 0, tree.getNumLeaves(), (inc == 0) ? 1 : inc);
191                                                                    numLeavesS.setModel(numLeavesSM);
192                                                                    if (numLeavesSM.getMaximum().compareTo(savedVal) == -1)
193                                                                             savedVal = new Integer(tree.getNumLeaves());
194                                                                    numLeavesS.setValue(savedVal);
195                                                                    
196                                                                    // update tempDepth spinner bounds, bounded by tree.maxTempDepth
197                                                                    savedVal = tempDepthS.getValue();
198                                                                    tempDepthSM = new SpinnerNumberModel(0.0, 0.0, tree.getMaxTempDepth(), 
199                                                                                                                                                                     tree.getMaxTempDepth() / 20.0);
200                                                                    tempDepthS.setModel(tempDepthSM);
201                                                                    if (tempDepthSM.getMaximum().compareTo(savedVal) == -1)
202                                                                             savedVal = new Double(tree.getMaxTempDepth());
203                                                                    tempDepthS.setValue(savedVal);
204                                                                    
205                                                                    // update level spinner bounds, bounded by tree.maxLevel
206                                                                    savedVal = levelS.getValue();
207                                                                    inc = tree.getMaxLevel() / 20;
208                                                                    levelSM = new SpinnerNumberModel(0, 0, tree.getMaxLevel(), (inc == 0) ? 1 : inc);
209                                                                    levelS.setModel(levelSM);
210                                                                    if (levelSM.getMaximum().compareTo(savedVal) == -1)
211                                                                             savedVal = new Integer(tree.getMaxLevel());
212                                                                    levelS.setValue(savedVal);
213                                                                    
214                                                                    // start with a blank list
215                                                                    Object[] blank = { };
216                                                                    leafL.setListData(blank);
217                                                                    // if manual selection and the editor is
218                                                                    // visible, then add leaves
219                                                                    //                                                              if ((leafCB.getSelectedIndex() == 6) && isVisible()) {
220                                                                    if (leafCB.getSelectedIndex() == 6) {
221                                                                             if (tree.getNumLeaves() < MAX_LEAVES) {
222                                                                                      // if manual leaf selection and tree hasn't
223                                                                                      // been built, then give the user the option
224                                                                                      // to build the tree
225                                                                                      if (TreeUtils.isTreeBuilt(tree)) {
226                                                                                                    if (tree.getNumLeaves() > 0) {
227                                                                                                             Collection obj = tree.getLeaves();
228                                                                                                             if (obj != null) leafL.setListData(obj.toArray());
229                                                                                                    }
230                                                                                      }
231                                                                             } else {
232                                                                                      String msg = "Too many leaves to display in the leaf "; 
233                                                                                      msg += "selection \nlist. Thus the user must manually select ";
234                                                                                      msg += "leaves from the command \nline. To do this ";
235                                                                                      msg += "use the query object's \"setLeaves()\" method.";
236                                                                                      CrimsonUtils.printMsg(msg, CrimsonUtils.WARNING);
237                                                                             }
238                                                                    }
239    
240                                                                    // start with a blank list
241                                                                    partitionsL.setListData(blank);
242                                                                    if (tree.getNumPartitions() > 0) {
243                                                                             Collection obj = tree.getPartitions();
244                                                                             if (obj != null) partitionsL.setListData(obj.toArray());
245                                                                    }
246    
247                                                                    // as long as the sequence selection isn't
248                                                                    // "manual", re-enable the partition selection
249                                                                    // buttons
250                                                                    if (sequenceCB.getSelectedIndex() < 3) {
251                                                                             selectAllB.setEnabled(true);
252                                                                             unselectAllB.setEnabled(true);
253                                                                             selectModelB.setEnabled(true);
254                                                                             unselectModelB.setEnabled(true);
255                                                             
256                                                                             if (sequenceCB.getSelectedIndex() == 1) {
257                                                                                      // codon position selection
258                                                                                      maxPositions = tree.getLength() / 3;
259                                                                             } else if (sequenceCB.getSelectedIndex() == 2) {
260                                                                                      // base pair position selection
261                                                                                      maxPositions = tree.getLength();
262                                                                             }
263                                                                             updateNumPositionsSM();
264                                                                    }
265                                                      }
266                                             }
267                                    });
268                      treeCtrlP.add(new JLabel("Tree:"));
269                      treeCtrlP.add(treeCB);
270                      
271                      // number of partitions
272                      treeCtrlP.add(new JLabel("Num Partitions:"));
273                      treePartitionsL.setBorder(loweredBorder);
274                      treeCtrlP.add(treePartitionsL);
275                      
276                      // number of leaves
277                      treeCtrlP.add(new JLabel("Num Leaves:"));
278                      treeLeavesL.setBorder(loweredBorder);
279                      treeCtrlP.add(treeLeavesL);
280                      
281                      // tempDepthThresh
282                      treeCtrlP.add(new JLabel("Max Temporal Depth:"));
283                      JPanel maxTempDepthP = new JPanel(new GridLayout(1,0,5,0));
284                      treeTempDepthB = new JButton("View Distribution");
285                      treeTempDepthB.setToolTipText("View the distribution of leaves for a specified temporal depth.");
286                      treeTempDepthB.addActionListener(new ActionListener() {
287                                             public void actionPerformed(ActionEvent e) {
288                                                      // tree needs to be built in order to compute the
289                                                      // distribution
290                                                      if (! tree.isBuilt()) tree.buildTree();
291                                                      new ViewDistributePanel(tree, 0);
292                                             }
293                                    });
294                      treeMaxTempDepthL.setBorder(loweredBorder);
295                      maxTempDepthP.add(treeMaxTempDepthL);
296                      maxTempDepthP.add(treeTempDepthB);
297                      treeCtrlP.add(maxTempDepthP);
298                      
299                      // levelThresh
300                      treeCtrlP.add(new JLabel("Max Level:"));
301                      JPanel maxLevelP = new JPanel(new GridLayout(1,0,5,0));
302                      treeLevelB = new JButton("View Distribution");
303                      treeLevelB.setToolTipText("View the distribution of leaves for a specified level.");
304                      treeLevelB.addActionListener(new ActionListener() {
305                                             public void actionPerformed(ActionEvent e) {
306                                                      // tree needs to be built in order to compute the
307                                                      // distribution
308                                                      if (! tree.isBuilt()) tree.buildTree();
309                                                      new ViewDistributePanel(tree, 1);
310                                             }
311                                    });
312                      treeMaxLevelL.setBorder(loweredBorder);
313                      maxLevelP.add(treeMaxLevelL);
314                      maxLevelP.add(treeLevelB);
315                      treeCtrlP.add(maxLevelP);
316                      
317                      // total sequence length
318                      treeCtrlP.add(new JLabel("Total Sequence Length (bp)"));
319                      treeLengthL.setBorder(loweredBorder);
320                      treeCtrlP.add(treeLengthL);
321                      
322                      treeP.add(treeCtrlP, BorderLayout.NORTH);
323                      // END TREE INFO SETUP
324                      // *************************************************
325                      
326                      // *************************************************
327                      // LEAF SELECTION PANEL
328                      JPanel leafP = new JPanel(new BorderLayout());
329                      JPanel leafCtrlP = new JPanel(new GridLayout(0,1,0,5));
330                      leafP.setBorder(BorderFactory.createTitledBorder(etchedPadBorder5, 
331                                                                                                                                                                    " Leaf Selection "));
332                      
333                      // Leaf Selection List
334                      leafCB = new JComboBox(LEAF_SELECTION);
335                      leafCB.setBorder(loweredBorder);
336                      leafCB.setEditable(false);
337                      leafCB.addActionListener(new ActionListener() {
338                                             public void actionPerformed(ActionEvent e) {
339                                                      int type = ((JComboBox) e.getSource()).getSelectedIndex();
340                                                      
341                                                      switch (type) {
342                                                      case 0:  // "select all"
343                                                                    numLeavesS.setEnabled(false);
344                                                                    tempDepthS.setEnabled(false);
345                                                                    levelS.setEnabled(false);
346                                                                    leafL.setEnabled(false);
347                                                                    break;
348                                                      case 1:  // "random"
349                                                                    numLeavesS.setEnabled(true);
350                                                                    tempDepthS.setEnabled(false);
351                                                                    levelS.setEnabled(false);
352                                                                    leafL.setEnabled(false);
353                                                                    break;
354                                                      case 2:  // "by tempDepth distributed"
355                                                                    numLeavesS.setEnabled(true);
356                                                                    tempDepthS.setEnabled(true);
357                                                                    levelS.setEnabled(false);
358                                                                    leafL.setEnabled(false);
359                                                                    break;
360                                                      case 3:  // "by tempDepth weighted"
361                                                                    numLeavesS.setEnabled(true);
362                                                                    tempDepthS.setEnabled(true);
363                                                                    levelS.setEnabled(false);
364                                                                    leafL.setEnabled(false);
365                                                                    break;
366                                                      case 4:  // "by level distributed"
367                                                                    numLeavesS.setEnabled(true);
368                                                                    tempDepthS.setEnabled(false);
369                                                                    levelS.setEnabled(true);
370                                                                    leafL.setEnabled(false);
371                                                                    break;
372                                                      case 5:  // "by level weighted"
373                                                                    numLeavesS.setEnabled(true);
374                                                                    tempDepthS.setEnabled(false);
375                                                                    levelS.setEnabled(true);
376                                                                    leafL.setEnabled(false);
377                                                                    break;
378                                                      case 6:  // "by hand"
379                                                                    numLeavesS.setEnabled(false);
380                                                                    tempDepthS.setEnabled(false);
381                                                                    levelS.setEnabled(false);
382                                                                    leafL.setEnabled(true);
383    
384                                                                    // start with a blank list
385                                                                    Object[] blank = { };
386                                                                    leafL.setListData(blank);
387                                                                    if (tree.getNumLeaves() < MAX_LEAVES) {
388                                                                             // if tree hasn't been built, then give
389                                                                             // the user the option to build the
390                                                                             // tree. If the user builds the tree, then
391                                                                             // load the leaves for manual selection.
392                                                                             if (TreeUtils.isTreeBuilt(tree)) {
393                                                                                      if (tree.getNumLeaves() > 0) {
394                                                                                                    Collection obj = tree.getLeaves();
395                                                                                                    if (obj != null) leafL.setListData(obj.toArray());
396                                                                                      }
397                                                                             }
398                                                                    } else {
399                                                                             String msg = "Too many leaves to display in the leaf selection \n"; 
400                                                                             msg += "list. Thus the user must manually select leaves from the command \n";
401                                                                             msg += "line. To do this use the query object's \"setLeaves()\" method.";
402                                                                             CrimsonUtils.printWarning(msg);
403                                                                    }
404    
405                                                                    break;
406                                                      default: // force a selection if nothing selected
407                                                                    leafCB.setSelectedIndex(0); 
408                                                                    break; 
409                                                      }
410                                             }
411                                    });
412                      leafCtrlP.add(new JLabel("Selection Method:"));
413                      leafCtrlP.add(leafCB);
414                      
415                      // Number of Leaves
416                      leafCtrlP.add(new JLabel("Number of Leaves:"));
417                      if (tree == null) {
418                                    numLeavesSM = new SpinnerNumberModel(0, 0, 0, 1);
419                      } else {
420                                    int inc = tree.getNumLeaves() / 20;
421                                    numLeavesSM = new SpinnerNumberModel(0, 0, tree.getNumLeaves(), (inc == 0) ? 1 : inc);
422                      }
423                      numLeavesS = new JSpinner(numLeavesSM);
424                      numLeavesS.setBorder(loweredBorder);
425                      numLeavesS.setEnabled(false);
426                      leafCtrlP.add(numLeavesS);
427                      
428                      // TempDepthThresh
429                      leafCtrlP.add(new JLabel("Temporal Depth:"));
430                      if (tree == null) {
431                                    tempDepthSM = new SpinnerNumberModel(0.0, 0.0, 0.0, 0.0);
432                      } else {
433                                    tempDepthSM = new SpinnerNumberModel(0.0, 0.0, tree.getMaxTempDepth(), 
434                                                                                                                                     tree.getMaxTempDepth() / 20.0);
435                      }
436                      tempDepthS = new JSpinner(tempDepthSM);
437                      tempDepthS.setBorder(loweredBorder);
438                      tempDepthS.setEnabled(false);
439                      leafCtrlP.add(tempDepthS);
440                      
441                      // LevelThresh
442                      leafCtrlP.add(new JLabel("Level:"));
443                      if (tree == null) {
444                                    levelSM = new SpinnerNumberModel(0, 0, 0, 0);
445                      } else {
446                                    int inc = tree.getMaxLevel() / 20;
447                                    levelSM = new SpinnerNumberModel(0, 0, tree.getMaxLevel(), (inc == 0) ? 1 : inc);
448                      }
449                      levelS = new JSpinner(levelSM);
450                      levelS.setBorder(loweredBorder);
451                      levelS.setEnabled(false);
452                      leafCtrlP.add(levelS);
453                      
454                      // Leaf List
455                      JPanel leafListP = new JPanel(new BorderLayout());
456                      JLabel leafListL = new JLabel("Leaves (ID [Level, Temp Depth]):");
457                      leafListL.setBorder(BorderFactory.createEmptyBorder(5,0,7,5));
458                      leafListP.add(leafListL, BorderLayout.NORTH);
459                      leafL.setEnabled(false);
460                      leafL.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
461                      // this list selection model will act like a normal
462                      // MULTIPLE_INTERVAL_SELECTION model, except it will be as if
463                      // the CTRL key is constantly pressed down
464                      DefaultListSelectionModel leafLM =
465                                    new DefaultListSelectionModel() {
466                                             public void setSelectionInterval(int index0, int index1) {
467                                                      //                                              if (this.getValueIsAdjusting()) return;
468    
469                                                      if (this.getSelectionMode() != ListSelectionModel.MULTIPLE_INTERVAL_SELECTION)
470                                                                    super.setSelectionInterval(index0, index1);
471                                                      else {
472                                                                    if (index0 == index1) {
473                                                                             // single click
474                                                                             if (super.isSelectedIndex(index0)) 
475                                                                                      // already selected, so unselect
476                                                                                      super.removeSelectionInterval(index0, index1);
477                                                                             else
478                                                                                      // not selected, so select
479                                                                                      super.addSelectionInterval(index0, index1);
480                                                                    } else {
481                                                                             // for a range, the SHIFT key must be
482                                                                             // pressed. in these cases we will just
483                                                                             // select the entire range
484                                                                             for (int i = index0; i <= index1; i++) {
485                                                                                      super.addSelectionInterval(i, i);
486                                                                             }
487                                                                    }
488                                                      }
489                                             }
490                                    };
491                      leafLM.addListSelectionListener(new ListSelectionListener() {
492                                             public void valueChanged(ListSelectionEvent e) {
493                                                      if (e.getValueIsAdjusting()) return;
494                                                      int[] selection = leafL.getSelectedIndices();
495                                                      numLeavesS.setValue(new Integer(selection.length));
496                                             }
497                                    });
498                      leafL.setSelectionModel(leafLM);
499                      JScrollPane leafSP = new JScrollPane(leafL);
500                      leafSP.setBorder(loweredBorder);
501                      leafListP.add(leafSP, BorderLayout.CENTER);
502                      
503                      leafP.add(leafCtrlP, BorderLayout.NORTH);
504                      leafP.add(leafListP, BorderLayout.CENTER);
505                      // END LEAF SELECTION PANEL
506                      // *************************************************
507                      
508                      // *************************************************
509                      // SEQUENCE SELECTION PANEL
510                      JPanel sequenceP = new JPanel(new BorderLayout());
511                      JPanel sequenceCtrlP = new JPanel(new GridLayout(0,1,0,5));
512                      sequenceP.setBorder(BorderFactory.createTitledBorder(etchedPadBorder5, " Sequence Selection "));
513                      
514                      // Sequence Selection List
515                      sequenceCB = new JComboBox(SEQUENCE_SELECTION);
516                      sequenceCB.setBorder(loweredBorder);
517                      sequenceCB.setEditable(false);
518                      sequenceCB.addActionListener(new ActionListener() {
519                                             public void actionPerformed(ActionEvent e) {
520                                                      int type = ((JComboBox) e.getSource()).getSelectedIndex();
521    
522                                                      // reset partition list selection
523                                                      partitionsL.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
524                                                      
525                                                      // if sequence selection is "manual" or no tree is
526                                                      // selected, then disable the partition selection
527                                                      // buttons
528                                                      if ((tree == null) || (sequenceCB.getSelectedIndex() < 3)) {
529                                                                    // re-enable selection buttons
530                                                                    selectAllB.setEnabled(false);
531                                                                    unselectAllB.setEnabled(false);
532                                                                    selectModelB.setEnabled(false);
533                                                                    unselectModelB.setEnabled(false);
534                                                      } else {
535                                                                    // disable selection buttons
536                                                                    selectAllB.setEnabled(true);
537                                                                    unselectAllB.setEnabled(true);
538                                                                    selectModelB.setEnabled(true);
539                                                                    unselectModelB.setEnabled(true);
540                                                      }
541    
542                                                      switch (type) {
543                                                      case 0:  // "select all"
544                                                      case 5:  // "select none"
545                                                                    numPositionsS.setEnabled(false);
546                                                                    positionTF.setEnabled(false);
547                                                                    break;
548                                                      case 1:  // "random codon selection"
549                                                                    maxPositions = tree.getLength() / 3;
550                                                                    updateNumPositionsSM();
551    
552                                                                    numPositionsS.setEnabled(true);
553                                                                    positionTF.setEnabled(false);
554                                                                    break;
555                                                      case 2:  // "random bp selection"
556                                                                    maxPositions = tree.getLength();
557                                                                    updateNumPositionsSM();
558    
559                                                                    numPositionsS.setEnabled(true);
560                                                                    positionTF.setEnabled(false);
561                                                                    break;
562                                                      case 3:  // "manual codon selection"
563                                                      case 4:  // "manual bp selection "
564                                                                    numPositionsS.setEnabled(false);
565                                                                    positionTF.setEnabled(true);
566    
567                                                                    // only allow one partition to be selected 
568                                                                    partitionsL.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
569                                                                    // if multiple partitions selected, then only
570                                                                    // select the first partition in the selected
571                                                                    // group. If nothing selected, then select the
572                                                                    // first partition in the list.
573                                                                    int index = partitionsL.getSelectedIndex();
574                                                                    if (partitionsL.getSelectedIndices().length > 1) {
575                                                                             String msg = "Must select one and only one partition when specifying\n";
576                                                                             msg += "sequence positions by hand.";
577                                                                             CrimsonUtils.printMsg(msg, CrimsonUtils.WARNING);
578                                                                    }
579                                                                    if (index == -1) index = 0;
580                                                                    partitionsL.clearSelection();
581                                                                    partitionsL.setSelectedIndex(index);
582    
583                                                                    break;
584                                                      default: // force a selection if nothing selected
585                                                                    sequenceCB.setSelectedIndex(0); 
586                                                                    break; 
587                                                      }
588                                             }
589                                    });
590                      sequenceCtrlP.add(new JLabel("Selection Method:"));
591                      sequenceCtrlP.add(sequenceCB);
592                      
593                      // Number of base pairs or codons 
594                      sequenceCtrlP.add(new JLabel("Number of Positions (bp/codon):"));
595                      if (tree == null) {
596                                    numPositionsSM = new SpinnerNumberModel(0, 0, 0, 1);
597                      } else {
598                                    int inc = maxPositions / 20;
599                                    numPositionsSM = new SpinnerNumberModel(0, 0, maxPositions, (inc == 0) ? 1 : inc);
600                      }
601                      numPositionsS = new JSpinner(numPositionsSM);
602                      numPositionsS.setBorder(loweredBorder);
603                      numPositionsS.setEnabled(false);
604                      sequenceCtrlP.add(numPositionsS);
605                      
606                      // Position
607                      sequenceCtrlP.add(new JLabel("Positions (bp/codon):"));
608                      positionTF.setBorder(loweredBorder);
609                      positionTF.setToolTipText("Use ':' between numbers and '-' for ranges. Ex. '1-10:14:80-200'");
610                      positionTF.setEnabled(false);
611                      sequenceCtrlP.add(positionTF);
612                      
613                      // Partitions 
614                      JPanel partitionsListP = new JPanel(new BorderLayout());
615                      JLabel partitionsListL = new JLabel("Partitions:");
616                      partitionsListL.setBorder(BorderFactory.createEmptyBorder(5,0,7,5));
617                      partitionsListP.add(partitionsListL, BorderLayout.NORTH);
618                      //
619    
620                      partitionsL.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
621                      // this list selection model will act like a normal
622                      // MULTIPLE_INTERVAL_SELECTION model, except it will be as if
623                      // the CTRL key is constantly pressed down
624                      DefaultListSelectionModel partitionsLM =
625                                    new DefaultListSelectionModel() {
626                                             public void setSelectionInterval(int index0, int index1) {
627                                                      if (this.getSelectionMode() != ListSelectionModel.MULTIPLE_INTERVAL_SELECTION)
628                                                                    super.setSelectionInterval(index0, index1);
629                                                      else {
630                                                                    if (index0 == index1) {
631                                                                             // single click
632                                                                             if (super.isSelectedIndex(index0)) 
633                                                                                      // already selected, so unselect
634                                                                                      super.removeSelectionInterval(index0, index1);
635                                                                             else
636                                                                                      // not selected, so select
637                                                                                      super.addSelectionInterval(index0, index1);
638                                                                    } else {
639                                                                             // for a range, the SHIFT key must be
640                                                                             // pressed. in these cases we will just
641                                                                             // select the entire range
642                                                                             for (int i = index0; i <= index1; i++) {
643                                                                                      super.addSelectionInterval(i, i);
644                                                                             }
645                                                                    }
646                                                      }
647                                             }
648                                    };
649                      partitionsL.setSelectionModel(partitionsLM);
650                      JScrollPane partitionsSP = new JScrollPane(partitionsL);
651                      partitionsSP.setBorder(loweredBorder);
652    
653                      JPanel partitionsInner = new JPanel(new BorderLayout());
654                      JPanel partitionsInnerBtns = new JPanel(new GridLayout(0,1,3,3));
655                      selectAllB = new JButton("Select All");
656                      selectAllB.addActionListener(new ActionListener() {
657                                             public void actionPerformed(ActionEvent e) {
658                                                      if (tree == null) return;
659                                                      partitionsL.setSelectionInterval(0, tree.getNumPartitions()-1);
660                                             }
661                                    });
662                      partitionsInnerBtns.add(selectAllB);
663                      unselectAllB = new JButton("Unselect All");
664                      unselectAllB.addActionListener(new ActionListener() {
665                                             public void actionPerformed(ActionEvent e) {
666                                                      partitionsL.clearSelection();
667                                                      thisFrame.repaint();
668                                             }
669                                    });
670                      partitionsInnerBtns.add(unselectAllB);
671                      selectModelB = new JButton("Select Model");
672                      selectModelB.addActionListener(new ActionListener() {
673                                             public void actionPerformed(ActionEvent e) {
674                                                      if (tree == null) return;
675    
676                                                      // get list of partitions for the existing tree
677                                                      // that contain the model selected, using the
678                                                      // modelSelector()
679                                                      ArrayList pList = tree.getPartitionsByModel(ModelUtils.modelSelector());
680    
681                                                      // convert the existing selection list to a
682                                                      // HashSet so it's easy to search for overlaps
683                                                      // between items already selected and items that
684                                                      // are to be selected
685                                                      HashSet selection = new HashSet(Arrays.asList(partitionsL.getSelectedValues()));
686    
687                                                      // for each item in the partition list, make sure
688                                                      // it's selected
689                                                      for (Iterator i = pList.iterator(); i.hasNext();) {
690                                                                    Partition partition = (Partition) i.next();
691                                                                    // if item not already selected, then select
692                                                                    // the item
693                                                                    if (! selection.contains(partition)) {
694                                                                             partitionsL.setSelectedValue(partition, false);
695                                                                    }
696                                                      }
697                                             }
698                                    });
699                      partitionsInnerBtns.add(selectModelB);
700                      unselectModelB = new JButton("Unselect Model");
701                      unselectModelB.addActionListener(new ActionListener() {
702                                             public void actionPerformed(ActionEvent e) {
703                                                      if (tree == null) return;
704    
705                                                      // get list of partitions for the existing tree
706                                                      // that contain the model selected, using the
707                                                      // modelSelector()
708                                                      ArrayList pList = tree.getPartitionsByModel(ModelUtils.modelSelector());
709    
710                                                      // convert the existing selection list to a
711                                                      // HashSet so it's easy to search for overlaps
712                                                      // between items already selected and items that
713                                                      // are to be selected
714                                                      Object[] values = partitionsL.getSelectedValues();
715                                                      int[] indices = partitionsL.getSelectedIndices();
716    
717                                                      // for each item in the partition list, make sure
718                                                      // it's selected
719                                                      for (Iterator i = pList.iterator(); i.hasNext();) {
720                                                                    Object partition = i.next();
721                                                                    // if item already selected, then unselect the
722                                                                    // item - by re-selecting the item
723                                                                    for (int j = 0; j < values.length; j++) {
724                                                                             if (values[j] == partition) {
725                                                                                      partitionsL.removeSelectionInterval(indices[j], indices[j]);
726                                                                                      break;
727                                                                             }
728                                                                    }
729                                                      }
730                                             }
731                                    });
732                      partitionsInnerBtns.add(unselectModelB);
733                      partitionsInner.add(partitionsSP, BorderLayout.CENTER);
734                      partitionsInner.add(partitionsInnerBtns, BorderLayout.EAST);
735    
736                      //
737                      //              partitionsListP.add(partitionsSP, BorderLayout.CENTER);
738                      partitionsListP.add(partitionsInner, BorderLayout.CENTER);
739                      
740                      sequenceP.add(sequenceCtrlP, BorderLayout.NORTH);
741                      sequenceP.add(partitionsListP, BorderLayout.CENTER);
742                      
743                      // *************************************************
744                      // SETUP INFO PANEL
745                      JPanel queryP = new JPanel(new BorderLayout());
746                      queryP.setBorder(BorderFactory.createEmptyBorder(10,0,10,0));
747                      queryP.add(new JLabel("Query: "), BorderLayout.WEST);
748                      JLabel idLabel = new JLabel("  " + query.getID() + "  ");
749                      idLabel.setBorder(loweredBorder);
750                      queryP.add(idLabel, BorderLayout.CENTER);
751    
752                      JPanel seedP = new JPanel(new BorderLayout());
753                      seedP.setBorder(BorderFactory.createEmptyBorder(10,0,10,0));
754                      seedP.add(new JLabel("Seed: "), BorderLayout.WEST);
755                      seedTF.setBorder(loweredBorder);
756                      seedP.add(seedTF, BorderLayout.CENTER);
757                      JPanel tmpSeedP = new JPanel(new BorderLayout());
758                      JButton genSeedB = new JButton("Generate Seed");
759                      genSeedB.addActionListener(new ActionListener() {
760                                             public void actionPerformed(ActionEvent e) {
761                                                      // Seed can't be larger than MAX_SEED
762                                                      long seed = System.currentTimeMillis() % MAX_SEED;
763                                                      seedTF.setText(Long.toString(seed));
764                                             }
765                                    });
766                      tmpSeedP.add(new JLabel(" "), BorderLayout.WEST);
767                      tmpSeedP.add(genSeedB, BorderLayout.CENTER);
768                      seedP.add(tmpSeedP, BorderLayout.EAST);
769    
770                      JPanel infoP = new JPanel(new GridLayout(1,0,15,0));
771                      infoP.add(queryP);
772                      infoP.add(seedP);
773                      
774                      // *************************************************
775                      // SETUP CONTROL PANEL
776                      JButton notesB = new JButton(new ImageIcon("icons/notes.png"));
777                      notesB.setToolTipText("Edit/view notes");
778                      notesB.addActionListener(new ActionListener() {
779                                             public void actionPerformed(ActionEvent e) {
780                                                      new NotesPanel(query);
781                                             }
782                                    });
783    
784                      JButton saveB = new JButton(new ImageIcon("icons/save.png"));
785                      saveB.setToolTipText("Save query and close window");
786                      saveB.addActionListener(new ActionListener() {
787                                             public void actionPerformed(ActionEvent e) {
788                                                      // if tempDepth/level selection, then make sure
789                                                      // the user's choice of tempDepth/level and number
790                                                      // of leaves selected are valid
791                                                      if (tree != null) {
792                                                                    // numSubtrees is set to 1 so that the
793                                                                    // condition below is only met by
794                                                                    // getSelectedIndex of 2 or 4
795                                                                    int numSubtrees = 1;
796                                                                    if (leafCB.getSelectedIndex() == 2) {
797                                                                             double tempDepthThresh = ((Double) tempDepthS.getValue()).doubleValue();
798                                                                             numSubtrees = tree.getTreesByTempDepth(tempDepthThresh).size();
799                                                                    } else if (leafCB.getSelectedIndex() == 4) {
800                                                                             int levelThresh = ((Integer) levelS.getValue()).intValue();
801                                                                             numSubtrees = tree.getTreesByLevel(levelThresh).size();
802                                                                    }
803                                                                    if (numSubtrees == 0) {
804                                                                             // warn user of invalid distribution
805                                                                             String msg = "Empty distribution using specified threshold.\n";
806                                                                             Object[] options = {"Change threshold", "Save anyway"};
807                                                                             int flag = JOptionPane.showOptionDialog(null, msg,
808                                                                                                                                                                                      "Threshold Confirmation",
809                                                                                                                                                                                      JOptionPane.YES_NO_OPTION,
810                                                                                                                                                                                      JOptionPane.QUESTION_MESSAGE,
811                                                                                                                                                                                      null,
812                                                                                                                                                                                      options,
813                                                                                                                                                                                      options[1]);
814                                                                             // "Change Threshold"
815                                                                             if (flag == JOptionPane.YES_OPTION) return;
816                                                                    } else {
817                                                                             int remainder = ((Integer) numLeavesS.getValue()).intValue() % numSubtrees;
818                                                                             if (remainder != 0) {
819                                                                                      // warn user that not getting full set of leaves
820                                                                                      String msg = remainder + " leaves will not be returned using the specified threshold.\n";
821                                                                                      msg += "At specified threshold, there are " + numSubtrees + " subtrees.\n";
822                                                                                      Object[] options = {"Change threshold", "Save anyway"};
823                                                                                      int flag = JOptionPane.showOptionDialog(null, msg,
824                                                                                                                                                                                                    "Threshold Confirmation",
825                                                                                                                                                                                                    JOptionPane.YES_NO_OPTION,
826                                                                                                                                                                                                    JOptionPane.QUESTION_MESSAGE,
827                                                                                                                                                                                                    null,
828                                                                                                                                                                                                    options,
829                                                                                                                                                                                                    options[1]);
830                                                                                      // "Change Threshold"
831                                                                                      if (flag == JOptionPane.YES_OPTION) return;
832                                                                             }
833                                                                    }
834                                                      }
835    
836                                                      saveQuery();
837                                                      thisFrame.dispose();
838                                             }
839                                    });
840    
841                      JButton runB = new JButton(new ImageIcon("icons/run.png"));
842                      runB.setToolTipText("Save and run query");
843                      runB.addActionListener(new ActionListener() {
844                                             public void actionPerformed(ActionEvent e) {
845                                                      // if tempDepth/level selection, then make sure
846                                                      // the user's choice of tempDepth/level and number
847                                                      // of leaves selected are valid
848                                                      if (tree != null) {
849                                                                    // numSubtrees is set to 1 so that the
850                                                                    // condition below is only met by
851                                                                    // getSelectedIndex of 2 or 4
852                                                                    int numSubtrees = 1;
853                                                                    if (leafCB.getSelectedIndex() == 2) {
854                                                                             double tempDepthThresh = ((Double) tempDepthS.getValue()).doubleValue();
855                                                                             numSubtrees = tree.getTreesByTempDepth(tempDepthThresh).size();
856                                                                    } else if (leafCB.getSelectedIndex() == 4) {
857                                                                             int levelThresh = ((Integer) levelS.getValue()).intValue();
858                                                                             numSubtrees = tree.getTreesByLevel(levelThresh).size();
859                                                                    }
860    
861                                                                    if (numSubtrees == 0) {
862                                                                             // warn user of invalid distribution
863                                                                             String msg = "Empty distribution using specified threshold.\n";
864                                                                             Object[] options = {"Change threshold", "Save anyway"};
865                                                                             int flag = JOptionPane.showOptionDialog(null, msg,
866                                                                                                                                                                                      "Threshold Confirmation",
867                                                                                                                                                                                      JOptionPane.YES_NO_OPTION,
868                                                                                                                                                                                      JOptionPane.QUESTION_MESSAGE,
869                                                                                                                                                                                      null,
870                                                                                                                                                                                      options,
871                                                                                                                                                                                      options[1]);
872                                                                             // "Change Threshold"
873                                                                             if (flag == JOptionPane.YES_OPTION) return;
874                                                                    } else {
875                                                                             int remainder = ((Integer) numLeavesS.getValue()).intValue() % numSubtrees;
876                                                                             if (remainder != 0) {
877                                                                                      // warn user that not getting full set of leaves
878                                                                                      String msg = remainder + " leaves will not be returned using the specified threshold.\n";
879                                                                                      msg += "At specified threshold, there are " + numSubtrees + " subtrees.\n";
880                                                                                      Object[] options = {"Change threshold", "Save anyway"};
881                                                                                      int flag = JOptionPane.showOptionDialog(null, msg,
882                                                                                                                                                                                                    "Threshold Confirmation",
883                                                                                                                                                                                                    JOptionPane.YES_NO_OPTION,
884                                                                                                                                                                                                    JOptionPane.QUESTION_MESSAGE,
885                                                                                                                                                                                                    null,
886                                                                                                                                                                                                    options,
887                                                                                                                                                                                                    options[1]);
888                                                                                      // "Change Threshold"
889                                                                                      if (flag == JOptionPane.YES_OPTION) return;
890                                                                             }
891                                                                    }
892                                                      }
893    
894                                                      saveQuery();
895                                                      QueryUtils.runQueryDialog(query.getID(), file, incSequence, repeat);
896                                                      thisFrame.dispose();
897                                             }
898                                    });
899    
900                      JButton cancelB = new JButton(new ImageIcon("icons/close.png"));
901                      cancelB.setToolTipText("Cancel changes");
902                      cancelB.addActionListener(new ActionListener() {
903                                             public void actionPerformed(ActionEvent e) {
904                                                      thisFrame.dispose();
905                                             }
906                                    });
907                      
908                      JPanel buttonP = new JPanel(new GridLayout(1,0,15,0));
909                      buttonP.setBorder(emptyBorder);
910                      buttonP.add(notesB);
911                      buttonP.add(saveB);
912                      buttonP.add(runB);
913                      buttonP.add(cancelB);
914    
915                      JPanel topP = new JPanel(new BorderLayout());
916                      topP.setBorder(etchedPadBorder5);
917                      topP.add(infoP, BorderLayout.WEST);
918                      topP.add(buttonP, BorderLayout.EAST);
919    
920                      // *************************************************
921                      // SETUP PANELS 
922                      JPanel mainP = new JPanel(new GridLayout(1,0,5,0));
923                      mainP.add(treeP);
924                      mainP.add(leafP);
925                      mainP.add(sequenceP);
926                      
927                      getContentPane().setLayout(new BorderLayout());
928                      getContentPane().add(topP, BorderLayout.NORTH);
929                      getContentPane().add(mainP, BorderLayout.CENTER);
930                      //              getContentPane().add(buttonP, BorderLayout.SOUTH);
931                      pack();
932                      
933                      // set the default window size
934                      setSize(getSize().width - 300, getSize().height + 30);
935    
936                      // *************************************************
937                      // INITIALIZE VARIABLES
938                      //              treeCB.setSelectedItem(query.getTreeID());
939                      String treeID = query.getTreeID();
940                      // propogate the tree's values to the necessary labels
941                      if (CrimsonUtils.isEmpty(treeID)) {  // blank treeID
942                                    //                                                JOptionPane.showMessageDialog(new Frame(), "No tree selected.",
943                                    //                                                                                                                                "Query Error", JOptionPane.ERROR_MESSAGE);
944                                    treeCB.setSelectedIndex(-1);
945                      } else if (! ObjectHandles.containsTree(treeID)) {  // invalid treeID
946                                    JOptionPane.showMessageDialog(new Frame(), "Tree (" + treeID+ ") doesn't exist.",
947                                                                                                                    "Query Error", JOptionPane.ERROR_MESSAGE);
948                                    treeCB.setSelectedIndex(-1);
949                      } else {
950                                    tree = ObjectHandles.getTree(treeID);
951    
952                                    treeCB.setSelectedItem(treeID);
953                                    treePartitionsL.setText(" " + tree.getNumPartitions());
954                                    treeLeavesL.setText(" " + tree.getNumLeaves());
955                                    treeMaxTempDepthL.setText(" " + tree.getMaxTempDepth());
956                                    treeMaxLevelL.setText(" " + tree.getMaxLevel());
957                                    treeLengthL.setText(" " + tree.getLength());
958                      }
959    
960                      // load leaf selection data
961                      leafCB.setSelectedIndex(query.getLeafSelection());
962                      numLeavesS.setValue(new Integer(query.getNumLeaves()));
963                      tempDepthS.setValue(new Double(query.getTempDepthThresh()));
964                      levelS.setValue(new Integer(query.getLevelThresh()));
965    
966                      if (tree != null) {
967                                    // if manual selection then load leaf data
968                                    if (query.getLeafSelection() == 6) {
969                                             for (Iterator i = query.getLeaves().iterator(); i.hasNext();) {
970                                                      leafL.setSelectedValue(tree.getSpeciesByID((String) i.next()), false);
971                                             }
972                                    }
973    
974                                    // load partition data
975                                    for (Iterator i = query.getPartitions().iterator(); i.hasNext();) {
976                                             partitionsL.setSelectedValue(ObjectHandles.getPartition((String) i.next()), false);
977                                             //                                      partitionsL.setSelectedValue(i.next(), false);
978                                    }
979                      }
980    
981                      // load sequence selection
982                      sequenceCB.setSelectedIndex(query.getSequenceSelection());
983                      
984                      // load number of positions (base pairs or codon)
985                      numPositionsS.setValue(new Integer(query.getNumPositions()));
986    
987                      // load position data
988                      StringBuffer sb = new StringBuffer("");
989                      Iterator i = query.getPositions().iterator();
990                      if (i.hasNext()) sb.append((String) i.next());
991                      while (i.hasNext()) sb.append(":" + (String) i.next());
992                      positionTF.setText(sb.toString());
993    
994                      // load seed
995                      if (query.getSeed() == -1) {
996                                    seedTF.setText("");
997                      } else {
998                                    seedTF.setText(Long.toString(query.getSeed()));
999                      }
1000    
1001                      // END INITIALIZE VARIABLES
1002                      // *************************************************
1003                      
1004                      // display the window
1005                      setVisible(true);
1006             }
1007    
1008             /** 
1009              * Update numPositions spinner bounds, bounded by sequence length.
1010              */
1011             private void updateNumPositionsSM() {
1012                      Object savedVal = numPositionsS.getValue();
1013                      int inc = maxPositions / 20;
1014                      numPositionsSM = new SpinnerNumberModel(0, 0, maxPositions, (inc == 0) ? 1 : inc);
1015                      numPositionsS.setModel(numPositionsSM);
1016                      if (numPositionsSM.getMaximum().compareTo(savedVal) == -1)
1017                                    savedVal = new Integer(maxPositions);
1018                      numPositionsS.setValue(savedVal);
1019             }
1020    
1021             /** This will save the changes to the query. */
1022             private void saveQuery() {
1023                      // set treeID
1024                      query.setTreeID((String) treeCB.getSelectedItem());
1025                      
1026                      // set seed
1027                      String seed = seedTF.getText();
1028                      if (CrimsonUtils.isEmpty(seed)) {
1029                                    query.setSeed(-1);
1030                      } else {
1031                                    query.setSeed(Long.parseLong(seedTF.getText()));
1032                      }
1033                      
1034                      // set leafSelection
1035                      query.setLeafSelection(leafCB.getSelectedIndex());
1036                      
1037                      // set numLeaves, tempDepth, level, and leaf list
1038                      switch (leafCB.getSelectedIndex()) {
1039                      case 0:  // select all leaves
1040                                    query.setNumLeaves(0);
1041                                    query.setTempDepthThresh(0);
1042                                    query.setLevelThresh(0);
1043                                    query.setLeaves(new HashSet());
1044                                    break;
1045                      case 1:  // random leaf selection
1046                                    query.setNumLeaves(((Integer) numLeavesS.getValue()).intValue());
1047                                    query.setTempDepthThresh(0);
1048                                    query.setLevelThresh(0);
1049                                    query.setLeaves(new HashSet());
1050                                    break;
1051                      case 2:  // select leaves by tempDepthThresh distributed
1052                                    query.setNumLeaves(((Integer) numLeavesS.getValue()).intValue());
1053                                    query.setTempDepthThresh(((Double) tempDepthS.getValue()).doubleValue());
1054                                    query.setLevelThresh(0);
1055                                    query.setLeaves(new HashSet());
1056                                    break;
1057                      case 3:  // select leaves by tempDepthThresh weighted
1058                                    query.setNumLeaves(((Integer) numLeavesS.getValue()).intValue());
1059                                    query.setTempDepthThresh(((Double) tempDepthS.getValue()).doubleValue());
1060                                    query.setLevelThresh(0);
1061                                    query.setLeaves(new HashSet());
1062                                    break;
1063                      case 4:  // select leaves by levelThresh distributed
1064                                    query.setNumLeaves(((Integer) numLeavesS.getValue()).intValue());
1065                                    query.setTempDepthThresh(0);
1066                                    query.setLevelThresh(((Integer) levelS.getValue()).intValue());
1067                                    query.setLeaves(new HashSet());
1068                                    break;
1069                      case 5:  // select leaves by levelThresh weighted
1070                                    query.setNumLeaves(((Integer) numLeavesS.getValue()).intValue());
1071                                    query.setTempDepthThresh(0);
1072                                    query.setLevelThresh(((Integer) levelS.getValue()).intValue());
1073                                    query.setLeaves(new HashSet());
1074                                    break;
1075                      case 6:  // select leaves by hand
1076                                    query.setNumLeaves(0);
1077                                    query.setTempDepthThresh(0);
1078                                    query.setLevelThresh(0);
1079                                    // set leaf list
1080                                    Object[] selection = leafL.getSelectedValues();
1081                                    HashSet leaves = new HashSet();
1082                                    for (int i = 0; i < selection.length; i++) {
1083                                             // only add the species ID
1084                                             leaves.add(((Species) selection[i]).getID());
1085                                    }
1086                                    query.setLeaves(leaves);
1087                                    break;
1088                      }
1089                      
1090                      // set sequenceSelection
1091                      query.setSequenceSelection(sequenceCB.getSelectedIndex());
1092                      
1093                      // set partitions
1094                      Object[] selection = partitionsL.getSelectedValues();
1095                      HashSet partitions = new HashSet();
1096                      for (int i = 0; i < selection.length; i++) {
1097                                    partitions.add(((Partition) selection[i]).getID());
1098                      }
1099                      query.setPartitions(partitions);
1100                      
1101                      // set numPositions
1102                      if ((sequenceCB.getSelectedIndex() == 1) || // random codon selection
1103                                    (sequenceCB.getSelectedIndex() == 2)) { // random bp selection
1104                                    query.setNumPositions(((Integer) numPositionsS.getValue()).intValue());
1105                      } else {
1106                                    query.setNumPositions(0);
1107                      }
1108                      
1109                      // set positions
1110                      if ((sequenceCB.getSelectedIndex() == 3) || // manual codon selection
1111                                    (sequenceCB.getSelectedIndex() == 4)) { // manual bp selection
1112                                    StringTokenizer tokens = new StringTokenizer(positionTF.getText(), ":");
1113                                    HashSet positions = new HashSet();
1114                                    while (tokens.hasMoreTokens()) {
1115                                             //                                      positions.add(tokens.nextToken().trim());
1116                                             String token = tokens.nextToken().trim();
1117                                             // this won't get the condition when 0 is the
1118                                             // beginning of a range
1119                                             if (token.compareTo("0") == 0) 
1120                                                      CrimsonUtils.printError("Position range begins at 1, not 0. This query will not run.");
1121                                             positions.add(token);
1122                                    }
1123                                    query.setPositions(positions);
1124                      } else {
1125                                    query.setPositions(new HashSet());
1126                      }
1127             }
1128    
1129             /** Edit notes field. */
1130             static class NotesPanel extends JFrame {
1131                      NotesPanel thisFrame;
1132                      
1133                      Query npQuery;
1134                      String npQueryID = "";
1135                      JTextArea npTextArea;
1136                      
1137                      public NotesPanel(Query query) {
1138                                    super("Notes Editor");
1139                                    
1140                                    // keep pointer to self so can 'dispose' Frame below
1141                                    thisFrame = this;
1142                                    
1143                                    setDefaultCloseOperation(DISPOSE_ON_CLOSE);
1144                                    
1145                                    this.npQuery = query;
1146    
1147                                    Border emptyBorder = BorderFactory.createEmptyBorder(5,5,5,5);
1148                                    Border loweredBorder = BorderFactory.createLoweredBevelBorder();
1149                                    Border etchedBorder = BorderFactory.createEtchedBorder();
1150                                    Border etchedPadBorder5 = 
1151                                             BorderFactory.createCompoundBorder(etchedBorder, emptyBorder);
1152                                    Border loweredPadBorder5 = 
1153                                             BorderFactory.createCompoundBorder(loweredBorder, emptyBorder);
1154                                    
1155                                    // *************************************************
1156                                    // SETUP BUTTONS 
1157                                    JPanel buttonP = new JPanel(new BorderLayout());
1158                                    JButton saveB = new JButton(new ImageIcon("icons/save.png"));
1159                                    saveB.setToolTipText("Save changes");
1160                                    saveB.addActionListener(new ActionListener() {
1161                                                      public void actionPerformed(ActionEvent e) {
1162                                                                    if (npQuery == null) {
1163                                                                             return;
1164                                                                    } else {
1165                                                                             npQuery.setNotes(npTextArea.getText());
1166                                                                    }                                        
1167                                                                    thisFrame.dispose();
1168                                                      }
1169                                             });
1170                                    buttonP.add(saveB, BorderLayout.WEST);
1171                                    JButton cancelB = new JButton(new ImageIcon("icons/close.png"));
1172                                    cancelB.setToolTipText("Cancel");
1173                                    cancelB.addActionListener(new ActionListener() {
1174                                                      public void actionPerformed(ActionEvent e) {
1175                                                                    thisFrame.dispose();
1176                                                      }
1177                                             });
1178                                    buttonP.add(cancelB, BorderLayout.EAST);
1179                                    
1180                                    // *************************************************
1181                                    // SETUP TEXTAREA 
1182                                    if (npQuery == null) {
1183                                             CrimsonUtils.printError("Can't view notes for null object.");
1184                                             return;
1185                                    } else {
1186                                             PlainDocument npNotesDoc = new PlainDocument();
1187                                             npNotesDoc.setDocumentFilter(GUIUtils.getDocLengthFilter());
1188                                             npTextArea = new JTextArea();
1189                                             npTextArea.setDocument(npNotesDoc);
1190                                             npTextArea.setText(npQuery.getNotes());
1191                                             npQueryID = npQuery.getID();
1192                                    }                                        
1193                                    npTextArea.setLineWrap(true);
1194                                    npTextArea.setWrapStyleWord(true);
1195                                    JScrollPane areaSP = new JScrollPane(npTextArea);
1196                                    areaSP.setBorder(loweredPadBorder5);
1197                                    areaSP.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
1198                                    areaSP.setPreferredSize(new Dimension(400, 200));
1199                                    
1200                                    // *************************************************
1201                                    // SETUP PANELS 
1202                                    JPanel infoP = new JPanel(new BorderLayout());
1203                                    infoP.setBorder(etchedPadBorder5);
1204                                    infoP.add(new JLabel("Query: " + npQueryID), BorderLayout.WEST);
1205                                    
1206                                    getContentPane().setLayout(new BorderLayout());
1207                                    getContentPane().add(infoP, BorderLayout.NORTH);
1208                                    getContentPane().add(areaSP, BorderLayout.CENTER);
1209                                    getContentPane().add(buttonP, BorderLayout.SOUTH);
1210                                    pack();
1211                                    
1212                                    // set the default window size
1213                                    setSize(getSize().width + 75, getSize().height + 30);
1214                                    
1215                                    // display the window
1216                                    setVisible(true);
1217                      }
1218             } // NotesPanel
1219    
1220             /** View tempDepth distribution. */
1221             class ViewDistributePanel extends JFrame {
1222                      ViewDistributePanel thisFrame;
1223                      int thisThreshType;
1224                      Tree thisTree;
1225                      
1226                      double maxDoubleValue;
1227                      int maxIntValue;
1228                      JSpinner viewS;
1229                      SpinnerModel viewSM;
1230                      JTextArea textArea;
1231    
1232                      public ViewDistributePanel(Tree tree, int threshType) {
1233                                    super("Distribution Viewer");
1234                                    
1235                                    // keep pointer to self so can 'dispose' Frame below
1236                                    thisFrame = this;
1237                                    thisThreshType = threshType;
1238                                    thisTree = tree;
1239    
1240                                    setDefaultCloseOperation(DISPOSE_ON_CLOSE);
1241                                    
1242                                    if (tree == null) {
1243                                             CrimsonUtils.printError("Can not view tree distribution with null tree.");
1244                                             thisFrame.dispose();
1245                                             return;
1246                                    }
1247                                    
1248                                    switch (threshType) {
1249                                    case 0: // temp depth threshold
1250                                             maxDoubleValue = tree.getMaxTempDepth();
1251    
1252                                             // use 5% of the tempDepth as the step size
1253                                             double dInc = maxDoubleValue / 20.0;
1254                                    
1255                                             // starts at (5 * inc) and goes to (maxValue + inc) in
1256                                             // case of any spinner induced roundoff problems.
1257                                             viewSM = new SpinnerNumberModel(5.0 * dInc, 0, maxDoubleValue, dInc);
1258    
1259                                             break;
1260    
1261                                    case 1: // level threshold
1262                                             maxIntValue = tree.getMaxLevel();
1263    
1264                                             // use 5% of the tempDepth as the step size
1265                                             int iInc = maxIntValue / 20;
1266                                    
1267                                             // starts at (5 * inc) and goes to (maxValue + inc) in
1268                                             // case of any spinner induced roundoff problems.
1269                                             viewSM = new SpinnerNumberModel(5 * iInc, 0, maxIntValue, (iInc == 0) ? 1 : iInc);
1270    
1271                                             break;
1272    
1273                                    default: 
1274                                             CrimsonUtils.printError("Bad threshold flag for ViewDistributionPanel().");
1275                                             return;
1276                                    }
1277                                    
1278                                    viewS = new JSpinner(viewSM);
1279    
1280                                    // *************************************************
1281                                    Border emptyBorder = BorderFactory.createEmptyBorder(5,5,5,5);
1282                                    Border loweredBorder = BorderFactory.createLoweredBevelBorder();
1283                                    Border etchedBorder = BorderFactory.createEtchedBorder();
1284                                    Border etchedPadBorder5 = 
1285                                             BorderFactory.createCompoundBorder(etchedBorder, emptyBorder);
1286                                    Border loweredPadBorder5 = 
1287                                             BorderFactory.createCompoundBorder(loweredBorder, emptyBorder);
1288                                                                    
1289                                    // *************************************************
1290                                    // SETUP UPDATE BUTTON 
1291                                    JButton updateB = new JButton("Update");
1292                                    updateB.addActionListener(new ActionListener() {
1293                                                      public void actionPerformed(ActionEvent e) {
1294                                                                    setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
1295    
1296                                                                    StringBuffer sb = new StringBuffer();
1297                                                                    ArrayList dist = new ArrayList();
1298                                                                    switch (thisThreshType) {
1299                                                                    case 0: // temp depth threshold
1300                                                                             dist = thisTree.getLeafCounts(thisTree.getTreesByTempDepth(((Double) viewS.getValue()).doubleValue()));
1301                                                                             break;
1302                                                                    case 1: // level threshold
1303                                                                             dist = thisTree.getLeafCounts(thisTree.getTreesByLevel(((Integer) viewS.getValue()).intValue()));
1304                                                                             break;
1305                                                                    }
1306                                                                    Iterator i = dist.iterator();
1307                                                                    if (i.hasNext()) sb.append(i.next());
1308                                                                    while (i.hasNext()) { sb.append(", " + i.next()); }
1309                                                                    sb.insert(0, "Count (" + dist.size() + "): ");
1310    
1311                                                                    textArea.setText(sb.toString());
1312    
1313                                                                    setCursor(null);
1314                                                      }
1315                                             });
1316                                    
1317                                    // *************************************************
1318                                    // SETUP CLOSE BUTTON 
1319                                    JButton closeB = new JButton("Close");
1320                                    closeB.addActionListener(new ActionListener() {
1321                                                      public void actionPerformed(ActionEvent e) {
1322                                                                    thisFrame.dispose();
1323                                                      }
1324                                             });
1325                                    
1326                                    // *************************************************
1327                                    // SETUP TEXTAREA 
1328                                    textArea = new JTextArea();
1329                                    if (CrimsonUtils.isEmpty(textArea.getText())) {
1330                                             String msg = "Press 'Update' button to compute distribution \n";
1331                                             msg += "based on selected value.";
1332                                             textArea.setText(msg);
1333                                    }
1334                                    textArea.setLineWrap(true);
1335                                    textArea.setWrapStyleWord(true);
1336                                    textArea.setEditable(false);
1337                                    textArea.setFont(new Font("Courier", Font.PLAIN, 14));
1338                                    JScrollPane areaSP = new JScrollPane(textArea);
1339                                    areaSP.setBorder(loweredPadBorder5);
1340                                    areaSP.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
1341                                    areaSP.setPreferredSize(new Dimension(400, 200));
1342                                    
1343                                    // *************************************************
1344                                    // SETUP PANELS 
1345                                    JPanel commandsP = new JPanel(new GridLayout(1,0,5,5));
1346                                    commandsP.setBorder(etchedPadBorder5);
1347                                    commandsP.add(new JLabel("Tree: " + tree.getID()));
1348                                    switch (threshType) {
1349                                    case 0: // temp depth threshold
1350                                             commandsP.add(new JLabel("Max Temp Depth: " + Double.toString(maxDoubleValue)));
1351                                             break;
1352                                    case 1: // level threshold
1353                                             commandsP.add(new JLabel("Max Level: " + Integer.toString(maxIntValue)));
1354                                             break;
1355                                    }
1356                                    commandsP.add(viewS);
1357                                    commandsP.add(updateB);
1358                                    commandsP.add(closeB);
1359                                    
1360                                    getContentPane().setLayout(new BorderLayout());
1361                                    getContentPane().add(commandsP, BorderLayout.NORTH);
1362                                    getContentPane().add(areaSP, BorderLayout.CENTER);
1363                                    pack();
1364                                    
1365                                    // set the default window size
1366                                    setSize(getSize().width + 75, getSize().height + 30);
1367                                    
1368                                    // display the window
1369                                    setVisible(true);
1370                      }
1371             } // ViewDistributePanel
1372    
1373    } // QueryEditor.java
1374