1 /* 2 * Copyright (C) 2008 Genome Research Limited 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 * 18 * @author: Tim Carver 19 */ 20 21 package uk.ac.sanger.artemis.circular; 22 23 import java.awt.Color; 24 import java.awt.Dimension; 25 import java.awt.Font; 26 import java.awt.GridBagConstraints; 27 import java.awt.GridBagLayout; 28 import java.awt.event.ActionEvent; 29 import java.awt.event.ActionListener; 30 import java.awt.event.ItemEvent; 31 import java.awt.event.ItemListener; 32 import java.io.BufferedReader; 33 import java.io.File; 34 import java.io.FileNotFoundException; 35 import java.io.FileReader; 36 import java.io.FileWriter; 37 import java.io.IOException; 38 import java.io.Writer; 39 import java.util.StringTokenizer; 40 import java.util.Vector; 41 42 import javax.swing.JButton; 43 import javax.swing.JCheckBox; 44 import javax.swing.JFileChooser; 45 import javax.swing.JFrame; 46 import javax.swing.JLabel; 47 import javax.swing.JMenu; 48 import javax.swing.JMenuBar; 49 import javax.swing.JMenuItem; 50 import javax.swing.JOptionPane; 51 import javax.swing.JPanel; 52 import javax.swing.JScrollPane; 53 import javax.swing.JTextField; 54 55 import uk.ac.sanger.artemis.Entry; 56 import uk.ac.sanger.artemis.Feature; 57 import uk.ac.sanger.artemis.FeatureKeyPredicate; 58 import uk.ac.sanger.artemis.FeatureKeyQualifierPredicate; 59 import uk.ac.sanger.artemis.FeaturePredicate; 60 import uk.ac.sanger.artemis.FeaturePredicateConjunction; 61 import uk.ac.sanger.artemis.FeaturePredicateVector; 62 import uk.ac.sanger.artemis.FeatureVector; 63 import uk.ac.sanger.artemis.components.KeyChoice; 64 import uk.ac.sanger.artemis.components.QualifierChoice; 65 import uk.ac.sanger.artemis.components.StickyFileChooser; 66 import uk.ac.sanger.artemis.io.Key; 67 import uk.ac.sanger.artemis.io.Range; 68 import uk.ac.sanger.artemis.io.RangeVector; 69 70 public class TrackManager extends JFrame 71 { 72 private static final long serialVersionUID = 1L; 73 private DNADraw dnaDraw; 74 75 private KeyChoice keyChoice[]; 76 private QualifierChoice qualifierChoice[]; 77 private JTextField qualifierValue[]; 78 private JCheckBox notQualifier[]; 79 private JCheckBox showForward[]; 80 private JCheckBox showReverse[]; 81 private JCheckBox showAny[]; 82 private TextFieldFloat trackSize[]; 83 private TextFieldFloat trackPosition[]; 84 TrackManager(final DNADraw dnaDraw)85 public TrackManager(final DNADraw dnaDraw) 86 { 87 super("Track Manager"); 88 this.dnaDraw = dnaDraw; 89 setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); 90 91 createMenu(); 92 JScrollPane jsp = new JScrollPane(getPanelComponents()); 93 getContentPane().add(jsp); 94 pack(); 95 } 96 97 /** 98 * Create a menu for the track manager. 99 */ createMenu()100 private void createMenu() 101 { 102 final JMenu menuFile = new JMenu("File"); 103 final JMenuBar menuBar = new JMenuBar(); 104 setJMenuBar(menuBar); 105 menuBar.add(menuFile); 106 menuFile.add(getExportTrackTemplateMenuItem(this, dnaDraw)); 107 menuFile.add(getImportTrackTemplateMenuItem(this)); 108 final JMenuItem closeMenu = new JMenuItem("Close"); 109 closeMenu.addActionListener(new ActionListener() 110 { 111 public void actionPerformed(ActionEvent e) 112 { 113 TrackManager.this.setVisible(false); 114 } 115 }); 116 menuFile.add(closeMenu); 117 } 118 getImportTrackTemplateMenuItem(final JFrame f)119 protected JMenuItem getImportTrackTemplateMenuItem(final JFrame f) 120 { 121 final JMenuItem readTemplate = new JMenuItem("Import Track Template..."); 122 readTemplate.addActionListener(new ActionListener() 123 { 124 public void actionPerformed(ActionEvent arg0) 125 { 126 StickyFileChooser fileDialog = new StickyFileChooser(); 127 int status = fileDialog.showOpenDialog(f); 128 if(status == JFileChooser.CANCEL_OPTION) 129 return; 130 131 final File fileRead = fileDialog.getSelectedFile(); 132 if(!fileRead.exists()) 133 { 134 JOptionPane.showMessageDialog(f, 135 fileRead.getName()+" not found.", 136 "Problem Reading File", 137 JOptionPane.WARNING_MESSAGE); 138 return; 139 } 140 141 try 142 { 143 final FileReader reader = new FileReader(fileRead); 144 BufferedReader inputStream = new BufferedReader(reader); 145 String inLine = null; 146 147 Track[] tracks = Wizard.getTracks(); 148 int trackCount = 0; 149 150 while ((inLine = inputStream.readLine()) != null) 151 { 152 if(inLine.startsWith("#") || inLine.trim().equals("")) 153 continue; 154 155 if(trackCount >= tracks.length) 156 { 157 addTrack(); 158 tracks = Wizard.getTracks(); 159 } 160 tracks[trackCount].setPropertiesFromTemplate(inLine); 161 trackCount++; 162 } 163 inputStream.close(); 164 reader.close(); 165 refresh(); 166 } 167 catch(FileNotFoundException e) 168 { 169 e.printStackTrace(); 170 } 171 catch(IOException e) 172 { 173 e.printStackTrace(); 174 } 175 } 176 }); 177 return readTemplate; 178 } 179 180 /** 181 * Menu Item with associated ActionListener for exporting the properties 182 * of this track. 183 * @param f 184 * @return 185 */ getExportTrackTemplateMenuItem(final JFrame f, final DNADraw dnaDraw)186 protected static JMenuItem getExportTrackTemplateMenuItem(final JFrame f, 187 final DNADraw dnaDraw) 188 { 189 final JMenuItem saveTemplate = new JMenuItem("Export Track Template..."); 190 saveTemplate.addActionListener(new ActionListener() 191 { 192 public void actionPerformed(ActionEvent arg0) 193 { 194 StickyFileChooser fileDialog = new StickyFileChooser(); 195 int status = fileDialog.showSaveDialog(f); 196 if(status == JFileChooser.CANCEL_OPTION) 197 return; 198 199 final File fileWrite = fileDialog.getSelectedFile(); 200 if(fileWrite.exists()) 201 { 202 status = JOptionPane.showConfirmDialog(f, fileWrite.getName()+ 203 " exists. Overwrite?", 204 "Selected File Exists", 205 JOptionPane.OK_CANCEL_OPTION); 206 if(status == JFileChooser.CANCEL_OPTION) 207 return; 208 } 209 210 final Track[] tracks = Wizard.getTracks(); 211 try 212 { 213 final Writer writer = new FileWriter(fileWrite); 214 Track.writeHeader(writer, dnaDraw); 215 for(int i=0; i<tracks.length; i++) 216 tracks[i].write(writer); 217 writer.close(); 218 } 219 catch(IOException e) 220 { 221 e.printStackTrace(); 222 } 223 } 224 }); 225 return saveTemplate; 226 } 227 getPanelComponents()228 private JPanel getPanelComponents() 229 { 230 final Track[] tracks = Wizard.getTracks(); 231 GridBagLayout grid = new GridBagLayout(); 232 final GridBagConstraints c = new GridBagConstraints(); 233 c.ipady = 3; 234 c.ipadx = 5; 235 236 final JPanel optionBox = new JPanel(grid); 237 keyChoice = new KeyChoice[tracks.length]; 238 qualifierChoice = new QualifierChoice[tracks.length]; 239 qualifierValue = new JTextField[tracks.length]; 240 notQualifier = new JCheckBox[tracks.length]; 241 showForward = new JCheckBox[tracks.length]; 242 showReverse = new JCheckBox[tracks.length]; 243 showAny = new JCheckBox[tracks.length]; 244 trackSize = new TextFieldFloat[tracks.length]; 245 trackPosition = new TextFieldFloat[tracks.length]; 246 247 c.anchor = GridBagConstraints.WEST; 248 c.gridx = 0; 249 c.gridy = 0; 250 optionBox.add(new JLabel("Track"), c); 251 c.gridx = 1; 252 optionBox.add(new JLabel("Key"), c); 253 c.gridx = 2; 254 c.gridwidth = 4; 255 optionBox.add(new JLabel("Qualifier"), c); 256 c.gridx = 6; 257 c.gridwidth = 1; 258 optionBox.add(new JLabel("Strand"), c); 259 c.gridx = 9; 260 optionBox.add(new JLabel("Size"), c); 261 c.gridx = 10; 262 optionBox.add(new JLabel("Position"), c); 263 264 for(int i = 0; i < tracks.length; i++) 265 { 266 final Track track = tracks[i]; 267 c.gridx = 0; 268 c.gridy = i+1; 269 c.anchor = GridBagConstraints.EAST; 270 271 optionBox.add(new JLabel(Integer.toString(i+1)+" "+track.getEntry().getName()), c); 272 273 c.gridx = 1; 274 c.anchor = GridBagConstraints.WEST; 275 276 final Key key; 277 if(track.getKeyStr() != null) 278 key = new Key(track.getKeyStr()); 279 else 280 key = new Key("-"); 281 282 Entry entry = dnaDraw.getArtemisEntryGroup().getDefaultEntry(); 283 if(entry == null) 284 entry = dnaDraw.getArtemisEntryGroup().getSequenceEntry(); 285 keyChoice[i] = new KeyChoice( 286 entry.getEntryInformation(),key); 287 288 optionBox.add(keyChoice[i], c); 289 290 c.gridx = 2; 291 notQualifier[i] = new JCheckBox("Not", !track.isNotQualifier()); 292 optionBox.add(notQualifier[i], c); 293 294 c.gridx = 3; 295 String qualifier = track.getQualifier(); 296 final int n = i; 297 final JButton addQualifier = new JButton("ADD QUALIFIER"); 298 addQualifier.addActionListener(new ActionListener() 299 { 300 public void actionPerformed(ActionEvent e) 301 { 302 c.gridx = 3; 303 c.gridy = n+1; 304 qualifierChoice[n] = new QualifierChoice( 305 dnaDraw.getArtemisEntryGroup().getDefaultEntry().getEntryInformation(),key, null, false); 306 optionBox.add(qualifierChoice[n], c); 307 308 c.gridx = 4; 309 qualifierValue[n] = new JTextField(track.getQualifierValue(), 10); 310 optionBox.add(qualifierValue[n], c); 311 312 optionBox.remove(addQualifier); 313 optionBox.repaint(); 314 optionBox.revalidate(); 315 } 316 }); 317 318 if(qualifier == null) 319 optionBox.add(addQualifier, c); 320 else 321 { 322 qualifierChoice[i] = new QualifierChoice( 323 entry.getEntryInformation(),key, qualifier, false); 324 optionBox.add(qualifierChoice[i], c); 325 c.gridx = 4; 326 qualifierValue[i] = new JTextField(track.getQualifierValue(), 10); 327 optionBox.add(qualifierValue[i], c); 328 } 329 330 final JButton removeButton = new JButton("X"); 331 Font font = dnaDraw.getFont().deriveFont(Font.BOLD); 332 removeButton.setFont(font); 333 removeButton.setToolTipText("REMOVE QUALIFIER"); 334 c.gridx = 5; 335 optionBox.add(removeButton, c); 336 removeButton.setForeground(new Color(139,35,35)); 337 removeButton.addActionListener(new ActionListener() 338 { 339 public void actionPerformed(ActionEvent e) 340 { 341 if(qualifierChoice[n] != null) 342 { 343 optionBox.remove(qualifierChoice[n]); 344 optionBox.remove(qualifierValue[n]); 345 } 346 347 c.gridx = 3; 348 c.gridy = n+1; 349 optionBox.add(addQualifier, c); 350 qualifierChoice[n] = null; 351 optionBox.repaint(); 352 optionBox.revalidate(); 353 } 354 }); 355 removeButton.setPreferredSize(new Dimension(35, 356 removeButton.getPreferredSize().height)); 357 358 c.gridx = 6; 359 showForward[i] = new JCheckBox("Forward", track.isShowForward()); 360 optionBox.add(showForward[i], c); 361 362 c.gridx = 7; 363 showReverse[i] = new JCheckBox("Reverse", track.isShowReverse()); 364 optionBox.add(showReverse[i], c); 365 366 c.gridx = 8; 367 showAny[i] = new JCheckBox("Any", track.isAny()); 368 optionBox.add(showAny[i], c); 369 370 c.gridx = 9; 371 trackSize[i] = new TextFieldFloat(); 372 trackSize[i].setValue(track.getSize()); 373 trackSize[i].setColumns(4); 374 optionBox.add(trackSize[i], c); 375 376 c.gridx = 10; 377 trackPosition[i] = new TextFieldFloat(); 378 trackPosition[i].setValue(track.getPosition()); 379 trackPosition[i].setColumns(4); 380 optionBox.add(trackPosition[i], c); 381 382 383 c.gridx = 11; 384 final JButton colourSelection = new JButton("COLOUR"); 385 386 colourSelection.addActionListener(new ActionListener() 387 { 388 public void actionPerformed(ActionEvent e) 389 { 390 final JFrame frameColour = new JFrame("Track "+(n+1)+" Colour"); 391 GridBagLayout grid = new GridBagLayout(); 392 final GridBagConstraints c = new GridBagConstraints(); 393 c.ipady = 3; 394 c.ipadx = 5; 395 c.anchor = GridBagConstraints.WEST; 396 397 final JPanel optionBox = new JPanel(grid); 398 frameColour.getContentPane().add(optionBox); 399 400 Color col = track.getColour(); 401 if(col == null) 402 col = Color.red; 403 404 final JButton colourButton = GeneticMarker.setUpColorButton(col); 405 c.gridx = 0; 406 c.gridy = 0; 407 optionBox.add(new JLabel("Pick a Colour:"),c); 408 c.gridx = 1; 409 c.gridy = 0; 410 optionBox.add(colourButton,c); 411 412 final JCheckBox colourQualifier = new JCheckBox("Use colour qualifier"); 413 if(track.getColour() == null) 414 colourQualifier.setSelected(true); 415 else 416 colourQualifier.setSelected(false); 417 418 colourQualifier.addItemListener(new ItemListener() 419 { 420 public void itemStateChanged(ItemEvent e) 421 { 422 if(colourQualifier.isSelected()) 423 track.setColour(null); 424 else 425 track.setColour(colourButton.getBackground()); 426 dnaDraw.repaint(); 427 } 428 }); 429 430 final JButton ok = new JButton("Apply Colour to All"); 431 ok.addActionListener(new ActionListener() 432 { 433 public void actionPerformed(ActionEvent e) 434 { 435 track.setColour(colourButton.getBackground()); 436 colourQualifier.setSelected(false); 437 dnaDraw.repaint(); 438 } 439 }); 440 c.gridx = 2; 441 c.gridy = 0; 442 optionBox.add(ok,c); 443 444 c.gridx = 1; 445 c.gridy = 1; 446 c.gridwidth = 2; 447 optionBox.add(colourQualifier, c); 448 449 c.gridx = 1; 450 c.gridy = 2; 451 final JButton close = new JButton("Close"); 452 close.addActionListener(new ActionListener() 453 { 454 public void actionPerformed(ActionEvent e) 455 { 456 frameColour.dispose(); 457 } 458 }); 459 optionBox.add(close,c); 460 461 frameColour.pack(); 462 frameColour.setVisible(true); 463 } 464 }); 465 optionBox.add(colourSelection, c); 466 467 468 c.gridx = 12; 469 final int trackIndex = i; 470 final JButton deleteTrack = new JButton("DELETE"); 471 deleteTrack.addActionListener(new ActionListener() 472 { 473 public void actionPerformed(ActionEvent e) 474 { 475 int val = JOptionPane.showConfirmDialog(dnaDraw, 476 "Delete track "+(trackIndex+1)+"?", 477 "Confirm", JOptionPane.OK_CANCEL_OPTION); 478 if(val == JOptionPane.CANCEL_OPTION) 479 return; 480 481 Wizard.deleteTrack(trackIndex); 482 getContentPane().removeAll(); 483 484 JScrollPane jsp = new JScrollPane(getPanelComponents()); 485 getContentPane().add(jsp); 486 pack(); 487 488 setVisible(true); 489 update(Wizard.getTracks()); 490 } 491 }); 492 optionBox.add(deleteTrack, c); 493 } 494 495 c.gridx = 0; 496 c.gridy = tracks.length+1; 497 c.gridwidth = 2; 498 499 JButton updateButton = new JButton("UPDATE TRACKS"); 500 optionBox.add(updateButton,c); 501 updateButton.addActionListener(new ActionListener() 502 { 503 public void actionPerformed(ActionEvent e) 504 { 505 update(tracks); 506 } 507 }); 508 509 c.gridx = 2; 510 c.gridy = tracks.length+1; 511 c.gridwidth = 2; 512 513 JButton addTrackButton = new JButton("ADD TRACK"); 514 optionBox.add(addTrackButton,c); 515 addTrackButton.addActionListener(new ActionListener() 516 { 517 public void actionPerformed(ActionEvent e) 518 { 519 addTrack(); 520 } 521 }); 522 523 return optionBox; 524 } 525 refresh()526 protected void refresh() 527 { 528 getContentPane().removeAll(); 529 JScrollPane jsp = new JScrollPane(getPanelComponents()); 530 getContentPane().add(jsp); 531 pack(); 532 } 533 addTrack()534 private void addTrack() 535 { 536 Entry entry; 537 if(Wizard.getTracks().length > 0) 538 entry = Wizard.getTracks()[0].getEntry(); 539 else 540 entry = dnaDraw.getArtemisEntryGroup().elementAt(0); 541 542 Wizard.addTrack( entry ); 543 refresh(); 544 setVisible(true); 545 } 546 547 /** 548 * Update the tracks based on the Track Manager settings 549 * @param tracks 550 */ update(final Track[] tracks)551 public void update(final Track[] tracks) 552 { 553 // update tracks 554 for(int i=0; i<tracks.length; i++) 555 { 556 if(keyChoice[i].getSelectedItem().getKeyString().equals("-")) 557 { 558 tracks[i].setFeaturePredicate(null); 559 tracks[i].setAny(showAny[i].isSelected()); 560 tracks[i].setKeyStr("-"); 561 } 562 else 563 { 564 tracks[i].setKeyStr(keyChoice[i].getSelectedItem().getKeyString()); 565 if(qualifierChoice[i] == null) 566 { 567 tracks[i].setFeaturePredicate(new FeatureKeyPredicate(keyChoice[i].getSelectedItem())); 568 tracks[i].setQualifier(null); 569 } 570 else 571 { 572 if(qualifierValue[i].getText().trim().equals("")) 573 { 574 tracks[i].setFeaturePredicate( 575 new FeatureKeyQualifierPredicate(keyChoice[i].getSelectedItem(), 576 (String)qualifierChoice[i].getSelectedItem(), !notQualifier[i].isSelected())); 577 } 578 else 579 { 580 581 final FeaturePredicateVector temp_predicates = 582 new FeaturePredicateVector(); 583 584 //final StringVector words = 585 // StringVector.getStrings(search_text, " "); 586 587 final StringTokenizer tok = new StringTokenizer(qualifierValue[i].getText(), " \n"); 588 589 while(tok.hasMoreTokens()) 590 { 591 final String this_word = tok.nextToken().trim(); 592 final FeaturePredicate new_predicate = 593 new FeatureKeyQualifierPredicate(keyChoice[i].getSelectedItem(), 594 (String)qualifierChoice[i].getSelectedItem(), 595 this_word, 596 false, 597 true); 598 599 temp_predicates.add(new_predicate); 600 } 601 602 FeaturePredicateConjunction key_and_qualifier_predicate = 603 new FeaturePredicateConjunction(temp_predicates, 604 FeaturePredicateConjunction.OR); 605 606 607 tracks[i].setFeaturePredicate(key_and_qualifier_predicate); 608 } 609 tracks[i].setQualifier((String)qualifierChoice[i].getSelectedItem()); 610 tracks[i].setQualifierValue(qualifierValue[i].getText()); 611 } 612 tracks[i].setAny(false); 613 } 614 tracks[i].setShowForward(showForward[i].isSelected()); 615 tracks[i].setShowReverse(showReverse[i].isSelected()); 616 tracks[i].setNotQualifier(!notQualifier[i].isSelected()); 617 tracks[i].setSize((float) trackSize[i].getValue()); 618 tracks[i].setPosition(trackPosition[i].getValue()); 619 } 620 621 // update viewer 622 updateDNADraw(dnaDraw, tracks); 623 } 624 625 updateDNADraw(final DNADraw dnaDraw, final Track[] tracks)626 private static void updateDNADraw(final DNADraw dnaDraw, final Track[] tracks) 627 { 628 dnaDraw.getBlock().removeAll(dnaDraw.getBlock()); 629 final FeatureVector features = dnaDraw.getArtemisEntryGroup().getAllFeatures(); 630 631 for(int i=0; i<features.size(); i++) 632 { 633 Feature f = features.elementAt(i); 634 Vector myTracks = new Vector(); 635 636 for(int j=0; j<tracks.length; j++) 637 { 638 if(tracks[j].isOnTrack(f)) 639 myTracks.add(tracks[j]); 640 } 641 642 if(myTracks.size() < 1) 643 continue; 644 645 Color col = f.getColour(); 646 if(col == null || col.equals(Color.white)) 647 col = Color.lightGray; 648 649 RangeVector ranges = f.getLocation().getRanges(); 650 651 for(int j=0; j<ranges.size(); j++) 652 { 653 Range range = (Range) ranges.get(j); 654 655 for(int k=0; k<myTracks.size(); k++) 656 { 657 Track myTrack = (Track)myTracks.get(k); 658 Block drawBlock = new Block(f.getIDString(), 659 range.getStart(), 660 range.getEnd(), 661 col, 662 myTrack.getSize(), 663 myTrack, dnaDraw); 664 665 drawBlock.setFeature(f); 666 dnaDraw.getBlock().add(drawBlock); 667 } 668 } 669 } 670 671 dnaDraw.repaint(); 672 } 673 674 } 675 676