001 /*
002 * PairwiseAlignmentFrame.java
003 *
004 * Copyright 2003 Sergio Anibal de Carvalho Junior
005 *
006 * This file is part of NeoBio.
007 *
008 * NeoBio is free software; you can redistribute it and/or modify it under the terms of
009 * the GNU General Public License as published by the Free Software Foundation; either
010 * version 2 of the License, or (at your option) any later version.
011 *
012 * NeoBio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
013 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
014 * PURPOSE. See the GNU General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License along with NeoBio;
017 * if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
018 * Boston, MA 02111-1307, USA.
019 *
020 * Proper attribution of the author as the source of the software would be appreciated.
021 *
022 * Sergio Anibal de Carvalho Junior mailto:sergioanibaljr@users.sourceforge.net
023 * Department of Computer Science http://www.dcs.kcl.ac.uk
024 * King's College London, UK http://www.kcl.ac.uk
025 *
026 * Please visit http://neobio.sourceforge.net
027 *
028 * This project was supervised by Professor Maxime Crochemore.
029 *
030 */
031
032 package neobio.gui;
033
034 import neobio.alignment.*;
035
036 import java.io.*;
037 import java.awt.*;
038 import java.awt.event.*;
039 import javax.swing.*;
040 import javax.swing.border.*;
041 import javax.swing.event.*;
042
043 /**
044 * This class is the internal frame of NeoBio's graphical interface for computing pairwise
045 * sequence alignments using one of the the algorithms provided in the {@link
046 * neobio.alignment} package.
047 *
048 * @author Sergio A. de Carvalho Jr.
049 */
050 public class PairwiseAlignmentFrame extends JInternalFrame
051 {
052 private static int window_number = 1;
053
054 private Frame parent_frame;
055
056 private JPanel input_panel, scoring_panel, algorithm_panel, output_panel;
057 private JPanel progress_tab_panel, output_tab_panel;
058 private JTextField seq1_field, seq2_field, matrix_field, output_field;
059 private JTextField match_field, mismatch_field, gap_field;
060 private JTextArea progress_area, output_area;
061 private JButton find_seq1_button, find_seq2_button, find_output_button;
062 private JButton find_matrix_button, run_button;
063 private JComboBox algorithm_combo;
064 private JTabbedPane output_tab;
065 private JRadioButton screen_button, file_button, basic_button, matrix_button;
066 private ButtonGroup scoring_group, output_group;
067 private JLabel seq1_label, seq2_label;
068 private JLabel match_label, mismatch_label, gap_label;
069
070 private JFileChooser find_dialog;
071
072 private boolean output_to_file, basic_scheme;
073
074 private String[] algorithm_name = {"Needleman & Wunsch (global alignment)",
075 "Smith & Waterman (local alignment)",
076 "Crochemore, Landau & Ziv-Ukelson for global alignment",
077 "Crochemore, Landau & Ziv-Ukelson for local alignment"};
078
079 private PairwiseAlignmentAlgorithm[] algorithm = {new NeedlemanWunsch(),
080 new SmithWaterman(),
081 new CrochemoreLandauZivUkelsonGlobalAlignment(),
082 new CrochemoreLandauZivUkelsonLocalAlignment()};
083
084 /**
085 * Creates a new instance of the internal frame.
086 *
087 * @param parent_frame the parent frame
088 */
089 public PairwiseAlignmentFrame (Frame parent_frame)
090 {
091 this.parent_frame = parent_frame;
092 initComponents();
093 }
094
095 private void initComponents()
096 {
097 JComponent pane;
098 GridBagConstraints c;
099
100 setIconifiable(true);
101 setMaximizable(true);
102 setResizable(true);
103 setClosable(true);
104 setTitle("Pairwise Sequence Alignment " + window_number++);
105 setMinimumSize(new Dimension(500, 500));
106
107 pane = (JComponent) getContentPane();
108 pane.setLayout(new GridBagLayout());
109
110 c = new GridBagConstraints();
111 c.insets = new Insets (4, 4, 4, 4);
112 c.fill = GridBagConstraints.BOTH;
113 c.weightx = 1.0; c.weighty = 0;
114
115 // input panel
116 input_panel = new JPanel ();
117 add (pane, input_panel, c, 0, 0);
118
119 // scoring panel
120 scoring_panel = new JPanel ();
121 add (pane, scoring_panel, c, 0, 1);
122
123 // output panel
124 output_panel = new JPanel ();
125 add (pane, output_panel, c, 0, 2);
126
127 // algorithm panel
128 algorithm_panel = new JPanel ();
129 add (pane, algorithm_panel, c, 0, 3);
130
131 c.weightx = 1.0; c.weighty = 1.0;
132
133 // output tab
134 output_tab = new JTabbedPane();
135 add (pane, output_tab, c, 0, 4);
136
137 find_dialog = new JFileChooser();
138 find_dialog.setDialogTitle("Find...");
139 find_dialog.setDialogType(JFileChooser.OPEN_DIALOG );
140
141 // ***************** INPUT PANEL *****************
142 input_panel.setLayout(new GridBagLayout());
143 input_panel.setBorder(BorderFactory.createTitledBorder(new EtchedBorder(
144 EtchedBorder.LOWERED), "Input"));
145
146 seq1_label = new JLabel("Sequence 1:");
147 seq2_label = new JLabel("Sequence 2:");
148
149 seq1_field = new JTextField();
150 seq1_field.addCaretListener (new CaretListener()
151 {
152 public void caretUpdate (CaretEvent e)
153 {
154 checkRunButtonStatus ();
155 }
156 });
157
158 seq2_field = new JTextField();
159 seq2_field.addCaretListener (new CaretListener()
160 {
161 public void caretUpdate (CaretEvent e)
162 {
163 checkRunButtonStatus ();
164 }
165 });
166
167 find_seq1_button = new JButton("Find...");
168 find_seq1_button.addActionListener (new ActionListener()
169 {
170 public void actionPerformed (ActionEvent e)
171 {
172 findSeq1ButtonActionPerformed();
173 }
174 });
175
176 find_seq2_button = new JButton("Find...");
177 find_seq2_button.addActionListener (new ActionListener()
178 {
179 public void actionPerformed (ActionEvent e)
180 {
181 findSeq2ButtonActionPerformed();
182 }
183 });
184
185 c.weightx = 0; c.weighty = 0; c.anchor = GridBagConstraints.EAST;
186 add (input_panel, seq1_label, c, 0, 0);
187 add (input_panel, seq2_label, c, 0, 1);
188
189 c.anchor = GridBagConstraints.CENTER;
190 add (input_panel, find_seq1_button, c, 2, 0);
191 add (input_panel, find_seq2_button, c, 2, 1);
192
193 c.weightx = 1.0; c.fill = GridBagConstraints.HORIZONTAL;
194 add (input_panel, seq1_field, c, 1, 0);
195 add (input_panel, seq2_field, c, 1, 1);
196
197 // ***************** SCORING SCHEME PANEL *****************
198 scoring_panel.setLayout(new GridBagLayout());
199 scoring_panel.setBorder(BorderFactory.createTitledBorder(new EtchedBorder(
200 EtchedBorder.LOWERED), "Scoring Scheme"));
201
202 basic_scheme = true;
203 basic_button = new JRadioButton("Basic:");
204 basic_button.setSelected(true);
205 basic_button.addItemListener (new ItemListener()
206 {
207 public void itemStateChanged (ItemEvent e)
208 {
209 schemeOptionStateChanged();
210 }
211 });
212
213 matrix_button = new JRadioButton("Substitution Matrix:");
214 matrix_button.addItemListener (new ItemListener()
215 {
216 public void itemStateChanged (ItemEvent e)
217 {
218 schemeOptionStateChanged();
219 }
220 });
221
222 match_label = new JLabel("Match:");
223 mismatch_label = new JLabel ("Mismatch:");
224 gap_label = new JLabel ("Gap:");
225
226 match_field = new JTextField("1", 2);
227 match_field.setHorizontalAlignment(JTextField.RIGHT);
228 match_field.addCaretListener (new CaretListener()
229 {
230 public void caretUpdate (CaretEvent e)
231 {
232 checkRunButtonStatus ();
233 }
234 });
235
236 mismatch_field = new JTextField("-1", 2);
237 mismatch_field.setHorizontalAlignment(JTextField.RIGHT);
238 mismatch_field.addCaretListener (new CaretListener()
239 {
240 public void caretUpdate (CaretEvent e)
241 {
242 checkRunButtonStatus ();
243 }
244 });
245
246 gap_field = new JTextField("-1", 2);
247 gap_field.setHorizontalAlignment(JTextField.RIGHT);
248 gap_field.addCaretListener (new CaretListener()
249 {
250 public void caretUpdate (CaretEvent e)
251 {
252 checkRunButtonStatus ();
253 }
254 });
255
256 matrix_field = new JTextField();
257 matrix_field.setEnabled(false);
258 matrix_field.addCaretListener (new CaretListener()
259 {
260 public void caretUpdate (CaretEvent e)
261 {
262 checkRunButtonStatus ();
263 }
264 });
265
266 find_matrix_button = new JButton("Find...");
267 find_matrix_button.setEnabled(false);
268 find_matrix_button.addActionListener (new ActionListener()
269 {
270 public void actionPerformed (ActionEvent e)
271 {
272 findMatrixButtonActionPerformed();
273 }
274 });
275
276 scoring_group = new ButtonGroup ();
277 scoring_group.add(basic_button);
278 scoring_group.add(matrix_button);
279
280 c.weightx = 0; c.fill = GridBagConstraints.NONE;
281 c.anchor = GridBagConstraints.WEST;
282 add (scoring_panel, basic_button, c, 0, 0);
283
284 c.anchor = GridBagConstraints.EAST;
285 add (scoring_panel, match_label, c, 1, 0);
286 add (scoring_panel, mismatch_label, c, 3, 0);
287 add (scoring_panel, gap_label, c, 5, 0);
288
289 c.anchor = GridBagConstraints.WEST;
290 add (scoring_panel, matrix_button, c, 0, 1);
291
292 c.anchor = GridBagConstraints.CENTER;
293 add (scoring_panel, find_matrix_button, c, 7, 1);
294
295 c.weightx = 1.0 / 3; c.fill = GridBagConstraints.HORIZONTAL;
296 add (scoring_panel, match_field, c, 2, 0);
297 add (scoring_panel, mismatch_field, c, 4, 0);
298 add (scoring_panel, gap_field, c, 6, 0);
299
300 c.weightx = 1.0; c.gridwidth = 6;
301 add (scoring_panel, matrix_field, c, 1, 1);
302 c.gridwidth = 1;
303
304 // ***************** OUTPUT PANEL *****************
305 output_panel.setLayout(new GridBagLayout());
306 output_panel.setBorder(BorderFactory.createTitledBorder(new EtchedBorder(
307 EtchedBorder.LOWERED), "Output"));
308
309 screen_button = new JRadioButton("Screen");
310 screen_button.setSelected(true);
311
312 output_to_file = false;
313 file_button = new JRadioButton("File:");
314 file_button.addItemListener (new ItemListener()
315 {
316 public void itemStateChanged (ItemEvent e)
317 {
318 outputOptionStateChanged();
319 }
320 });
321
322 output_field = new JTextField();
323 output_field.setEnabled(false);
324 output_field.addCaretListener (new CaretListener()
325 {
326 public void caretUpdate (CaretEvent e)
327 {
328 checkRunButtonStatus ();
329 }
330 });
331
332 find_output_button = new JButton("Find...");
333 find_output_button.setEnabled(false);
334 find_output_button.addActionListener (new ActionListener()
335 {
336 public void actionPerformed (ActionEvent e)
337 {
338 findOutputButtonActionPerformed();
339 }
340 });
341
342 output_group = new ButtonGroup ();
343 output_group.add(screen_button);
344 output_group.add(file_button);
345
346 c.weightx = 0; c.weighty = 0; c.fill = GridBagConstraints.NONE;
347 add (output_panel, screen_button, c, 0, 0);
348 add (output_panel, file_button, c, 1, 0);
349 add (output_panel, find_output_button, c, 3, 0);
350
351 c.weightx = 1.0; c.weighty = 0; c.fill = GridBagConstraints.HORIZONTAL;
352 add (output_panel, output_field, c, 2, 0);
353
354 // ***************** ALGORITHM PANEL *****************
355 algorithm_panel.setLayout(new GridBagLayout());
356 algorithm_panel.setBorder(BorderFactory.createTitledBorder(new EtchedBorder(
357 EtchedBorder.LOWERED), "Alignment Algorithm"));
358
359 algorithm_combo = new JComboBox(algorithm_name);
360
361 run_button = new JButton("Run");
362 run_button.setEnabled(false);
363 run_button.addActionListener (new ActionListener()
364 {
365 public void actionPerformed (ActionEvent e)
366 {
367 runButtonActionPerformed();
368 }
369 });
370
371
372 c.weightx = 1.0; c.weighty = 0; c.fill = GridBagConstraints.HORIZONTAL;
373 add (algorithm_panel, algorithm_combo, c, 0, 0);
374
375 c.weightx = 0; c.weighty = 0; c.fill = GridBagConstraints.NONE;
376 add (algorithm_panel, run_button, c, 1, 0);
377
378 // ***************** OUTPUT TAB *****************
379 progress_area = new JTextArea ();
380 progress_area.setEditable (false);
381 progress_area.setBorder (BorderFactory.createBevelBorder(BevelBorder.LOWERED));
382 progress_tab_panel = new JPanel ();
383 progress_tab_panel.setLayout (new GridLayout());
384 progress_tab_panel.add (new JScrollPane (progress_area));
385 output_tab.addTab ("Progress", progress_tab_panel);
386
387 output_area = new JTextArea ();
388 output_area.setEditable (false);
389 output_area.setBorder (BorderFactory.createBevelBorder(BevelBorder.LOWERED));
390 output_area.setFont (new Font("Monospaced", Font.PLAIN, 12));
391 output_tab_panel = new JPanel();
392 output_tab_panel.setLayout (new GridLayout());
393 output_tab_panel.add (new JScrollPane (output_area));
394 output_tab.addTab ("Output", output_tab_panel);
395 }
396
397 private void add (JComponent a, JComponent b, GridBagConstraints c, int x, int y)
398 {
399 c.gridx = x;
400 c.gridy = y;
401 a.add (b, c);
402 }
403
404 private void findSeq1ButtonActionPerformed ()
405 {
406 int c = find_dialog.showOpenDialog (this);
407
408 if (c != JFileChooser.APPROVE_OPTION) return;
409
410 seq1_field.setText (find_dialog.getSelectedFile().getPath());
411 }
412
413 private void findSeq2ButtonActionPerformed ()
414 {
415 int c = find_dialog.showOpenDialog (this);
416
417 if (c != JFileChooser.APPROVE_OPTION) return;
418
419 seq2_field.setText (find_dialog.getSelectedFile().getPath());
420 }
421
422 private void findMatrixButtonActionPerformed ()
423 {
424 int c = find_dialog.showOpenDialog (this);
425
426 if (c != JFileChooser.APPROVE_OPTION) return;
427
428 matrix_field.setText (find_dialog.getSelectedFile().getPath());
429 }
430
431 private void findOutputButtonActionPerformed ()
432 {
433 int c = find_dialog.showOpenDialog (this);
434
435 if (c != JFileChooser.APPROVE_OPTION) return;
436
437 output_field.setText (find_dialog.getSelectedFile().getPath());
438 }
439
440 private void schemeOptionStateChanged ()
441 {
442 basic_scheme = basic_button.isSelected();
443
444 match_label.setEnabled(basic_scheme);
445 match_field.setEnabled(basic_scheme);
446 mismatch_label.setEnabled(basic_scheme);
447 mismatch_field.setEnabled(basic_scheme);
448 gap_label.setEnabled(basic_scheme);
449 gap_field.setEnabled(basic_scheme);
450
451 matrix_field.setEnabled (!basic_scheme);
452 find_matrix_button.setEnabled (!basic_scheme);
453
454 checkRunButtonStatus();
455 }
456
457 private void outputOptionStateChanged ()
458 {
459 output_to_file = file_button.isSelected();
460
461 output_field.setEnabled (output_to_file);
462 find_output_button.setEnabled (output_to_file);
463
464 checkRunButtonStatus();
465 }
466
467 private void checkRunButtonStatus ()
468 {
469 boolean run = true;
470
471 if (seq1_field.getText().length() == 0 || seq2_field.getText().length() == 0)
472 {
473 run = false;
474 }
475 else
476 {
477 if (file_button.isSelected() && output_field.getText().length() == 0)
478 {
479 run = false;
480 }
481 else
482 {
483 if (matrix_button.isSelected())
484 {
485 if (matrix_field.getText().length() == 0)
486 {
487 run = false;
488 }
489 }
490 else
491 {
492 if (match_field.getText().length() == 0
493 || mismatch_field.getText().length() == 0
494 || gap_field.getText().length() == 0)
495 {
496 run = false;
497 }
498 }
499 }
500 }
501
502 if ((run_button.isEnabled() && !run) || (!run_button.isEnabled() && run))
503 run_button.setEnabled(run);
504 }
505
506 private void runButtonActionPerformed ()
507 {
508 ScoringScheme scoring;
509 PairwiseAlignment alignment;
510 FileReader seq1_file, seq2_file, matrix_file;
511 BufferedWriter output_file;
512 String seq1_filename, seq2_filename;
513 String matrix_filename, output_filename, message;
514 int alg, match, mismatch, gap;
515 long start, elapsed;
516
517 alg = algorithm_combo.getSelectedIndex();
518
519 output_tab.setSelectedIndex(0);
520
521 output_area.setText ("");
522
523 // ***************** SET SCORING SCHEME *****************
524 if (basic_scheme)
525 {
526 progress_area.setText ("Creating scoring scheme... ");
527 try
528 {
529 match = Integer.parseInt (match_field.getText());
530 mismatch = Integer.parseInt (mismatch_field.getText());
531 gap = Integer.parseInt (gap_field.getText());
532
533 scoring = new BasicScoringScheme (match, mismatch, gap);
534 algorithm[alg].setScoringScheme(scoring);
535 progress_area.append ("OK");
536 }
537 catch (NumberFormatException e)
538 {
539 message = "Invalid scoring arguments.";
540 progress_area.append ("\n" + message);
541 showError (message);
542 return;
543 }
544 }
545 else
546 {
547 matrix_filename = matrix_field.getText ();
548 progress_area.setText ("Loading matrix file... ");
549 try
550 {
551 matrix_file = new FileReader (matrix_filename);
552 }
553 catch (FileNotFoundException e)
554 {
555 message = "File \"" + matrix_filename + "\" not found.";
556 progress_area.append("\n" + message);
557 showError (message);
558 return;
559 }
560
561 try
562 {
563 try
564 {
565 scoring = new ScoringMatrix (matrix_file);
566 algorithm[alg].setScoringScheme(scoring);
567 progress_area.append ("OK");
568 }
569 catch (InvalidScoringMatrixException e)
570 {
571 matrix_file.close();
572 message = "Invalid matrix file \"" + matrix_filename + "\".";
573 progress_area.append ("\n" + message);
574 showError (message);
575 return;
576 }
577 matrix_file.close();
578 }
579 catch (IOException e)
580 {
581 message = "Error reading file.";
582 progress_area.append("\n" + message);
583 showError (message);
584 return;
585 }
586 }
587
588 // ***************** LOAD SEQUENCES *****************
589 progress_area.append ("\n\nLoading sequences... ");
590
591 seq1_filename = seq1_field.getText ();
592 try
593 {
594 seq1_file = new FileReader (seq1_filename);
595 }
596 catch (FileNotFoundException e)
597 {
598 message = "File \"" + seq1_filename +"\" not found.";
599 progress_area.append("\n" + message);
600 showError (message);
601 return;
602 }
603
604 seq2_filename = seq2_field.getText ();
605 try
606 {
607 seq2_file = new FileReader (seq2_filename);
608 }
609 catch (FileNotFoundException e)
610 {
611 message = "File \"" + seq2_filename +"\" not found.";
612 progress_area.append("\n" + message);
613 showError (message);
614 return;
615 }
616
617 try
618 {
619 try
620 {
621 start = System.currentTimeMillis();
622 algorithm[alg].loadSequences (seq1_file, seq2_file);
623 elapsed = System.currentTimeMillis() - start;
624 progress_area.append ("OK");
625 progress_area.append ("\n[ Elapsed time: " + elapsed + " milliseconds ]");
626
627 }
628 catch (InvalidSequenceException e)
629 {
630 seq1_file.close();
631 seq2_file.close();
632 message = "Invalid sequence files.";
633 progress_area.append ("\n" + message);
634 showError (message);
635 return;
636 }
637 seq1_file.close();
638 seq2_file.close();
639 }
640 catch (IOException e)
641 {
642 message = "Error reading sequence files.";
643 progress_area.append("\n" + message);
644 showError (message);
645 return;
646 }
647
648 // ***************** EXECUTE ALGORITHM *****************
649 progress_area.append("\n\nRunning " + algorithm_combo.getSelectedItem() + "... ");
650 try
651 {
652 start = System.currentTimeMillis();
653 alignment = algorithm[alg].getPairwiseAlignment();
654 elapsed = System.currentTimeMillis() - start;
655 progress_area.append ("OK");
656 progress_area.append ("\n[ Elapsed time: " + elapsed + " milliseconds ]");
657 }
658 catch (IncompatibleScoringSchemeException e)
659 {
660 message = "Scoring matrix is not compatible with loaded sequences.";
661 progress_area.append ("\n" + message);
662 showError (message);
663 return;
664 }
665 catch (OutOfMemoryError e)
666 {
667 message = "Insufficient memory to compute an alignment";
668 progress_area.append ("\n" + message);
669 showError (message);
670 return;
671 }
672
673 // ***************** DISPLAY / SAVE OUTPUT *****************
674 if (output_to_file)
675 {
676 output_filename = output_field.getText ();
677 progress_area.append ("\n\nSaving alignment... ");
678 try
679 {
680 int length = alignment.getGappedSequence1().length();
681
682 output_file = new BufferedWriter(new FileWriter (output_filename));
683 output_file.write(alignment.getGappedSequence1(), 0, length);
684 output_file.newLine();
685 output_file.write(alignment.getScoreTagLine(), 0, length);
686 output_file.newLine();
687 output_file.write(alignment.getGappedSequence2(), 0, length);
688 output_file.newLine();
689 String tmp = "Score: " + alignment.getScore();
690 output_file.write(tmp, 0, tmp.length());
691 output_file.close();
692 }
693 catch (IOException e)
694 {
695 message = "Error writing file \"" + output_filename +"\".";
696 progress_area.append("\n" + message);
697 showError (message);
698 return;
699 }
700 progress_area.append ("OK");
701 }
702 else
703 {
704 output_area.setText (alignment.toString());
705 output_tab.setSelectedIndex(1);
706 }
707 }
708
709 private void showError (String message)
710 {
711 JOptionPane.showMessageDialog(this, message, "Error", JOptionPane.ERROR_MESSAGE);
712 }
713 }