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