Merge branch 'test_paolo_JAL-1065' into Tcoffee_JAL-1065
[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               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 = 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 ) { 
3885                        // TODO: raise a dialog box here rather than bomb out.
3886                   
3887                           throw new RuntimeException("The file provided does not match the T-Coffee scores file format"); 
3888                   }
3889
3890                   /*
3891                    * check that the score matrix matches the alignment dimensions
3892                    */
3893                   AlignmentI aln; 
3894                   if( (aln=viewport.alignment) != null && (aln.getHeight() != result.getHeight() || aln.getWidth() != result.getWidth()) ) {
3895                       // TODO: raise a dialog box here rather than bomb out.
3896                     throw new RuntimeException("The scores matrix does not match the alignment dimensions");
3897                   }
3898                   if (result.annotateAlignment(alignPanel.getAlignment(), true))
3899                   {
3900                           tcoffeeColour.setEnabled(true);
3901                           tcoffeeColour.setSelected(true);
3902                           // switch to this color
3903                           changeColour(new TCoffeeColourScheme(alignPanel.getAlignment()));
3904                   } else {
3905                     tcoffeeColour.setEnabled(false);
3906                     tcoffeeColour.setSelected(false);
3907                   }
3908               } 
3909               catch (Exception ex) {
3910                 JOptionPane.showMessageDialog(
3911                                         Desktop.desktop, 
3912                                         ex.getMessage(), 
3913                                         "Problem reading tree file", 
3914                                         JOptionPane.WARNING_MESSAGE);
3915
3916                 ex.printStackTrace();
3917               }
3918             }
3919
3920   } 
3921
3922   
3923   @Override
3924   protected void tcoffeeColorScheme_actionPerformed(ActionEvent e) {
3925           changeColour( new TCoffeeColourScheme(alignPanel.getAlignment()) );
3926   }
3927   
3928 //  /**
3929 //   * Load the (T-Coffee) score file from the specified url 
3930 //   * 
3931 //   * @param url The absolute path from where download and read the score file
3932 //   * @throws IOException 
3933 //   */
3934 //  public void loadScoreFile(URL url ) throws IOException {
3935 //        
3936 //        TCoffeeScoreFile result = new TCoffeeScoreFile();
3937 //        result.parse( new InputStreamReader( url.openStream() ) );
3938 //        tcoffeeScoreFile = result;
3939 //  }  
3940   
3941   public TreePanel ShowNewickTree(NewickFile nf, String title)
3942   {
3943     return ShowNewickTree(nf, title, 600, 500, 4, 5);
3944   }
3945
3946   public TreePanel ShowNewickTree(NewickFile nf, String title,
3947           AlignmentView input)
3948   {
3949     return ShowNewickTree(nf, title, input, 600, 500, 4, 5);
3950   }
3951
3952   public TreePanel ShowNewickTree(NewickFile nf, String title, int w,
3953           int h, int x, int y)
3954   {
3955     return ShowNewickTree(nf, title, null, w, h, x, y);
3956   }
3957
3958   /**
3959    * Add a treeviewer for the tree extracted from a newick file object to the
3960    * current alignment view
3961    * 
3962    * @param nf
3963    *          the tree
3964    * @param title
3965    *          tree viewer title
3966    * @param input
3967    *          Associated alignment input data (or null)
3968    * @param w
3969    *          width
3970    * @param h
3971    *          height
3972    * @param x
3973    *          position
3974    * @param y
3975    *          position
3976    * @return TreePanel handle
3977    */
3978   public TreePanel ShowNewickTree(NewickFile nf, String title,
3979           AlignmentView input, int w, int h, int x, int y)
3980   {
3981     TreePanel tp = null;
3982
3983     try
3984     {
3985       nf.parse();
3986
3987       if (nf.getTree() != null)
3988       {
3989         tp = new TreePanel(alignPanel, "FromFile", title, nf, input);
3990
3991         tp.setSize(w, h);
3992
3993         if (x > 0 && y > 0)
3994         {
3995           tp.setLocation(x, y);
3996         }
3997
3998         Desktop.addInternalFrame(tp, title, w, h);
3999       }
4000     } catch (Exception ex)
4001     {
4002       ex.printStackTrace();
4003     }
4004
4005     return tp;
4006   }
4007
4008   private boolean buildingMenu = false;
4009
4010   /**
4011    * Generates menu items and listener event actions for web service clients
4012    * 
4013    */
4014   public void BuildWebServiceMenu()
4015   {
4016     while (buildingMenu)
4017     {
4018       try
4019       {
4020         System.err.println("Waiting for building menu to finish.");
4021         Thread.sleep(10);
4022       } catch (Exception e)
4023       {
4024       }
4025       ;
4026     }
4027     final AlignFrame me = this;
4028     buildingMenu = true;
4029     new Thread(new Runnable()
4030     {
4031       public void run()
4032       {
4033         try
4034         {
4035           System.err.println("Building ws menu again "
4036                   + Thread.currentThread());
4037           // TODO: add support for context dependent disabling of services based
4038           // on
4039           // alignment and current selection
4040           // TODO: add additional serviceHandle parameter to specify abstract
4041           // handler
4042           // class independently of AbstractName
4043           // TODO: add in rediscovery GUI function to restart discoverer
4044           // TODO: group services by location as well as function and/or
4045           // introduce
4046           // object broker mechanism.
4047           final Vector wsmenu = new Vector();
4048           final IProgressIndicator af = me;
4049           final JMenu msawsmenu = new JMenu("Alignment");
4050           final JMenu secstrmenu = new JMenu(
4051                   "Secondary Structure Prediction");
4052           final JMenu seqsrchmenu = new JMenu(
4053                   "Sequence Database Search");
4054           final JMenu analymenu = new JMenu(
4055                   "Analysis");
4056           // JAL-940 - only show secondary structure prediction services from the legacy server
4057           if (// Cache.getDefault("SHOW_JWS1_SERVICES", true)
4058                   // && 
4059                   Discoverer.services != null
4060                   && (Discoverer.services.size() > 0))
4061           {
4062             // TODO: refactor to allow list of AbstractName/Handler bindings to
4063             // be
4064             // stored or retrieved from elsewhere
4065             Vector msaws = null; // (Vector) Discoverer.services.get("MsaWS");
4066             Vector secstrpr = (Vector) Discoverer.services
4067                     .get("SecStrPred");
4068             Vector seqsrch = null; // (Vector) Discoverer.services.get("SeqSearch");
4069             // TODO: move GUI generation code onto service implementation - so a
4070             // client instance attaches itself to the GUI with method call like
4071             // jalview.ws.MsaWSClient.bind(servicehandle, Desktop.instance,
4072             // alignframe)
4073             if (msaws != null)
4074             {
4075               // Add any Multiple Sequence Alignment Services
4076               for (int i = 0, j = msaws.size(); i < j; i++)
4077               {
4078                 final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) msaws
4079                         .get(i);
4080                 jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer
4081                         .getServiceClient(sh);
4082                 impl.attachWSMenuEntry(msawsmenu, me);
4083
4084               }
4085             }
4086             if (secstrpr != null)
4087             {
4088               // Add any secondary structure prediction services
4089               for (int i = 0, j = secstrpr.size(); i < j; i++)
4090               {
4091                 final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) secstrpr
4092                         .get(i);
4093                 jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer
4094                         .getServiceClient(sh);
4095                 impl.attachWSMenuEntry(secstrmenu, me);
4096               }
4097             }
4098             if (seqsrch != null)
4099             {
4100               // Add any sequence search services
4101               for (int i = 0, j = seqsrch.size(); i < j; i++)
4102               {
4103                 final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) seqsrch
4104                         .elementAt(i);
4105                 jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer
4106                         .getServiceClient(sh);
4107                 impl.attachWSMenuEntry(seqsrchmenu, me);
4108               }
4109             }
4110           }
4111
4112           // TODO: move into separate menu builder class.
4113           if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
4114           {
4115             Jws2Discoverer jws2servs = Jws2Discoverer.getDiscoverer();
4116             if (jws2servs != null)
4117             {
4118               if (jws2servs.hasServices())
4119               {
4120                 jws2servs.attachWSMenuEntry(msawsmenu, me);
4121               }
4122             }
4123           }
4124           // Add all submenus in the order they should appear on the web services menu
4125           wsmenu.add(msawsmenu);
4126           wsmenu.add(secstrmenu);
4127           wsmenu.add(analymenu);
4128           // No search services yet
4129           // wsmenu.add(seqsrchmenu);
4130
4131           javax.swing.SwingUtilities.invokeLater(new Runnable()
4132           {
4133             public void run()
4134             {
4135               try
4136               {
4137                 webService.removeAll();
4138                 // first, add discovered services onto the webservices menu
4139                 if (wsmenu.size() > 0)
4140                 {
4141                   for (int i = 0, j = wsmenu.size(); i < j; i++)
4142                   {
4143                     webService.add((JMenu) wsmenu.get(i));
4144                   }
4145                 }
4146                 else
4147                 {
4148                   webService.add(me.webServiceNoServices);
4149                 }
4150                 build_urlServiceMenu(me.webService);
4151                 build_fetchdbmenu(webService);
4152               } catch (Exception e)
4153               {
4154               }
4155               ;
4156             }
4157           });
4158         } catch (Exception e)
4159         {
4160         }
4161         ;
4162
4163         buildingMenu = false;
4164       }
4165     }).start();
4166
4167   }
4168
4169
4170   /**
4171    * construct any groupURL type service menu entries.
4172    * 
4173    * @param webService
4174    */
4175   private void build_urlServiceMenu(JMenu webService)
4176   {
4177     // TODO: remove this code when 2.7 is released
4178     // DEBUG - alignmentView
4179     /*
4180      * JMenuItem testAlView = new JMenuItem("Test AlignmentView"); final
4181      * AlignFrame af = this; testAlView.addActionListener(new ActionListener() {
4182      * 
4183      * @Override public void actionPerformed(ActionEvent e) {
4184      * jalview.datamodel.AlignmentView.testSelectionViews(af.viewport.alignment,
4185      * af.viewport.colSel, af.viewport.selectionGroup); }
4186      * 
4187      * }); webService.add(testAlView);
4188      */
4189     // TODO: refactor to RestClient discoverer and merge menu entries for
4190     // rest-style services with other types of analysis/calculation service
4191     // SHmmr test client - still being implemented.
4192     // DEBUG - alignmentView
4193     
4194     for (jalview.ws.rest.RestClient client: jalview.ws.rest.RestClient.getRestClients()) {
4195       client.attachWSMenuEntry(JvSwingUtils.findOrCreateMenu(webService, client.getAction()), this);
4196     }
4197
4198     if (Cache.getDefault("SHOW_ENFIN_SERVICES", true))
4199     {
4200       jalview.ws.EnfinEnvision2OneWay.getInstance().attachWSMenuEntry(
4201               webService, this);
4202     }
4203   }
4204
4205   /*
4206    * public void vamsasStore_actionPerformed(ActionEvent e) { JalviewFileChooser
4207    * chooser = new JalviewFileChooser(jalview.bin.Cache.
4208    * getProperty("LAST_DIRECTORY"));
4209    * 
4210    * chooser.setFileView(new JalviewFileView()); chooser.setDialogTitle("Export
4211    * to Vamsas file"); chooser.setToolTipText("Export");
4212    * 
4213    * int value = chooser.showSaveDialog(this);
4214    * 
4215    * if (value == JalviewFileChooser.APPROVE_OPTION) {
4216    * jalview.io.VamsasDatastore vs = new jalview.io.VamsasDatastore(viewport);
4217    * //vs.store(chooser.getSelectedFile().getAbsolutePath() ); vs.storeJalview(
4218    * chooser.getSelectedFile().getAbsolutePath(), this); } }
4219    */
4220   /**
4221    * prototype of an automatically enabled/disabled analysis function
4222    * 
4223    */
4224   protected void setShowProductsEnabled()
4225   {
4226     SequenceI[] selection = viewport.getSequenceSelection();
4227     if (canShowProducts(selection, viewport.getSelectionGroup() != null,
4228             viewport.getAlignment().getDataset()))
4229     {
4230       showProducts.setEnabled(true);
4231
4232     }
4233     else
4234     {
4235       showProducts.setEnabled(false);
4236     }
4237   }
4238
4239   /**
4240    * search selection for sequence xRef products and build the show products
4241    * menu.
4242    * 
4243    * @param selection
4244    * @param dataset
4245    * @return true if showProducts menu should be enabled.
4246    */
4247   public boolean canShowProducts(SequenceI[] selection,
4248           boolean isRegionSelection, Alignment dataset)
4249   {
4250     boolean showp = false;
4251     try
4252     {
4253       showProducts.removeAll();
4254       final boolean dna = viewport.getAlignment().isNucleotide();
4255       final Alignment ds = dataset;
4256       String[] ptypes = (selection == null || selection.length == 0) ? null
4257               : CrossRef.findSequenceXrefTypes(dna, selection, dataset);
4258       // Object[] prods =
4259       // CrossRef.buildXProductsList(viewport.getAlignment().isNucleotide(),
4260       // selection, dataset, true);
4261       final SequenceI[] sel = selection;
4262       for (int t = 0; ptypes != null && t < ptypes.length; t++)
4263       {
4264         showp = true;
4265         final boolean isRegSel = isRegionSelection;
4266         final AlignFrame af = this;
4267         final String source = ptypes[t];
4268         JMenuItem xtype = new JMenuItem(ptypes[t]);
4269         xtype.addActionListener(new ActionListener()
4270         {
4271
4272           public void actionPerformed(ActionEvent e)
4273           {
4274             // TODO: new thread for this call with vis-delay
4275             af.showProductsFor(af.viewport.getSequenceSelection(), ds,
4276                     isRegSel, dna, source);
4277           }
4278
4279         });
4280         showProducts.add(xtype);
4281       }
4282       showProducts.setVisible(showp);
4283       showProducts.setEnabled(showp);
4284     } catch (Exception e)
4285     {
4286       jalview.bin.Cache.log
4287               .warn("canTranslate threw an exception - please report to help@jalview.org",
4288                       e);
4289       return false;
4290     }
4291     return showp;
4292   }
4293
4294   protected void showProductsFor(SequenceI[] sel, Alignment ds,
4295           boolean isRegSel, boolean dna, String source)
4296   {
4297     final boolean fisRegSel = isRegSel;
4298     final boolean fdna = dna;
4299     final String fsrc = source;
4300     final AlignFrame ths = this;
4301     final SequenceI[] fsel = sel;
4302     Runnable foo = new Runnable()
4303     {
4304
4305       public void run()
4306       {
4307         final long sttime = System.currentTimeMillis();
4308         ths.setProgressBar("Searching for sequences from " + fsrc, sttime);
4309         try
4310         {
4311           Alignment ds = ths.getViewport().alignment.getDataset(); // update
4312           // our local
4313           // dataset
4314           // reference
4315           Alignment prods = CrossRef
4316                   .findXrefSequences(fsel, fdna, fsrc, ds);
4317           if (prods != null)
4318           {
4319             SequenceI[] sprods = new SequenceI[prods.getHeight()];
4320             for (int s = 0; s < sprods.length; s++)
4321             {
4322               sprods[s] = (prods.getSequenceAt(s)).deriveSequence();
4323               if (ds.getSequences() == null
4324                       || !ds.getSequences().contains(
4325                               sprods[s].getDatasetSequence()))
4326                 ds.addSequence(sprods[s].getDatasetSequence());
4327               sprods[s].updatePDBIds();
4328             }
4329             Alignment al = new Alignment(sprods);
4330             AlignedCodonFrame[] cf = prods.getCodonFrames();
4331             al.setDataset(ds);
4332             for (int s = 0; cf != null && s < cf.length; s++)
4333             {
4334               al.addCodonFrame(cf[s]);
4335               cf[s] = null;
4336             }
4337             AlignFrame naf = new AlignFrame(al, DEFAULT_WIDTH,
4338                     DEFAULT_HEIGHT);
4339             String newtitle = "" + ((fdna) ? "Proteins " : "Nucleotides ")
4340                     + " for " + ((fisRegSel) ? "selected region of " : "")
4341                     + getTitle();
4342             Desktop.addInternalFrame(naf, newtitle, DEFAULT_WIDTH,
4343                     DEFAULT_HEIGHT);
4344           }
4345           else
4346           {
4347             System.err.println("No Sequences generated for xRef type "
4348                     + fsrc);
4349           }
4350         } catch (Exception e)
4351         {
4352           jalview.bin.Cache.log.error(
4353                   "Exception when finding crossreferences", e);
4354         } catch (OutOfMemoryError e)
4355         {
4356           new OOMWarning("whilst fetching crossreferences", e);
4357         } catch (Error e)
4358         {
4359           jalview.bin.Cache.log.error("Error when finding crossreferences",
4360                   e);
4361         }
4362         ths.setProgressBar("Finished searching for sequences from " + fsrc,
4363                 sttime);
4364       }
4365
4366     };
4367     Thread frunner = new Thread(foo);
4368     frunner.start();
4369   }
4370
4371   public boolean canShowTranslationProducts(SequenceI[] selection,
4372           AlignmentI alignment)
4373   {
4374     // old way
4375     try
4376     {
4377       return (jalview.analysis.Dna.canTranslate(selection,
4378               viewport.getViewAsVisibleContigs(true)));
4379     } catch (Exception e)
4380     {
4381       jalview.bin.Cache.log
4382               .warn("canTranslate threw an exception - please report to help@jalview.org",
4383                       e);
4384       return false;
4385     }
4386   }
4387
4388   public void showProducts_actionPerformed(ActionEvent e)
4389   {
4390     // /////////////////////////////
4391     // Collect Data to be translated/transferred
4392
4393     SequenceI[] selection = viewport.getSequenceSelection();
4394     AlignmentI al = null;
4395     try
4396     {
4397       al = jalview.analysis.Dna.CdnaTranslate(selection, viewport
4398               .getViewAsVisibleContigs(true), viewport.getGapCharacter(),
4399               viewport.getAlignment().getDataset());
4400     } catch (Exception ex)
4401     {
4402       al = null;
4403       jalview.bin.Cache.log.debug("Exception during translation.", ex);
4404     }
4405     if (al == null)
4406     {
4407       JOptionPane
4408               .showMessageDialog(
4409                       Desktop.desktop,
4410                       "Please select at least three bases in at least one sequence in order to perform a cDNA translation.",
4411                       "Translation Failed", JOptionPane.WARNING_MESSAGE);
4412     }
4413     else
4414     {
4415       AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
4416       Desktop.addInternalFrame(af, "Translation of " + this.getTitle(),
4417               DEFAULT_WIDTH, DEFAULT_HEIGHT);
4418     }
4419   }
4420
4421   public void showTranslation_actionPerformed(ActionEvent e)
4422   {
4423     // /////////////////////////////
4424     // Collect Data to be translated/transferred
4425
4426     SequenceI[] selection = viewport.getSequenceSelection();
4427     String[] seqstring = viewport.getViewAsString(true);
4428     AlignmentI al = null;
4429     try
4430     {
4431       al = jalview.analysis.Dna.CdnaTranslate(selection, seqstring,
4432               viewport.getViewAsVisibleContigs(true), viewport
4433                       .getGapCharacter(), viewport.alignment
4434                       .getAlignmentAnnotation(), viewport.alignment
4435                       .getWidth(), viewport.getAlignment().getDataset());
4436     } catch (Exception ex)
4437     {
4438       al = null;
4439       jalview.bin.Cache.log.debug("Exception during translation.", ex);
4440     }
4441     if (al == null)
4442     {
4443       JOptionPane
4444               .showMessageDialog(
4445                       Desktop.desktop,
4446                       "Please select at least three bases in at least one sequence in order to perform a cDNA translation.",
4447                       "Translation Failed", JOptionPane.WARNING_MESSAGE);
4448     }
4449     else
4450     {
4451       AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
4452       Desktop.addInternalFrame(af, "Translation of " + this.getTitle(),
4453               DEFAULT_WIDTH, DEFAULT_HEIGHT);
4454     }
4455   }
4456
4457   /**
4458    * Try to load a features file onto the alignment.
4459    * 
4460    * @param file
4461    *          contents or path to retrieve file
4462    * @param type
4463    *          access mode of file (see jalview.io.AlignFile)
4464    * @return true if features file was parsed corectly.
4465    */
4466   public boolean parseFeaturesFile(String file, String type)
4467   {
4468     boolean featuresFile = false;
4469     try
4470     {
4471       featuresFile = new FeaturesFile(file, type)
4472               .parse(viewport.alignment.getDataset(),
4473                       alignPanel.seqPanel.seqCanvas.getFeatureRenderer().featureColours,
4474                       false, jalview.bin.Cache.getDefault(
4475                               "RELAXEDSEQIDMATCHING", false));
4476     } catch (Exception ex)
4477     {
4478       ex.printStackTrace();
4479     }
4480
4481     if (featuresFile)
4482     {
4483       viewport.showSequenceFeatures = true;
4484       showSeqFeatures.setSelected(true);
4485       if (alignPanel.seqPanel.seqCanvas.fr != null)
4486       {
4487         // update the min/max ranges where necessary
4488         alignPanel.seqPanel.seqCanvas.fr.findAllFeatures(true);
4489       }
4490       if (featureSettings != null)
4491       {
4492         featureSettings.setTableData();
4493       }
4494       alignPanel.paintAlignment(true);
4495     }
4496
4497     return featuresFile;
4498   }
4499
4500   public void dragEnter(DropTargetDragEvent evt)
4501   {
4502   }
4503
4504   public void dragExit(DropTargetEvent evt)
4505   {
4506   }
4507
4508   public void dragOver(DropTargetDragEvent evt)
4509   {
4510   }
4511
4512   public void dropActionChanged(DropTargetDragEvent evt)
4513   {
4514   }
4515
4516   public void drop(DropTargetDropEvent evt)
4517   {
4518     Transferable t = evt.getTransferable();
4519     java.util.List files = null;
4520
4521     try
4522     {
4523       DataFlavor uriListFlavor = new DataFlavor(
4524               "text/uri-list;class=java.lang.String");
4525       if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
4526       {
4527         // Works on Windows and MacOSX
4528         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
4529         files = (java.util.List) t
4530                 .getTransferData(DataFlavor.javaFileListFlavor);
4531       }
4532       else if (t.isDataFlavorSupported(uriListFlavor))
4533       {
4534         // This is used by Unix drag system
4535         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
4536         String data = (String) t.getTransferData(uriListFlavor);
4537         files = new java.util.ArrayList(1);
4538         for (java.util.StringTokenizer st = new java.util.StringTokenizer(
4539                 data, "\r\n"); st.hasMoreTokens();)
4540         {
4541           String s = st.nextToken();
4542           if (s.startsWith("#"))
4543           {
4544             // the line is a comment (as per the RFC 2483)
4545             continue;
4546           }
4547
4548           java.net.URI uri = new java.net.URI(s);
4549           // check to see if we can handle this kind of URI
4550           if (uri.getScheme().toLowerCase().startsWith("http"))
4551           {
4552             files.add(uri.toString());
4553           }
4554           else
4555           {
4556             // otherwise preserve old behaviour: catch all for file objects
4557             java.io.File file = new java.io.File(uri);
4558             files.add(file.toString());
4559           }
4560         }
4561       }
4562     } catch (Exception e)
4563     {
4564       e.printStackTrace();
4565     }
4566     if (files != null)
4567     {
4568       try
4569       {
4570         // check to see if any of these files have names matching sequences in
4571         // the alignment
4572         SequenceIdMatcher idm = new SequenceIdMatcher(viewport
4573                 .getAlignment().getSequencesArray());
4574         /**
4575          * Object[] { String,SequenceI}
4576          */
4577         ArrayList<Object[]> filesmatched = new ArrayList<Object[]>();
4578         ArrayList<String> filesnotmatched = new ArrayList<String>();
4579         for (int i = 0; i < files.size(); i++)
4580         {
4581           String file = files.get(i).toString();
4582           String pdbfn = "";
4583           String protocol = FormatAdapter.checkProtocol(file);
4584           if (protocol == jalview.io.FormatAdapter.FILE)
4585           {
4586             File fl = new File(file);
4587             pdbfn = fl.getName();
4588           }
4589           else if (protocol == jalview.io.FormatAdapter.URL)
4590           {
4591             URL url = new URL(file);
4592             pdbfn = url.getFile();
4593           }
4594           if (pdbfn.length() > 0)
4595           {
4596             // attempt to find a match in the alignment
4597             SequenceI[] mtch = idm.findAllIdMatches(pdbfn);
4598             int l = 0, c = pdbfn.indexOf(".");
4599             while (mtch == null && c != -1)
4600             {
4601               do 
4602               {
4603                 l = c;
4604               } while ((c = pdbfn.indexOf(".", l)) > l);
4605               if (l > -1)
4606               {
4607                 pdbfn = pdbfn.substring(0, l);
4608               }
4609               mtch = idm.findAllIdMatches(pdbfn);
4610             }
4611             if (mtch != null)
4612             {
4613               String type = null;
4614               try
4615               {
4616                 type = new IdentifyFile().Identify(file, protocol);
4617               } catch (Exception ex)
4618               {
4619                 type = null;
4620               }
4621               if (type != null)
4622               {
4623                 if (type.equalsIgnoreCase("PDB"))
4624                 {
4625                   filesmatched.add(new Object[]
4626                   { file, protocol, mtch });
4627                   continue;
4628                 }
4629               }
4630             }
4631             // File wasn't named like one of the sequences or wasn't a PDB file.
4632             filesnotmatched.add(file);
4633           }
4634         }
4635         int assocfiles = 0;
4636         if (filesmatched.size() > 0)
4637         {
4638           if (Cache.getDefault("AUTOASSOCIATE_PDBANDSEQS", false)
4639                   || JOptionPane
4640                           .showConfirmDialog(
4641                                   this,
4642                                   "Do you want to automatically associate the "
4643                                           + filesmatched.size()
4644                                           + " PDB files with sequences in the alignment that have the same name ?",
4645                                   "Automatically Associate PDB files by name",
4646                                   JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)
4647
4648           {
4649             for (Object[] fm : filesmatched)
4650             {
4651               // try and associate
4652               // TODO: may want to set a standard ID naming formalism for
4653               // associating PDB files which have no IDs.
4654               for (SequenceI toassoc: (SequenceI[])fm[2]) {
4655               PDBEntry pe = new AssociatePdbFileWithSeq()
4656                       .associatePdbWithSeq((String) fm[0], (String) fm[1],
4657                               toassoc, false);
4658               if (pe != null)
4659               {
4660                 System.err
4661                         .println("Associated file : " + ((String) fm[0])
4662                                 + " with "
4663                                 + toassoc.getDisplayId(true));
4664                 assocfiles++;
4665               }
4666               }
4667               alignPanel.paintAlignment(true);
4668             }
4669           }
4670         }
4671         if (filesnotmatched.size() > 0)
4672         {
4673           if (assocfiles > 0
4674                   && (Cache.getDefault(
4675                           "AUTOASSOCIATE_PDBANDSEQS_IGNOREOTHERS", false) || JOptionPane
4676                           .showConfirmDialog(
4677                                   this,
4678                                   "<html>Do you want to <em>ignore</em> the "
4679                                           + filesnotmatched.size()
4680                                           + " files whose names did not match any sequence IDs ?</html>",
4681                                   "Ignore unmatched dropped files ?",
4682                                   JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION))
4683           {
4684             return;
4685           }
4686           for (String fn : filesnotmatched)
4687           {
4688             loadJalviewDataFile(fn, null, null, null);
4689           }
4690
4691         }
4692       } catch (Exception ex)
4693       {
4694         ex.printStackTrace();
4695       }
4696     }
4697   }
4698
4699   /**
4700    * Attempt to load a "dropped" file or URL string: First by testing whether
4701    * it's and Annotation file, then a JNet file, and finally a features file. If
4702    * all are false then the user may have dropped an alignment file onto this
4703    * AlignFrame.
4704    * 
4705    * @param file
4706    *          either a filename or a URL string.
4707    */
4708   public void loadJalviewDataFile(String file, String protocol,
4709           String format, SequenceI assocSeq)
4710   {
4711     try
4712     {
4713       if (protocol == null)
4714       {
4715         protocol = jalview.io.FormatAdapter.checkProtocol(file);
4716       }
4717       // if the file isn't identified, or not positively identified as some
4718       // other filetype (PFAM is default unidentified alignment file type) then
4719       // try to parse as annotation.
4720       boolean isAnnotation = (format == null || format
4721               .equalsIgnoreCase("PFAM")) ? new AnnotationFile()
4722               .readAnnotationFile(viewport.alignment, file, protocol)
4723               : false;
4724
4725       if (!isAnnotation)
4726       {
4727         // try to see if its a JNet 'concise' style annotation file *before* we
4728         // try to parse it as a features file
4729         if (format == null)
4730         {
4731           format = new IdentifyFile().Identify(file, protocol);
4732         }
4733         if (format.equalsIgnoreCase("JnetFile"))
4734         {
4735           jalview.io.JPredFile predictions = new jalview.io.JPredFile(file,
4736                   protocol);
4737           new JnetAnnotationMaker().add_annotation(predictions,
4738                   viewport.getAlignment(), 0, false);
4739           isAnnotation = true;
4740         }
4741         else
4742         {
4743           /*
4744            * if (format.equalsIgnoreCase("PDB")) {
4745            * 
4746            * String pdbfn = ""; // try to match up filename with sequence id try
4747            * { if (protocol == jalview.io.FormatAdapter.FILE) { File fl = new
4748            * File(file); pdbfn = fl.getName(); } else if (protocol ==
4749            * jalview.io.FormatAdapter.URL) { URL url = new URL(file); pdbfn =
4750            * url.getFile(); } } catch (Exception e) { } ; if (assocSeq == null)
4751            * { SequenceIdMatcher idm = new SequenceIdMatcher(viewport
4752            * .getAlignment().getSequencesArray()); if (pdbfn.length() > 0) { //
4753            * attempt to find a match in the alignment SequenceI mtch =
4754            * idm.findIdMatch(pdbfn); int l = 0, c = pdbfn.indexOf("."); while
4755            * (mtch == null && c != -1) { while ((c = pdbfn.indexOf(".", l)) > l)
4756            * { l = c; } if (l > -1) { pdbfn = pdbfn.substring(0, l); } mtch =
4757            * idm.findIdMatch(pdbfn); } if (mtch != null) { // try and associate
4758            * // prompt ? PDBEntry pe = new AssociatePdbFileWithSeq()
4759            * .associatePdbWithSeq(file, protocol, mtch, true); if (pe != null) {
4760            * System.err.println("Associated file : " + file + " with " +
4761            * mtch.getDisplayId(true)); alignPanel.paintAlignment(true); } } //
4762            * TODO: maybe need to load as normal otherwise return; } }
4763            */
4764           // try to parse it as a features file
4765           boolean isGroupsFile = parseFeaturesFile(file, protocol);
4766           // if it wasn't a features file then we just treat it as a general
4767           // alignment file to load into the current view.
4768           if (!isGroupsFile)
4769           {
4770             new FileLoader().LoadFile(viewport, file, protocol, format);
4771           }
4772           else
4773           {
4774             alignPanel.paintAlignment(true);
4775           }
4776         }
4777       }
4778       if (isAnnotation)
4779       {
4780
4781         alignPanel.adjustAnnotationHeight();
4782         viewport.updateSequenceIdColours();
4783         buildSortByAnnotationScoresMenu();
4784         alignPanel.paintAlignment(true);
4785       }
4786     } catch (Exception ex)
4787     {
4788       ex.printStackTrace();
4789     }
4790   }
4791
4792   public void tabSelectionChanged(int index)
4793   {
4794     if (index > -1)
4795     {
4796       alignPanel = (AlignmentPanel) alignPanels.elementAt(index);
4797       viewport = alignPanel.av;
4798       setMenusFromViewport(viewport);
4799     }
4800   }
4801
4802   public void tabbedPane_mousePressed(MouseEvent e)
4803   {
4804     if (SwingUtilities.isRightMouseButton(e))
4805     {
4806       String reply = JOptionPane.showInternalInputDialog(this,
4807               "Enter View Name", "Edit View Name",
4808               JOptionPane.QUESTION_MESSAGE);
4809
4810       if (reply != null)
4811       {
4812         viewport.viewName = reply;
4813         tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), reply);
4814       }
4815     }
4816   }
4817
4818   public AlignViewport getCurrentView()
4819   {
4820     return viewport;
4821   }
4822
4823   /**
4824    * Open the dialog for regex description parsing.
4825    */
4826   protected void extractScores_actionPerformed(ActionEvent e)
4827   {
4828     ParseProperties pp = new jalview.analysis.ParseProperties(
4829             viewport.alignment);
4830     // TODO: verify regex and introduce GUI dialog for version 2.5
4831     // if (pp.getScoresFromDescription("col", "score column ",
4832     // "\\W*([-+]?\\d*\\.?\\d*e?-?\\d*)\\W+([-+]?\\d*\\.?\\d*e?-?\\d*)",
4833     // true)>0)
4834     if (pp.getScoresFromDescription("description column",
4835             "score in description column ", "\\W*([-+eE0-9.]+)", true) > 0)
4836     {
4837       buildSortByAnnotationScoresMenu();
4838     }
4839   }
4840
4841   /*
4842    * (non-Javadoc)
4843    * 
4844    * @see
4845    * jalview.jbgui.GAlignFrame#showDbRefs_actionPerformed(java.awt.event.ActionEvent
4846    * )
4847    */
4848   protected void showDbRefs_actionPerformed(ActionEvent e)
4849   {
4850     viewport.setShowDbRefs(showDbRefsMenuitem.isSelected());
4851   }
4852
4853   /*
4854    * (non-Javadoc)
4855    * 
4856    * @seejalview.jbgui.GAlignFrame#showNpFeats_actionPerformed(java.awt.event.
4857    * ActionEvent)
4858    */
4859   protected void showNpFeats_actionPerformed(ActionEvent e)
4860   {
4861     viewport.setShowNpFeats(showNpFeatsMenuitem.isSelected());
4862   }
4863
4864   /**
4865    * find the viewport amongst the tabs in this alignment frame and close that
4866    * tab
4867    * 
4868    * @param av
4869    */
4870   public boolean closeView(AlignViewport av)
4871   {
4872     if (viewport == av)
4873     {
4874       this.closeMenuItem_actionPerformed(false);
4875       return true;
4876     }
4877     Component[] comp = tabbedPane.getComponents();
4878     for (int i = 0; comp != null && i < comp.length; i++)
4879     {
4880       if (comp[i] instanceof AlignmentPanel)
4881       {
4882         if (((AlignmentPanel) comp[i]).av == av)
4883         {
4884           // close the view.
4885           closeView((AlignmentPanel) comp[i]);
4886           return true;
4887         }
4888       }
4889     }
4890     return false;
4891   }
4892
4893   protected void build_fetchdbmenu(JMenu webService)
4894   {
4895     // Temporary hack - DBRef Fetcher always top level ws entry.
4896     // TODO We probably want to store a sequence database checklist in
4897     // preferences and have checkboxes.. rather than individual sources selected
4898     // here
4899     final JMenu rfetch = new JMenu("Fetch DB References");
4900     rfetch.setToolTipText("Retrieve and parse sequence database records for the alignment or the currently selected sequences");
4901     webService.add(rfetch);
4902
4903     JMenuItem fetchr = new JMenuItem("Standard Databases");
4904     fetchr.setToolTipText("Fetch from EMBL/EMBLCDS or Uniprot/PDB and any selected DAS sources");
4905     fetchr.addActionListener(new ActionListener()
4906     {
4907
4908       public void actionPerformed(ActionEvent e)
4909       {
4910         new Thread(new Runnable()
4911         {
4912
4913           public void run()
4914           {
4915             new jalview.ws.DBRefFetcher(alignPanel.av
4916                     .getSequenceSelection(), alignPanel.alignFrame)
4917                     .fetchDBRefs(false);
4918           }
4919         }).start();
4920
4921       }
4922
4923     });
4924     rfetch.add(fetchr);
4925     final AlignFrame me = this;
4926     new Thread(new Runnable()
4927     {
4928       public void run()
4929       {
4930         final jalview.ws.SequenceFetcher sf = SequenceFetcher
4931                 .getSequenceFetcherSingleton(me);
4932         final String[] otherdb = sf.getOrderedSupportedSources();
4933         // sf.getDbInstances(jalview.ws.dbsources.DasSequenceSource.class);
4934         // jalview.util.QuickSort.sort(otherdb, otherdb);
4935         javax.swing.SwingUtilities.invokeLater(new Runnable()
4936         {
4937           public void run()
4938           {
4939
4940             JMenu dfetch = new JMenu();
4941             JMenuItem fetchr;
4942             rfetch.add(dfetch);
4943             int comp = 0, mcomp = 15;
4944             String mname = null;
4945             if (otherdb != null && otherdb.length > 0)
4946             {
4947               for (int i = 0; i < otherdb.length; i++)
4948               {
4949                 String dbname = sf.getSourceProxy(otherdb[i]).getDbName();
4950                 if (mname == null)
4951                 {
4952                   mname = "from '" + dbname + "'";
4953                 }
4954                 fetchr = new JMenuItem(otherdb[i]);
4955                 final String[] dassource = new String[]
4956                 { otherdb[i] };
4957                 fetchr.addActionListener(new ActionListener()
4958                 {
4959
4960                   public void actionPerformed(ActionEvent e)
4961                   {
4962                     new Thread(new Runnable()
4963                     {
4964
4965                       public void run()
4966                       {
4967                         new jalview.ws.DBRefFetcher(alignPanel.av
4968                                 .getSequenceSelection(),
4969                                 alignPanel.alignFrame, dassource)
4970                                 .fetchDBRefs(false);
4971                       }
4972                     }).start();
4973                   }
4974
4975                 });
4976                 fetchr.setToolTipText("Retrieve from " + dbname);
4977                 dfetch.add(fetchr);
4978                 if (comp++ == mcomp || i == (otherdb.length - 1))
4979                 {
4980                   dfetch.setText(mname + " to '" + dbname + "'");
4981                   rfetch.add(dfetch);
4982                   dfetch = new JMenu();
4983                   mname = null;
4984                   comp = 0;
4985                 }
4986               }
4987             }
4988           }
4989         });
4990       }
4991     }).start();
4992
4993   }
4994
4995   /**
4996    * Left justify the whole alignment.
4997    */
4998   protected void justifyLeftMenuItem_actionPerformed(ActionEvent e)
4999   {
5000     AlignmentI al = viewport.getAlignment();
5001     al.justify(false);
5002     viewport.firePropertyChange("alignment", null, al);
5003   }
5004
5005   /**
5006    * Right justify the whole alignment.
5007    */
5008   protected void justifyRightMenuItem_actionPerformed(ActionEvent e)
5009   {
5010     AlignmentI al = viewport.getAlignment();
5011     al.justify(true);
5012     viewport.firePropertyChange("alignment", null, al);
5013   }
5014
5015   public void setShowSeqFeatures(boolean b)
5016   {
5017     showSeqFeatures.setSelected(true);
5018     viewport.setShowSequenceFeatures(true);
5019   }
5020
5021   /*
5022    * (non-Javadoc)
5023    * 
5024    * @see
5025    * jalview.jbgui.GAlignFrame#showUnconservedMenuItem_actionPerformed(java.
5026    * awt.event.ActionEvent)
5027    */
5028   protected void showUnconservedMenuItem_actionPerformed(ActionEvent e)
5029   {
5030     viewport.setShowUnconserved(showNonconservedMenuItem.getState());
5031     alignPanel.paintAlignment(true);
5032   }
5033
5034   /*
5035    * (non-Javadoc)
5036    * 
5037    * @see
5038    * jalview.jbgui.GAlignFrame#showGroupConsensus_actionPerformed(java.awt.event
5039    * .ActionEvent)
5040    */
5041   protected void showGroupConsensus_actionPerformed(ActionEvent e)
5042   {
5043     viewport.setShowGroupConsensus(showGroupConsensus.getState());
5044     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5045
5046   }
5047
5048   /*
5049    * (non-Javadoc)
5050    * 
5051    * @see
5052    * jalview.jbgui.GAlignFrame#showGroupConservation_actionPerformed(java.awt
5053    * .event.ActionEvent)
5054    */
5055   protected void showGroupConservation_actionPerformed(ActionEvent e)
5056   {
5057     viewport.setShowGroupConservation(showGroupConservation.getState());
5058     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5059   }
5060
5061   /*
5062    * (non-Javadoc)
5063    * 
5064    * @see
5065    * jalview.jbgui.GAlignFrame#showConsensusHistogram_actionPerformed(java.awt
5066    * .event.ActionEvent)
5067    */
5068   protected void showConsensusHistogram_actionPerformed(ActionEvent e)
5069   {
5070     viewport.setShowConsensusHistogram(showConsensusHistogram.getState());
5071     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5072   }
5073
5074   /*
5075    * (non-Javadoc)
5076    * 
5077    * @see
5078    * jalview.jbgui.GAlignFrame#showConsensusProfile_actionPerformed(java.awt
5079    * .event.ActionEvent)
5080    */
5081   protected void showSequenceLogo_actionPerformed(ActionEvent e)
5082   {
5083     viewport.setShowSequenceLogo(showSequenceLogo.getState());
5084     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5085   }
5086
5087   protected void applyAutoAnnotationSettings_actionPerformed(ActionEvent e)
5088   {
5089     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
5090   }
5091
5092   /*
5093    * (non-Javadoc)
5094    * 
5095    * @see
5096    * jalview.jbgui.GAlignFrame#makeGrpsFromSelection_actionPerformed(java.awt
5097    * .event.ActionEvent)
5098    */
5099   protected void makeGrpsFromSelection_actionPerformed(ActionEvent e)
5100   {
5101     if (viewport.getSelectionGroup() != null)
5102     {
5103       SequenceGroup[] gps = jalview.analysis.Grouping.makeGroupsFrom(
5104               viewport.getSequenceSelection(),
5105               viewport.getAlignmentView(true).getSequenceStrings(
5106                       viewport.getGapCharacter()),
5107               viewport.alignment.getGroups());
5108       viewport.alignment.deleteAllGroups();
5109       viewport.sequenceColours = null;
5110       viewport.setSelectionGroup(null);
5111       // set view properties for each group
5112       for (int g = 0; g < gps.length; g++)
5113       {
5114         gps[g].setShowNonconserved(viewport.getShowUnconserved());
5115         gps[g].setshowSequenceLogo(viewport.isShowSequenceLogo());
5116         viewport.alignment.addGroup(gps[g]);
5117         Color col = new Color((int) (Math.random() * 255),
5118                 (int) (Math.random() * 255), (int) (Math.random() * 255));
5119         col = col.brighter();
5120         for (Enumeration sq = gps[g].getSequences(null).elements(); sq
5121                 .hasMoreElements(); viewport.setSequenceColour(
5122                 (SequenceI) sq.nextElement(), col))
5123           ;
5124       }
5125       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
5126       alignPanel.updateAnnotation();
5127       alignPanel.paintAlignment(true);
5128     }
5129   }
5130
5131   /**
5132    * make the given alignmentPanel the currently selected tab
5133    * 
5134    * @param alignmentPanel
5135    */
5136   public void setDisplayedView(AlignmentPanel alignmentPanel)
5137   {
5138     if (!viewport.getSequenceSetId().equals(
5139             alignmentPanel.av.getSequenceSetId()))
5140     {
5141       throw new Error(
5142               "Implementation error: cannot show a view from another alignment in an AlignFrame.");
5143     }
5144     if (tabbedPane != null
5145             & alignPanels.indexOf(alignmentPanel) != tabbedPane.getSelectedIndex())
5146     {
5147       tabbedPane.setSelectedIndex(alignPanels.indexOf(alignmentPanel));
5148     }
5149   }
5150 }
5151
5152 class PrintThread extends Thread
5153 {
5154   AlignmentPanel ap;
5155
5156   public PrintThread(AlignmentPanel ap)
5157   {
5158     this.ap = ap;
5159   }
5160
5161   static PageFormat pf;
5162
5163   public void run()
5164   {
5165     PrinterJob printJob = PrinterJob.getPrinterJob();
5166
5167     if (pf != null)
5168     {
5169       printJob.setPrintable(ap, pf);
5170     }
5171     else
5172     {
5173       printJob.setPrintable(ap);
5174     }
5175
5176     if (printJob.printDialog())
5177     {
5178       try
5179       {
5180         printJob.print();
5181       } catch (Exception PrintException)
5182       {
5183         PrintException.printStackTrace();
5184       }
5185     }
5186   }
5187 }