scrubbed classpath. again.
[jalview.git] / src / jalview / gui / AlignFrame.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)
3  * Copyright (C) 2011 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
10  * 
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.gui;
19
20 import jalview.analysis.AAFrequency;
21 import jalview.analysis.AlignmentSorter;
22 import jalview.analysis.Conservation;
23 import jalview.analysis.CrossRef;
24 import jalview.analysis.NJTree;
25 import jalview.analysis.ParseProperties;
26 import jalview.analysis.SequenceIdMatcher;
27 import jalview.bin.Cache;
28 import jalview.commands.CommandI;
29 import jalview.commands.EditCommand;
30 import jalview.commands.OrderCommand;
31 import jalview.commands.RemoveGapColCommand;
32 import jalview.commands.RemoveGapsCommand;
33 import jalview.commands.SlideSequencesCommand;
34 import jalview.commands.TrimRegionCommand;
35 import jalview.datamodel.AlignedCodonFrame;
36 import jalview.datamodel.Alignment;
37 import jalview.datamodel.AlignmentAnnotation;
38 import jalview.datamodel.AlignmentI;
39 import jalview.datamodel.AlignmentOrder;
40 import jalview.datamodel.AlignmentView;
41 import jalview.datamodel.ColumnSelection;
42 import jalview.datamodel.PDBEntry;
43 import jalview.datamodel.SeqCigar;
44 import jalview.datamodel.Sequence;
45 import jalview.datamodel.SequenceGroup;
46 import jalview.datamodel.SequenceI;
47 import jalview.io.AlignmentProperties;
48 import jalview.io.AnnotationFile;
49 import jalview.io.FeaturesFile;
50 import jalview.io.FileLoader;
51 import jalview.io.FormatAdapter;
52 import jalview.io.HTMLOutput;
53 import jalview.io.IdentifyFile;
54 import jalview.io.JalviewFileChooser;
55 import jalview.io.JalviewFileView;
56 import jalview.io.JnetAnnotationMaker;
57 import jalview.io.NewickFile;
58 import jalview.io.TCoffeeScoreFile;
59 import jalview.jbgui.GAlignFrame;
60 import jalview.schemes.Blosum62ColourScheme;
61 import jalview.schemes.BuriedColourScheme;
62 import jalview.schemes.ClustalxColourScheme;
63 import jalview.schemes.ColourSchemeI;
64 import jalview.schemes.ColourSchemeProperty;
65 import jalview.schemes.HelixColourScheme;
66 import jalview.schemes.HydrophobicColourScheme;
67 import jalview.schemes.NucleotideColourScheme;
68 import jalview.schemes.PIDColourScheme;
69 import jalview.schemes.ResidueProperties;
70 import jalview.schemes.StrandColourScheme;
71 import jalview.schemes.TCoffeeColourScheme;
72 import jalview.schemes.TaylorColourScheme;
73 import jalview.schemes.TurnColourScheme;
74 import jalview.schemes.UserColourScheme;
75 import jalview.schemes.ZappoColourScheme;
76 import jalview.ws.jws1.Discoverer;
77 import jalview.ws.jws2.Jws2Discoverer;
78
79 import java.awt.BorderLayout;
80 import java.awt.Color;
81 import java.awt.Component;
82 import java.awt.GridLayout;
83 import java.awt.Rectangle;
84 import java.awt.Toolkit;
85 import java.awt.datatransfer.Clipboard;
86 import java.awt.datatransfer.DataFlavor;
87 import java.awt.datatransfer.StringSelection;
88 import java.awt.datatransfer.Transferable;
89 import java.awt.dnd.DnDConstants;
90 import java.awt.dnd.DropTargetDragEvent;
91 import java.awt.dnd.DropTargetDropEvent;
92 import java.awt.dnd.DropTargetEvent;
93 import java.awt.dnd.DropTargetListener;
94 import java.awt.event.ActionEvent;
95 import java.awt.event.ActionListener;
96 import java.awt.event.KeyAdapter;
97 import java.awt.event.KeyEvent;
98 import java.awt.event.MouseAdapter;
99 import java.awt.event.MouseEvent;
100 import java.awt.print.PageFormat;
101 import java.awt.print.PrinterJob;
102 import java.beans.PropertyChangeEvent;
103 import java.io.File;
104 import java.net.URL;
105 import java.util.ArrayList;
106 import java.util.Enumeration;
107 import java.util.Hashtable;
108 import java.util.Vector;
109
110 import javax.swing.JButton;
111 import javax.swing.JEditorPane;
112 import javax.swing.JInternalFrame;
113 import javax.swing.JLabel;
114 import javax.swing.JLayeredPane;
115 import javax.swing.JMenu;
116 import javax.swing.JMenuItem;
117 import javax.swing.JOptionPane;
118 import javax.swing.JPanel;
119 import javax.swing.JProgressBar;
120 import javax.swing.JRadioButtonMenuItem;
121 import javax.swing.JScrollPane;
122 import javax.swing.SwingUtilities;
123
124 /**
125  * DOCUMENT ME!
126  * 
127  * @author $author$
128  * @version $Revision$
129  */
130 public class AlignFrame extends GAlignFrame implements DropTargetListener,
131         IProgressIndicator
132 {
133
134   /** DOCUMENT ME!! */
135   public static final int DEFAULT_WIDTH = 700;
136
137   /** DOCUMENT ME!! */
138   public static final int DEFAULT_HEIGHT = 500;
139
140   public AlignmentPanel alignPanel;
141
142   AlignViewport viewport;
143
144   Vector alignPanels = new Vector();
145   
146   /**
147    * Last format used to load or save alignments in this window
148    */
149   String currentFileFormat = null;
150
151   /**
152    * Current filename for this alignment
153    */
154   String fileName = null;
155
156   /**
157    * Creates a new AlignFrame object with specific width and height.
158    * 
159    * @param al
160    * @param width
161    * @param height
162    */
163   public AlignFrame(AlignmentI al, int width, int height)
164   {
165     this(al, null, width, height);
166   }
167
168   /**
169    * Creates a new AlignFrame object with specific width, height and
170    * sequenceSetId
171    * 
172    * @param al
173    * @param width
174    * @param height
175    * @param sequenceSetId
176    */
177   public AlignFrame(AlignmentI al, int width, int height,
178           String sequenceSetId)
179   {
180     this(al, null, width, height, sequenceSetId);
181   }
182
183   /**
184    * Creates a new AlignFrame object with specific width, height and
185    * sequenceSetId
186    * 
187    * @param al
188    * @param width
189    * @param height
190    * @param sequenceSetId
191    * @param viewId
192    */
193   public AlignFrame(AlignmentI al, int width, int height,
194           String sequenceSetId, String viewId)
195   {
196     this(al, null, width, height, sequenceSetId, viewId);
197   }
198
199   /**
200    * new alignment window with hidden columns
201    * 
202    * @param al
203    *          AlignmentI
204    * @param hiddenColumns
205    *          ColumnSelection or null
206    * @param width
207    *          Width of alignment frame
208    * @param height
209    *          height of frame.
210    */
211   public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
212           int width, int height)
213   {
214     this(al, hiddenColumns, width, height, null);
215   }
216
217   /**
218    * Create alignment frame for al with hiddenColumns, a specific width and
219    * height, and specific sequenceId
220    * 
221    * @param al
222    * @param hiddenColumns
223    * @param width
224    * @param height
225    * @param sequenceSetId
226    *          (may be null)
227    */
228   public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
229           int width, int height, String sequenceSetId)
230   {
231     this(al, hiddenColumns, width, height, sequenceSetId, null);
232   }
233
234   /**
235    * Create alignment frame for al with hiddenColumns, a specific width and
236    * height, and specific sequenceId
237    * 
238    * @param al
239    * @param hiddenColumns
240    * @param width
241    * @param height
242    * @param sequenceSetId
243    *          (may be null)
244    * @param viewId
245    *          (may be null)
246    */
247   public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
248           int width, int height, String sequenceSetId, String viewId)
249   {
250     setSize(width, height);
251     viewport = new AlignViewport(al, hiddenColumns, sequenceSetId, viewId);
252
253     alignPanel = new AlignmentPanel(this, viewport);
254
255     if (al.getDataset() == null)
256     {
257       al.setDataset(null);
258     }
259
260     addAlignmentPanel(alignPanel, true);
261     init();
262   }
263
264   /**
265    * Make a new AlignFrame from exisiting alignmentPanels
266    * 
267    * @param ap
268    *          AlignmentPanel
269    * @param av
270    *          AlignViewport
271    */
272   public AlignFrame(AlignmentPanel ap)
273   {
274     viewport = ap.av;
275     alignPanel = ap;
276     addAlignmentPanel(ap, false);
277     init();
278   }
279
280   /**
281    * initalise the alignframe from the underlying viewport data and the
282    * configurations
283    */
284   void init()
285   {
286     if (viewport.conservation == null)
287     {
288       BLOSUM62Colour.setEnabled(false);
289       conservationMenuItem.setEnabled(false);
290       modifyConservation.setEnabled(false);
291       // PIDColour.setEnabled(false);
292       // abovePIDThreshold.setEnabled(false);
293       // modifyPID.setEnabled(false);
294     }
295
296     String sortby = jalview.bin.Cache.getDefault("SORT_ALIGNMENT",
297             "No sort");
298
299     if (sortby.equals("Id"))
300     {
301       sortIDMenuItem_actionPerformed(null);
302     }
303     else if (sortby.equals("Pairwise Identity"))
304     {
305       sortPairwiseMenuItem_actionPerformed(null);
306     }
307
308     if (Desktop.desktop != null)
309     {
310       this.setDropTarget(new java.awt.dnd.DropTarget(this, this));
311       addServiceListeners();
312       setGUINucleotide(viewport.alignment.isNucleotide());
313     }
314
315     setMenusFromViewport(viewport);
316     buildSortByAnnotationScoresMenu();
317     if (viewport.wrapAlignment)
318     {
319       wrapMenuItem_actionPerformed(null);
320     }
321
322     if (jalview.bin.Cache.getDefault("SHOW_OVERVIEW", false))
323     {
324       this.overviewMenuItem_actionPerformed(null);
325     }
326
327     addKeyListener();
328
329   }
330
331   /**
332    * Change the filename and format for the alignment, and enable the 'reload'
333    * button functionality.
334    * 
335    * @param file
336    *          valid filename
337    * @param format
338    *          format of file
339    */
340   public void setFileName(String file, String format)
341   {
342     fileName = file;
343     currentFileFormat = format;
344     reload.setEnabled(true);
345   }
346
347   void addKeyListener()
348   {
349     addKeyListener(new KeyAdapter()
350     {
351       public void keyPressed(KeyEvent evt)
352       {
353         if (viewport.cursorMode
354                 && ((evt.getKeyCode() >= KeyEvent.VK_0 && evt.getKeyCode() <= KeyEvent.VK_9) || (evt
355                         .getKeyCode() >= KeyEvent.VK_NUMPAD0 && evt
356                         .getKeyCode() <= KeyEvent.VK_NUMPAD9))
357                 && Character.isDigit(evt.getKeyChar()))
358           alignPanel.seqPanel.numberPressed(evt.getKeyChar());
359
360         switch (evt.getKeyCode())
361         {
362
363         case 27: // escape key
364           deselectAllSequenceMenuItem_actionPerformed(null);
365
366           break;
367
368         case KeyEvent.VK_DOWN:
369           if (evt.isAltDown() || !viewport.cursorMode)
370             moveSelectedSequences(false);
371           if (viewport.cursorMode)
372             alignPanel.seqPanel.moveCursor(0, 1);
373           break;
374
375         case KeyEvent.VK_UP:
376           if (evt.isAltDown() || !viewport.cursorMode)
377             moveSelectedSequences(true);
378           if (viewport.cursorMode)
379             alignPanel.seqPanel.moveCursor(0, -1);
380
381           break;
382
383         case KeyEvent.VK_LEFT:
384           if (evt.isAltDown() || !viewport.cursorMode)
385             slideSequences(false, alignPanel.seqPanel.getKeyboardNo1());
386           else
387             alignPanel.seqPanel.moveCursor(-1, 0);
388
389           break;
390
391         case KeyEvent.VK_RIGHT:
392           if (evt.isAltDown() || !viewport.cursorMode)
393             slideSequences(true, alignPanel.seqPanel.getKeyboardNo1());
394           else
395             alignPanel.seqPanel.moveCursor(1, 0);
396           break;
397
398         case KeyEvent.VK_SPACE:
399           if (viewport.cursorMode)
400           {
401             alignPanel.seqPanel.insertGapAtCursor(evt.isControlDown()
402                     || evt.isShiftDown() || evt.isAltDown());
403           }
404           break;
405
406         case KeyEvent.VK_DELETE:
407         case KeyEvent.VK_BACK_SPACE:
408           if (!viewport.cursorMode)
409           {
410             cut_actionPerformed(null);
411           }
412           else
413           {
414             alignPanel.seqPanel.deleteGapAtCursor(evt.isControlDown()
415                     || evt.isShiftDown() || evt.isAltDown());
416           }
417
418           break;
419
420         case KeyEvent.VK_S:
421           if (viewport.cursorMode)
422           {
423             alignPanel.seqPanel.setCursorRow();
424           }
425           break;
426         case KeyEvent.VK_C:
427           if (viewport.cursorMode && !evt.isControlDown())
428           {
429             alignPanel.seqPanel.setCursorColumn();
430           }
431           break;
432         case KeyEvent.VK_P:
433           if (viewport.cursorMode)
434           {
435             alignPanel.seqPanel.setCursorPosition();
436           }
437           break;
438
439         case KeyEvent.VK_ENTER:
440         case KeyEvent.VK_COMMA:
441           if (viewport.cursorMode)
442           {
443             alignPanel.seqPanel.setCursorRowAndColumn();
444           }
445           break;
446
447         case KeyEvent.VK_Q:
448           if (viewport.cursorMode)
449           {
450             alignPanel.seqPanel.setSelectionAreaAtCursor(true);
451           }
452           break;
453         case KeyEvent.VK_M:
454           if (viewport.cursorMode)
455           {
456             alignPanel.seqPanel.setSelectionAreaAtCursor(false);
457           }
458           break;
459
460         case KeyEvent.VK_F2:
461           viewport.cursorMode = !viewport.cursorMode;
462           statusBar.setText("Keyboard editing mode is "
463                   + (viewport.cursorMode ? "on" : "off"));
464           if (viewport.cursorMode)
465           {
466             alignPanel.seqPanel.seqCanvas.cursorX = viewport.startRes;
467             alignPanel.seqPanel.seqCanvas.cursorY = viewport.startSeq;
468           }
469           alignPanel.seqPanel.seqCanvas.repaint();
470           break;
471
472         case KeyEvent.VK_F1:
473           try
474           {
475             ClassLoader cl = jalview.gui.Desktop.class.getClassLoader();
476             java.net.URL url = javax.help.HelpSet.findHelpSet(cl,
477                     "help/help");
478             javax.help.HelpSet hs = new javax.help.HelpSet(cl, url);
479
480             javax.help.HelpBroker hb = hs.createHelpBroker();
481             hb.setCurrentID("home");
482             hb.setDisplayed(true);
483           } catch (Exception ex)
484           {
485             ex.printStackTrace();
486           }
487           break;
488         case KeyEvent.VK_H:
489         {
490           boolean toggleSeqs = !evt.isControlDown();
491           boolean toggleCols = !evt.isShiftDown();
492           toggleHiddenRegions(toggleSeqs, toggleCols);
493           break;
494         }
495         case KeyEvent.VK_PAGE_UP:
496           if (viewport.wrapAlignment)
497           {
498             alignPanel.scrollUp(true);
499           }
500           else
501           {
502             alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
503                     - viewport.endSeq + viewport.startSeq);
504           }
505           break;
506         case KeyEvent.VK_PAGE_DOWN:
507           if (viewport.wrapAlignment)
508           {
509             alignPanel.scrollUp(false);
510           }
511           else
512           {
513             alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
514                     + viewport.endSeq - viewport.startSeq);
515           }
516           break;
517         }
518       }
519
520       public void keyReleased(KeyEvent evt)
521       {
522         switch (evt.getKeyCode())
523         {
524         case KeyEvent.VK_LEFT:
525           if (evt.isAltDown() || !viewport.cursorMode)
526             viewport.firePropertyChange("alignment", null, viewport
527                     .getAlignment().getSequences());
528           break;
529
530         case KeyEvent.VK_RIGHT:
531           if (evt.isAltDown() || !viewport.cursorMode)
532             viewport.firePropertyChange("alignment", null, viewport
533                     .getAlignment().getSequences());
534           break;
535         }
536       }
537     });
538   }
539
540   public void addAlignmentPanel(final AlignmentPanel ap, boolean newPanel)
541   {
542     ap.alignFrame = this;
543
544     alignPanels.addElement(ap);
545
546     PaintRefresher.Register(ap, ap.av.getSequenceSetId());
547
548     int aSize = alignPanels.size();
549
550     tabbedPane.setVisible(aSize > 1 || ap.av.viewName != null);
551
552     if (aSize == 1 && ap.av.viewName == null)
553     {
554       this.getContentPane().add(ap, BorderLayout.CENTER);
555     }
556     else
557     {
558       if (aSize == 2)
559       {
560         setInitialTabVisible();
561       }
562
563       expandViews.setEnabled(true);
564       gatherViews.setEnabled(true);
565       tabbedPane.addTab(ap.av.viewName, ap);
566
567       ap.setVisible(false);
568     }
569
570     if (newPanel)
571     {
572       if (ap.av.padGaps)
573       {
574         ap.av.alignment.padGaps();
575       }
576       ap.av.updateConservation(ap);
577       ap.av.updateConsensus(ap);
578     }
579   }
580
581   public void setInitialTabVisible()
582   {
583     expandViews.setEnabled(true);
584     gatherViews.setEnabled(true);
585     tabbedPane.setVisible(true);
586     AlignmentPanel first = (AlignmentPanel) alignPanels.firstElement();
587     tabbedPane.addTab(first.av.viewName, first);
588     this.getContentPane().add(tabbedPane, BorderLayout.CENTER);
589   }
590
591   public AlignViewport getViewport()
592   {
593     return viewport;
594   }
595
596   /* Set up intrinsic listeners for dynamically generated GUI bits. */
597   private void addServiceListeners()
598   {
599     final java.beans.PropertyChangeListener thisListener;
600     Desktop.instance.addJalviewPropertyChangeListener("services",
601             thisListener = new java.beans.PropertyChangeListener()
602             {
603               public void propertyChange(PropertyChangeEvent evt)
604               {
605                 // // System.out.println("Discoverer property change.");
606                 // if (evt.getPropertyName().equals("services"))
607                 {
608                   SwingUtilities.invokeLater(new Runnable()
609                   {
610
611                     public void run()
612                     {
613                       System.err
614                               .println("Rebuild WS Menu for service change");
615                       BuildWebServiceMenu();
616                     }
617
618                   });
619                 }
620               }
621             });
622     addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
623     {
624       public void internalFrameClosed(
625               javax.swing.event.InternalFrameEvent evt)
626       {
627         System.out.println("deregistering discoverer listener");
628         Desktop.instance.removeJalviewPropertyChangeListener("services",
629                 thisListener);
630         closeMenuItem_actionPerformed(true);
631       };
632     });
633     // Finally, build the menu once to get current service state
634     new Thread(new Runnable()
635     {
636       public void run()
637       {
638         BuildWebServiceMenu();
639       }
640     }).start();
641   }
642
643   public void setGUINucleotide(boolean nucleotide)
644   {
645     showTranslation.setVisible(nucleotide);
646     conservationMenuItem.setEnabled(!nucleotide);
647     modifyConservation.setEnabled(!nucleotide);
648     showGroupConservation.setEnabled(!nucleotide);
649     // Remember AlignFrame always starts as protein
650     if (!nucleotide)
651     {
652       calculateMenu.remove(calculateMenu.getItemCount() - 2);
653     }
654   }
655
656   /**
657    * set up menus for the currently viewport. This may be called after any
658    * operation that affects the data in the current view (selection changed,
659    * etc) to update the menus to reflect the new state.
660    */
661   public void setMenusForViewport()
662   {
663     setMenusFromViewport(viewport);
664   }
665
666   /**
667    * Need to call this method when tabs are selected for multiple views, or when
668    * loading from Jalview2XML.java
669    * 
670    * @param av
671    *          AlignViewport
672    */
673   void setMenusFromViewport(AlignViewport av)
674   {
675     padGapsMenuitem.setSelected(av.padGaps);
676     colourTextMenuItem.setSelected(av.showColourText);
677     abovePIDThreshold.setSelected(av.getAbovePIDThreshold());
678     conservationMenuItem.setSelected(av.getConservationSelected());
679     seqLimits.setSelected(av.getShowJVSuffix());
680     idRightAlign.setSelected(av.rightAlignIds);
681     centreColumnLabelsMenuItem.setState(av.centreColumnLabels);
682     renderGapsMenuItem.setSelected(av.renderGaps);
683     wrapMenuItem.setSelected(av.wrapAlignment);
684     scaleAbove.setVisible(av.wrapAlignment);
685     scaleLeft.setVisible(av.wrapAlignment);
686     scaleRight.setVisible(av.wrapAlignment);
687     annotationPanelMenuItem.setState(av.showAnnotation);
688     viewBoxesMenuItem.setSelected(av.showBoxes);
689     viewTextMenuItem.setSelected(av.showText);
690     showNonconservedMenuItem.setSelected(av.showUnconserved);
691     showGroupConsensus.setSelected(av.showGroupConsensus);
692     showGroupConservation.setSelected(av.showGroupConservation);
693     showConsensusHistogram.setSelected(av.showConsensusHistogram);
694     showSequenceLogo.setSelected(av.showSequenceLogo);
695     setColourSelected(ColourSchemeProperty.getColourName(av
696             .getGlobalColourScheme()));
697
698     showSeqFeatures.setSelected(av.showSequenceFeatures);
699     hiddenMarkers.setState(av.showHiddenMarkers);
700     applyToAllGroups.setState(av.colourAppliesToAllGroups);
701     showNpFeatsMenuitem.setSelected(av.isShowNpFeats());
702     showDbRefsMenuitem.setSelected(av.isShowDbRefs());
703     autoCalculate.setSelected(av.autoCalculateConsensus);
704     sortByTree.setSelected(av.sortByTree);
705     listenToViewSelections.setSelected(av.followSelection);
706     
707     setShowProductsEnabled();
708
709     updateEditMenuBar();
710   }
711
712   Hashtable progressBars, progressBarHandlers;
713
714   /*
715    * (non-Javadoc)
716    * 
717    * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
718    */
719   public void setProgressBar(String message, long id)
720   {
721     if (progressBars == null)
722     {
723       progressBars = new Hashtable();
724       progressBarHandlers = new Hashtable();
725     }
726
727     JPanel progressPanel;
728     Long lId = new Long(id);
729     GridLayout layout = (GridLayout) statusPanel.getLayout();
730     if (progressBars.get(lId) != null)
731     {
732       progressPanel = (JPanel) progressBars.get(new Long(id));
733       statusPanel.remove(progressPanel);
734       progressBars.remove(lId);
735       progressPanel = null;
736       if (message != null)
737       {
738         statusBar.setText(message);
739       }
740       if (progressBarHandlers.contains(lId))
741       {
742         progressBarHandlers.remove(lId);
743       }
744       layout.setRows(layout.getRows() - 1);
745     }
746     else
747     {
748       progressPanel = new JPanel(new BorderLayout(10, 5));
749
750       JProgressBar progressBar = new JProgressBar();
751       progressBar.setIndeterminate(true);
752
753       progressPanel.add(new JLabel(message), BorderLayout.WEST);
754       progressPanel.add(progressBar, BorderLayout.CENTER);
755
756       layout.setRows(layout.getRows() + 1);
757       statusPanel.add(progressPanel);
758
759       progressBars.put(lId, progressPanel);
760     }
761     // update GUI
762     // setMenusForViewport();
763     validate();
764   }
765
766   public void registerHandler(final long id,
767           final IProgressIndicatorHandler handler)
768   {
769     if (progressBarHandlers == null || !progressBars.contains(new Long(id)))
770     {
771       throw new Error(
772               "call setProgressBar before registering the progress bar's handler.");
773     }
774     progressBarHandlers.put(new Long(id), handler);
775     final JPanel progressPanel = (JPanel) progressBars.get(new Long(id));
776     if (handler.canCancel())
777     {
778       JButton cancel = new JButton("Cancel");
779       final IProgressIndicator us = this;
780       cancel.addActionListener(new ActionListener()
781       {
782
783         public void actionPerformed(ActionEvent e)
784         {
785           handler.cancelActivity(id);
786           us.setProgressBar(
787                   "Cancelled "
788                           + ((JLabel) progressPanel.getComponent(0))
789                                   .getText(), id);
790         }
791       });
792       progressPanel.add(cancel, BorderLayout.EAST);
793     }
794   }
795
796   /**
797    * 
798    * @return true if any progress bars are still active
799    */
800   public boolean operationInProgress()
801   {
802     if (progressBars != null && progressBars.size() > 0)
803     {
804       return true;
805     }
806     return false;
807   }
808
809   /*
810    * Added so Castor Mapping file can obtain Jalview Version
811    */
812   public String getVersion()
813   {
814     return jalview.bin.Cache.getProperty("VERSION");
815   }
816
817   public FeatureRenderer getFeatureRenderer()
818   {
819     return alignPanel.seqPanel.seqCanvas.getFeatureRenderer();
820   }
821
822   public void fetchSequence_actionPerformed(ActionEvent e)
823   {
824     new SequenceFetcher(this);
825   }
826
827   public void addFromFile_actionPerformed(ActionEvent e)
828   {
829     Desktop.instance.inputLocalFileMenuItem_actionPerformed(viewport);
830   }
831
832   public void reload_actionPerformed(ActionEvent e)
833   {
834     if (fileName != null)
835     {
836       // TODO: work out how to recover feature settings for correct view(s) when
837       // file is reloaded.
838       if (currentFileFormat.equals("Jalview"))
839       {
840         JInternalFrame[] frames = Desktop.desktop.getAllFrames();
841         for (int i = 0; i < frames.length; i++)
842         {
843           if (frames[i] instanceof AlignFrame && frames[i] != this
844                   && ((AlignFrame) frames[i]).fileName.equals(fileName))
845           {
846             try
847             {
848               frames[i].setSelected(true);
849               Desktop.instance.closeAssociatedWindows();
850             } catch (java.beans.PropertyVetoException ex)
851             {
852             }
853           }
854
855         }
856         Desktop.instance.closeAssociatedWindows();
857
858         FileLoader loader = new FileLoader();
859         String protocol = fileName.startsWith("http:") ? "URL" : "File";
860         loader.LoadFile(viewport, fileName, protocol, currentFileFormat);
861       }
862       else
863       {
864         Rectangle bounds = this.getBounds();
865
866         FileLoader loader = new FileLoader();
867         String protocol = fileName.startsWith("http:") ? "URL" : "File";
868         AlignFrame newframe = loader.LoadFileWaitTillLoaded(fileName,
869                 protocol, currentFileFormat);
870
871         newframe.setBounds(bounds);
872         if (featureSettings != null && featureSettings.isShowing())
873         {
874           final Rectangle fspos = featureSettings.frame.getBounds();
875           // TODO: need a 'show feature settings' function that takes bounds -
876           // need to refactor Desktop.addFrame
877           newframe.featureSettings_actionPerformed(null);
878           final FeatureSettings nfs = newframe.featureSettings;
879           SwingUtilities.invokeLater(new Runnable()
880           {
881             public void run()
882             {
883               nfs.frame.setBounds(fspos);
884             }
885           });
886           this.featureSettings.close();
887           this.featureSettings = null;
888         }
889         this.closeMenuItem_actionPerformed(true);
890       }
891     }
892   }
893
894   public void addFromText_actionPerformed(ActionEvent e)
895   {
896     Desktop.instance.inputTextboxMenuItem_actionPerformed(viewport);
897   }
898
899   public void addFromURL_actionPerformed(ActionEvent e)
900   {
901     Desktop.instance.inputURLMenuItem_actionPerformed(viewport);
902   }
903
904   public void save_actionPerformed(ActionEvent e)
905   {
906     if (fileName == null
907             || (currentFileFormat == null || !jalview.io.FormatAdapter
908                     .isValidIOFormat(currentFileFormat, true))
909             || fileName.startsWith("http"))
910     {
911       saveAs_actionPerformed(null);
912     }
913     else
914     {
915       saveAlignment(fileName, currentFileFormat);
916     }
917   }
918
919   /**
920    * DOCUMENT ME!
921    * 
922    * @param e
923    *          DOCUMENT ME!
924    */
925   public void saveAs_actionPerformed(ActionEvent e)
926   {
927     JalviewFileChooser chooser = new JalviewFileChooser(
928             jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
929             jalview.io.AppletFormatAdapter.WRITABLE_EXTENSIONS,
930             jalview.io.AppletFormatAdapter.WRITABLE_FNAMES,
931             currentFileFormat, false);
932
933     chooser.setFileView(new JalviewFileView());
934     chooser.setDialogTitle("Save Alignment to file");
935     chooser.setToolTipText("Save");
936
937     int value = chooser.showSaveDialog(this);
938
939     if (value == JalviewFileChooser.APPROVE_OPTION)
940     {
941       currentFileFormat = chooser.getSelectedFormat();
942       if (currentFileFormat == null)
943       {
944         JOptionPane.showInternalMessageDialog(Desktop.desktop,
945                 "You must select a file format before saving!",
946                 "File format not specified", JOptionPane.WARNING_MESSAGE);
947         value = chooser.showSaveDialog(this);
948         return;
949       }
950
951       fileName = chooser.getSelectedFile().getPath();
952
953       jalview.bin.Cache.setProperty("DEFAULT_FILE_FORMAT",
954               currentFileFormat);
955
956       jalview.bin.Cache.setProperty("LAST_DIRECTORY", fileName);
957       if (currentFileFormat.indexOf(" ") > -1)
958       {
959         currentFileFormat = currentFileFormat.substring(0,
960                 currentFileFormat.indexOf(" "));
961       }
962       saveAlignment(fileName, currentFileFormat);
963     }
964   }
965
966   public boolean saveAlignment(String file, String format)
967   {
968     boolean success = true;
969
970     if (format.equalsIgnoreCase("Jalview"))
971     {
972       String shortName = title;
973
974       if (shortName.indexOf(java.io.File.separatorChar) > -1)
975       {
976         shortName = shortName.substring(shortName
977                 .lastIndexOf(java.io.File.separatorChar) + 1);
978       }
979
980       success = new Jalview2XML().SaveAlignment(this, file, shortName);
981
982       statusBar.setText("Successfully saved to file: " + fileName + " in "
983               + format + " format.");
984
985     }
986     else
987     {
988       if (!jalview.io.AppletFormatAdapter.isValidFormat(format, true))
989       {
990         warningMessage("Cannot save file " + fileName + " using format "
991                 + format, "Alignment output format not supported");
992         saveAs_actionPerformed(null);
993         // JBPNote need to have a raise_gui flag here
994         return false;
995       }
996
997       String[] omitHidden = null;
998
999       if (viewport.hasHiddenColumns)
1000       {
1001         int reply = JOptionPane
1002                 .showInternalConfirmDialog(
1003                         Desktop.desktop,
1004                         "The Alignment contains hidden columns."
1005                                 + "\nDo you want to save only the visible alignment?",
1006                         "Save / Omit Hidden Columns",
1007                         JOptionPane.YES_NO_OPTION,
1008                         JOptionPane.QUESTION_MESSAGE);
1009
1010         if (reply == JOptionPane.YES_OPTION)
1011         {
1012           omitHidden = viewport.getViewAsString(false);
1013         }
1014       }
1015       FormatAdapter f = new FormatAdapter();
1016       String output = f.formatSequences(format,
1017               (Alignment) viewport.alignment, // class cast exceptions will
1018               // occur in the distant future
1019               omitHidden, f.getCacheSuffixDefault(format), viewport.colSel);
1020
1021       if (output == null)
1022       {
1023         success = false;
1024       }
1025       else
1026       {
1027         try
1028         {
1029           java.io.PrintWriter out = new java.io.PrintWriter(
1030                   new java.io.FileWriter(file));
1031
1032           out.print(output);
1033           out.close();
1034           this.setTitle(file);
1035           statusBar.setText("Successfully saved to file: " + fileName
1036                   + " in " + format + " format.");
1037         } catch (Exception ex)
1038         {
1039           success = false;
1040           ex.printStackTrace();
1041         }
1042       }
1043     }
1044
1045     if (!success)
1046     {
1047       JOptionPane.showInternalMessageDialog(this, "Couldn't save file: "
1048               + fileName, "Error Saving File", JOptionPane.WARNING_MESSAGE);
1049     }
1050
1051     return success;
1052   }
1053
1054   private void warningMessage(String warning, String title)
1055   {
1056     if (new jalview.util.Platform().isHeadless())
1057     {
1058       System.err.println("Warning: " + title + "\nWarning: " + warning);
1059
1060     }
1061     else
1062     {
1063       JOptionPane.showInternalMessageDialog(this, warning, title,
1064               JOptionPane.WARNING_MESSAGE);
1065     }
1066     return;
1067   }
1068
1069   /**
1070    * DOCUMENT ME!
1071    * 
1072    * @param e
1073    *          DOCUMENT ME!
1074    */
1075   protected void outputText_actionPerformed(ActionEvent e)
1076   {
1077     String[] omitHidden = null;
1078
1079     if (viewport.hasHiddenColumns)
1080     {
1081       int reply = JOptionPane
1082               .showInternalConfirmDialog(
1083                       Desktop.desktop,
1084                       "The Alignment contains hidden columns."
1085                               + "\nDo you want to output only the visible alignment?",
1086                       "Save / Omit Hidden Columns",
1087                       JOptionPane.YES_NO_OPTION,
1088                       JOptionPane.QUESTION_MESSAGE);
1089
1090       if (reply == JOptionPane.YES_OPTION)
1091       {
1092         omitHidden = viewport.getViewAsString(false);
1093       }
1094     }
1095
1096     CutAndPasteTransfer cap = new CutAndPasteTransfer();
1097     cap.setForInput(null);
1098
1099     try
1100     {
1101       cap.setText(new FormatAdapter().formatSequences(e.getActionCommand(),
1102               viewport.alignment, omitHidden, viewport.colSel));
1103       Desktop.addInternalFrame(cap,
1104               "Alignment output - " + e.getActionCommand(), 600, 500);
1105     } catch (OutOfMemoryError oom)
1106     {
1107       new OOMWarning("Outputting alignment as " + e.getActionCommand(), oom);
1108       cap.dispose();
1109     }
1110
1111   }
1112
1113   /**
1114    * DOCUMENT ME!
1115    * 
1116    * @param e
1117    *          DOCUMENT ME!
1118    */
1119   protected void htmlMenuItem_actionPerformed(ActionEvent e)
1120   {
1121     new HTMLOutput(alignPanel,
1122             alignPanel.seqPanel.seqCanvas.getSequenceRenderer(),
1123             alignPanel.seqPanel.seqCanvas.getFeatureRenderer());
1124   }
1125
1126   public void createImageMap(File file, String image)
1127   {
1128     alignPanel.makePNGImageMap(file, image);
1129   }
1130
1131   /**
1132    * DOCUMENT ME!
1133    * 
1134    * @param e
1135    *          DOCUMENT ME!
1136    */
1137   public void createPNG(File f)
1138   {
1139     alignPanel.makePNG(f);
1140   }
1141
1142   /**
1143    * DOCUMENT ME!
1144    * 
1145    * @param e
1146    *          DOCUMENT ME!
1147    */
1148   public void createEPS(File f)
1149   {
1150     alignPanel.makeEPS(f);
1151   }
1152
1153   public void pageSetup_actionPerformed(ActionEvent e)
1154   {
1155     PrinterJob printJob = PrinterJob.getPrinterJob();
1156     PrintThread.pf = printJob.pageDialog(printJob.defaultPage());
1157   }
1158
1159   /**
1160    * DOCUMENT ME!
1161    * 
1162    * @param e
1163    *          DOCUMENT ME!
1164    */
1165   public void printMenuItem_actionPerformed(ActionEvent e)
1166   {
1167     // Putting in a thread avoids Swing painting problems
1168     PrintThread thread = new PrintThread(alignPanel);
1169     thread.start();
1170   }
1171
1172   public void exportFeatures_actionPerformed(ActionEvent e)
1173   {
1174     new AnnotationExporter().exportFeatures(alignPanel);
1175   }
1176
1177   public void exportAnnotations_actionPerformed(ActionEvent e)
1178   {
1179     new AnnotationExporter().exportAnnotations(
1180             alignPanel,
1181             viewport.showAnnotation ? viewport.alignment
1182                     .getAlignmentAnnotation() : null, viewport.alignment
1183                     .getGroups(),
1184             ((Alignment) viewport.alignment).alignmentProperties);
1185   }
1186
1187   public void associatedData_actionPerformed(ActionEvent e)
1188   {
1189     // Pick the tree file
1190     JalviewFileChooser chooser = new JalviewFileChooser(
1191             jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
1192     chooser.setFileView(new JalviewFileView());
1193     chooser.setDialogTitle("Load Jalview Annotations or Features File");
1194     chooser.setToolTipText("Load Jalview Annotations / Features file");
1195
1196     int value = chooser.showOpenDialog(null);
1197
1198     if (value == JalviewFileChooser.APPROVE_OPTION)
1199     {
1200       String choice = chooser.getSelectedFile().getPath();
1201       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
1202       loadJalviewDataFile(choice, null, null, null);
1203     }
1204
1205   }
1206
1207   /**
1208    * Close the current view or all views in the alignment frame. If the frame
1209    * only contains one view then the alignment will be removed from memory.
1210    * 
1211    * @param closeAllTabs
1212    */
1213   public void closeMenuItem_actionPerformed(boolean closeAllTabs)
1214   {
1215     if (alignPanels != null && alignPanels.size() < 2)
1216     {
1217       closeAllTabs = true;
1218     }
1219
1220     try
1221     {
1222       if (alignPanels != null)
1223       {
1224         if (closeAllTabs)
1225         {
1226           if (this.isClosed())
1227           {
1228             // really close all the windows - otherwise wait till
1229             // setClosed(true) is called
1230             for (int i = 0; i < alignPanels.size(); i++)
1231             {
1232               AlignmentPanel ap = (AlignmentPanel) alignPanels.elementAt(i);
1233               ap.closePanel();
1234             }
1235           }
1236         }
1237         else
1238         {
1239           closeView(alignPanel);
1240         }
1241       }
1242
1243       if (closeAllTabs)
1244       {
1245         this.setClosed(true);
1246       }
1247     } catch (Exception ex)
1248     {
1249       ex.printStackTrace();
1250     }
1251   }
1252
1253   /**
1254    * close alignPanel2 and shuffle tabs appropriately.
1255    * 
1256    * @param alignPanel2
1257    */
1258   public void closeView(AlignmentPanel alignPanel2)
1259   {
1260     int index = tabbedPane.getSelectedIndex();
1261     int closedindex = tabbedPane.indexOfComponent(alignPanel2);
1262     alignPanels.removeElement(alignPanel2);
1263     // Unnecessary
1264     // if (viewport == alignPanel2.av)
1265     // {
1266     // viewport = null;
1267     // }
1268     alignPanel2.closePanel();
1269     alignPanel2 = null;
1270
1271     tabbedPane.removeTabAt(closedindex);
1272     tabbedPane.validate();
1273
1274     if (index > closedindex || index == tabbedPane.getTabCount())
1275     {
1276       // modify currently selected tab index if necessary.
1277       index--;
1278     }
1279
1280     this.tabSelectionChanged(index);
1281   }
1282
1283   /**
1284    * DOCUMENT ME!
1285    */
1286   void updateEditMenuBar()
1287   {
1288
1289     if (viewport.historyList.size() > 0)
1290     {
1291       undoMenuItem.setEnabled(true);
1292       CommandI command = (CommandI) viewport.historyList.peek();
1293       undoMenuItem.setText("Undo " + command.getDescription());
1294     }
1295     else
1296     {
1297       undoMenuItem.setEnabled(false);
1298       undoMenuItem.setText("Undo");
1299     }
1300
1301     if (viewport.redoList.size() > 0)
1302     {
1303       redoMenuItem.setEnabled(true);
1304
1305       CommandI command = (CommandI) viewport.redoList.peek();
1306       redoMenuItem.setText("Redo " + command.getDescription());
1307     }
1308     else
1309     {
1310       redoMenuItem.setEnabled(false);
1311       redoMenuItem.setText("Redo");
1312     }
1313   }
1314
1315   public void addHistoryItem(CommandI command)
1316   {
1317     if (command.getSize() > 0)
1318     {
1319       viewport.historyList.push(command);
1320       viewport.redoList.clear();
1321       updateEditMenuBar();
1322       viewport.hasHiddenColumns = (viewport.colSel != null
1323               && viewport.colSel.getHiddenColumns() != null && viewport.colSel
1324               .getHiddenColumns().size() > 0);
1325     }
1326   }
1327
1328   /**
1329    * 
1330    * @return alignment objects for all views
1331    */
1332   AlignmentI[] getViewAlignments()
1333   {
1334     if (alignPanels != null)
1335     {
1336       Enumeration e = alignPanels.elements();
1337       AlignmentI[] als = new AlignmentI[alignPanels.size()];
1338       for (int i = 0; e.hasMoreElements(); i++)
1339       {
1340         als[i] = ((AlignmentPanel) e.nextElement()).av.getAlignment();
1341       }
1342       return als;
1343     }
1344     if (viewport != null)
1345     {
1346       return new AlignmentI[]
1347       { viewport.alignment };
1348     }
1349     return null;
1350   }
1351
1352   /**
1353    * DOCUMENT ME!
1354    * 
1355    * @param e
1356    *          DOCUMENT ME!
1357    */
1358   protected void undoMenuItem_actionPerformed(ActionEvent e)
1359   {
1360     if (viewport.historyList.empty())
1361       return;
1362     CommandI command = (CommandI) viewport.historyList.pop();
1363     viewport.redoList.push(command);
1364     command.undoCommand(getViewAlignments());
1365
1366     AlignViewport originalSource = getOriginatingSource(command);
1367     updateEditMenuBar();
1368
1369     if (originalSource != null)
1370     {
1371       originalSource.hasHiddenColumns = (viewport.colSel != null
1372               && viewport.colSel.getHiddenColumns() != null && viewport.colSel
1373               .getHiddenColumns().size() > 0);
1374       originalSource.firePropertyChange("alignment", null,
1375               originalSource.alignment.getSequences());
1376     }
1377   }
1378
1379   /**
1380    * DOCUMENT ME!
1381    * 
1382    * @param e
1383    *          DOCUMENT ME!
1384    */
1385   protected void redoMenuItem_actionPerformed(ActionEvent e)
1386   {
1387     if (viewport.redoList.size() < 1)
1388     {
1389       return;
1390     }
1391
1392     CommandI command = (CommandI) viewport.redoList.pop();
1393     viewport.historyList.push(command);
1394     command.doCommand(getViewAlignments());
1395
1396     AlignViewport originalSource = getOriginatingSource(command);
1397     updateEditMenuBar();
1398
1399     if (originalSource != null)
1400     {
1401       originalSource.hasHiddenColumns = (viewport.colSel != null
1402               && viewport.colSel.getHiddenColumns() != null && viewport.colSel
1403               .getHiddenColumns().size() > 0);
1404       originalSource.firePropertyChange("alignment", null,
1405               originalSource.alignment.getSequences());
1406     }
1407   }
1408
1409   AlignViewport getOriginatingSource(CommandI command)
1410   {
1411     AlignViewport originalSource = null;
1412     // For sequence removal and addition, we need to fire
1413     // the property change event FROM the viewport where the
1414     // original alignment was altered
1415     AlignmentI al = null;
1416     if (command instanceof EditCommand)
1417     {
1418       EditCommand editCommand = (EditCommand) command;
1419       al = editCommand.getAlignment();
1420       Vector comps = (Vector) PaintRefresher.components.get(viewport
1421               .getSequenceSetId());
1422
1423       for (int i = 0; i < comps.size(); i++)
1424       {
1425         if (comps.elementAt(i) instanceof AlignmentPanel)
1426         {
1427           if (al == ((AlignmentPanel) comps.elementAt(i)).av.alignment)
1428           {
1429             originalSource = ((AlignmentPanel) comps.elementAt(i)).av;
1430             break;
1431           }
1432         }
1433       }
1434     }
1435
1436     if (originalSource == null)
1437     {
1438       // The original view is closed, we must validate
1439       // the current view against the closed view first
1440       if (al != null)
1441       {
1442         PaintRefresher.validateSequences(al, viewport.alignment);
1443       }
1444
1445       originalSource = viewport;
1446     }
1447
1448     return originalSource;
1449   }
1450
1451   /**
1452    * DOCUMENT ME!
1453    * 
1454    * @param up
1455    *          DOCUMENT ME!
1456    */
1457   public void moveSelectedSequences(boolean up)
1458   {
1459     SequenceGroup sg = viewport.getSelectionGroup();
1460
1461     if (sg == null)
1462     {
1463       return;
1464     }
1465
1466     if (up)
1467     {
1468       for (int i = 1; i < viewport.alignment.getHeight(); i++)
1469       {
1470         SequenceI seq = viewport.alignment.getSequenceAt(i);
1471
1472         if (!sg.getSequences(null).contains(seq))
1473         {
1474           continue;
1475         }
1476
1477         SequenceI temp = viewport.alignment.getSequenceAt(i - 1);
1478
1479         if (sg.getSequences(null).contains(temp))
1480         {
1481           continue;
1482         }
1483
1484         viewport.alignment.getSequences().setElementAt(temp, i);
1485         viewport.alignment.getSequences().setElementAt(seq, i - 1);
1486       }
1487     }
1488     else
1489     {
1490       for (int i = viewport.alignment.getHeight() - 2; i > -1; i--)
1491       {
1492         SequenceI seq = viewport.alignment.getSequenceAt(i);
1493
1494         if (!sg.getSequences(null).contains(seq))
1495         {
1496           continue;
1497         }
1498
1499         SequenceI temp = viewport.alignment.getSequenceAt(i + 1);
1500
1501         if (sg.getSequences(null).contains(temp))
1502         {
1503           continue;
1504         }
1505
1506         viewport.alignment.getSequences().setElementAt(temp, i);
1507         viewport.alignment.getSequences().setElementAt(seq, i + 1);
1508       }
1509     }
1510
1511     alignPanel.paintAlignment(true);
1512   }
1513
1514   synchronized void slideSequences(boolean right, int size)
1515   {
1516     Vector sg = new Vector();
1517     if (viewport.cursorMode)
1518     {
1519       sg.addElement(viewport.alignment
1520               .getSequenceAt(alignPanel.seqPanel.seqCanvas.cursorY));
1521     }
1522     else if (viewport.getSelectionGroup() != null
1523             && viewport.getSelectionGroup().getSize() != viewport.alignment
1524                     .getHeight())
1525     {
1526       sg = viewport.getSelectionGroup().getSequences(
1527               viewport.hiddenRepSequences);
1528     }
1529
1530     if (sg.size() < 1)
1531     {
1532       return;
1533     }
1534
1535     Vector invertGroup = new Vector();
1536
1537     for (int i = 0; i < viewport.alignment.getHeight(); i++)
1538     {
1539       if (!sg.contains(viewport.alignment.getSequenceAt(i)))
1540         invertGroup.add(viewport.alignment.getSequenceAt(i));
1541     }
1542
1543     SequenceI[] seqs1 = new SequenceI[sg.size()];
1544     for (int i = 0; i < sg.size(); i++)
1545       seqs1[i] = (SequenceI) sg.elementAt(i);
1546
1547     SequenceI[] seqs2 = new SequenceI[invertGroup.size()];
1548     for (int i = 0; i < invertGroup.size(); i++)
1549       seqs2[i] = (SequenceI) invertGroup.elementAt(i);
1550
1551     SlideSequencesCommand ssc;
1552     if (right)
1553       ssc = new SlideSequencesCommand("Slide Sequences", seqs2, seqs1,
1554               size, viewport.getGapCharacter());
1555     else
1556       ssc = new SlideSequencesCommand("Slide Sequences", seqs1, seqs2,
1557               size, viewport.getGapCharacter());
1558
1559     int groupAdjustment = 0;
1560     if (ssc.getGapsInsertedBegin() && right)
1561     {
1562       if (viewport.cursorMode)
1563         alignPanel.seqPanel.moveCursor(size, 0);
1564       else
1565         groupAdjustment = size;
1566     }
1567     else if (!ssc.getGapsInsertedBegin() && !right)
1568     {
1569       if (viewport.cursorMode)
1570         alignPanel.seqPanel.moveCursor(-size, 0);
1571       else
1572         groupAdjustment = -size;
1573     }
1574
1575     if (groupAdjustment != 0)
1576     {
1577       viewport.getSelectionGroup().setStartRes(
1578               viewport.getSelectionGroup().getStartRes() + groupAdjustment);
1579       viewport.getSelectionGroup().setEndRes(
1580               viewport.getSelectionGroup().getEndRes() + groupAdjustment);
1581     }
1582
1583     boolean appendHistoryItem = false;
1584     if (viewport.historyList != null && viewport.historyList.size() > 0
1585             && viewport.historyList.peek() instanceof SlideSequencesCommand)
1586     {
1587       appendHistoryItem = ssc
1588               .appendSlideCommand((SlideSequencesCommand) viewport.historyList
1589                       .peek());
1590     }
1591
1592     if (!appendHistoryItem)
1593       addHistoryItem(ssc);
1594
1595     repaint();
1596   }
1597
1598   /**
1599    * DOCUMENT ME!
1600    * 
1601    * @param e
1602    *          DOCUMENT ME!
1603    */
1604   protected void copy_actionPerformed(ActionEvent e)
1605   {
1606     System.gc();
1607     if (viewport.getSelectionGroup() == null)
1608     {
1609       return;
1610     }
1611     // TODO: preserve the ordering of displayed alignment annotation in any
1612     // internal paste (particularly sequence associated annotation)
1613     SequenceI[] seqs = viewport.getSelectionAsNewSequence();
1614     String[] omitHidden = null;
1615
1616     if (viewport.hasHiddenColumns)
1617     {
1618       omitHidden = viewport.getViewAsString(true);
1619     }
1620
1621     String output = new FormatAdapter().formatSequences("Fasta", seqs,
1622             omitHidden);
1623
1624     StringSelection ss = new StringSelection(output);
1625
1626     try
1627     {
1628       jalview.gui.Desktop.internalCopy = true;
1629       // Its really worth setting the clipboard contents
1630       // to empty before setting the large StringSelection!!
1631       Toolkit.getDefaultToolkit().getSystemClipboard()
1632               .setContents(new StringSelection(""), null);
1633
1634       Toolkit.getDefaultToolkit().getSystemClipboard()
1635               .setContents(ss, Desktop.instance);
1636     } catch (OutOfMemoryError er)
1637     {
1638       new OOMWarning("copying region", er);
1639       return;
1640     }
1641
1642     Vector hiddenColumns = null;
1643     if (viewport.hasHiddenColumns)
1644     {
1645       hiddenColumns = new Vector();
1646       int hiddenOffset = viewport.getSelectionGroup().getStartRes(), hiddenCutoff = viewport
1647               .getSelectionGroup().getEndRes();
1648       for (int i = 0; i < viewport.getColumnSelection().getHiddenColumns()
1649               .size(); i++)
1650       {
1651         int[] region = (int[]) viewport.getColumnSelection()
1652                 .getHiddenColumns().elementAt(i);
1653         if (region[0] >= hiddenOffset && region[1] <= hiddenCutoff)
1654         {
1655           hiddenColumns.addElement(new int[]
1656           { region[0] - hiddenOffset, region[1] - hiddenOffset });
1657         }
1658       }
1659     }
1660
1661     Desktop.jalviewClipboard = new Object[]
1662     { seqs, viewport.alignment.getDataset(), hiddenColumns };
1663     statusBar.setText("Copied " + seqs.length + " sequences to clipboard.");
1664   }
1665
1666   /**
1667    * DOCUMENT ME!
1668    * 
1669    * @param e
1670    *          DOCUMENT ME!
1671    */
1672   protected void pasteNew_actionPerformed(ActionEvent e)
1673   {
1674     paste(true);
1675   }
1676
1677   /**
1678    * DOCUMENT ME!
1679    * 
1680    * @param e
1681    *          DOCUMENT ME!
1682    */
1683   protected void pasteThis_actionPerformed(ActionEvent e)
1684   {
1685     paste(false);
1686   }
1687
1688   /**
1689    * Paste contents of Jalview clipboard
1690    * 
1691    * @param newAlignment
1692    *          true to paste to a new alignment, otherwise add to this.
1693    */
1694   void paste(boolean newAlignment)
1695   {
1696     boolean externalPaste = true;
1697     try
1698     {
1699       Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
1700       Transferable contents = c.getContents(this);
1701
1702       if (contents == null)
1703       {
1704         return;
1705       }
1706
1707       String str, format;
1708       try
1709       {
1710         str = (String) contents.getTransferData(DataFlavor.stringFlavor);
1711         if (str.length() < 1)
1712         {
1713           return;
1714         }
1715
1716         format = new IdentifyFile().Identify(str, "Paste");
1717
1718       } catch (OutOfMemoryError er)
1719       {
1720         new OOMWarning("Out of memory pasting sequences!!", er);
1721         return;
1722       }
1723
1724       SequenceI[] sequences;
1725       boolean annotationAdded = false;
1726       AlignmentI alignment = null;
1727
1728       if (Desktop.jalviewClipboard != null)
1729       {
1730         // The clipboard was filled from within Jalview, we must use the
1731         // sequences
1732         // And dataset from the copied alignment
1733         SequenceI[] newseq = (SequenceI[]) Desktop.jalviewClipboard[0];
1734         // be doubly sure that we create *new* sequence objects.
1735         sequences = new SequenceI[newseq.length];
1736         for (int i = 0; i < newseq.length; i++)
1737         {
1738           sequences[i] = new Sequence(newseq[i]);
1739         }
1740         alignment = new Alignment(sequences);
1741         externalPaste = false;
1742       }
1743       else
1744       {
1745         // parse the clipboard as an alignment.
1746         alignment = new FormatAdapter().readFile(str, "Paste", format);
1747         sequences = alignment.getSequencesArray();
1748       }
1749
1750       int alwidth = 0;
1751
1752       if (newAlignment)
1753       {
1754
1755         if (Desktop.jalviewClipboard != null)
1756         {
1757           // dataset is inherited
1758           alignment.setDataset((Alignment) Desktop.jalviewClipboard[1]);
1759         }
1760         else
1761         {
1762           // new dataset is constructed
1763           alignment.setDataset(null);
1764         }
1765         alwidth = alignment.getWidth() + 1;
1766       }
1767       else
1768       {
1769         AlignmentI pastedal = alignment; // preserve pasted alignment object
1770         // Add pasted sequences and dataset into existing alignment.
1771         alignment = viewport.getAlignment();
1772         alwidth = alignment.getWidth() + 1;
1773         // decide if we need to import sequences from an existing dataset
1774         boolean importDs = Desktop.jalviewClipboard != null
1775                 && Desktop.jalviewClipboard[1] != alignment.getDataset();
1776         // importDs==true instructs us to copy over new dataset sequences from
1777         // an existing alignment
1778         Vector newDs = (importDs) ? new Vector() : null; // used to create
1779         // minimum dataset set
1780
1781         for (int i = 0; i < sequences.length; i++)
1782         {
1783           if (importDs)
1784           {
1785             newDs.addElement(null);
1786           }
1787           SequenceI ds = sequences[i].getDatasetSequence(); // null for a simple
1788           // paste
1789           if (importDs && ds != null)
1790           {
1791             if (!newDs.contains(ds))
1792             {
1793               newDs.setElementAt(ds, i);
1794               ds = new Sequence(ds);
1795               // update with new dataset sequence
1796               sequences[i].setDatasetSequence(ds);
1797             }
1798             else
1799             {
1800               ds = sequences[newDs.indexOf(ds)].getDatasetSequence();
1801             }
1802           }
1803           else
1804           {
1805             // copy and derive new dataset sequence
1806             sequences[i] = sequences[i].deriveSequence();
1807             alignment.getDataset().addSequence(
1808                     sequences[i].getDatasetSequence());
1809             // TODO: avoid creation of duplicate dataset sequences with a
1810             // 'contains' method using SequenceI.equals()/SequenceI.contains()
1811           }
1812           alignment.addSequence(sequences[i]); // merges dataset
1813         }
1814         if (newDs != null)
1815         {
1816           newDs.clear(); // tidy up
1817         }
1818         if (pastedal.getAlignmentAnnotation() != null)
1819         {
1820           // Add any annotation attached to alignment.
1821           AlignmentAnnotation[] alann = pastedal.getAlignmentAnnotation();
1822           for (int i = 0; i < alann.length; i++)
1823           {
1824             annotationAdded = true;
1825             if (alann[i].sequenceRef == null && !alann[i].autoCalculated)
1826             {
1827               AlignmentAnnotation newann = new AlignmentAnnotation(alann[i]);
1828               newann.padAnnotation(alwidth);
1829               alignment.addAnnotation(newann);
1830             }
1831           }
1832         }
1833       }
1834       if (!newAlignment)
1835       {
1836         // /////
1837         // ADD HISTORY ITEM
1838         //
1839         addHistoryItem(new EditCommand("Add sequences", EditCommand.PASTE,
1840                 sequences, 0, alignment.getWidth(), alignment));
1841       }
1842       // Add any annotations attached to sequences
1843       for (int i = 0; i < sequences.length; i++)
1844       {
1845         if (sequences[i].getAnnotation() != null)
1846         {
1847           for (int a = 0; a < sequences[i].getAnnotation().length; a++)
1848           {
1849             annotationAdded = true;
1850             sequences[i].getAnnotation()[a].adjustForAlignment();
1851             sequences[i].getAnnotation()[a].padAnnotation(alwidth);
1852             alignment.addAnnotation(sequences[i].getAnnotation()[a]); // annotation
1853             // was
1854             // duplicated
1855             // earlier
1856             alignment
1857                     .setAnnotationIndex(sequences[i].getAnnotation()[a], a);
1858           }
1859         }
1860       }
1861       if (!newAlignment)
1862       {
1863
1864         // propagate alignment changed.
1865         viewport.setEndSeq(alignment.getHeight());
1866         if (annotationAdded)
1867         {
1868           // Duplicate sequence annotation in all views.
1869           AlignmentI[] alview = this.getViewAlignments();
1870           for (int i = 0; i < sequences.length; i++)
1871           {
1872             AlignmentAnnotation sann[] = sequences[i].getAnnotation();
1873             if (sann == null)
1874               continue;
1875             for (int avnum = 0; avnum < alview.length; avnum++)
1876             {
1877               if (alview[avnum] != alignment)
1878               {
1879                 // duplicate in a view other than the one with input focus
1880                 int avwidth = alview[avnum].getWidth() + 1;
1881                 // this relies on sann being preserved after we
1882                 // modify the sequence's annotation array for each duplication
1883                 for (int a = 0; a < sann.length; a++)
1884                 {
1885                   AlignmentAnnotation newann = new AlignmentAnnotation(
1886                           sann[a]);
1887                   sequences[i].addAlignmentAnnotation(newann);
1888                   newann.padAnnotation(avwidth);
1889                   alview[avnum].addAnnotation(newann); // annotation was
1890                   // duplicated earlier
1891                   alview[avnum].setAnnotationIndex(newann, a);
1892                 }
1893               }
1894             }
1895           }
1896           buildSortByAnnotationScoresMenu();
1897         }
1898         viewport.firePropertyChange("alignment", null,
1899                 alignment.getSequences());
1900
1901       }
1902       else
1903       {
1904         AlignFrame af = new AlignFrame(alignment, DEFAULT_WIDTH,
1905                 DEFAULT_HEIGHT);
1906         String newtitle = new String("Copied sequences");
1907
1908         if (Desktop.jalviewClipboard != null
1909                 && Desktop.jalviewClipboard[2] != null)
1910         {
1911           Vector hc = (Vector) Desktop.jalviewClipboard[2];
1912           for (int i = 0; i < hc.size(); i++)
1913           {
1914             int[] region = (int[]) hc.elementAt(i);
1915             af.viewport.hideColumns(region[0], region[1]);
1916           }
1917         }
1918
1919         // >>>This is a fix for the moment, until a better solution is
1920         // found!!<<<
1921         af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer()
1922                 .transferSettings(
1923                         alignPanel.seqPanel.seqCanvas.getFeatureRenderer());
1924
1925         // TODO: maintain provenance of an alignment, rather than just make the
1926         // title a concatenation of operations.
1927         if (!externalPaste)
1928         {
1929           if (title.startsWith("Copied sequences"))
1930           {
1931             newtitle = title;
1932           }
1933           else
1934           {
1935             newtitle = newtitle.concat("- from " + title);
1936           }
1937         }
1938         else
1939         {
1940           newtitle = new String("Pasted sequences");
1941         }
1942
1943         Desktop.addInternalFrame(af, newtitle, DEFAULT_WIDTH,
1944                 DEFAULT_HEIGHT);
1945
1946       }
1947
1948     } catch (Exception ex)
1949     {
1950       ex.printStackTrace();
1951       System.out.println("Exception whilst pasting: " + ex);
1952       // could be anything being pasted in here
1953     }
1954
1955   }
1956
1957   /**
1958    * DOCUMENT ME!
1959    * 
1960    * @param e
1961    *          DOCUMENT ME!
1962    */
1963   protected void cut_actionPerformed(ActionEvent e)
1964   {
1965     copy_actionPerformed(null);
1966     delete_actionPerformed(null);
1967   }
1968
1969   /**
1970    * DOCUMENT ME!
1971    * 
1972    * @param e
1973    *          DOCUMENT ME!
1974    */
1975   protected void delete_actionPerformed(ActionEvent evt)
1976   {
1977
1978     SequenceGroup sg = viewport.getSelectionGroup();
1979     if (sg == null)
1980     {
1981       return;
1982     }
1983
1984     Vector seqs = new Vector();
1985     SequenceI seq;
1986     for (int i = 0; i < sg.getSize(); i++)
1987     {
1988       seq = sg.getSequenceAt(i);
1989       seqs.addElement(seq);
1990     }
1991
1992     // If the cut affects all sequences, remove highlighted columns
1993     if (sg.getSize() == viewport.alignment.getHeight())
1994     {
1995       viewport.getColumnSelection().removeElements(sg.getStartRes(),
1996               sg.getEndRes() + 1);
1997     }
1998
1999     SequenceI[] cut = new SequenceI[seqs.size()];
2000     for (int i = 0; i < seqs.size(); i++)
2001     {
2002       cut[i] = (SequenceI) seqs.elementAt(i);
2003     }
2004
2005     /*
2006      * //ADD HISTORY ITEM
2007      */
2008     addHistoryItem(new EditCommand("Cut Sequences", EditCommand.CUT, cut,
2009             sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,
2010             viewport.alignment));
2011
2012     viewport.setSelectionGroup(null);
2013     viewport.sendSelection();
2014     viewport.alignment.deleteGroup(sg);
2015
2016     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
2017             .getSequences());
2018     if (viewport.getAlignment().getHeight() < 1)
2019     {
2020       try
2021       {
2022         this.setClosed(true);
2023       } catch (Exception ex)
2024       {
2025       }
2026     }
2027   }
2028
2029   /**
2030    * DOCUMENT ME!
2031    * 
2032    * @param e
2033    *          DOCUMENT ME!
2034    */
2035   protected void deleteGroups_actionPerformed(ActionEvent e)
2036   {
2037     viewport.alignment.deleteAllGroups();
2038     viewport.sequenceColours = null;
2039     viewport.setSelectionGroup(null);
2040     PaintRefresher.Refresh(this, viewport.getSequenceSetId());
2041     alignPanel.updateAnnotation();
2042     alignPanel.paintAlignment(true);
2043   }
2044
2045   /**
2046    * DOCUMENT ME!
2047    * 
2048    * @param e
2049    *          DOCUMENT ME!
2050    */
2051   public void selectAllSequenceMenuItem_actionPerformed(ActionEvent e)
2052   {
2053     SequenceGroup sg = new SequenceGroup();
2054
2055     for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
2056     {
2057       sg.addSequence(viewport.getAlignment().getSequenceAt(i), false);
2058     }
2059
2060     sg.setEndRes(viewport.alignment.getWidth() - 1);
2061     viewport.setSelectionGroup(sg);
2062     viewport.sendSelection();
2063     alignPanel.paintAlignment(true);
2064     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
2065   }
2066
2067   /**
2068    * DOCUMENT ME!
2069    * 
2070    * @param e
2071    *          DOCUMENT ME!
2072    */
2073   public void deselectAllSequenceMenuItem_actionPerformed(ActionEvent e)
2074   {
2075     if (viewport.cursorMode)
2076     {
2077       alignPanel.seqPanel.keyboardNo1 = null;
2078       alignPanel.seqPanel.keyboardNo2 = null;
2079     }
2080     viewport.setSelectionGroup(null);
2081     viewport.getColumnSelection().clear();
2082     viewport.setSelectionGroup(null);
2083     alignPanel.seqPanel.seqCanvas.highlightSearchResults(null);
2084     alignPanel.idPanel.idCanvas.searchResults = null;
2085     alignPanel.paintAlignment(true);
2086     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
2087     viewport.sendSelection();
2088   }
2089
2090   /**
2091    * DOCUMENT ME!
2092    * 
2093    * @param e
2094    *          DOCUMENT ME!
2095    */
2096   public void invertSequenceMenuItem_actionPerformed(ActionEvent e)
2097   {
2098     SequenceGroup sg = viewport.getSelectionGroup();
2099
2100     if (sg == null)
2101     {
2102       selectAllSequenceMenuItem_actionPerformed(null);
2103
2104       return;
2105     }
2106
2107     for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
2108     {
2109       sg.addOrRemove(viewport.getAlignment().getSequenceAt(i), false);
2110     }
2111
2112     alignPanel.paintAlignment(true);
2113     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
2114     viewport.sendSelection();
2115   }
2116
2117   public void invertColSel_actionPerformed(ActionEvent e)
2118   {
2119     viewport.invertColumnSelection();
2120     alignPanel.paintAlignment(true);
2121     viewport.sendSelection();
2122   }
2123
2124   /**
2125    * DOCUMENT ME!
2126    * 
2127    * @param e
2128    *          DOCUMENT ME!
2129    */
2130   public void remove2LeftMenuItem_actionPerformed(ActionEvent e)
2131   {
2132     trimAlignment(true);
2133   }
2134
2135   /**
2136    * DOCUMENT ME!
2137    * 
2138    * @param e
2139    *          DOCUMENT ME!
2140    */
2141   public void remove2RightMenuItem_actionPerformed(ActionEvent e)
2142   {
2143     trimAlignment(false);
2144   }
2145
2146   void trimAlignment(boolean trimLeft)
2147   {
2148     ColumnSelection colSel = viewport.getColumnSelection();
2149     int column;
2150
2151     if (colSel.size() > 0)
2152     {
2153       if (trimLeft)
2154       {
2155         column = colSel.getMin();
2156       }
2157       else
2158       {
2159         column = colSel.getMax();
2160       }
2161
2162       SequenceI[] seqs;
2163       if (viewport.getSelectionGroup() != null)
2164       {
2165         seqs = viewport.getSelectionGroup().getSequencesAsArray(
2166                 viewport.hiddenRepSequences);
2167       }
2168       else
2169       {
2170         seqs = viewport.alignment.getSequencesArray();
2171       }
2172
2173       TrimRegionCommand trimRegion;
2174       if (trimLeft)
2175       {
2176         trimRegion = new TrimRegionCommand("Remove Left",
2177                 TrimRegionCommand.TRIM_LEFT, seqs, column,
2178                 viewport.alignment, viewport.colSel,
2179                 viewport.selectionGroup);
2180         viewport.setStartRes(0);
2181       }
2182       else
2183       {
2184         trimRegion = new TrimRegionCommand("Remove Right",
2185                 TrimRegionCommand.TRIM_RIGHT, seqs, column,
2186                 viewport.alignment, viewport.colSel,
2187                 viewport.selectionGroup);
2188       }
2189
2190       statusBar.setText("Removed " + trimRegion.getSize() + " columns.");
2191
2192       addHistoryItem(trimRegion);
2193
2194       Vector groups = viewport.alignment.getGroups();
2195
2196       for (int i = 0; i < groups.size(); i++)
2197       {
2198         SequenceGroup sg = (SequenceGroup) groups.get(i);
2199
2200         if ((trimLeft && !sg.adjustForRemoveLeft(column))
2201                 || (!trimLeft && !sg.adjustForRemoveRight(column)))
2202         {
2203           viewport.alignment.deleteGroup(sg);
2204         }
2205       }
2206
2207       viewport.firePropertyChange("alignment", null, viewport
2208               .getAlignment().getSequences());
2209     }
2210   }
2211
2212   /**
2213    * DOCUMENT ME!
2214    * 
2215    * @param e
2216    *          DOCUMENT ME!
2217    */
2218   public void removeGappedColumnMenuItem_actionPerformed(ActionEvent e)
2219   {
2220     int start = 0, end = viewport.alignment.getWidth() - 1;
2221
2222     SequenceI[] seqs;
2223     if (viewport.getSelectionGroup() != null)
2224     {
2225       seqs = viewport.getSelectionGroup().getSequencesAsArray(
2226               viewport.hiddenRepSequences);
2227       start = viewport.getSelectionGroup().getStartRes();
2228       end = viewport.getSelectionGroup().getEndRes();
2229     }
2230     else
2231     {
2232       seqs = viewport.alignment.getSequencesArray();
2233     }
2234
2235     RemoveGapColCommand removeGapCols = new RemoveGapColCommand(
2236             "Remove Gapped Columns", seqs, start, end, viewport.alignment);
2237
2238     addHistoryItem(removeGapCols);
2239
2240     statusBar.setText("Removed " + removeGapCols.getSize()
2241             + " empty columns.");
2242
2243     // This is to maintain viewport position on first residue
2244     // of first sequence
2245     SequenceI seq = viewport.alignment.getSequenceAt(0);
2246     int startRes = seq.findPosition(viewport.startRes);
2247     // ShiftList shifts;
2248     // viewport.getAlignment().removeGaps(shifts=new ShiftList());
2249     // edit.alColumnChanges=shifts.getInverse();
2250     // if (viewport.hasHiddenColumns)
2251     // viewport.getColumnSelection().compensateForEdits(shifts);
2252     viewport.setStartRes(seq.findIndex(startRes) - 1);
2253     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
2254             .getSequences());
2255
2256   }
2257
2258   /**
2259    * DOCUMENT ME!
2260    * 
2261    * @param e
2262    *          DOCUMENT ME!
2263    */
2264   public void removeAllGapsMenuItem_actionPerformed(ActionEvent e)
2265   {
2266     int start = 0, end = viewport.alignment.getWidth() - 1;
2267
2268     SequenceI[] seqs;
2269     if (viewport.getSelectionGroup() != null)
2270     {
2271       seqs = viewport.getSelectionGroup().getSequencesAsArray(
2272               viewport.hiddenRepSequences);
2273       start = viewport.getSelectionGroup().getStartRes();
2274       end = viewport.getSelectionGroup().getEndRes();
2275     }
2276     else
2277     {
2278       seqs = viewport.alignment.getSequencesArray();
2279     }
2280
2281     // This is to maintain viewport position on first residue
2282     // of first sequence
2283     SequenceI seq = viewport.alignment.getSequenceAt(0);
2284     int startRes = seq.findPosition(viewport.startRes);
2285
2286     addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end,
2287             viewport.alignment));
2288
2289     viewport.setStartRes(seq.findIndex(startRes) - 1);
2290
2291     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
2292             .getSequences());
2293
2294   }
2295
2296   /**
2297    * DOCUMENT ME!
2298    * 
2299    * @param e
2300    *          DOCUMENT ME!
2301    */
2302   public void padGapsMenuitem_actionPerformed(ActionEvent e)
2303   {
2304     viewport.padGaps = padGapsMenuitem.isSelected();
2305     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
2306             .getSequences());
2307   }
2308
2309   // else
2310   {
2311     // if (justifySeqs>0)
2312     {
2313       // alignment.justify(justifySeqs!=RIGHT_JUSTIFY);
2314     }
2315   }
2316
2317   // }
2318
2319   /**
2320    * DOCUMENT ME!
2321    * 
2322    * @param e
2323    *          DOCUMENT ME!
2324    */
2325   public void findMenuItem_actionPerformed(ActionEvent e)
2326   {
2327     new Finder();
2328   }
2329
2330   public void newView_actionPerformed(ActionEvent e)
2331   {
2332     newView(true);
2333   }
2334
2335   /**
2336    * 
2337    * @param copyAnnotation
2338    *          if true then duplicate all annnotation, groups and settings
2339    * @return new alignment panel, already displayed.
2340    */
2341   public AlignmentPanel newView(boolean copyAnnotation)
2342   {
2343     return newView(null, copyAnnotation);
2344   }
2345
2346   /**
2347    * 
2348    * @param viewTitle
2349    *          title of newly created view
2350    * @return new alignment panel, already displayed.
2351    */
2352   public AlignmentPanel newView(String viewTitle)
2353   {
2354     return newView(viewTitle, true);
2355   }
2356
2357   /**
2358    * 
2359    * @param viewTitle
2360    *          title of newly created view
2361    * @param copyAnnotation
2362    *          if true then duplicate all annnotation, groups and settings
2363    * @return new alignment panel, already displayed.
2364    */
2365   public AlignmentPanel newView(String viewTitle, boolean copyAnnotation)
2366   {
2367     AlignmentPanel newap = new Jalview2XML().copyAlignPanel(alignPanel,
2368             true);
2369     if (!copyAnnotation)
2370     {
2371       // just remove all the current annotation except for the automatic stuff
2372       newap.av.alignment.deleteAllGroups();
2373       for (AlignmentAnnotation alan : newap.av.alignment
2374               .getAlignmentAnnotation())
2375       {
2376         if (!alan.autoCalculated)
2377         {
2378           newap.av.alignment.deleteAnnotation(alan);
2379         }
2380         ;
2381       }
2382     }
2383
2384     newap.av.gatherViewsHere = false;
2385
2386     if (viewport.viewName == null)
2387     {
2388       viewport.viewName = "Original";
2389     }
2390
2391     newap.av.historyList = viewport.historyList;
2392     newap.av.redoList = viewport.redoList;
2393
2394     int index = Desktop.getViewCount(viewport.getSequenceSetId());
2395     // make sure the new view has a unique name - this is essential for Jalview
2396     // 2 archives
2397     boolean addFirstIndex = false;
2398     if (viewTitle == null || viewTitle.trim().length() == 0)
2399     {
2400       viewTitle = "View";
2401       addFirstIndex = true;
2402     }
2403     else
2404     {
2405       index = 1;// we count from 1 if given a specific name
2406     }
2407     String newViewName = viewTitle + ((addFirstIndex) ? " " + index : "");
2408     Vector comps = (Vector) PaintRefresher.components.get(viewport
2409             .getSequenceSetId());
2410     Vector existingNames = new Vector();
2411     for (int i = 0; i < comps.size(); i++)
2412     {
2413       if (comps.elementAt(i) instanceof AlignmentPanel)
2414       {
2415         AlignmentPanel ap = (AlignmentPanel) comps.elementAt(i);
2416         if (!existingNames.contains(ap.av.viewName))
2417         {
2418           existingNames.addElement(ap.av.viewName);
2419         }
2420       }
2421     }
2422
2423     while (existingNames.contains(newViewName))
2424     {
2425       newViewName = viewTitle + " " + (++index);
2426     }
2427
2428     newap.av.viewName = newViewName;
2429
2430     addAlignmentPanel(newap, true);
2431
2432     if (alignPanels.size() == 2)
2433     {
2434       viewport.gatherViewsHere = true;
2435     }
2436     tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
2437     return newap;
2438   }
2439
2440   public void expandViews_actionPerformed(ActionEvent e)
2441   {
2442     Desktop.instance.explodeViews(this);
2443   }
2444
2445   public void gatherViews_actionPerformed(ActionEvent e)
2446   {
2447     Desktop.instance.gatherViews(this);
2448   }
2449
2450   /**
2451    * DOCUMENT ME!
2452    * 
2453    * @param e
2454    *          DOCUMENT ME!
2455    */
2456   public void font_actionPerformed(ActionEvent e)
2457   {
2458     new FontChooser(alignPanel);
2459   }
2460
2461   /**
2462    * DOCUMENT ME!
2463    * 
2464    * @param e
2465    *          DOCUMENT ME!
2466    */
2467   protected void seqLimit_actionPerformed(ActionEvent e)
2468   {
2469     viewport.setShowJVSuffix(seqLimits.isSelected());
2470
2471     alignPanel.idPanel.idCanvas.setPreferredSize(alignPanel
2472             .calculateIdWidth());
2473     alignPanel.paintAlignment(true);
2474   }
2475
2476   public void idRightAlign_actionPerformed(ActionEvent e)
2477   {
2478     viewport.rightAlignIds = idRightAlign.isSelected();
2479     alignPanel.paintAlignment(true);
2480   }
2481
2482   public void centreColumnLabels_actionPerformed(ActionEvent e)
2483   {
2484     viewport.centreColumnLabels = centreColumnLabelsMenuItem.getState();
2485     alignPanel.paintAlignment(true);
2486   }
2487
2488   /*
2489    * (non-Javadoc)
2490    * 
2491    * @see jalview.jbgui.GAlignFrame#followHighlight_actionPerformed()
2492    */
2493   protected void followHighlight_actionPerformed()
2494   {
2495     if (viewport.followHighlight = this.followHighlightMenuItem.getState())
2496     {
2497       alignPanel.scrollToPosition(
2498               alignPanel.seqPanel.seqCanvas.searchResults, false);
2499     }
2500   }
2501
2502   /**
2503    * DOCUMENT ME!
2504    * 
2505    * @param e
2506    *          DOCUMENT ME!
2507    */
2508   protected void colourTextMenuItem_actionPerformed(ActionEvent e)
2509   {
2510     viewport.setColourText(colourTextMenuItem.isSelected());
2511     alignPanel.paintAlignment(true);
2512   }
2513
2514   /**
2515    * DOCUMENT ME!
2516    * 
2517    * @param e
2518    *          DOCUMENT ME!
2519    */
2520   public void wrapMenuItem_actionPerformed(ActionEvent e)
2521   {
2522     scaleAbove.setVisible(wrapMenuItem.isSelected());
2523     scaleLeft.setVisible(wrapMenuItem.isSelected());
2524     scaleRight.setVisible(wrapMenuItem.isSelected());
2525     viewport.setWrapAlignment(wrapMenuItem.isSelected());
2526     alignPanel.setWrapAlignment(wrapMenuItem.isSelected());
2527   }
2528
2529   public void showAllSeqs_actionPerformed(ActionEvent e)
2530   {
2531     viewport.showAllHiddenSeqs();
2532   }
2533
2534   public void showAllColumns_actionPerformed(ActionEvent e)
2535   {
2536     viewport.showAllHiddenColumns();
2537     repaint();
2538   }
2539
2540   public void hideSelSequences_actionPerformed(ActionEvent e)
2541   {
2542     viewport.hideAllSelectedSeqs();
2543     alignPanel.paintAlignment(true);
2544   }
2545
2546   /**
2547    * called by key handler and the hide all/show all menu items
2548    * 
2549    * @param toggleSeqs
2550    * @param toggleCols
2551    */
2552   private void toggleHiddenRegions(boolean toggleSeqs, boolean toggleCols)
2553   {
2554
2555     boolean hide = false;
2556     SequenceGroup sg = viewport.getSelectionGroup();
2557     if (!toggleSeqs && !toggleCols)
2558     {
2559       // Hide everything by the current selection - this is a hack - we do the
2560       // invert and then hide
2561       // first check that there will be visible columns after the invert.
2562       if ((viewport.colSel != null && viewport.colSel.getSelected() != null && viewport.colSel
2563               .getSelected().size() > 0)
2564               || (sg != null && sg.getSize() > 0 && sg.getStartRes() <= sg
2565                       .getEndRes()))
2566       {
2567         // now invert the sequence set, if required - empty selection implies
2568         // that no hiding is required.
2569         if (sg != null)
2570         {
2571           invertSequenceMenuItem_actionPerformed(null);
2572           sg = viewport.getSelectionGroup();
2573           toggleSeqs = true;
2574
2575         }
2576         viewport.expandColSelection(sg, true);
2577         // finally invert the column selection and get the new sequence
2578         // selection.
2579         invertColSel_actionPerformed(null);
2580         toggleCols = true;
2581       }
2582     }
2583
2584     if (toggleSeqs)
2585     {
2586       if (sg != null && sg.getSize() != viewport.alignment.getHeight())
2587       {
2588         hideSelSequences_actionPerformed(null);
2589         hide = true;
2590       }
2591       else if (!(toggleCols && viewport.colSel.getSelected().size() > 0))
2592       {
2593         showAllSeqs_actionPerformed(null);
2594       }
2595     }
2596
2597     if (toggleCols)
2598     {
2599       if (viewport.colSel.getSelected().size() > 0)
2600       {
2601         hideSelColumns_actionPerformed(null);
2602         if (!toggleSeqs)
2603         {
2604           viewport.selectionGroup = sg;
2605         }
2606       }
2607       else if (!hide)
2608       {
2609         showAllColumns_actionPerformed(null);
2610       }
2611     }
2612   }
2613
2614   /*
2615    * (non-Javadoc)
2616    * 
2617    * @see
2618    * jalview.jbgui.GAlignFrame#hideAllButSelection_actionPerformed(java.awt.
2619    * event.ActionEvent)
2620    */
2621   public void hideAllButSelection_actionPerformed(ActionEvent e)
2622   {
2623     toggleHiddenRegions(false, false);
2624   }
2625
2626   /*
2627    * (non-Javadoc)
2628    * 
2629    * @see
2630    * jalview.jbgui.GAlignFrame#hideAllSelection_actionPerformed(java.awt.event
2631    * .ActionEvent)
2632    */
2633   public void hideAllSelection_actionPerformed(ActionEvent e)
2634   {
2635     SequenceGroup sg = viewport.getSelectionGroup();
2636     viewport.expandColSelection(sg, false);
2637     viewport.hideAllSelectedSeqs();
2638     viewport.hideSelectedColumns();
2639     alignPanel.paintAlignment(true);
2640   }
2641
2642   /*
2643    * (non-Javadoc)
2644    * 
2645    * @see
2646    * jalview.jbgui.GAlignFrame#showAllhidden_actionPerformed(java.awt.event.
2647    * ActionEvent)
2648    */
2649   public void showAllhidden_actionPerformed(ActionEvent e)
2650   {
2651     viewport.showAllHiddenColumns();
2652     viewport.showAllHiddenSeqs();
2653     alignPanel.paintAlignment(true);
2654   }
2655
2656   public void hideSelColumns_actionPerformed(ActionEvent e)
2657   {
2658     viewport.hideSelectedColumns();
2659     alignPanel.paintAlignment(true);
2660   }
2661
2662   public void hiddenMarkers_actionPerformed(ActionEvent e)
2663   {
2664     viewport.setShowHiddenMarkers(hiddenMarkers.isSelected());
2665     repaint();
2666   }
2667
2668   /**
2669    * DOCUMENT ME!
2670    * 
2671    * @param e
2672    *          DOCUMENT ME!
2673    */
2674   protected void scaleAbove_actionPerformed(ActionEvent e)
2675   {
2676     viewport.setScaleAboveWrapped(scaleAbove.isSelected());
2677     alignPanel.paintAlignment(true);
2678   }
2679
2680   /**
2681    * DOCUMENT ME!
2682    * 
2683    * @param e
2684    *          DOCUMENT ME!
2685    */
2686   protected void scaleLeft_actionPerformed(ActionEvent e)
2687   {
2688     viewport.setScaleLeftWrapped(scaleLeft.isSelected());
2689     alignPanel.paintAlignment(true);
2690   }
2691
2692   /**
2693    * DOCUMENT ME!
2694    * 
2695    * @param e
2696    *          DOCUMENT ME!
2697    */
2698   protected void scaleRight_actionPerformed(ActionEvent e)
2699   {
2700     viewport.setScaleRightWrapped(scaleRight.isSelected());
2701     alignPanel.paintAlignment(true);
2702   }
2703
2704   /**
2705    * DOCUMENT ME!
2706    * 
2707    * @param e
2708    *          DOCUMENT ME!
2709    */
2710   public void viewBoxesMenuItem_actionPerformed(ActionEvent e)
2711   {
2712     viewport.setShowBoxes(viewBoxesMenuItem.isSelected());
2713     alignPanel.paintAlignment(true);
2714   }
2715
2716   /**
2717    * DOCUMENT ME!
2718    * 
2719    * @param e
2720    *          DOCUMENT ME!
2721    */
2722   public void viewTextMenuItem_actionPerformed(ActionEvent e)
2723   {
2724     viewport.setShowText(viewTextMenuItem.isSelected());
2725     alignPanel.paintAlignment(true);
2726   }
2727
2728   /**
2729    * DOCUMENT ME!
2730    * 
2731    * @param e
2732    *          DOCUMENT ME!
2733    */
2734   protected void renderGapsMenuItem_actionPerformed(ActionEvent e)
2735   {
2736     viewport.setRenderGaps(renderGapsMenuItem.isSelected());
2737     alignPanel.paintAlignment(true);
2738   }
2739
2740   public FeatureSettings featureSettings;
2741
2742   public void featureSettings_actionPerformed(ActionEvent e)
2743   {
2744     if (featureSettings != null)
2745     {
2746       featureSettings.close();
2747       featureSettings = null;
2748     }
2749     if (!showSeqFeatures.isSelected())
2750     {
2751       // make sure features are actually displayed
2752       showSeqFeatures.setSelected(true);
2753       showSeqFeatures_actionPerformed(null);
2754     }
2755     featureSettings = new FeatureSettings(this);
2756   }
2757
2758   /**
2759    * Set or clear 'Show Sequence Features'
2760    * 
2761    * @param evt
2762    *          DOCUMENT ME!
2763    */
2764   public void showSeqFeatures_actionPerformed(ActionEvent evt)
2765   {
2766     viewport.setShowSequenceFeatures(showSeqFeatures.isSelected());
2767     alignPanel.paintAlignment(true);
2768     if (alignPanel.getOverviewPanel() != null)
2769     {
2770       alignPanel.getOverviewPanel().updateOverviewImage();
2771     }
2772   }
2773
2774   /**
2775    * Set or clear 'Show Sequence Features'
2776    * 
2777    * @param evt
2778    *          DOCUMENT ME!
2779    */
2780   public void showSeqFeaturesHeight_actionPerformed(ActionEvent evt)
2781   {
2782     viewport.setShowSequenceFeaturesHeight(showSeqFeaturesHeight
2783             .isSelected());
2784     if (viewport.getShowSequenceFeaturesHeight())
2785     {
2786       // ensure we're actually displaying features
2787       viewport.setShowSequenceFeatures(true);
2788       showSeqFeatures.setSelected(true);
2789     }
2790     alignPanel.paintAlignment(true);
2791     if (alignPanel.getOverviewPanel() != null)
2792     {
2793       alignPanel.getOverviewPanel().updateOverviewImage();
2794     }
2795   }
2796
2797   /**
2798    * DOCUMENT ME!
2799    * 
2800    * @param e
2801    *          DOCUMENT ME!
2802    */
2803   public void annotationPanelMenuItem_actionPerformed(ActionEvent e)
2804   {
2805     viewport.setShowAnnotation(annotationPanelMenuItem.isSelected());
2806     alignPanel.setAnnotationVisible(annotationPanelMenuItem.isSelected());
2807   }
2808
2809   public void alignmentProperties()
2810   {
2811     JEditorPane editPane = new JEditorPane("text/html", "");
2812     editPane.setEditable(false);
2813     StringBuffer contents = new AlignmentProperties(viewport.alignment)
2814             .formatAsHtml();
2815     editPane.setText("<html>" + contents.toString() + "</html>");
2816     JInternalFrame frame = new JInternalFrame();
2817     frame.getContentPane().add(new JScrollPane(editPane));
2818
2819     Desktop.instance.addInternalFrame(frame, "Alignment Properties: "
2820             + getTitle(), 500, 400);
2821   }
2822
2823   /**
2824    * DOCUMENT ME!
2825    * 
2826    * @param e
2827    *          DOCUMENT ME!
2828    */
2829   public void overviewMenuItem_actionPerformed(ActionEvent e)
2830   {
2831     if (alignPanel.overviewPanel != null)
2832     {
2833       return;
2834     }
2835
2836     JInternalFrame frame = new JInternalFrame();
2837     OverviewPanel overview = new OverviewPanel(alignPanel);
2838     frame.setContentPane(overview);
2839     Desktop.addInternalFrame(frame, "Overview " + this.getTitle(),
2840             frame.getWidth(), frame.getHeight());
2841     frame.pack();
2842     frame.setLayer(JLayeredPane.PALETTE_LAYER);
2843     frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
2844     {
2845       public void internalFrameClosed(
2846               javax.swing.event.InternalFrameEvent evt)
2847       {
2848         alignPanel.setOverviewPanel(null);
2849       };
2850     });
2851
2852     alignPanel.setOverviewPanel(overview);
2853   }
2854
2855   public void textColour_actionPerformed(ActionEvent e)
2856   {
2857     new TextColourChooser().chooseColour(alignPanel, null);
2858   }
2859
2860   /**
2861    * DOCUMENT ME!
2862    * 
2863    * @param e
2864    *          DOCUMENT ME!
2865    */
2866   protected void noColourmenuItem_actionPerformed(ActionEvent e)
2867   {
2868     changeColour(null);
2869   }
2870
2871   /**
2872    * DOCUMENT ME!
2873    * 
2874    * @param e
2875    *          DOCUMENT ME!
2876    */
2877   public void clustalColour_actionPerformed(ActionEvent e)
2878   {
2879     changeColour(new ClustalxColourScheme(
2880             viewport.alignment.getSequences(),
2881             viewport.alignment.getWidth()));
2882   }
2883
2884   /**
2885    * DOCUMENT ME!
2886    * 
2887    * @param e
2888    *          DOCUMENT ME!
2889    */
2890   public void zappoColour_actionPerformed(ActionEvent e)
2891   {
2892     changeColour(new ZappoColourScheme());
2893   }
2894
2895   /**
2896    * DOCUMENT ME!
2897    * 
2898    * @param e
2899    *          DOCUMENT ME!
2900    */
2901   public void taylorColour_actionPerformed(ActionEvent e)
2902   {
2903     changeColour(new TaylorColourScheme());
2904   }
2905
2906   /**
2907    * DOCUMENT ME!
2908    * 
2909    * @param e
2910    *          DOCUMENT ME!
2911    */
2912   public void hydrophobicityColour_actionPerformed(ActionEvent e)
2913   {
2914     changeColour(new HydrophobicColourScheme());
2915   }
2916
2917   /**
2918    * DOCUMENT ME!
2919    * 
2920    * @param e
2921    *          DOCUMENT ME!
2922    */
2923   public void helixColour_actionPerformed(ActionEvent e)
2924   {
2925     changeColour(new HelixColourScheme());
2926   }
2927
2928   /**
2929    * DOCUMENT ME!
2930    * 
2931    * @param e
2932    *          DOCUMENT ME!
2933    */
2934   public void strandColour_actionPerformed(ActionEvent e)
2935   {
2936     changeColour(new StrandColourScheme());
2937   }
2938
2939   /**
2940    * DOCUMENT ME!
2941    * 
2942    * @param e
2943    *          DOCUMENT ME!
2944    */
2945   public void turnColour_actionPerformed(ActionEvent e)
2946   {
2947     changeColour(new TurnColourScheme());
2948   }
2949
2950   /**
2951    * DOCUMENT ME!
2952    * 
2953    * @param e
2954    *          DOCUMENT ME!
2955    */
2956   public void buriedColour_actionPerformed(ActionEvent e)
2957   {
2958     changeColour(new BuriedColourScheme());
2959   }
2960
2961   /**
2962    * DOCUMENT ME!
2963    * 
2964    * @param e
2965    *          DOCUMENT ME!
2966    */
2967   public void nucleotideColour_actionPerformed(ActionEvent e)
2968   {
2969     changeColour(new NucleotideColourScheme());
2970   }
2971
2972   public void annotationColour_actionPerformed(ActionEvent e)
2973   {
2974     new AnnotationColourChooser(viewport, alignPanel);
2975   }
2976
2977   /**
2978    * DOCUMENT ME!
2979    * 
2980    * @param e
2981    *          DOCUMENT ME!
2982    */
2983   protected void applyToAllGroups_actionPerformed(ActionEvent e)
2984   {
2985     viewport.setColourAppliesToAllGroups(applyToAllGroups.isSelected());
2986   }
2987
2988   /**
2989    * DOCUMENT ME!
2990    * 
2991    * @param cs
2992    *          DOCUMENT ME!
2993    */
2994   public void changeColour(ColourSchemeI cs)
2995   {
2996     int threshold = 0;
2997
2998     if (cs != null)
2999     {
3000       if (viewport.getAbovePIDThreshold())
3001       {
3002         threshold = SliderPanel.setPIDSliderSource(alignPanel, cs,
3003                 "Background");
3004
3005         cs.setThreshold(threshold, viewport.getIgnoreGapsConsensus());
3006
3007         viewport.setGlobalColourScheme(cs);
3008       }
3009       else
3010       {
3011         cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
3012       }
3013
3014       if (viewport.getConservationSelected())
3015       {
3016
3017         Alignment al = (Alignment) viewport.alignment;
3018         Conservation c = new Conservation("All",
3019                 ResidueProperties.propHash, 3, al.getSequences(), 0,
3020                 al.getWidth() - 1);
3021
3022         c.calculate();
3023         c.verdict(false, viewport.ConsPercGaps);
3024
3025         cs.setConservation(c);
3026
3027         cs.setConservationInc(SliderPanel.setConservationSlider(alignPanel,
3028                 cs, "Background"));
3029       }
3030       else
3031       {
3032         cs.setConservation(null);
3033       }
3034
3035       cs.setConsensus(viewport.hconsensus);
3036     }
3037
3038     viewport.setGlobalColourScheme(cs);
3039
3040     if (viewport.getColourAppliesToAllGroups())
3041     {
3042       Vector groups = viewport.alignment.getGroups();
3043
3044       for (int i = 0; i < groups.size(); i++)
3045       {
3046         SequenceGroup sg = (SequenceGroup) groups.elementAt(i);
3047
3048         if (cs == null)
3049         {
3050           sg.cs = null;
3051           continue;
3052         }
3053
3054         if (cs instanceof ClustalxColourScheme)
3055         {
3056           sg.cs = new ClustalxColourScheme(
3057                   sg.getSequences(viewport.hiddenRepSequences),
3058                   sg.getWidth());
3059         }
3060         else if (cs instanceof UserColourScheme)
3061         {
3062           sg.cs = new UserColourScheme(((UserColourScheme) cs).getColours());
3063         }
3064         else
3065         {
3066           try
3067           {
3068             sg.cs = (ColourSchemeI) cs.getClass().newInstance();
3069           } catch (Exception ex)
3070           {
3071           }
3072         }
3073
3074         if (viewport.getAbovePIDThreshold()
3075                 || cs instanceof PIDColourScheme
3076                 || cs instanceof Blosum62ColourScheme)
3077         {
3078           sg.cs.setThreshold(threshold, viewport.getIgnoreGapsConsensus());
3079
3080           sg.cs.setConsensus(AAFrequency.calculate(
3081                   sg.getSequences(viewport.hiddenRepSequences),
3082                   sg.getStartRes(), sg.getEndRes() + 1));
3083         }
3084         else
3085         {
3086           sg.cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
3087         }
3088
3089         if (viewport.getConservationSelected())
3090         {
3091           Conservation c = new Conservation("Group",
3092                   ResidueProperties.propHash, 3,
3093                   sg.getSequences(viewport.hiddenRepSequences),
3094                   sg.getStartRes(), sg.getEndRes() + 1);
3095           c.calculate();
3096           c.verdict(false, viewport.ConsPercGaps);
3097           sg.cs.setConservation(c);
3098         }
3099         else
3100         {
3101           sg.cs.setConservation(null);
3102         }
3103       }
3104     }
3105
3106     if (alignPanel.getOverviewPanel() != null)
3107     {
3108       alignPanel.getOverviewPanel().updateOverviewImage();
3109     }
3110
3111     alignPanel.paintAlignment(true);
3112   }
3113
3114   /**
3115    * DOCUMENT ME!
3116    * 
3117    * @param e
3118    *          DOCUMENT ME!
3119    */
3120   protected void modifyPID_actionPerformed(ActionEvent e)
3121   {
3122     if (viewport.getAbovePIDThreshold()
3123             && viewport.globalColourScheme != null)
3124     {
3125       SliderPanel.setPIDSliderSource(alignPanel,
3126               viewport.getGlobalColourScheme(), "Background");
3127       SliderPanel.showPIDSlider();
3128     }
3129   }
3130
3131   /**
3132    * DOCUMENT ME!
3133    * 
3134    * @param e
3135    *          DOCUMENT ME!
3136    */
3137   protected void modifyConservation_actionPerformed(ActionEvent e)
3138   {
3139     if (viewport.getConservationSelected()
3140             && viewport.globalColourScheme != null)
3141     {
3142       SliderPanel.setConservationSlider(alignPanel,
3143               viewport.globalColourScheme, "Background");
3144       SliderPanel.showConservationSlider();
3145     }
3146   }
3147
3148   /**
3149    * DOCUMENT ME!
3150    * 
3151    * @param e
3152    *          DOCUMENT ME!
3153    */
3154   protected void conservationMenuItem_actionPerformed(ActionEvent e)
3155   {
3156     viewport.setConservationSelected(conservationMenuItem.isSelected());
3157
3158     viewport.setAbovePIDThreshold(false);
3159     abovePIDThreshold.setSelected(false);
3160
3161     changeColour(viewport.getGlobalColourScheme());
3162
3163     modifyConservation_actionPerformed(null);
3164   }
3165
3166   /**
3167    * DOCUMENT ME!
3168    * 
3169    * @param e
3170    *          DOCUMENT ME!
3171    */
3172   public void abovePIDThreshold_actionPerformed(ActionEvent e)
3173   {
3174     viewport.setAbovePIDThreshold(abovePIDThreshold.isSelected());
3175
3176     conservationMenuItem.setSelected(false);
3177     viewport.setConservationSelected(false);
3178
3179     changeColour(viewport.getGlobalColourScheme());
3180
3181     modifyPID_actionPerformed(null);
3182   }
3183
3184   /**
3185    * DOCUMENT ME!
3186    * 
3187    * @param e
3188    *          DOCUMENT ME!
3189    */
3190   public void userDefinedColour_actionPerformed(ActionEvent e)
3191   {
3192     if (e.getActionCommand().equals("User Defined..."))
3193     {
3194       new UserDefinedColours(alignPanel, null);
3195     }
3196     else
3197     {
3198       UserColourScheme udc = (UserColourScheme) UserDefinedColours
3199               .getUserColourSchemes().get(e.getActionCommand());
3200
3201       changeColour(udc);
3202     }
3203   }
3204
3205   public void updateUserColourMenu()
3206   {
3207
3208     Component[] menuItems = colourMenu.getMenuComponents();
3209     int i, iSize = menuItems.length;
3210     for (i = 0; i < iSize; i++)
3211     {
3212       if (menuItems[i].getName() != null
3213               && menuItems[i].getName().equals("USER_DEFINED"))
3214       {
3215         colourMenu.remove(menuItems[i]);
3216         iSize--;
3217       }
3218     }
3219     if (jalview.gui.UserDefinedColours.getUserColourSchemes() != null)
3220     {
3221       java.util.Enumeration userColours = jalview.gui.UserDefinedColours
3222               .getUserColourSchemes().keys();
3223
3224       while (userColours.hasMoreElements())
3225       {
3226         final JRadioButtonMenuItem radioItem = new JRadioButtonMenuItem(
3227                 userColours.nextElement().toString());
3228         radioItem.setName("USER_DEFINED");
3229         radioItem.addMouseListener(new MouseAdapter()
3230         {
3231           public void mousePressed(MouseEvent evt)
3232           {
3233             if (evt.isControlDown()
3234                     || SwingUtilities.isRightMouseButton(evt))
3235             {
3236               radioItem.removeActionListener(radioItem.getActionListeners()[0]);
3237
3238               int option = JOptionPane.showInternalConfirmDialog(
3239                       jalview.gui.Desktop.desktop,
3240                       "Remove from default list?",
3241                       "Remove user defined colour",
3242                       JOptionPane.YES_NO_OPTION);
3243               if (option == JOptionPane.YES_OPTION)
3244               {
3245                 jalview.gui.UserDefinedColours
3246                         .removeColourFromDefaults(radioItem.getText());
3247                 colourMenu.remove(radioItem);
3248               }
3249               else
3250               {
3251                 radioItem.addActionListener(new ActionListener()
3252                 {
3253                   public void actionPerformed(ActionEvent evt)
3254                   {
3255                     userDefinedColour_actionPerformed(evt);
3256                   }
3257                 });
3258               }
3259             }
3260           }
3261         });
3262         radioItem.addActionListener(new ActionListener()
3263         {
3264           public void actionPerformed(ActionEvent evt)
3265           {
3266             userDefinedColour_actionPerformed(evt);
3267           }
3268         });
3269
3270         colourMenu.insert(radioItem, 15);
3271         colours.add(radioItem);
3272       }
3273     }
3274   }
3275
3276   /**
3277    * DOCUMENT ME!
3278    * 
3279    * @param e
3280    *          DOCUMENT ME!
3281    */
3282   public void PIDColour_actionPerformed(ActionEvent e)
3283   {
3284     changeColour(new PIDColourScheme());
3285   }
3286
3287   /**
3288    * DOCUMENT ME!
3289    * 
3290    * @param e
3291    *          DOCUMENT ME!
3292    */
3293   public void BLOSUM62Colour_actionPerformed(ActionEvent e)
3294   {
3295     changeColour(new Blosum62ColourScheme());
3296   }
3297
3298   /**
3299    * DOCUMENT ME!
3300    * 
3301    * @param e
3302    *          DOCUMENT ME!
3303    */
3304   public void sortPairwiseMenuItem_actionPerformed(ActionEvent e)
3305   {
3306     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3307     AlignmentSorter.sortByPID(viewport.getAlignment(), viewport
3308             .getAlignment().getSequenceAt(0), null);
3309     addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
3310             viewport.alignment));
3311     alignPanel.paintAlignment(true);
3312   }
3313
3314   /**
3315    * DOCUMENT ME!
3316    * 
3317    * @param e
3318    *          DOCUMENT ME!
3319    */
3320   public void sortIDMenuItem_actionPerformed(ActionEvent e)
3321   {
3322     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3323     AlignmentSorter.sortByID(viewport.getAlignment());
3324     addHistoryItem(new OrderCommand("ID Sort", oldOrder, viewport.alignment));
3325     alignPanel.paintAlignment(true);
3326   }
3327
3328   /**
3329    * DOCUMENT ME!
3330    * 
3331    * @param e
3332    *          DOCUMENT ME!
3333    */
3334   public void sortLengthMenuItem_actionPerformed(ActionEvent e)
3335   {
3336     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3337     AlignmentSorter.sortByLength(viewport.getAlignment());
3338     addHistoryItem(new OrderCommand("Length Sort", oldOrder,
3339             viewport.alignment));
3340     alignPanel.paintAlignment(true);
3341   }
3342
3343   /**
3344    * DOCUMENT ME!
3345    * 
3346    * @param e
3347    *          DOCUMENT ME!
3348    */
3349   public void sortGroupMenuItem_actionPerformed(ActionEvent e)
3350   {
3351     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3352     AlignmentSorter.sortByGroup(viewport.getAlignment());
3353     addHistoryItem(new OrderCommand("Group Sort", oldOrder,
3354             viewport.alignment));
3355
3356     alignPanel.paintAlignment(true);
3357   }
3358
3359   /**
3360    * DOCUMENT ME!
3361    * 
3362    * @param e
3363    *          DOCUMENT ME!
3364    */
3365   public void removeRedundancyMenuItem_actionPerformed(ActionEvent e)
3366   {
3367     new RedundancyPanel(alignPanel, this);
3368   }
3369
3370   /**
3371    * DOCUMENT ME!
3372    * 
3373    * @param e
3374    *          DOCUMENT ME!
3375    */
3376   public void pairwiseAlignmentMenuItem_actionPerformed(ActionEvent e)
3377   {
3378     if ((viewport.getSelectionGroup() == null)
3379             || (viewport.getSelectionGroup().getSize() < 2))
3380     {
3381       JOptionPane.showInternalMessageDialog(this,
3382               "You must select at least 2 sequences.", "Invalid Selection",
3383               JOptionPane.WARNING_MESSAGE);
3384     }
3385     else
3386     {
3387       JInternalFrame frame = new JInternalFrame();
3388       frame.setContentPane(new PairwiseAlignPanel(viewport));
3389       Desktop.addInternalFrame(frame, "Pairwise Alignment", 600, 500);
3390     }
3391   }
3392
3393   /**
3394    * DOCUMENT ME!
3395    * 
3396    * @param e
3397    *          DOCUMENT ME!
3398    */
3399   public void PCAMenuItem_actionPerformed(ActionEvent e)
3400   {
3401     if (((viewport.getSelectionGroup() != null)
3402             && (viewport.getSelectionGroup().getSize() < 4) && (viewport
3403             .getSelectionGroup().getSize() > 0))
3404             || (viewport.getAlignment().getHeight() < 4))
3405     {
3406       JOptionPane.showInternalMessageDialog(this,
3407               "Principal component analysis must take\n"
3408                       + "at least 4 input sequences.",
3409               "Sequence selection insufficient",
3410               JOptionPane.WARNING_MESSAGE);
3411
3412       return;
3413     }
3414
3415     new PCAPanel(alignPanel);
3416   }
3417
3418   public void autoCalculate_actionPerformed(ActionEvent e)
3419   {
3420     viewport.autoCalculateConsensus = autoCalculate.isSelected();
3421     if (viewport.autoCalculateConsensus)
3422     {
3423       viewport.firePropertyChange("alignment", null, viewport
3424               .getAlignment().getSequences());
3425     }
3426   }
3427   public void sortByTreeOption_actionPerformed(ActionEvent e)
3428   {
3429     viewport.sortByTree = sortByTree.isSelected();
3430   }
3431
3432   @Override
3433   protected void listenToViewSelections_actionPerformed(ActionEvent e)
3434   {
3435     viewport.followSelection = listenToViewSelections.isSelected();
3436   }
3437   /**
3438    * DOCUMENT ME!
3439    * 
3440    * @param e
3441    *          DOCUMENT ME!
3442    */
3443   public void averageDistanceTreeMenuItem_actionPerformed(ActionEvent e)
3444   {
3445     NewTreePanel("AV", "PID", "Average distance tree using PID");
3446   }
3447
3448   /**
3449    * DOCUMENT ME!
3450    * 
3451    * @param e
3452    *          DOCUMENT ME!
3453    */
3454   public void neighbourTreeMenuItem_actionPerformed(ActionEvent e)
3455   {
3456     NewTreePanel("NJ", "PID", "Neighbour joining tree using PID");
3457   }
3458
3459   /**
3460    * DOCUMENT ME!
3461    * 
3462    * @param e
3463    *          DOCUMENT ME!
3464    */
3465   protected void njTreeBlosumMenuItem_actionPerformed(ActionEvent e)
3466   {
3467     NewTreePanel("NJ", "BL", "Neighbour joining tree using BLOSUM62");
3468   }
3469
3470   /**
3471    * DOCUMENT ME!
3472    * 
3473    * @param e
3474    *          DOCUMENT ME!
3475    */
3476   protected void avTreeBlosumMenuItem_actionPerformed(ActionEvent e)
3477   {
3478     NewTreePanel("AV", "BL", "Average distance tree using BLOSUM62");
3479   }
3480
3481   /**
3482    * DOCUMENT ME!
3483    * 
3484    * @param type
3485    *          DOCUMENT ME!
3486    * @param pwType
3487    *          DOCUMENT ME!
3488    * @param title
3489    *          DOCUMENT ME!
3490    */
3491   void NewTreePanel(String type, String pwType, String title)
3492   {
3493     TreePanel tp;
3494
3495     if (viewport.getSelectionGroup() != null)
3496     {
3497       if (viewport.getSelectionGroup().getSize() < 3)
3498       {
3499         JOptionPane
3500                 .showMessageDialog(
3501                         Desktop.desktop,
3502                         "You need to have more than two sequences selected to build a tree!",
3503                         "Not enough sequences", JOptionPane.WARNING_MESSAGE);
3504         return;
3505       }
3506
3507       int s = 0;
3508       SequenceGroup sg = viewport.getSelectionGroup();
3509
3510       /* Decide if the selection is a column region */
3511       while (s < sg.getSize())
3512       {
3513         if (((SequenceI) sg.getSequences(null).elementAt(s++)).getLength() < sg
3514                 .getEndRes())
3515         {
3516           JOptionPane
3517                   .showMessageDialog(
3518                           Desktop.desktop,
3519                           "The selected region to create a tree may\nonly contain residues or gaps.\n"
3520                                   + "Try using the Pad function in the edit menu,\n"
3521                                   + "or one of the multiple sequence alignment web services.",
3522                           "Sequences in selection are not aligned",
3523                           JOptionPane.WARNING_MESSAGE);
3524
3525           return;
3526         }
3527       }
3528
3529       title = title + " on region";
3530       tp = new TreePanel(alignPanel, type, pwType);
3531     }
3532     else
3533     {
3534       // are the visible sequences aligned?
3535       if (!viewport.alignment.isAligned(false))
3536       {
3537         JOptionPane
3538                 .showMessageDialog(
3539                         Desktop.desktop,
3540                         "The sequences must be aligned before creating a tree.\n"
3541                                 + "Try using the Pad function in the edit menu,\n"
3542                                 + "or one of the multiple sequence alignment web services.",
3543                         "Sequences not aligned",
3544                         JOptionPane.WARNING_MESSAGE);
3545
3546         return;
3547       }
3548
3549       if (viewport.alignment.getHeight() < 2)
3550       {
3551         return;
3552       }
3553
3554       tp = new TreePanel(alignPanel, type, pwType);
3555     }
3556
3557     title += " from ";
3558
3559     if (viewport.viewName != null)
3560     {
3561       title += viewport.viewName + " of ";
3562     }
3563
3564     title += this.title;
3565
3566     Desktop.addInternalFrame(tp, title, 600, 500);
3567   }
3568
3569   /**
3570    * DOCUMENT ME!
3571    * 
3572    * @param title
3573    *          DOCUMENT ME!
3574    * @param order
3575    *          DOCUMENT ME!
3576    */
3577   public void addSortByOrderMenuItem(String title,
3578           final AlignmentOrder order)
3579   {
3580     final JMenuItem item = new JMenuItem("by " + title);
3581     sort.add(item);
3582     item.addActionListener(new java.awt.event.ActionListener()
3583     {
3584       public void actionPerformed(ActionEvent e)
3585       {
3586         SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3587
3588         // TODO: JBPNote - have to map order entries to curent SequenceI
3589         // pointers
3590         AlignmentSorter.sortBy(viewport.getAlignment(), order);
3591
3592         addHistoryItem(new OrderCommand(order.getName(), oldOrder,
3593                 viewport.alignment));
3594
3595         alignPanel.paintAlignment(true);
3596       }
3597     });
3598   }
3599
3600   /**
3601    * Add a new sort by annotation score menu item
3602    * 
3603    * @param sort
3604    *          the menu to add the option to
3605    * @param scoreLabel
3606    *          the label used to retrieve scores for each sequence on the
3607    *          alignment
3608    */
3609   public void addSortByAnnotScoreMenuItem(JMenu sort,
3610           final String scoreLabel)
3611   {
3612     final JMenuItem item = new JMenuItem(scoreLabel);
3613     sort.add(item);
3614     item.addActionListener(new java.awt.event.ActionListener()
3615     {
3616       public void actionPerformed(ActionEvent e)
3617       {
3618         SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3619         AlignmentSorter.sortByAnnotationScore(scoreLabel,
3620                 viewport.getAlignment());// ,viewport.getSelectionGroup());
3621         addHistoryItem(new OrderCommand("Sort by " + scoreLabel, oldOrder,
3622                 viewport.alignment));
3623         alignPanel.paintAlignment(true);
3624       }
3625     });
3626   }
3627
3628   /**
3629    * last hash for alignment's annotation array - used to minimise cost of
3630    * rebuild.
3631    */
3632   protected int _annotationScoreVectorHash;
3633
3634   /**
3635    * search the alignment and rebuild the sort by annotation score submenu the
3636    * last alignment annotation vector hash is stored to minimize cost of
3637    * rebuilding in subsequence calls.
3638    * 
3639    */
3640   public void buildSortByAnnotationScoresMenu()
3641   {
3642     if (viewport.alignment.getAlignmentAnnotation() == null)
3643     {
3644       return;
3645     }
3646
3647     if (viewport.alignment.getAlignmentAnnotation().hashCode() != _annotationScoreVectorHash)
3648     {
3649       sortByAnnotScore.removeAll();
3650       // almost certainly a quicker way to do this - but we keep it simple
3651       Hashtable scoreSorts = new Hashtable();
3652       AlignmentAnnotation aann[];
3653       Enumeration sq = viewport.alignment.getSequences().elements();
3654       while (sq.hasMoreElements())
3655       {
3656         aann = ((SequenceI) sq.nextElement()).getAnnotation();
3657         for (int i = 0; aann != null && i < aann.length; i++)
3658         {
3659           if (aann[i].hasScore() && aann[i].sequenceRef != null)
3660           {
3661             scoreSorts.put(aann[i].label, aann[i].label);
3662           }
3663         }
3664       }
3665       Enumeration labels = scoreSorts.keys();
3666       while (labels.hasMoreElements())
3667       {
3668         addSortByAnnotScoreMenuItem(sortByAnnotScore,
3669                 (String) labels.nextElement());
3670       }
3671       sortByAnnotScore.setVisible(scoreSorts.size() > 0);
3672       scoreSorts.clear();
3673
3674       _annotationScoreVectorHash = viewport.alignment
3675               .getAlignmentAnnotation().hashCode();
3676     }
3677   }
3678
3679   /**
3680    * Maintain the Order by->Displayed Tree menu. Creates a new menu item for a
3681    * TreePanel with an appropriate <code>jalview.analysis.AlignmentSorter</code>
3682    * call. Listeners are added to remove the menu item when the treePanel is
3683    * closed, and adjust the tree leaf to sequence mapping when the alignment is
3684    * modified.
3685    * 
3686    * @param treePanel
3687    *          Displayed tree window.
3688    * @param title
3689    *          SortBy menu item title.
3690    */
3691   public void buildTreeMenu()
3692   {
3693     sortByTreeMenu.removeAll();
3694
3695     Vector comps = (Vector) PaintRefresher.components.get(viewport
3696             .getSequenceSetId());
3697     Vector treePanels = new Vector();
3698     int i, iSize = comps.size();
3699     for (i = 0; i < iSize; i++)
3700     {
3701       if (comps.elementAt(i) instanceof TreePanel)
3702       {
3703         treePanels.add(comps.elementAt(i));
3704       }
3705     }
3706
3707     iSize = treePanels.size();
3708
3709     if (iSize < 1)
3710     {
3711       sortByTreeMenu.setVisible(false);
3712       return;
3713     }
3714
3715     sortByTreeMenu.setVisible(true);
3716
3717     for (i = 0; i < treePanels.size(); i++)
3718     {
3719       final TreePanel tp = (TreePanel) treePanels.elementAt(i);
3720       final JMenuItem item = new JMenuItem(tp.getTitle());
3721       final NJTree tree = ((TreePanel) treePanels.elementAt(i)).getTree();
3722       item.addActionListener(new java.awt.event.ActionListener()
3723       {
3724         public void actionPerformed(ActionEvent e)
3725         {
3726           tp.sortByTree_actionPerformed(null);
3727           addHistoryItem(tp.sortAlignmentIn(alignPanel));
3728           
3729         }
3730       });
3731
3732       sortByTreeMenu.add(item);
3733     }
3734   }
3735
3736   public boolean sortBy(AlignmentOrder alorder, String undoname)
3737   {
3738     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3739     AlignmentSorter.sortBy(viewport.getAlignment(), alorder);
3740     if (undoname != null)
3741     {
3742       addHistoryItem(new OrderCommand(undoname, oldOrder,
3743               viewport.alignment));
3744     }
3745     alignPanel.paintAlignment(true);
3746     return true;
3747   }
3748
3749   /**
3750    * Work out whether the whole set of sequences or just the selected set will
3751    * be submitted for multiple alignment.
3752    * 
3753    */
3754   public jalview.datamodel.AlignmentView gatherSequencesForAlignment()
3755   {
3756     // Now, check we have enough sequences
3757     AlignmentView msa = null;
3758
3759     if ((viewport.getSelectionGroup() != null)
3760             && (viewport.getSelectionGroup().getSize() > 1))
3761     {
3762       // JBPNote UGLY! To prettify, make SequenceGroup and Alignment conform to
3763       // some common interface!
3764       /*
3765        * SequenceGroup seqs = viewport.getSelectionGroup(); int sz; msa = new
3766        * SequenceI[sz = seqs.getSize(false)];
3767        * 
3768        * for (int i = 0; i < sz; i++) { msa[i] = (SequenceI)
3769        * seqs.getSequenceAt(i); }
3770        */
3771       msa = viewport.getAlignmentView(true);
3772     }
3773     else
3774     {
3775       /*
3776        * Vector seqs = viewport.getAlignment().getSequences();
3777        * 
3778        * if (seqs.size() > 1) { msa = new SequenceI[seqs.size()];
3779        * 
3780        * for (int i = 0; i < seqs.size(); i++) { msa[i] = (SequenceI)
3781        * seqs.elementAt(i); } }
3782        */
3783       msa = viewport.getAlignmentView(false);
3784     }
3785     return msa;
3786   }
3787
3788   /**
3789    * Decides what is submitted to a secondary structure prediction service: the
3790    * first sequence in the alignment, or in the current selection, or, if the
3791    * alignment is 'aligned' (ie padded with gaps), then the currently selected
3792    * region or the whole alignment. (where the first sequence in the set is the
3793    * one that the prediction will be for).
3794    */
3795   public AlignmentView gatherSeqOrMsaForSecStrPrediction()
3796   {
3797     AlignmentView seqs = null;
3798
3799     if ((viewport.getSelectionGroup() != null)
3800             && (viewport.getSelectionGroup().getSize() > 0))
3801     {
3802       seqs = viewport.getAlignmentView(true);
3803     }
3804     else
3805     {
3806       seqs = viewport.getAlignmentView(false);
3807     }
3808     // limit sequences - JBPNote in future - could spawn multiple prediction
3809     // jobs
3810     // TODO: viewport.alignment.isAligned is a global state - the local
3811     // selection may well be aligned - we preserve 2.0.8 behaviour for moment.
3812     if (!viewport.alignment.isAligned(false))
3813     {
3814       seqs.setSequences(new SeqCigar[]
3815       { seqs.getSequences()[0] });
3816       // TODO: if seqs.getSequences().length>1 then should really have warned
3817       // user!
3818
3819     }
3820     return seqs;
3821   }
3822
3823   /**
3824    * DOCUMENT ME!
3825    * 
3826    * @param e
3827    *          DOCUMENT ME!
3828    */
3829   protected void LoadtreeMenuItem_actionPerformed(ActionEvent e)
3830   {
3831     // Pick the tree file
3832     JalviewFileChooser chooser = new JalviewFileChooser(
3833             jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
3834     chooser.setFileView(new JalviewFileView());
3835     chooser.setDialogTitle("Select a newick-like tree file");
3836     chooser.setToolTipText("Load a tree file");
3837
3838     int value = chooser.showOpenDialog(null);
3839
3840     if (value == JalviewFileChooser.APPROVE_OPTION)
3841     {
3842       String choice = chooser.getSelectedFile().getPath();
3843       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
3844       jalview.io.NewickFile fin = null;
3845       try
3846       {
3847         fin = new jalview.io.NewickFile(choice, "File");
3848         viewport.setCurrentTree(ShowNewickTree(fin, choice).getTree());
3849       } catch (Exception ex)
3850       {
3851         JOptionPane.showMessageDialog(Desktop.desktop, ex.getMessage(),
3852                 "Problem reading tree file", JOptionPane.WARNING_MESSAGE);
3853         ex.printStackTrace();
3854       }
3855       if (fin != null && fin.hasWarningMessage())
3856       {
3857         JOptionPane.showMessageDialog(Desktop.desktop,
3858                 fin.getWarningMessage(), "Possible problem with tree file",
3859                 JOptionPane.WARNING_MESSAGE);
3860       }
3861     }
3862   }
3863   
3864   @Override
3865   public void loadScores_actionPerformed(ActionEvent e)
3866   {
3867             // Pick the tree file
3868             JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
3869             chooser.setFileView(new JalviewFileView());
3870             chooser.setDialogTitle("Select a T-Coffee scores ascii file");
3871             chooser.setToolTipText("Load a score file");
3872
3873             int value = chooser.showOpenDialog(null);
3874
3875             if (value == JalviewFileChooser.APPROVE_OPTION)
3876             {
3877               String sFilePath = chooser.getSelectedFile().getPath();
3878               jalview.bin.Cache.setProperty("LAST_DIRECTORY", sFilePath);
3879             
3880               
3881               try 
3882               {
3883                   TCoffeeScoreFile result = TCoffeeScoreFile.load(new File(sFilePath));
3884                   if( result == null ) { throw new RuntimeException("The file provided does not match the T-Coffee scores file format"); }
3885
3886                   // TODO check that the loaded scores matches the current MSA 'dimension'
3887                   if (result.annotateAlignment(alignPanel.getAlignment(), true))
3888                   {
3889                           tcoffeeColour.setEnabled(true);
3890                           tcoffeeColour.setSelected(true);
3891                           // switch to this color
3892                           changeColour(new TCoffeeColourScheme(alignPanel.getAlignment()));
3893                   } else {
3894                     tcoffeeColour.setEnabled(false);
3895                     tcoffeeColour.setSelected(false);
3896                   }
3897               } 
3898               catch (Exception ex) {
3899                 JOptionPane.showMessageDialog(
3900                                         Desktop.desktop, 
3901                                         ex.getMessage(), 
3902                                         "Problem reading tree file", 
3903                                         JOptionPane.WARNING_MESSAGE);
3904
3905                 ex.printStackTrace();
3906               }
3907             }
3908
3909   } 
3910
3911   
3912   @Override
3913   protected void tcoffeeColorScheme_actionPerformed(ActionEvent e) {
3914           changeColour( new TCoffeeColourScheme(alignPanel.getAlignment()) );
3915   }
3916   
3917 //  /**
3918 //   * Load the (T-Coffee) score file from the specified url 
3919 //   * 
3920 //   * @param url The absolute path from where download and read the score file
3921 //   * @throws IOException 
3922 //   */
3923 //  public void loadScoreFile(URL url ) throws IOException {
3924 //        
3925 //        TCoffeeScoreFile result = new TCoffeeScoreFile();
3926 //        result.parse( new InputStreamReader( url.openStream() ) );
3927 //        tcoffeeScoreFile = result;
3928 //  }  
3929   
3930   public TreePanel ShowNewickTree(NewickFile nf, String title)
3931   {
3932     return ShowNewickTree(nf, title, 600, 500, 4, 5);
3933   }
3934
3935   public TreePanel ShowNewickTree(NewickFile nf, String title,
3936           AlignmentView input)
3937   {
3938     return ShowNewickTree(nf, title, input, 600, 500, 4, 5);
3939   }
3940
3941   public TreePanel ShowNewickTree(NewickFile nf, String title, int w,
3942           int h, int x, int y)
3943   {
3944     return ShowNewickTree(nf, title, null, w, h, x, y);
3945   }
3946
3947   /**
3948    * Add a treeviewer for the tree extracted from a newick file object to the
3949    * current alignment view
3950    * 
3951    * @param nf
3952    *          the tree
3953    * @param title
3954    *          tree viewer title
3955    * @param input
3956    *          Associated alignment input data (or null)
3957    * @param w
3958    *          width
3959    * @param h
3960    *          height
3961    * @param x
3962    *          position
3963    * @param y
3964    *          position
3965    * @return TreePanel handle
3966    */
3967   public TreePanel ShowNewickTree(NewickFile nf, String title,
3968           AlignmentView input, int w, int h, int x, int y)
3969   {
3970     TreePanel tp = null;
3971
3972     try
3973     {
3974       nf.parse();
3975
3976       if (nf.getTree() != null)
3977       {
3978         tp = new TreePanel(alignPanel, "FromFile", title, nf, input);
3979
3980         tp.setSize(w, h);
3981
3982         if (x > 0 && y > 0)
3983         {
3984           tp.setLocation(x, y);
3985         }
3986
3987         Desktop.addInternalFrame(tp, title, w, h);
3988       }
3989     } catch (Exception ex)
3990     {
3991       ex.printStackTrace();
3992     }
3993
3994     return tp;
3995   }
3996
3997   private boolean buildingMenu = false;
3998
3999   /**
4000    * Generates menu items and listener event actions for web service clients
4001    * 
4002    */
4003   public void BuildWebServiceMenu()
4004   {
4005     while (buildingMenu)
4006     {
4007       try
4008       {
4009         System.err.println("Waiting for building menu to finish.");
4010         Thread.sleep(10);
4011       } catch (Exception e)
4012       {
4013       }
4014       ;
4015     }
4016     final AlignFrame me = this;
4017     buildingMenu = true;
4018     new Thread(new Runnable()
4019     {
4020       public void run()
4021       {
4022         try
4023         {
4024           System.err.println("Building ws menu again "
4025                   + Thread.currentThread());
4026           // TODO: add support for context dependent disabling of services based
4027           // on
4028           // alignment and current selection
4029           // TODO: add additional serviceHandle parameter to specify abstract
4030           // handler
4031           // class independently of AbstractName
4032           // TODO: add in rediscovery GUI function to restart discoverer
4033           // TODO: group services by location as well as function and/or
4034           // introduce
4035           // object broker mechanism.
4036           final Vector wsmenu = new Vector();
4037           final IProgressIndicator af = me;
4038           final JMenu msawsmenu = new JMenu("Alignment");
4039           final JMenu secstrmenu = new JMenu(
4040                   "Secondary Structure Prediction");
4041           final JMenu seqsrchmenu = new JMenu(
4042                   "Sequence Database Search");
4043           final JMenu analymenu = new JMenu(
4044                   "Analysis");
4045           // JAL-940 - only show secondary structure prediction services from the legacy server
4046           if (// Cache.getDefault("SHOW_JWS1_SERVICES", true)
4047                   // && 
4048                   Discoverer.services != null
4049                   && (Discoverer.services.size() > 0))
4050           {
4051             // TODO: refactor to allow list of AbstractName/Handler bindings to
4052             // be
4053             // stored or retrieved from elsewhere
4054             Vector msaws = null; // (Vector) Discoverer.services.get("MsaWS");
4055             Vector secstrpr = (Vector) Discoverer.services
4056                     .get("SecStrPred");
4057             Vector seqsrch = null; // (Vector) Discoverer.services.get("SeqSearch");
4058             // TODO: move GUI generation code onto service implementation - so a
4059             // client instance attaches itself to the GUI with method call like
4060             // jalview.ws.MsaWSClient.bind(servicehandle, Desktop.instance,
4061             // alignframe)
4062             if (msaws != null)
4063             {
4064               // Add any Multiple Sequence Alignment Services
4065               for (int i = 0, j = msaws.size(); i < j; i++)
4066               {
4067                 final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) msaws
4068                         .get(i);
4069                 jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer
4070                         .getServiceClient(sh);
4071                 impl.attachWSMenuEntry(msawsmenu, me);
4072
4073               }
4074             }
4075             if (secstrpr != null)
4076             {
4077               // Add any secondary structure prediction services
4078               for (int i = 0, j = secstrpr.size(); i < j; i++)
4079               {
4080                 final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) secstrpr
4081                         .get(i);
4082                 jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer
4083                         .getServiceClient(sh);
4084                 impl.attachWSMenuEntry(secstrmenu, me);
4085               }
4086             }
4087             if (seqsrch != null)
4088             {
4089               // Add any sequence search services
4090               for (int i = 0, j = seqsrch.size(); i < j; i++)
4091               {
4092                 final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) seqsrch
4093                         .elementAt(i);
4094                 jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer
4095                         .getServiceClient(sh);
4096                 impl.attachWSMenuEntry(seqsrchmenu, me);
4097               }
4098             }
4099           }
4100
4101           // TODO: move into separate menu builder class.
4102           if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
4103           {
4104             Jws2Discoverer jws2servs = Jws2Discoverer.getDiscoverer();
4105             if (jws2servs != null)
4106             {
4107               if (jws2servs.hasServices())
4108               {
4109                 jws2servs.attachWSMenuEntry(msawsmenu, me);
4110               }
4111             }
4112           }
4113           // Add all submenus in the order they should appear on the web services menu
4114           wsmenu.add(msawsmenu);
4115           wsmenu.add(secstrmenu);
4116           wsmenu.add(analymenu);
4117           // No search services yet
4118           // wsmenu.add(seqsrchmenu);
4119
4120           javax.swing.SwingUtilities.invokeLater(new Runnable()
4121           {
4122             public void run()
4123             {
4124               try
4125               {
4126                 webService.removeAll();
4127                 // first, add discovered services onto the webservices menu
4128                 if (wsmenu.size() > 0)
4129                 {
4130                   for (int i = 0, j = wsmenu.size(); i < j; i++)
4131                   {
4132                     webService.add((JMenu) wsmenu.get(i));
4133                   }
4134                 }
4135                 else
4136                 {
4137                   webService.add(me.webServiceNoServices);
4138                 }
4139                 build_urlServiceMenu(me.webService);
4140                 build_fetchdbmenu(webService);
4141               } catch (Exception e)
4142               {
4143               }
4144               ;
4145             }
4146           });
4147         } catch (Exception e)
4148         {
4149         }
4150         ;
4151
4152         buildingMenu = false;
4153       }
4154     }).start();
4155
4156   }
4157
4158
4159   /**
4160    * construct any groupURL type service menu entries.
4161    * 
4162    * @param webService
4163    */
4164   private void build_urlServiceMenu(JMenu webService)
4165   {
4166     // TODO: remove this code when 2.7 is released
4167     // DEBUG - alignmentView
4168     /*
4169      * JMenuItem testAlView = new JMenuItem("Test AlignmentView"); final
4170      * AlignFrame af = this; testAlView.addActionListener(new ActionListener() {
4171      * 
4172      * @Override public void actionPerformed(ActionEvent e) {
4173      * jalview.datamodel.AlignmentView.testSelectionViews(af.viewport.alignment,
4174      * af.viewport.colSel, af.viewport.selectionGroup); }
4175      * 
4176      * }); webService.add(testAlView);
4177      */
4178     // TODO: refactor to RestClient discoverer and merge menu entries for
4179     // rest-style services with other types of analysis/calculation service
4180     // SHmmr test client - still being implemented.
4181     // DEBUG - alignmentView
4182     
4183     for (jalview.ws.rest.RestClient client: jalview.ws.rest.RestClient.getRestClients()) {
4184       client.attachWSMenuEntry(JvSwingUtils.findOrCreateMenu(webService, client.getAction()), this);
4185     }
4186
4187     if (Cache.getDefault("SHOW_ENFIN_SERVICES", true))
4188     {
4189       jalview.ws.EnfinEnvision2OneWay.getInstance().attachWSMenuEntry(
4190               webService, this);
4191     }
4192   }
4193
4194   /*
4195    * public void vamsasStore_actionPerformed(ActionEvent e) { JalviewFileChooser
4196    * chooser = new JalviewFileChooser(jalview.bin.Cache.
4197    * getProperty("LAST_DIRECTORY"));
4198    * 
4199    * chooser.setFileView(new JalviewFileView()); chooser.setDialogTitle("Export
4200    * to Vamsas file"); chooser.setToolTipText("Export");
4201    * 
4202    * int value = chooser.showSaveDialog(this);
4203    * 
4204    * if (value == JalviewFileChooser.APPROVE_OPTION) {
4205    * jalview.io.VamsasDatastore vs = new jalview.io.VamsasDatastore(viewport);
4206    * //vs.store(chooser.getSelectedFile().getAbsolutePath() ); vs.storeJalview(
4207    * chooser.getSelectedFile().getAbsolutePath(), this); } }
4208    */
4209   /**
4210    * prototype of an automatically enabled/disabled analysis function
4211    * 
4212    */
4213   protected void setShowProductsEnabled()
4214   {
4215     SequenceI[] selection = viewport.getSequenceSelection();
4216     if (canShowProducts(selection, viewport.getSelectionGroup() != null,
4217             viewport.getAlignment().getDataset()))
4218     {
4219       showProducts.setEnabled(true);
4220
4221     }
4222     else
4223     {
4224       showProducts.setEnabled(false);
4225     }
4226   }
4227
4228   /**
4229    * search selection for sequence xRef products and build the show products
4230    * menu.
4231    * 
4232    * @param selection
4233    * @param dataset
4234    * @return true if showProducts menu should be enabled.
4235    */
4236   public boolean canShowProducts(SequenceI[] selection,
4237           boolean isRegionSelection, Alignment dataset)
4238   {
4239     boolean showp = false;
4240     try
4241     {
4242       showProducts.removeAll();
4243       final boolean dna = viewport.getAlignment().isNucleotide();
4244       final Alignment ds = dataset;
4245       String[] ptypes = (selection == null || selection.length == 0) ? null
4246               : CrossRef.findSequenceXrefTypes(dna, selection, dataset);
4247       // Object[] prods =
4248       // CrossRef.buildXProductsList(viewport.getAlignment().isNucleotide(),
4249       // selection, dataset, true);
4250       final SequenceI[] sel = selection;
4251       for (int t = 0; ptypes != null && t < ptypes.length; t++)
4252       {
4253         showp = true;
4254         final boolean isRegSel = isRegionSelection;
4255         final AlignFrame af = this;
4256         final String source = ptypes[t];
4257         JMenuItem xtype = new JMenuItem(ptypes[t]);
4258         xtype.addActionListener(new ActionListener()
4259         {
4260
4261           public void actionPerformed(ActionEvent e)
4262           {
4263             // TODO: new thread for this call with vis-delay
4264             af.showProductsFor(af.viewport.getSequenceSelection(), ds,
4265                     isRegSel, dna, source);
4266           }
4267
4268         });
4269         showProducts.add(xtype);
4270       }
4271       showProducts.setVisible(showp);
4272       showProducts.setEnabled(showp);
4273     } catch (Exception e)
4274     {
4275       jalview.bin.Cache.log
4276               .warn("canTranslate threw an exception - please report to help@jalview.org",
4277                       e);
4278       return false;
4279     }
4280     return showp;
4281   }
4282
4283   protected void showProductsFor(SequenceI[] sel, Alignment ds,
4284           boolean isRegSel, boolean dna, String source)
4285   {
4286     final boolean fisRegSel = isRegSel;
4287     final boolean fdna = dna;
4288     final String fsrc = source;
4289     final AlignFrame ths = this;
4290     final SequenceI[] fsel = sel;
4291     Runnable foo = new Runnable()
4292     {
4293
4294       public void run()
4295       {
4296         final long sttime = System.currentTimeMillis();
4297         ths.setProgressBar("Searching for sequences from " + fsrc, sttime);
4298         try
4299         {
4300           Alignment ds = ths.getViewport().alignment.getDataset(); // update
4301           // our local
4302           // dataset
4303           // reference
4304           Alignment prods = CrossRef
4305                   .findXrefSequences(fsel, fdna, fsrc, ds);
4306           if (prods != null)
4307           {
4308             SequenceI[] sprods = new SequenceI[prods.getHeight()];
4309             for (int s = 0; s < sprods.length; s++)
4310             {
4311               sprods[s] = (prods.getSequenceAt(s)).deriveSequence();
4312               if (ds.getSequences() == null
4313                       || !ds.getSequences().contains(
4314                               sprods[s].getDatasetSequence()))
4315                 ds.addSequence(sprods[s].getDatasetSequence());
4316               sprods[s].updatePDBIds();
4317             }
4318             Alignment al = new Alignment(sprods);
4319             AlignedCodonFrame[] cf = prods.getCodonFrames();
4320             al.setDataset(ds);
4321             for (int s = 0; cf != null && s < cf.length; s++)
4322             {
4323               al.addCodonFrame(cf[s]);
4324               cf[s] = null;
4325             }
4326             AlignFrame naf = new AlignFrame(al, DEFAULT_WIDTH,
4327                     DEFAULT_HEIGHT);
4328             String newtitle = "" + ((fdna) ? "Proteins " : "Nucleotides ")
4329                     + " for " + ((fisRegSel) ? "selected region of " : "")
4330                     + getTitle();
4331             Desktop.addInternalFrame(naf, newtitle, DEFAULT_WIDTH,
4332                     DEFAULT_HEIGHT);
4333           }
4334           else
4335           {
4336             System.err.println("No Sequences generated for xRef type "
4337                     + fsrc);
4338           }
4339         } catch (Exception e)
4340         {
4341           jalview.bin.Cache.log.error(
4342                   "Exception when finding crossreferences", e);
4343         } catch (OutOfMemoryError e)
4344         {
4345           new OOMWarning("whilst fetching crossreferences", e);
4346         } catch (Error e)
4347         {
4348           jalview.bin.Cache.log.error("Error when finding crossreferences",
4349                   e);
4350         }
4351         ths.setProgressBar("Finished searching for sequences from " + fsrc,
4352                 sttime);
4353       }
4354
4355     };
4356     Thread frunner = new Thread(foo);
4357     frunner.start();
4358   }
4359
4360   public boolean canShowTranslationProducts(SequenceI[] selection,
4361           AlignmentI alignment)
4362   {
4363     // old way
4364     try
4365     {
4366       return (jalview.analysis.Dna.canTranslate(selection,
4367               viewport.getViewAsVisibleContigs(true)));
4368     } catch (Exception e)
4369     {
4370       jalview.bin.Cache.log
4371               .warn("canTranslate threw an exception - please report to help@jalview.org",
4372                       e);
4373       return false;
4374     }
4375   }
4376
4377   public void showProducts_actionPerformed(ActionEvent e)
4378   {
4379     // /////////////////////////////
4380     // Collect Data to be translated/transferred
4381
4382     SequenceI[] selection = viewport.getSequenceSelection();
4383     AlignmentI al = null;
4384     try
4385     {
4386       al = jalview.analysis.Dna.CdnaTranslate(selection, viewport
4387               .getViewAsVisibleContigs(true), viewport.getGapCharacter(),
4388               viewport.getAlignment().getDataset());
4389     } catch (Exception ex)
4390     {
4391       al = null;
4392       jalview.bin.Cache.log.debug("Exception during translation.", ex);
4393     }
4394     if (al == null)
4395     {
4396       JOptionPane
4397               .showMessageDialog(
4398                       Desktop.desktop,
4399                       "Please select at least three bases in at least one sequence in order to perform a cDNA translation.",
4400                       "Translation Failed", JOptionPane.WARNING_MESSAGE);
4401     }
4402     else
4403     {
4404       AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
4405       Desktop.addInternalFrame(af, "Translation of " + this.getTitle(),
4406               DEFAULT_WIDTH, DEFAULT_HEIGHT);
4407     }
4408   }
4409
4410   public void showTranslation_actionPerformed(ActionEvent e)
4411   {
4412     // /////////////////////////////
4413     // Collect Data to be translated/transferred
4414
4415     SequenceI[] selection = viewport.getSequenceSelection();
4416     String[] seqstring = viewport.getViewAsString(true);
4417     AlignmentI al = null;
4418     try
4419     {
4420       al = jalview.analysis.Dna.CdnaTranslate(selection, seqstring,
4421               viewport.getViewAsVisibleContigs(true), viewport
4422                       .getGapCharacter(), viewport.alignment
4423                       .getAlignmentAnnotation(), viewport.alignment
4424                       .getWidth(), viewport.getAlignment().getDataset());
4425     } catch (Exception ex)
4426     {
4427       al = null;
4428       jalview.bin.Cache.log.debug("Exception during translation.", ex);
4429     }
4430     if (al == null)
4431     {
4432       JOptionPane
4433               .showMessageDialog(
4434                       Desktop.desktop,
4435                       "Please select at least three bases in at least one sequence in order to perform a cDNA translation.",
4436                       "Translation Failed", JOptionPane.WARNING_MESSAGE);
4437     }
4438     else
4439     {
4440       AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
4441       Desktop.addInternalFrame(af, "Translation of " + this.getTitle(),
4442               DEFAULT_WIDTH, DEFAULT_HEIGHT);
4443     }
4444   }
4445
4446   /**
4447    * Try to load a features file onto the alignment.
4448    * 
4449    * @param file
4450    *          contents or path to retrieve file
4451    * @param type
4452    *          access mode of file (see jalview.io.AlignFile)
4453    * @return true if features file was parsed corectly.
4454    */
4455   public boolean parseFeaturesFile(String file, String type)
4456   {
4457     boolean featuresFile = false;
4458     try
4459     {
4460       featuresFile = new FeaturesFile(file, type)
4461               .parse(viewport.alignment.getDataset(),
4462                       alignPanel.seqPanel.seqCanvas.getFeatureRenderer().featureColours,
4463                       false, jalview.bin.Cache.getDefault(
4464                               "RELAXEDSEQIDMATCHING", false));
4465     } catch (Exception ex)
4466     {
4467       ex.printStackTrace();
4468     }
4469
4470     if (featuresFile)
4471     {
4472       viewport.showSequenceFeatures = true;
4473       showSeqFeatures.setSelected(true);
4474       if (alignPanel.seqPanel.seqCanvas.fr != null)
4475       {
4476         // update the min/max ranges where necessary
4477         alignPanel.seqPanel.seqCanvas.fr.findAllFeatures(true);
4478       }
4479       if (featureSettings != null)
4480       {
4481         featureSettings.setTableData();
4482       }
4483       alignPanel.paintAlignment(true);
4484     }
4485
4486     return featuresFile;
4487   }
4488
4489   public void dragEnter(DropTargetDragEvent evt)
4490   {
4491   }
4492
4493   public void dragExit(DropTargetEvent evt)
4494   {
4495   }
4496
4497   public void dragOver(DropTargetDragEvent evt)
4498   {
4499   }
4500
4501   public void dropActionChanged(DropTargetDragEvent evt)
4502   {
4503   }
4504
4505   public void drop(DropTargetDropEvent evt)
4506   {
4507     Transferable t = evt.getTransferable();
4508     java.util.List files = null;
4509
4510     try
4511     {
4512       DataFlavor uriListFlavor = new DataFlavor(
4513               "text/uri-list;class=java.lang.String");
4514       if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
4515       {
4516         // Works on Windows and MacOSX
4517         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
4518         files = (java.util.List) t
4519                 .getTransferData(DataFlavor.javaFileListFlavor);
4520       }
4521       else if (t.isDataFlavorSupported(uriListFlavor))
4522       {
4523         // This is used by Unix drag system
4524         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
4525         String data = (String) t.getTransferData(uriListFlavor);
4526         files = new java.util.ArrayList(1);
4527         for (java.util.StringTokenizer st = new java.util.StringTokenizer(
4528                 data, "\r\n"); st.hasMoreTokens();)
4529         {
4530           String s = st.nextToken();
4531           if (s.startsWith("#"))
4532           {
4533             // the line is a comment (as per the RFC 2483)
4534             continue;
4535           }
4536
4537           java.net.URI uri = new java.net.URI(s);
4538           // check to see if we can handle this kind of URI
4539           if (uri.getScheme().toLowerCase().startsWith("http"))
4540           {
4541             files.add(uri.toString());
4542           }
4543           else
4544           {
4545             // otherwise preserve old behaviour: catch all for file objects
4546             java.io.File file = new java.io.File(uri);
4547             files.add(file.toString());
4548           }
4549         }
4550       }
4551     } catch (Exception e)
4552     {
4553       e.printStackTrace();
4554     }
4555     if (files != null)
4556     {
4557       try
4558       {
4559         // check to see if any of these files have names matching sequences in
4560         // the alignment
4561         SequenceIdMatcher idm = new SequenceIdMatcher(viewport
4562                 .getAlignment().getSequencesArray());
4563         /**
4564          * Object[] { String,SequenceI}
4565          */
4566         ArrayList<Object[]> filesmatched = new ArrayList<Object[]>();
4567         ArrayList<String> filesnotmatched = new ArrayList<String>();
4568         for (int i = 0; i < files.size(); i++)
4569         {
4570           String file = files.get(i).toString();
4571           String pdbfn = "";
4572           String protocol = FormatAdapter.checkProtocol(file);
4573           if (protocol == jalview.io.FormatAdapter.FILE)
4574           {
4575             File fl = new File(file);
4576             pdbfn = fl.getName();
4577           }
4578           else if (protocol == jalview.io.FormatAdapter.URL)
4579           {
4580             URL url = new URL(file);
4581             pdbfn = url.getFile();
4582           }
4583           if (pdbfn.length() > 0)
4584           {
4585             // attempt to find a match in the alignment
4586             SequenceI[] mtch = idm.findAllIdMatches(pdbfn);
4587             int l = 0, c = pdbfn.indexOf(".");
4588             while (mtch == null && c != -1)
4589             {
4590               do 
4591               {
4592                 l = c;
4593               } while ((c = pdbfn.indexOf(".", l)) > l);
4594               if (l > -1)
4595               {
4596                 pdbfn = pdbfn.substring(0, l);
4597               }
4598               mtch = idm.findAllIdMatches(pdbfn);
4599             }
4600             if (mtch != null)
4601             {
4602               String type = null;
4603               try
4604               {
4605                 type = new IdentifyFile().Identify(file, protocol);
4606               } catch (Exception ex)
4607               {
4608                 type = null;
4609               }
4610               if (type != null)
4611               {
4612                 if (type.equalsIgnoreCase("PDB"))
4613                 {
4614                   filesmatched.add(new Object[]
4615                   { file, protocol, mtch });
4616                   continue;
4617                 }
4618               }
4619             }
4620             // File wasn't named like one of the sequences or wasn't a PDB file.
4621             filesnotmatched.add(file);
4622           }
4623         }
4624         int assocfiles = 0;
4625         if (filesmatched.size() > 0)
4626         {
4627           if (Cache.getDefault("AUTOASSOCIATE_PDBANDSEQS", false)
4628                   || JOptionPane
4629                           .showConfirmDialog(
4630                                   this,
4631                                   "Do you want to automatically associate the "
4632                                           + filesmatched.size()
4633                                           + " PDB files with sequences in the alignment that have the same name ?",
4634                                   "Automatically Associate PDB files by name",
4635                                   JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)
4636
4637           {
4638             for (Object[] fm : filesmatched)
4639             {
4640               // try and associate
4641               // TODO: may want to set a standard ID naming formalism for
4642               // associating PDB files which have no IDs.
4643               for (SequenceI toassoc: (SequenceI[])fm[2]) {
4644               PDBEntry pe = new AssociatePdbFileWithSeq()
4645                       .associatePdbWithSeq((String) fm[0], (String) fm[1],
4646                               toassoc, false);
4647               if (pe != null)
4648               {
4649                 System.err
4650                         .println("Associated file : " + ((String) fm[0])
4651                                 + " with "
4652                                 + toassoc.getDisplayId(true));
4653                 assocfiles++;
4654               }
4655               }
4656               alignPanel.paintAlignment(true);
4657             }
4658           }
4659         }
4660         if (filesnotmatched.size() > 0)
4661         {
4662           if (assocfiles > 0
4663                   && (Cache.getDefault(
4664                           "AUTOASSOCIATE_PDBANDSEQS_IGNOREOTHERS", false) || JOptionPane
4665                           .showConfirmDialog(
4666                                   this,
4667                                   "<html>Do you want to <em>ignore</em> the "
4668                                           + filesnotmatched.size()
4669                                           + " files whose names did not match any sequence IDs ?</html>",
4670                                   "Ignore unmatched dropped files ?",
4671                                   JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION))
4672           {
4673             return;
4674           }
4675           for (String fn : filesnotmatched)
4676           {
4677             loadJalviewDataFile(fn, null, null, null);
4678           }
4679
4680         }
4681       } catch (Exception ex)
4682       {
4683         ex.printStackTrace();
4684       }
4685     }
4686   }
4687
4688   /**
4689    * Attempt to load a "dropped" file or URL string: First by testing whether
4690    * it's and Annotation file, then a JNet file, and finally a features file. If
4691    * all are false then the user may have dropped an alignment file onto this
4692    * AlignFrame.
4693    * 
4694    * @param file
4695    *          either a filename or a URL string.
4696    */
4697   public void loadJalviewDataFile(String file, String protocol,
4698           String format, SequenceI assocSeq)
4699   {
4700     try
4701     {
4702       if (protocol == null)
4703       {
4704         protocol = jalview.io.FormatAdapter.checkProtocol(file);
4705       }
4706       // if the file isn't identified, or not positively identified as some
4707       // other filetype (PFAM is default unidentified alignment file type) then
4708       // try to parse as annotation.
4709       boolean isAnnotation = (format == null || format
4710               .equalsIgnoreCase("PFAM")) ? new AnnotationFile()
4711               .readAnnotationFile(viewport.alignment, file, protocol)
4712               : false;
4713
4714       if (!isAnnotation)
4715       {
4716         // try to see if its a JNet 'concise' style annotation file *before* we
4717         // try to parse it as a features file
4718         if (format == null)
4719         {
4720           format = new IdentifyFile().Identify(file, protocol);
4721         }
4722         if (format.equalsIgnoreCase("JnetFile"))
4723         {
4724           jalview.io.JPredFile predictions = new jalview.io.JPredFile(file,
4725                   protocol);
4726           new JnetAnnotationMaker().add_annotation(predictions,
4727                   viewport.getAlignment(), 0, false);
4728           isAnnotation = true;
4729         }
4730         else
4731         {
4732           /*
4733            * if (format.equalsIgnoreCase("PDB")) {
4734            * 
4735            * String pdbfn = ""; // try to match up filename with sequence id try
4736            * { if (protocol == jalview.io.FormatAdapter.FILE) { File fl = new
4737            * File(file); pdbfn = fl.getName(); } else if (protocol ==
4738            * jalview.io.FormatAdapter.URL) { URL url = new URL(file); pdbfn =
4739            * url.getFile(); } } catch (Exception e) { } ; if (assocSeq == null)
4740            * { SequenceIdMatcher idm = new SequenceIdMatcher(viewport
4741            * .getAlignment().getSequencesArray()); if (pdbfn.length() > 0) { //
4742            * attempt to find a match in the alignment SequenceI mtch =
4743            * idm.findIdMatch(pdbfn); int l = 0, c = pdbfn.indexOf("."); while
4744            * (mtch == null && c != -1) { while ((c = pdbfn.indexOf(".", l)) > l)
4745            * { l = c; } if (l > -1) { pdbfn = pdbfn.substring(0, l); } mtch =
4746            * idm.findIdMatch(pdbfn); } if (mtch != null) { // try and associate
4747            * // prompt ? PDBEntry pe = new AssociatePdbFileWithSeq()
4748            * .associatePdbWithSeq(file, protocol, mtch, true); if (pe != null) {
4749            * System.err.println("Associated file : " + file + " with " +
4750            * mtch.getDisplayId(true)); alignPanel.paintAlignment(true); } } //
4751            * TODO: maybe need to load as normal otherwise return; } }
4752            */
4753           // try to parse it as a features file
4754           boolean isGroupsFile = parseFeaturesFile(file, protocol);
4755           // if it wasn't a features file then we just treat it as a general
4756           // alignment file to load into the current view.
4757           if (!isGroupsFile)
4758           {
4759             new FileLoader().LoadFile(viewport, file, protocol, format);
4760           }
4761           else
4762           {
4763             alignPanel.paintAlignment(true);
4764           }
4765         }
4766       }
4767       if (isAnnotation)
4768       {
4769
4770         alignPanel.adjustAnnotationHeight();
4771         viewport.updateSequenceIdColours();
4772         buildSortByAnnotationScoresMenu();
4773         alignPanel.paintAlignment(true);
4774       }
4775     } catch (Exception ex)
4776     {
4777       ex.printStackTrace();
4778     }
4779   }
4780
4781   public void tabSelectionChanged(int index)
4782   {
4783     if (index > -1)
4784     {
4785       alignPanel = (AlignmentPanel) alignPanels.elementAt(index);
4786       viewport = alignPanel.av;
4787       setMenusFromViewport(viewport);
4788     }
4789   }
4790
4791   public void tabbedPane_mousePressed(MouseEvent e)
4792   {
4793     if (SwingUtilities.isRightMouseButton(e))
4794     {
4795       String reply = JOptionPane.showInternalInputDialog(this,
4796               "Enter View Name", "Edit View Name",
4797               JOptionPane.QUESTION_MESSAGE);
4798
4799       if (reply != null)
4800       {
4801         viewport.viewName = reply;
4802         tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), reply);
4803       }
4804     }
4805   }
4806
4807   public AlignViewport getCurrentView()
4808   {
4809     return viewport;
4810   }
4811
4812   /**
4813    * Open the dialog for regex description parsing.
4814    */
4815   protected void extractScores_actionPerformed(ActionEvent e)
4816   {
4817     ParseProperties pp = new jalview.analysis.ParseProperties(
4818             viewport.alignment);
4819     // TODO: verify regex and introduce GUI dialog for version 2.5
4820     // if (pp.getScoresFromDescription("col", "score column ",
4821     // "\\W*([-+]?\\d*\\.?\\d*e?-?\\d*)\\W+([-+]?\\d*\\.?\\d*e?-?\\d*)",
4822     // true)>0)
4823     if (pp.getScoresFromDescription("description column",
4824             "score in description column ", "\\W*([-+eE0-9.]+)", true) > 0)
4825     {
4826       buildSortByAnnotationScoresMenu();
4827     }
4828   }
4829
4830   /*
4831    * (non-Javadoc)
4832    * 
4833    * @see
4834    * jalview.jbgui.GAlignFrame#showDbRefs_actionPerformed(java.awt.event.ActionEvent
4835    * )
4836    */
4837   protected void showDbRefs_actionPerformed(ActionEvent e)
4838   {
4839     viewport.setShowDbRefs(showDbRefsMenuitem.isSelected());
4840   }
4841
4842   /*
4843    * (non-Javadoc)
4844    * 
4845    * @seejalview.jbgui.GAlignFrame#showNpFeats_actionPerformed(java.awt.event.
4846    * ActionEvent)
4847    */
4848   protected void showNpFeats_actionPerformed(ActionEvent e)
4849   {
4850     viewport.setShowNpFeats(showNpFeatsMenuitem.isSelected());
4851   }
4852
4853   /**
4854    * find the viewport amongst the tabs in this alignment frame and close that
4855    * tab
4856    * 
4857    * @param av
4858    */
4859   public boolean closeView(AlignViewport av)
4860   {
4861     if (viewport == av)
4862     {
4863       this.closeMenuItem_actionPerformed(false);
4864       return true;
4865     }
4866     Component[] comp = tabbedPane.getComponents();
4867     for (int i = 0; comp != null && i < comp.length; i++)
4868     {
4869       if (comp[i] instanceof AlignmentPanel)
4870       {
4871         if (((AlignmentPanel) comp[i]).av == av)
4872         {
4873           // close the view.
4874           closeView((AlignmentPanel) comp[i]);
4875           return true;
4876         }
4877       }
4878     }
4879     return false;
4880   }
4881
4882   protected void build_fetchdbmenu(JMenu webService)
4883   {
4884     // Temporary hack - DBRef Fetcher always top level ws entry.
4885     // TODO We probably want to store a sequence database checklist in
4886     // preferences and have checkboxes.. rather than individual sources selected
4887     // here
4888     final JMenu rfetch = new JMenu("Fetch DB References");
4889     rfetch.setToolTipText("Retrieve and parse sequence database records for the alignment or the currently selected sequences");
4890     webService.add(rfetch);
4891
4892     JMenuItem fetchr = new JMenuItem("Standard Databases");
4893     fetchr.setToolTipText("Fetch from EMBL/EMBLCDS or Uniprot/PDB and any selected DAS sources");
4894     fetchr.addActionListener(new ActionListener()
4895     {
4896
4897       public void actionPerformed(ActionEvent e)
4898       {
4899         new Thread(new Runnable()
4900         {
4901
4902           public void run()
4903           {
4904             new jalview.ws.DBRefFetcher(alignPanel.av
4905                     .getSequenceSelection(), alignPanel.alignFrame)
4906                     .fetchDBRefs(false);
4907           }
4908         }).start();
4909
4910       }
4911
4912     });
4913     rfetch.add(fetchr);
4914     final AlignFrame me = this;
4915     new Thread(new Runnable()
4916     {
4917       public void run()
4918       {
4919         final jalview.ws.SequenceFetcher sf = SequenceFetcher
4920                 .getSequenceFetcherSingleton(me);
4921         final String[] otherdb = sf.getOrderedSupportedSources();
4922         // sf.getDbInstances(jalview.ws.dbsources.DasSequenceSource.class);
4923         // jalview.util.QuickSort.sort(otherdb, otherdb);
4924         javax.swing.SwingUtilities.invokeLater(new Runnable()
4925         {
4926           public void run()
4927           {
4928
4929             JMenu dfetch = new JMenu();
4930             JMenuItem fetchr;
4931             rfetch.add(dfetch);
4932             int comp = 0, mcomp = 15;
4933             String mname = null;
4934             if (otherdb != null && otherdb.length > 0)
4935             {
4936               for (int i = 0; i < otherdb.length; i++)
4937               {
4938                 String dbname = sf.getSourceProxy(otherdb[i]).getDbName();
4939                 if (mname == null)
4940                 {
4941                   mname = "from '" + dbname + "'";
4942                 }
4943                 fetchr = new JMenuItem(otherdb[i]);
4944                 final String[] dassource = new String[]
4945                 { otherdb[i] };
4946                 fetchr.addActionListener(new ActionListener()
4947                 {
4948
4949                   public void actionPerformed(ActionEvent e)
4950                   {
4951                     new Thread(new Runnable()
4952                     {
4953
4954                       public void run()
4955                       {
4956                         new jalview.ws.DBRefFetcher(alignPanel.av
4957                                 .getSequenceSelection(),
4958                                 alignPanel.alignFrame, dassource)
4959                                 .fetchDBRefs(false);
4960                       }
4961                     }).start();
4962                   }
4963
4964                 });
4965                 fetchr.setToolTipText("Retrieve from " + dbname);
4966                 dfetch.add(fetchr);
4967                 if (comp++ == mcomp || i == (otherdb.length - 1))
4968                 {
4969                   dfetch.setText(mname + " to '" + dbname + "'");
4970                   rfetch.add(dfetch);
4971                   dfetch = new JMenu();
4972                   mname = null;
4973                   comp = 0;
4974                 }
4975               }
4976             }
4977           }
4978         });
4979       }
4980     }).start();
4981
4982   }
4983
4984   /**
4985    * Left justify the whole alignment.
4986    */
4987   protected void justifyLeftMenuItem_actionPerformed(ActionEvent e)
4988   {
4989     AlignmentI al = viewport.getAlignment();
4990     al.justify(false);
4991     viewport.firePropertyChange("alignment", null, al);
4992   }
4993
4994   /**
4995    * Right justify the whole alignment.
4996    */
4997   protected void justifyRightMenuItem_actionPerformed(ActionEvent e)
4998   {
4999     AlignmentI al = viewport.getAlignment();
5000     al.justify(true);
5001     viewport.firePropertyChange("alignment", null, al);
5002   }
5003
5004   public void setShowSeqFeatures(boolean b)
5005   {
5006     showSeqFeatures.setSelected(true);
5007     viewport.setShowSequenceFeatures(true);
5008   }
5009
5010   /*
5011    * (non-Javadoc)
5012    * 
5013    * @see
5014    * jalview.jbgui.GAlignFrame#showUnconservedMenuItem_actionPerformed(java.
5015    * awt.event.ActionEvent)
5016    */
5017   protected void showUnconservedMenuItem_actionPerformed(ActionEvent e)
5018   {
5019     viewport.setShowUnconserved(showNonconservedMenuItem.getState());
5020     alignPanel.paintAlignment(true);
5021   }
5022
5023   /*
5024    * (non-Javadoc)
5025    * 
5026    * @see
5027    * jalview.jbgui.GAlignFrame#showGroupConsensus_actionPerformed(java.awt.event
5028    * .ActionEvent)
5029    */
5030   protected void showGroupConsensus_actionPerformed(ActionEvent e)
5031   {
5032     viewport.setShowGroupConsensus(showGroupConsensus.getState());
5033     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5034
5035   }
5036
5037   /*
5038    * (non-Javadoc)
5039    * 
5040    * @see
5041    * jalview.jbgui.GAlignFrame#showGroupConservation_actionPerformed(java.awt
5042    * .event.ActionEvent)
5043    */
5044   protected void showGroupConservation_actionPerformed(ActionEvent e)
5045   {
5046     viewport.setShowGroupConservation(showGroupConservation.getState());
5047     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5048   }
5049
5050   /*
5051    * (non-Javadoc)
5052    * 
5053    * @see
5054    * jalview.jbgui.GAlignFrame#showConsensusHistogram_actionPerformed(java.awt
5055    * .event.ActionEvent)
5056    */
5057   protected void showConsensusHistogram_actionPerformed(ActionEvent e)
5058   {
5059     viewport.setShowConsensusHistogram(showConsensusHistogram.getState());
5060     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5061   }
5062
5063   /*
5064    * (non-Javadoc)
5065    * 
5066    * @see
5067    * jalview.jbgui.GAlignFrame#showConsensusProfile_actionPerformed(java.awt
5068    * .event.ActionEvent)
5069    */
5070   protected void showSequenceLogo_actionPerformed(ActionEvent e)
5071   {
5072     viewport.setShowSequenceLogo(showSequenceLogo.getState());
5073     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5074   }
5075
5076   protected void applyAutoAnnotationSettings_actionPerformed(ActionEvent e)
5077   {
5078     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5079   }
5080
5081   /*
5082    * (non-Javadoc)
5083    * 
5084    * @see
5085    * jalview.jbgui.GAlignFrame#makeGrpsFromSelection_actionPerformed(java.awt
5086    * .event.ActionEvent)
5087    */
5088   protected void makeGrpsFromSelection_actionPerformed(ActionEvent e)
5089   {
5090     if (viewport.getSelectionGroup() != null)
5091     {
5092       SequenceGroup[] gps = jalview.analysis.Grouping.makeGroupsFrom(
5093               viewport.getSequenceSelection(),
5094               viewport.getAlignmentView(true).getSequenceStrings(
5095                       viewport.getGapCharacter()),
5096               viewport.alignment.getGroups());
5097       viewport.alignment.deleteAllGroups();
5098       viewport.sequenceColours = null;
5099       viewport.setSelectionGroup(null);
5100       // set view properties for each group
5101       for (int g = 0; g < gps.length; g++)
5102       {
5103         gps[g].setShowNonconserved(viewport.getShowUnconserved());
5104         gps[g].setshowSequenceLogo(viewport.isShowSequenceLogo());
5105         viewport.alignment.addGroup(gps[g]);
5106         Color col = new Color((int) (Math.random() * 255),
5107                 (int) (Math.random() * 255), (int) (Math.random() * 255));
5108         col = col.brighter();
5109         for (Enumeration sq = gps[g].getSequences(null).elements(); sq
5110                 .hasMoreElements(); viewport.setSequenceColour(
5111                 (SequenceI) sq.nextElement(), col))
5112           ;
5113       }
5114       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
5115       alignPanel.updateAnnotation();
5116       alignPanel.paintAlignment(true);
5117     }
5118   }
5119
5120   /**
5121    * make the given alignmentPanel the currently selected tab
5122    * 
5123    * @param alignmentPanel
5124    */
5125   public void setDisplayedView(AlignmentPanel alignmentPanel)
5126   {
5127     if (!viewport.getSequenceSetId().equals(
5128             alignmentPanel.av.getSequenceSetId()))
5129     {
5130       throw new Error(
5131               "Implementation error: cannot show a view from another alignment in an AlignFrame.");
5132     }
5133     if (tabbedPane != null
5134             & alignPanels.indexOf(alignmentPanel) != tabbedPane.getSelectedIndex())
5135     {
5136       tabbedPane.setSelectedIndex(alignPanels.indexOf(alignmentPanel));
5137     }
5138   }
5139 }
5140
5141 class PrintThread extends Thread
5142 {
5143   AlignmentPanel ap;
5144
5145   public PrintThread(AlignmentPanel ap)
5146   {
5147     this.ap = ap;
5148   }
5149
5150   static PageFormat pf;
5151
5152   public void run()
5153   {
5154     PrinterJob printJob = PrinterJob.getPrinterJob();
5155
5156     if (pf != null)
5157     {
5158       printJob.setPrintable(ap, pf);
5159     }
5160     else
5161     {
5162       printJob.setPrintable(ap);
5163     }
5164
5165     if (printJob.printDialog())
5166     {
5167       try
5168       {
5169         printJob.print();
5170       } catch (Exception PrintException)
5171       {
5172         PrintException.printStackTrace();
5173       }
5174     }
5175   }
5176 }