applied 2009 GPL license
[jalview.git] / src / jalview / appletgui / AlignFrame.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4.0.b2)
3  * Copyright (C) 2009 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18  */
19 package jalview.appletgui;
20
21 import java.io.*;
22 import java.net.*;
23 import java.util.*;
24
25 import java.awt.*;
26 import java.awt.event.*;
27
28 import jalview.analysis.*;
29 import jalview.commands.*;
30 import jalview.datamodel.*;
31 import jalview.io.*;
32 import jalview.schemes.*;
33
34 public class AlignFrame extends EmbmenuFrame implements ActionListener,
35         ItemListener, KeyListener
36 {
37   public AlignmentPanel alignPanel;
38
39   public AlignViewport viewport;
40
41   int DEFAULT_WIDTH = 700;
42
43   int DEFAULT_HEIGHT = 500;
44
45   String jalviewServletURL;
46
47   public AlignFrame(AlignmentI al, jalview.bin.JalviewLite applet,
48           String title, boolean embedded)
49   {
50
51     if (applet != null)
52     {
53       jalviewServletURL = applet.getParameter("APPLICATION_URL");
54     }
55
56     try
57     {
58       jbInit();
59     } catch (Exception ex)
60     {
61       ex.printStackTrace();
62     }
63
64     viewport = new AlignViewport(al, applet);
65     alignPanel = new AlignmentPanel(this, viewport);
66
67     viewport.updateConservation(alignPanel);
68     viewport.updateConsensus(alignPanel);
69
70     annotationPanelMenuItem.setState(viewport.showAnnotation);
71
72     seqLimits.setState(viewport.showJVSuffix);
73
74     if (applet != null)
75     {
76       String param = applet.getParameter("sortBy");
77       if (param != null)
78       {
79         if (param.equalsIgnoreCase("Id"))
80         {
81           sortIDMenuItem_actionPerformed();
82         }
83         else if (param.equalsIgnoreCase("Pairwise Identity"))
84         {
85           sortPairwiseMenuItem_actionPerformed();
86         }
87       }
88
89       param = applet.getParameter("wrap");
90       if (param != null)
91       {
92         if (param.equalsIgnoreCase("true"))
93         {
94           wrapMenuItem.setState(true);
95           wrapMenuItem_actionPerformed();
96         }
97       }
98       param = applet.getParameter("centrecolumnlabels");
99       if (param != null)
100       {
101         centreColumnLabelFlag.setState(true);
102         centreColumnLabelFlag_stateChanged();
103       }
104
105       try
106       {
107         param = applet.getParameter("windowWidth");
108         if (param != null)
109         {
110           int width = Integer.parseInt(param);
111           DEFAULT_WIDTH = width;
112         }
113         param = applet.getParameter("windowHeight");
114         if (param != null)
115         {
116           int height = Integer.parseInt(param);
117           DEFAULT_HEIGHT = height;
118         }
119       } catch (Exception ex)
120       {
121       }
122
123     }
124
125     // Some JVMS send keyevents to Top frame or lowest panel,
126     // Havent worked out why yet. So add to both this frame and seqCanvas for
127     // now
128     this.addKeyListener(this);
129     alignPanel.seqPanel.seqCanvas.addKeyListener(this);
130     alignPanel.idPanel.idCanvas.addKeyListener(this);
131     alignPanel.scalePanel.addKeyListener(this);
132     alignPanel.annotationPanel.addKeyListener(this);
133     createAlignFrameWindow(embedded, title);
134     alignPanel.validate();
135     alignPanel.paintAlignment(true);
136   }
137
138   public AlignViewport getAlignViewport()
139   {
140     return viewport;
141   }
142
143   public SeqCanvas getSeqcanvas()
144   {
145     return alignPanel.seqPanel.seqCanvas;
146   }
147
148   /**
149    * DOCUMENT ME!
150    * 
151    * @param String
152    *                DOCUMENT ME!
153    */
154
155   public void parseFeaturesFile(String file, String type)
156   {
157     Hashtable featureLinks = new Hashtable();
158     boolean featuresFile = false;
159     try
160     {
161       featuresFile = new jalview.io.FeaturesFile(file, type).parse(
162               viewport.alignment, alignPanel.seqPanel.seqCanvas
163                       .getFeatureRenderer().featureColours, featureLinks,
164               true);
165     } catch (Exception ex)
166     {
167       ex.printStackTrace();
168     }
169
170     if (featuresFile)
171     {
172       if (featureLinks.size() > 0)
173       {
174         alignPanel.seqPanel.seqCanvas.getFeatureRenderer().featureLinks = featureLinks;
175       }
176       viewport.showSequenceFeatures = true;
177       sequenceFeatures.setState(true);
178       alignPanel.paintAlignment(true);
179     }
180
181   }
182
183   public void keyPressed(KeyEvent evt)
184   {
185     if (viewport.cursorMode
186             && ((evt.getKeyCode() >= KeyEvent.VK_0 && evt.getKeyCode() <= KeyEvent.VK_9) || (evt
187                     .getKeyCode() >= KeyEvent.VK_NUMPAD0 && evt
188                     .getKeyCode() <= KeyEvent.VK_NUMPAD9))
189             && Character.isDigit(evt.getKeyChar()))
190       alignPanel.seqPanel.numberPressed(evt.getKeyChar());
191
192     switch (evt.getKeyCode())
193     {
194     case 27: // escape key
195       deselectAllSequenceMenuItem_actionPerformed();
196       break;
197     case KeyEvent.VK_X:
198       if (evt.isControlDown() || evt.isMetaDown())
199       {
200         cut_actionPerformed();
201       }
202       break;
203     case KeyEvent.VK_C:
204       if (viewport.cursorMode && !evt.isControlDown())
205       {
206         alignPanel.seqPanel.setCursorColumn();
207       }
208       if (evt.isControlDown() || evt.isMetaDown())
209       {
210         copy_actionPerformed();
211       }
212       break;
213     case KeyEvent.VK_V:
214       if (evt.isControlDown())
215       {
216         paste(evt.isShiftDown());
217       }
218       break;
219     case KeyEvent.VK_A:
220       if (evt.isControlDown() || evt.isMetaDown())
221       {
222         selectAllSequenceMenuItem_actionPerformed();
223       }
224       break;
225     case KeyEvent.VK_DOWN:
226       if (viewport.cursorMode)
227       {
228         alignPanel.seqPanel.moveCursor(0, 1);
229       }
230       else
231       {
232         moveSelectedSequences(false);
233       }
234       break;
235
236     case KeyEvent.VK_UP:
237       if (viewport.cursorMode)
238       {
239         alignPanel.seqPanel.moveCursor(0, -1);
240       }
241       else
242       {
243         moveSelectedSequences(true);
244       }
245       break;
246
247     case KeyEvent.VK_LEFT:
248       if (evt.isAltDown() || !viewport.cursorMode)
249         slideSequences(false, alignPanel.seqPanel.getKeyboardNo1());
250       else
251         alignPanel.seqPanel.moveCursor(-1, 0);
252       break;
253
254     case KeyEvent.VK_RIGHT:
255       if (evt.isAltDown() || !viewport.cursorMode)
256         slideSequences(true, alignPanel.seqPanel.getKeyboardNo1());
257       else
258         alignPanel.seqPanel.moveCursor(1, 0);
259       break;
260
261     case KeyEvent.VK_SPACE:
262       if (viewport.cursorMode)
263       {
264         alignPanel.seqPanel.insertGapAtCursor(evt.isControlDown()
265                 || evt.isShiftDown() || evt.isAltDown());
266       }
267       break;
268
269     case KeyEvent.VK_DELETE:
270     case KeyEvent.VK_BACK_SPACE:
271       if (viewport.cursorMode)
272       {
273         alignPanel.seqPanel.deleteGapAtCursor(evt.isControlDown()
274                 || evt.isShiftDown() || evt.isAltDown());
275       }
276       else
277       {
278         cut_actionPerformed();
279         alignPanel.seqPanel.seqCanvas.repaint();
280       }
281       break;
282
283     case KeyEvent.VK_S:
284       if (viewport.cursorMode)
285       {
286         alignPanel.seqPanel.setCursorRow();
287       }
288       break;
289     case KeyEvent.VK_P:
290       if (viewport.cursorMode)
291       {
292         alignPanel.seqPanel.setCursorPosition();
293       }
294       break;
295
296     case KeyEvent.VK_ENTER:
297     case KeyEvent.VK_COMMA:
298       if (viewport.cursorMode)
299       {
300         alignPanel.seqPanel.setCursorRowAndColumn();
301       }
302       break;
303
304     case KeyEvent.VK_Q:
305       if (viewport.cursorMode)
306       {
307         alignPanel.seqPanel.setSelectionAreaAtCursor(true);
308       }
309       break;
310     case KeyEvent.VK_M:
311       if (viewport.cursorMode)
312       {
313         alignPanel.seqPanel.setSelectionAreaAtCursor(false);
314       }
315       break;
316
317     case KeyEvent.VK_F2:
318       viewport.cursorMode = !viewport.cursorMode;
319       statusBar.setText("Keyboard editing mode is "
320               + (viewport.cursorMode ? "on" : "off"));
321       if (viewport.cursorMode)
322       {
323         alignPanel.seqPanel.seqCanvas.cursorX = viewport.startRes;
324         alignPanel.seqPanel.seqCanvas.cursorY = viewport.startSeq;
325       }
326       break;
327
328     case KeyEvent.VK_F:
329       if (evt.isControlDown())
330       {
331         findMenuItem_actionPerformed();
332       }
333       break;
334
335     case KeyEvent.VK_H:
336     {
337       boolean toggleSeqs = !evt.isControlDown();
338       boolean toggleCols = !evt.isShiftDown();
339       boolean hide = false;
340       SequenceGroup sg = viewport.getSelectionGroup();
341
342       if (toggleSeqs)
343       {
344         if (sg != null && sg.getSize() != viewport.alignment.getHeight())
345         {
346           hide = true;
347           viewport.hideAllSelectedSeqs();
348         }
349         else if (!(toggleCols && viewport.colSel.getSelected().size() > 0))
350         {
351           viewport.showAllHiddenSeqs();
352         }
353       }
354
355       if (toggleCols)
356       {
357         if (viewport.colSel.getSelected().size() > 0)
358         {
359           viewport.hideSelectedColumns();
360           if (!toggleSeqs)
361           {
362             viewport.selectionGroup = sg;
363           }
364         }
365         else if (!hide)
366         {
367           viewport.showAllHiddenColumns();
368         }
369       }
370       break;
371     }
372
373     case KeyEvent.VK_PAGE_UP:
374       if (viewport.wrapAlignment)
375       {
376         alignPanel.scrollUp(true);
377       }
378       else
379       {
380         alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
381                 - viewport.endSeq + viewport.startSeq);
382       }
383       break;
384
385     case KeyEvent.VK_PAGE_DOWN:
386       if (viewport.wrapAlignment)
387       {
388         alignPanel.scrollUp(false);
389       }
390       else
391       {
392         alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
393                 + viewport.endSeq - viewport.startSeq);
394       }
395       break;
396
397     case KeyEvent.VK_Z:
398       if (evt.isControlDown())
399       {
400         undoMenuItem_actionPerformed();
401       }
402       break;
403
404     case KeyEvent.VK_Y:
405       if (evt.isControlDown())
406       {
407         redoMenuItem_actionPerformed();
408       }
409       break;
410
411     case KeyEvent.VK_L:
412       if (evt.isControlDown())
413       {
414         trimAlignment(true);
415       }
416       break;
417
418     case KeyEvent.VK_R:
419       if (evt.isControlDown())
420       {
421         trimAlignment(false);
422       }
423       break;
424
425     case KeyEvent.VK_E:
426       if (evt.isControlDown())
427       {
428         if (evt.isShiftDown())
429         {
430           this.removeAllGapsMenuItem_actionPerformed();
431         }
432         else
433         {
434           removeGappedColumnMenuItem_actionPerformed();
435         }
436       }
437       break;
438     case KeyEvent.VK_I:
439       if (evt.isControlDown())
440       {
441         if (evt.isAltDown())
442         {
443           viewport.invertColumnSelection();
444         }
445         else
446         {
447           this.invertSequenceMenuItem_actionPerformed();
448         }
449       }
450       break;
451
452     case KeyEvent.VK_U:
453       if (evt.isControlDown())
454       {
455         this.deleteGroups_actionPerformed();
456       }
457       break;
458
459     case KeyEvent.VK_T:
460       if (evt.isControlDown())
461       {
462         newView(null);
463       }
464       break;
465
466     }
467     alignPanel.paintAlignment(true);
468   }
469
470   public void keyReleased(KeyEvent evt)
471   {
472   }
473
474   public void keyTyped(KeyEvent evt)
475   {
476   }
477
478   public void itemStateChanged(ItemEvent evt)
479   {
480     if (evt.getSource() == colourTextMenuItem)
481     {
482       colourTextMenuItem_actionPerformed();
483     }
484     else if (evt.getSource() == wrapMenuItem)
485     {
486       wrapMenuItem_actionPerformed();
487     }
488     else if (evt.getSource() == scaleAbove)
489     {
490       viewport.setScaleAboveWrapped(scaleAbove.getState());
491     }
492     else if (evt.getSource() == scaleLeft)
493     {
494       viewport.setScaleLeftWrapped(scaleLeft.getState());
495     }
496     else if (evt.getSource() == scaleRight)
497     {
498       viewport.setScaleRightWrapped(scaleRight.getState());
499     }
500     else if (evt.getSource() == seqLimits)
501     {
502       seqLimits_itemStateChanged();
503     }
504     else if (evt.getSource() == viewBoxesMenuItem)
505     {
506       viewport.setShowBoxes(viewBoxesMenuItem.getState());
507     }
508     else if (evt.getSource() == viewTextMenuItem)
509     {
510       viewport.setShowText(viewTextMenuItem.getState());
511     }
512     else if (evt.getSource() == renderGapsMenuItem)
513     {
514       viewport.setRenderGaps(renderGapsMenuItem.getState());
515     }
516     else if (evt.getSource() == annotationPanelMenuItem)
517     {
518       viewport.setShowAnnotation(annotationPanelMenuItem.getState());
519       alignPanel.setAnnotationVisible(annotationPanelMenuItem.getState());
520     }
521     else if (evt.getSource() == sequenceFeatures)
522     {
523       viewport.showSequenceFeatures(sequenceFeatures.getState());
524       alignPanel.seqPanel.seqCanvas.repaint();
525     }
526     else if (evt.getSource() == conservationMenuItem)
527     {
528       conservationMenuItem_actionPerformed();
529     }
530     else if (evt.getSource() == abovePIDThreshold)
531     {
532       abovePIDThreshold_actionPerformed();
533     }
534     else if (evt.getSource() == applyToAllGroups)
535     {
536       viewport.setColourAppliesToAllGroups(applyToAllGroups.getState());
537     }
538     else if (evt.getSource() == autoCalculate)
539     {
540       viewport.autocalculateConsensus = autoCalculate.getState();
541     }
542     else if (evt.getSource() == this.centreColumnLabelFlag)
543     {
544       centreColumnLabelFlag_stateChanged();
545     }
546
547     alignPanel.paintAlignment(true);
548   }
549
550   private void centreColumnLabelFlag_stateChanged()
551   {
552     viewport.centreColumnLabels = centreColumnLabelFlag.getState();
553     this.alignPanel.annotationPanel.repaint();
554   }
555
556   public void actionPerformed(ActionEvent evt)
557   {
558     Object source = evt.getSource();
559
560     if (source == inputText)
561     {
562       inputText_actionPerformed();
563     }
564     else if (source == loadTree)
565     {
566       loadTree_actionPerformed();
567     }
568     else if (source == loadApplication)
569     {
570       launchFullApplication();
571     }
572     else if (source == loadAnnotations)
573     {
574       loadAnnotations();
575     }
576     else if (source == outputAnnotations)
577     {
578       outputAnnotations(true);
579     }
580     else if (source == outputFeatures)
581     {
582       outputFeatures(true, "Jalview");
583     }
584     else if (source == closeMenuItem)
585     {
586       closeMenuItem_actionPerformed();
587     }
588     else if (source == copy)
589     {
590       copy_actionPerformed();
591     }
592     else if (source == undoMenuItem)
593     {
594       undoMenuItem_actionPerformed();
595     }
596     else if (source == redoMenuItem)
597     {
598       redoMenuItem_actionPerformed();
599     }
600     else if (source == inputText)
601     {
602       inputText_actionPerformed();
603     }
604     else if (source == closeMenuItem)
605     {
606       closeMenuItem_actionPerformed();
607     }
608     else if (source == undoMenuItem)
609     {
610       undoMenuItem_actionPerformed();
611     }
612     else if (source == redoMenuItem)
613     {
614       redoMenuItem_actionPerformed();
615     }
616     else if (source == copy)
617     {
618       copy_actionPerformed();
619     }
620     else if (source == pasteNew)
621     {
622       pasteNew_actionPerformed();
623     }
624     else if (source == pasteThis)
625     {
626       pasteThis_actionPerformed();
627     }
628     else if (source == cut)
629     {
630       cut_actionPerformed();
631     }
632     else if (source == delete)
633     {
634       delete_actionPerformed();
635     }
636     else if (source == deleteGroups)
637     {
638       deleteGroups_actionPerformed();
639     }
640     else if (source == selectAllSequenceMenuItem)
641     {
642       selectAllSequenceMenuItem_actionPerformed();
643     }
644     else if (source == deselectAllSequenceMenuItem)
645     {
646       deselectAllSequenceMenuItem_actionPerformed();
647     }
648     else if (source == invertSequenceMenuItem)
649     {
650       invertSequenceMenuItem_actionPerformed();
651     }
652     else if (source == invertColSel)
653     {
654       viewport.invertColumnSelection();
655       alignPanel.paintAlignment(true);
656     }
657     else if (source == remove2LeftMenuItem)
658     {
659       trimAlignment(true);
660     }
661     else if (source == remove2RightMenuItem)
662     {
663       trimAlignment(false);
664     }
665     else if (source == removeGappedColumnMenuItem)
666     {
667       removeGappedColumnMenuItem_actionPerformed();
668     }
669     else if (source == removeAllGapsMenuItem)
670     {
671       removeAllGapsMenuItem_actionPerformed();
672     }
673     else if (source == findMenuItem)
674     {
675       findMenuItem_actionPerformed();
676     }
677     else if (source == font)
678     {
679       new FontChooser(alignPanel);
680     }
681     else if (source == newView)
682     {
683       newView(null);
684     }
685     else if (source == showColumns)
686     {
687       viewport.showAllHiddenColumns();
688       alignPanel.paintAlignment(true);
689     }
690     else if (source == showSeqs)
691     {
692       viewport.showAllHiddenSeqs();
693     }
694     else if (source == hideColumns)
695     {
696       viewport.hideSelectedColumns();
697       alignPanel.paintAlignment(true);
698     }
699     else if (source == hideSequences
700             && viewport.getSelectionGroup() != null)
701     {
702       viewport.hideAllSelectedSeqs();
703     }
704     else if (source == featureSettings)
705     {
706       new FeatureSettings(alignPanel);
707     }
708     else if (source == alProperties)
709     {
710       StringBuffer contents = new StringBuffer();
711
712       float avg = 0;
713       int min = Integer.MAX_VALUE, max = 0;
714       for (int i = 0; i < viewport.alignment.getHeight(); i++)
715       {
716         int size = viewport.alignment.getSequenceAt(i).getEnd()
717                 - viewport.alignment.getSequenceAt(i).getStart();
718         avg += size;
719         if (size > max)
720           max = size;
721         if (size < min)
722           min = size;
723       }
724       avg = avg / (float) viewport.alignment.getHeight();
725
726       contents.append("\nSequences: " + viewport.alignment.getHeight());
727       contents.append("\nMinimum Sequence Length: " + min);
728       contents.append("\nMaximum Sequence Length: " + max);
729       contents.append("\nAverage Length: " + (int) avg);
730
731       if (((Alignment) viewport.alignment).alignmentProperties != null)
732       {
733         Hashtable props = ((Alignment) viewport.alignment).alignmentProperties;
734         Enumeration en = props.keys();
735         while (en.hasMoreElements())
736         {
737           String key = en.nextElement().toString();
738           contents.append("\n" + key + "\t" + props.get(key));
739         }
740       }
741
742       CutAndPasteTransfer cap = new CutAndPasteTransfer(false, this);
743       cap.setText(contents.toString());
744       Frame frame = new Frame();
745       frame.add(cap);
746       jalview.bin.JalviewLite.addFrame(frame, "Alignment Properties: "
747               + getTitle(), 400, 250);
748     }
749     else if (source == overviewMenuItem)
750     {
751       overviewMenuItem_actionPerformed();
752     }
753     else if (source == noColourmenuItem)
754     {
755       changeColour(null);
756     }
757     else if (source == clustalColour)
758     {
759       abovePIDThreshold.setState(false);
760       changeColour(new ClustalxColourScheme(viewport.alignment
761               .getSequences(), viewport.alignment.getWidth()));
762     }
763     else if (source == zappoColour)
764     {
765       changeColour(new ZappoColourScheme());
766     }
767     else if (source == taylorColour)
768     {
769       changeColour(new TaylorColourScheme());
770     }
771     else if (source == hydrophobicityColour)
772     {
773       changeColour(new HydrophobicColourScheme());
774     }
775     else if (source == helixColour)
776     {
777       changeColour(new HelixColourScheme());
778     }
779     else if (source == strandColour)
780     {
781       changeColour(new StrandColourScheme());
782     }
783     else if (source == turnColour)
784     {
785       changeColour(new TurnColourScheme());
786     }
787     else if (source == buriedColour)
788     {
789       changeColour(new BuriedColourScheme());
790     }
791     else if (source == nucleotideColour)
792     {
793       changeColour(new NucleotideColourScheme());
794     }
795     else if (source == modifyPID)
796     {
797       modifyPID_actionPerformed();
798     }
799     else if (source == modifyConservation)
800     {
801       modifyConservation_actionPerformed();
802     }
803     else if (source == userDefinedColour)
804     {
805       new UserDefinedColours(alignPanel, null);
806     }
807     else if (source == PIDColour)
808     {
809       changeColour(new PIDColourScheme());
810     }
811     else if (source == BLOSUM62Colour)
812     {
813       changeColour(new Blosum62ColourScheme());
814     }
815     else if (source == annotationColour)
816     {
817       new AnnotationColourChooser(viewport, alignPanel);
818     }
819     else if (source == sortPairwiseMenuItem)
820     {
821       sortPairwiseMenuItem_actionPerformed();
822     }
823     else if (source == sortIDMenuItem)
824     {
825       sortIDMenuItem_actionPerformed();
826     }
827     else if (source == sortGroupMenuItem)
828     {
829       sortGroupMenuItem_actionPerformed();
830     }
831     else if (source == removeRedundancyMenuItem)
832     {
833       removeRedundancyMenuItem_actionPerformed();
834     }
835     else if (source == pairwiseAlignmentMenuItem)
836     {
837       pairwiseAlignmentMenuItem_actionPerformed();
838     }
839     else if (source == PCAMenuItem)
840     {
841       PCAMenuItem_actionPerformed();
842     }
843     else if (source == averageDistanceTreeMenuItem)
844     {
845       averageDistanceTreeMenuItem_actionPerformed();
846     }
847     else if (source == neighbourTreeMenuItem)
848     {
849       neighbourTreeMenuItem_actionPerformed();
850     }
851     else if (source == njTreeBlosumMenuItem)
852     {
853       njTreeBlosumMenuItem_actionPerformed();
854     }
855     else if (source == avDistanceTreeBlosumMenuItem)
856     {
857       avTreeBlosumMenuItem_actionPerformed();
858     }
859     else if (source == documentation)
860     {
861       documentation_actionPerformed();
862     }
863     else if (source == about)
864     {
865       about_actionPerformed();
866     }
867
868   }
869
870   public void inputText_actionPerformed()
871   {
872     CutAndPasteTransfer cap = new CutAndPasteTransfer(true, this);
873     Frame frame = new Frame();
874     frame.add(cap);
875     jalview.bin.JalviewLite.addFrame(frame, "Cut & Paste Input", 500, 500);
876   }
877
878   protected void outputText_actionPerformed(ActionEvent e)
879   {
880     CutAndPasteTransfer cap = new CutAndPasteTransfer(true, this);
881     Frame frame = new Frame();
882     frame.add(cap);
883     jalview.bin.JalviewLite.addFrame(frame, "Alignment output - "
884             + e.getActionCommand(), 600, 500);
885     cap.setText(new AppletFormatAdapter().formatSequences(e
886             .getActionCommand(), viewport.getAlignment(),
887             viewport.showJVSuffix));
888   }
889
890   public void loadAnnotations()
891   {
892     CutAndPasteTransfer cap = new CutAndPasteTransfer(true, this);
893     cap.setText("Paste your features / annotations file here.");
894     cap.setAnnotationImport();
895     Frame frame = new Frame();
896     frame.add(cap);
897     jalview.bin.JalviewLite.addFrame(frame, "Paste Annotations ", 400, 300);
898
899   }
900
901   public String outputAnnotations(boolean displayTextbox)
902   {
903     String annotation = new AnnotationFile().printAnnotations(
904             viewport.showAnnotation ? viewport.alignment
905                     .getAlignmentAnnotation() : null, viewport.alignment
906                     .getGroups(),
907             ((Alignment) viewport.alignment).alignmentProperties);
908
909     if (displayTextbox)
910     {
911       CutAndPasteTransfer cap = new CutAndPasteTransfer(false, this);
912       Frame frame = new Frame();
913       frame.add(cap);
914       jalview.bin.JalviewLite.addFrame(frame, "Annotations", 600, 500);
915       cap.setText(annotation);
916     }
917
918     return annotation;
919   }
920
921   public String outputFeatures(boolean displayTextbox, String format)
922   {
923     String features;
924     if (format.equalsIgnoreCase("Jalview"))
925     {
926       features = new FeaturesFile().printJalviewFormat(viewport.alignment
927               .getSequencesArray(), viewport.featuresDisplayed);
928     }
929     else
930     {
931       features = new FeaturesFile().printGFFFormat(viewport.alignment
932               .getSequencesArray(), viewport.featuresDisplayed);
933     }
934
935     if (displayTextbox)
936     {
937       CutAndPasteTransfer cap = new CutAndPasteTransfer(false, this);
938       Frame frame = new Frame();
939       frame.add(cap);
940       jalview.bin.JalviewLite.addFrame(frame, "Features", 600, 500);
941
942       cap.setText(features);
943     }
944
945     return features;
946   }
947
948   void launchFullApplication()
949   {
950     StringBuffer url = new StringBuffer(jalviewServletURL);
951
952     url.append("?open="
953             + appendProtocol(viewport.applet.getParameter("file")));
954
955     if (viewport.applet.getParameter("features") != null)
956     {
957       url.append("&features=");
958       url.append(appendProtocol(viewport.applet.getParameter("features")));
959     }
960
961     if (viewport.applet.getParameter("annotations") != null)
962     {
963       url.append("&annotations=");
964       url
965               .append(appendProtocol(viewport.applet
966                       .getParameter("annotations")));
967     }
968
969     if (viewport.applet.getParameter("jnetfile") != null)
970     {
971       url.append("&annotations=");
972       url.append(appendProtocol(viewport.applet.getParameter("jnetfile")));
973     }
974
975     if (viewport.applet.getParameter("defaultColour") != null)
976     {
977       url.append("&colour="
978               + removeWhiteSpace(viewport.applet
979                       .getParameter("defaultColour")));
980     }
981
982     if (viewport.applet.getParameter("userDefinedColour") != null)
983     {
984       url.append("&colour="
985               + removeWhiteSpace(viewport.applet
986                       .getParameter("userDefinedColour")));
987     }
988     if (viewport.applet.getParameter("tree") != null)
989     {
990       url.append("&tree="
991               + appendProtocol(viewport.applet.getParameter("tree")));
992     }
993     if (viewport.applet.getParameter("treeFile") != null)
994     {
995       url.append("&tree="
996               + appendProtocol(viewport.applet.getParameter("treeFile")));
997     }
998
999     showURL(url.toString(), "FULL_APP");
1000   }
1001
1002   String removeWhiteSpace(String colour)
1003   {
1004     StringBuffer sb = new StringBuffer();
1005     for (int i = 0; i < colour.length(); i++)
1006     {
1007       if (Character.isWhitespace(colour.charAt(i)))
1008       {
1009         sb.append("%20");
1010       }
1011       else
1012       {
1013         sb.append(colour.charAt(i));
1014       }
1015     }
1016
1017     return sb.toString();
1018   }
1019
1020   String appendProtocol(String url)
1021   {
1022     try
1023     {
1024       new URL(url);
1025       url = URLEncoder.encode(url);
1026     }
1027     /*
1028      * When we finally deprecate 1.1 compatibility, we can start to use
1029      * URLEncoder.encode(url,"UTF-8") and then we'll need this catch: catch
1030      * (UnsupportedEncodingException ex) { System.err.println("WARNING -
1031      * IMPLEMENTATION ERROR - UNSUPPORTED ENCODING EXCEPTION FOR "+url);
1032      * ex.printStackTrace(); }
1033      */
1034     catch (java.net.MalformedURLException ex)
1035     {
1036       url = viewport.applet.getCodeBase() + url;
1037     }
1038     return url;
1039   }
1040
1041   public void closeMenuItem_actionPerformed()
1042   {
1043     PaintRefresher.RemoveComponent(alignPanel);
1044     PaintRefresher.RemoveComponent(alignPanel.seqPanel.seqCanvas);
1045     PaintRefresher.RemoveComponent(alignPanel.idPanel.idCanvas);
1046
1047     if (PaintRefresher.components.size() == 0 && viewport.applet == null)
1048     {
1049       System.exit(0);
1050     }
1051
1052     this.dispose();
1053   }
1054
1055   /**
1056    * DOCUMENT ME!
1057    */
1058   void updateEditMenuBar()
1059   {
1060
1061     if (viewport.historyList.size() > 0)
1062     {
1063       undoMenuItem.setEnabled(true);
1064       CommandI command = (CommandI) viewport.historyList.peek();
1065       undoMenuItem.setLabel("Undo " + command.getDescription());
1066     }
1067     else
1068     {
1069       undoMenuItem.setEnabled(false);
1070       undoMenuItem.setLabel("Undo");
1071     }
1072
1073     if (viewport.redoList.size() > 0)
1074     {
1075       redoMenuItem.setEnabled(true);
1076
1077       CommandI command = (CommandI) viewport.redoList.peek();
1078       redoMenuItem.setLabel("Redo " + command.getDescription());
1079     }
1080     else
1081     {
1082       redoMenuItem.setEnabled(false);
1083       redoMenuItem.setLabel("Redo");
1084     }
1085   }
1086
1087   public void addHistoryItem(CommandI command)
1088   {
1089     if (command.getSize() > 0)
1090     {
1091       viewport.historyList.push(command);
1092       viewport.redoList.removeAllElements();
1093       updateEditMenuBar();
1094       viewport.hasHiddenColumns = viewport.colSel.getHiddenColumns() != null;
1095     }
1096   }
1097
1098   /**
1099    * DOCUMENT ME!
1100    * 
1101    * @param e
1102    *                DOCUMENT ME!
1103    */
1104   protected void undoMenuItem_actionPerformed()
1105   {
1106     if (viewport.historyList.size() < 1)
1107     {
1108       return;
1109     }
1110
1111     CommandI command = (CommandI) viewport.historyList.pop();
1112     viewport.redoList.push(command);
1113     command.undoCommand(null);
1114
1115     AlignViewport originalSource = getOriginatingSource(command);
1116
1117     originalSource.hasHiddenColumns = viewport.colSel.getHiddenColumns() != null;
1118     updateEditMenuBar();
1119     originalSource.firePropertyChange("alignment", null,
1120             originalSource.alignment.getSequences());
1121   }
1122
1123   /**
1124    * DOCUMENT ME!
1125    * 
1126    * @param e
1127    *                DOCUMENT ME!
1128    */
1129   protected void redoMenuItem_actionPerformed()
1130   {
1131     if (viewport.redoList.size() < 1)
1132     {
1133       return;
1134     }
1135
1136     CommandI command = (CommandI) viewport.redoList.pop();
1137     viewport.historyList.push(command);
1138     command.doCommand(null);
1139
1140     AlignViewport originalSource = getOriginatingSource(command);
1141     originalSource.hasHiddenColumns = viewport.colSel.getHiddenColumns() != null;
1142
1143     updateEditMenuBar();
1144     originalSource.firePropertyChange("alignment", null,
1145             originalSource.alignment.getSequences());
1146   }
1147
1148   AlignViewport getOriginatingSource(CommandI command)
1149   {
1150     AlignViewport originalSource = null;
1151     // For sequence removal and addition, we need to fire
1152     // the property change event FROM the viewport where the
1153     // original alignment was altered
1154     AlignmentI al = null;
1155     if (command instanceof EditCommand)
1156     {
1157       EditCommand editCommand = (EditCommand) command;
1158       al = editCommand.getAlignment();
1159       Vector comps = (Vector) PaintRefresher.components.get(viewport
1160               .getSequenceSetId());
1161       for (int i = 0; i < comps.size(); i++)
1162       {
1163         if (comps.elementAt(i) instanceof AlignmentPanel)
1164         {
1165           if (al == ((AlignmentPanel) comps.elementAt(i)).av.alignment)
1166           {
1167             originalSource = ((AlignmentPanel) comps.elementAt(i)).av;
1168             break;
1169           }
1170         }
1171       }
1172     }
1173
1174     if (originalSource == null)
1175     {
1176       // The original view is closed, we must validate
1177       // the current view against the closed view first
1178       if (al != null)
1179       {
1180         PaintRefresher.validateSequences(al, viewport.alignment);
1181       }
1182
1183       originalSource = viewport;
1184     }
1185
1186     return originalSource;
1187   }
1188
1189   public void moveSelectedSequences(boolean up)
1190   {
1191     SequenceGroup sg = viewport.getSelectionGroup();
1192     if (sg == null)
1193     {
1194       return;
1195     }
1196
1197     if (up)
1198     {
1199       for (int i = 1; i < viewport.alignment.getHeight(); i++)
1200       {
1201         SequenceI seq = viewport.alignment.getSequenceAt(i);
1202         if (!sg.getSequences(null).contains(seq))
1203         {
1204           continue;
1205         }
1206
1207         SequenceI temp = viewport.alignment.getSequenceAt(i - 1);
1208         if (sg.getSequences(null).contains(temp))
1209         {
1210           continue;
1211         }
1212
1213         viewport.alignment.getSequences().setElementAt(temp, i);
1214         viewport.alignment.getSequences().setElementAt(seq, i - 1);
1215       }
1216     }
1217     else
1218     {
1219       for (int i = viewport.alignment.getHeight() - 2; i > -1; i--)
1220       {
1221         SequenceI seq = viewport.alignment.getSequenceAt(i);
1222         if (!sg.getSequences(viewport.hiddenRepSequences).contains(seq))
1223         {
1224           continue;
1225         }
1226
1227         SequenceI temp = viewport.alignment.getSequenceAt(i + 1);
1228         if (sg.getSequences(viewport.hiddenRepSequences).contains(temp))
1229         {
1230           continue;
1231         }
1232
1233         viewport.alignment.getSequences().setElementAt(temp, i);
1234         viewport.alignment.getSequences().setElementAt(seq, i + 1);
1235       }
1236     }
1237
1238     alignPanel.paintAlignment(true);
1239   }
1240
1241   synchronized void slideSequences(boolean right, int size)
1242   {
1243     Vector sg = new Vector();
1244     if (viewport.cursorMode)
1245     {
1246       sg.addElement(viewport.alignment
1247               .getSequenceAt(alignPanel.seqPanel.seqCanvas.cursorY));
1248     }
1249     else if (viewport.getSelectionGroup() != null
1250             && viewport.getSelectionGroup().getSize() != viewport.alignment
1251                     .getHeight())
1252     {
1253       sg = viewport.getSelectionGroup().getSequences(
1254               viewport.hiddenRepSequences);
1255     }
1256
1257     if (sg.size() < 1)
1258     {
1259       return;
1260     }
1261
1262     Vector invertGroup = new Vector();
1263
1264     for (int i = 0; i < viewport.alignment.getHeight(); i++)
1265     {
1266       if (!sg.contains(viewport.alignment.getSequenceAt(i)))
1267         invertGroup.addElement(viewport.alignment.getSequenceAt(i));
1268     }
1269
1270     SequenceI[] seqs1 = new SequenceI[sg.size()];
1271     for (int i = 0; i < sg.size(); i++)
1272       seqs1[i] = (SequenceI) sg.elementAt(i);
1273
1274     SequenceI[] seqs2 = new SequenceI[invertGroup.size()];
1275     for (int i = 0; i < invertGroup.size(); i++)
1276       seqs2[i] = (SequenceI) invertGroup.elementAt(i);
1277
1278     SlideSequencesCommand ssc;
1279     if (right)
1280       ssc = new SlideSequencesCommand("Slide Sequences", seqs2, seqs1,
1281               size, viewport.getGapCharacter());
1282     else
1283       ssc = new SlideSequencesCommand("Slide Sequences", seqs1, seqs2,
1284               size, viewport.getGapCharacter());
1285
1286     int groupAdjustment = 0;
1287     if (ssc.getGapsInsertedBegin() && right)
1288     {
1289       if (viewport.cursorMode)
1290         alignPanel.seqPanel.moveCursor(size, 0);
1291       else
1292         groupAdjustment = size;
1293     }
1294     else if (!ssc.getGapsInsertedBegin() && !right)
1295     {
1296       if (viewport.cursorMode)
1297         alignPanel.seqPanel.moveCursor(-size, 0);
1298       else
1299         groupAdjustment = -size;
1300     }
1301
1302     if (groupAdjustment != 0)
1303     {
1304       viewport.getSelectionGroup().setStartRes(
1305               viewport.getSelectionGroup().getStartRes() + groupAdjustment);
1306       viewport.getSelectionGroup().setEndRes(
1307               viewport.getSelectionGroup().getEndRes() + groupAdjustment);
1308     }
1309
1310     boolean appendHistoryItem = false;
1311     if (viewport.historyList != null && viewport.historyList.size() > 0
1312             && viewport.historyList.peek() instanceof SlideSequencesCommand)
1313     {
1314       appendHistoryItem = ssc
1315               .appendSlideCommand((SlideSequencesCommand) viewport.historyList
1316                       .peek());
1317     }
1318
1319     if (!appendHistoryItem)
1320       addHistoryItem(ssc);
1321
1322     repaint();
1323   }
1324
1325   static StringBuffer copiedSequences;
1326
1327   static Vector copiedHiddenColumns;
1328
1329   protected void copy_actionPerformed()
1330   {
1331     if (viewport.getSelectionGroup() == null)
1332     {
1333       return;
1334     }
1335
1336     SequenceGroup sg = viewport.getSelectionGroup();
1337     copiedSequences = new StringBuffer();
1338     Hashtable orderedSeqs = new Hashtable();
1339     for (int i = 0; i < sg.getSize(); i++)
1340     {
1341       SequenceI seq = sg.getSequenceAt(i);
1342       int index = viewport.alignment.findIndex(seq);
1343       orderedSeqs.put(index + "", seq);
1344     }
1345
1346     int index = 0, startRes, endRes;
1347     char ch;
1348
1349     if (viewport.hasHiddenColumns && viewport.getSelectionGroup() != null)
1350     {
1351       copiedHiddenColumns = new Vector();
1352       int hiddenOffset = viewport.getSelectionGroup().getStartRes();
1353       for (int i = 0; i < viewport.getColumnSelection().getHiddenColumns()
1354               .size(); i++)
1355       {
1356         int[] region = (int[]) viewport.getColumnSelection()
1357                 .getHiddenColumns().elementAt(i);
1358
1359         copiedHiddenColumns.addElement(new int[]
1360         { region[0] - hiddenOffset, region[1] - hiddenOffset });
1361       }
1362     }
1363     else
1364     {
1365       copiedHiddenColumns = null;
1366     }
1367
1368     for (int i = 0; i < sg.getSize(); i++)
1369     {
1370       SequenceI seq = null;
1371
1372       while (seq == null)
1373       {
1374         if (orderedSeqs.containsKey(index + ""))
1375         {
1376           seq = (SequenceI) orderedSeqs.get(index + "");
1377           index++;
1378
1379           break;
1380         }
1381         else
1382         {
1383           index++;
1384         }
1385       }
1386
1387       // FIND START RES
1388       // Returns residue following index if gap
1389       startRes = seq.findPosition(sg.getStartRes());
1390
1391       // FIND END RES
1392       // Need to find the residue preceeding index if gap
1393       endRes = 0;
1394
1395       for (int j = 0; j < sg.getEndRes() + 1 && j < seq.getLength(); j++)
1396       {
1397         ch = seq.getCharAt(j);
1398         if (!jalview.util.Comparison.isGap((ch)))
1399         {
1400           endRes++;
1401         }
1402       }
1403
1404       if (endRes > 0)
1405       {
1406         endRes += seq.getStart() - 1;
1407       }
1408
1409       copiedSequences.append(seq.getName()
1410               + "\t"
1411               + startRes
1412               + "\t"
1413               + endRes
1414               + "\t"
1415               + seq.getSequenceAsString(sg.getStartRes(),
1416                       sg.getEndRes() + 1) + "\n");
1417     }
1418
1419   }
1420
1421   protected void pasteNew_actionPerformed()
1422   {
1423     paste(true);
1424   }
1425
1426   protected void pasteThis_actionPerformed()
1427   {
1428     paste(false);
1429   }
1430
1431   void paste(boolean newAlignment)
1432   {
1433     try
1434     {
1435
1436       if (copiedSequences == null)
1437       {
1438         return;
1439       }
1440
1441       StringTokenizer st = new StringTokenizer(copiedSequences.toString());
1442       Vector seqs = new Vector();
1443       while (st.hasMoreElements())
1444       {
1445         String name = st.nextToken();
1446         int start = Integer.parseInt(st.nextToken());
1447         int end = Integer.parseInt(st.nextToken());
1448         seqs.addElement(new Sequence(name, st.nextToken(), start, end));
1449       }
1450       SequenceI[] newSeqs = new SequenceI[seqs.size()];
1451       for (int i = 0; i < seqs.size(); i++)
1452       {
1453         newSeqs[i] = (SequenceI) seqs.elementAt(i);
1454       }
1455
1456       if (newAlignment)
1457       {
1458         String newtitle = new String("Copied sequences");
1459         if (getTitle().startsWith("Copied sequences"))
1460         {
1461           newtitle = getTitle();
1462         }
1463         else
1464         {
1465           newtitle = newtitle.concat("- from " + getTitle());
1466         }
1467         AlignFrame af = new AlignFrame(new Alignment(newSeqs),
1468                 viewport.applet, newtitle, false);
1469         if (copiedHiddenColumns != null)
1470         {
1471           for (int i = 0; i < copiedHiddenColumns.size(); i++)
1472           {
1473             int[] region = (int[]) copiedHiddenColumns.elementAt(i);
1474             af.viewport.hideColumns(region[0], region[1]);
1475           }
1476         }
1477
1478         jalview.bin.JalviewLite.addFrame(af, newtitle, DEFAULT_WIDTH,
1479                 DEFAULT_HEIGHT);
1480       }
1481       else
1482       {
1483         addSequences(newSeqs);
1484       }
1485
1486     } catch (Exception ex)
1487     {
1488     } // could be anything being pasted in here
1489
1490   }
1491
1492   void addSequences(SequenceI[] seqs)
1493   {
1494     for (int i = 0; i < seqs.length; i++)
1495     {
1496       viewport.alignment.addSequence(seqs[i]);
1497     }
1498
1499     // !newAlignment
1500     addHistoryItem(new EditCommand("Add sequences", EditCommand.PASTE,
1501             seqs, 0, viewport.alignment.getWidth(), viewport.alignment));
1502
1503     viewport.setEndSeq(viewport.alignment.getHeight());
1504     viewport.alignment.getWidth();
1505     viewport.firePropertyChange("alignment", null, viewport.alignment
1506             .getSequences());
1507
1508   }
1509
1510   protected void cut_actionPerformed()
1511   {
1512     copy_actionPerformed();
1513     delete_actionPerformed();
1514   }
1515
1516   protected void delete_actionPerformed()
1517   {
1518
1519     SequenceGroup sg = viewport.getSelectionGroup();
1520     if (sg == null)
1521     {
1522       return;
1523     }
1524
1525     Vector seqs = new Vector();
1526     SequenceI seq;
1527     for (int i = 0; i < sg.getSize(); i++)
1528     {
1529       seq = sg.getSequenceAt(i);
1530       seqs.addElement(seq);
1531     }
1532
1533     // If the cut affects all sequences, remove highlighted columns
1534     if (sg.getSize() == viewport.alignment.getHeight())
1535     {
1536       viewport.getColumnSelection().removeElements(sg.getStartRes(),
1537               sg.getEndRes() + 1);
1538     }
1539
1540     SequenceI[] cut = new SequenceI[seqs.size()];
1541     for (int i = 0; i < seqs.size(); i++)
1542     {
1543       cut[i] = (SequenceI) seqs.elementAt(i);
1544     }
1545
1546     /*
1547      * //ADD HISTORY ITEM
1548      */
1549     addHistoryItem(new EditCommand("Cut Sequences", EditCommand.CUT, cut,
1550             sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,
1551             viewport.alignment));
1552
1553     viewport.setSelectionGroup(null);
1554     viewport.alignment.deleteGroup(sg);
1555
1556     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
1557             .getSequences());
1558
1559     if (viewport.getAlignment().getHeight() < 1)
1560     {
1561       this.setVisible(false);
1562     }
1563   }
1564
1565   protected void deleteGroups_actionPerformed()
1566   {
1567     viewport.alignment.deleteAllGroups();
1568     viewport.sequenceColours = null;
1569     viewport.setSelectionGroup(null);
1570
1571     alignPanel.paintAlignment(true);
1572   }
1573
1574   public void selectAllSequenceMenuItem_actionPerformed()
1575   {
1576     SequenceGroup sg = new SequenceGroup();
1577     for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
1578     {
1579       sg.addSequence(viewport.getAlignment().getSequenceAt(i), false);
1580     }
1581     sg.setEndRes(viewport.alignment.getWidth() - 1);
1582     viewport.setSelectionGroup(sg);
1583     alignPanel.paintAlignment(true);
1584     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
1585   }
1586
1587   public void deselectAllSequenceMenuItem_actionPerformed()
1588   {
1589     if (viewport.cursorMode)
1590     {
1591       alignPanel.seqPanel.keyboardNo1 = null;
1592       alignPanel.seqPanel.keyboardNo2 = null;
1593     }
1594     viewport.setSelectionGroup(null);
1595     viewport.getColumnSelection().clear();
1596     viewport.setSelectionGroup(null);
1597     alignPanel.idPanel.idCanvas.searchResults = null;
1598     alignPanel.seqPanel.seqCanvas.highlightSearchResults(null);
1599     alignPanel.paintAlignment(true);
1600     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
1601   }
1602
1603   public void invertSequenceMenuItem_actionPerformed()
1604   {
1605     SequenceGroup sg = viewport.getSelectionGroup();
1606     for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
1607     {
1608       sg.addOrRemove(viewport.getAlignment().getSequenceAt(i), false);
1609     }
1610
1611     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
1612   }
1613
1614   void trimAlignment(boolean trimLeft)
1615   {
1616     ColumnSelection colSel = viewport.getColumnSelection();
1617     int column;
1618
1619     if (colSel.size() > 0)
1620     {
1621       if (trimLeft)
1622       {
1623         column = colSel.getMin();
1624       }
1625       else
1626       {
1627         column = colSel.getMax();
1628       }
1629
1630       SequenceI[] seqs;
1631       if (viewport.getSelectionGroup() != null)
1632       {
1633         seqs = viewport.getSelectionGroup().getSequencesAsArray(
1634                 viewport.hiddenRepSequences);
1635       }
1636       else
1637       {
1638         seqs = viewport.alignment.getSequencesArray();
1639       }
1640
1641       TrimRegionCommand trimRegion;
1642       if (trimLeft)
1643       {
1644         trimRegion = new TrimRegionCommand("Remove Left",
1645                 TrimRegionCommand.TRIM_LEFT, seqs, column,
1646                 viewport.alignment, viewport.colSel,
1647                 viewport.selectionGroup);
1648         viewport.setStartRes(0);
1649       }
1650       else
1651       {
1652         trimRegion = new TrimRegionCommand("Remove Right",
1653                 TrimRegionCommand.TRIM_RIGHT, seqs, column,
1654                 viewport.alignment, viewport.colSel,
1655                 viewport.selectionGroup);
1656       }
1657
1658       statusBar.setText("Removed " + trimRegion.getSize() + " columns.");
1659
1660       addHistoryItem(trimRegion);
1661
1662       Vector groups = viewport.alignment.getGroups();
1663
1664       for (int i = 0; i < groups.size(); i++)
1665       {
1666         SequenceGroup sg = (SequenceGroup) groups.elementAt(i);
1667
1668         if ((trimLeft && !sg.adjustForRemoveLeft(column))
1669                 || (!trimLeft && !sg.adjustForRemoveRight(column)))
1670         {
1671           viewport.alignment.deleteGroup(sg);
1672         }
1673       }
1674
1675       viewport.firePropertyChange("alignment", null, viewport
1676               .getAlignment().getSequences());
1677     }
1678   }
1679
1680   public void removeGappedColumnMenuItem_actionPerformed()
1681   {
1682     int start = 0, end = viewport.alignment.getWidth() - 1;
1683
1684     SequenceI[] seqs;
1685     if (viewport.getSelectionGroup() != null)
1686     {
1687       seqs = viewport.getSelectionGroup().getSequencesAsArray(
1688               viewport.hiddenRepSequences);
1689       start = viewport.getSelectionGroup().getStartRes();
1690       end = viewport.getSelectionGroup().getEndRes();
1691     }
1692     else
1693     {
1694       seqs = viewport.alignment.getSequencesArray();
1695     }
1696
1697     RemoveGapColCommand removeGapCols = new RemoveGapColCommand(
1698             "Remove Gapped Columns", seqs, start, end, viewport.alignment);
1699
1700     addHistoryItem(removeGapCols);
1701
1702     statusBar.setText("Removed " + removeGapCols.getSize()
1703             + " empty columns.");
1704
1705     // This is to maintain viewport position on first residue
1706     // of first sequence
1707     SequenceI seq = viewport.alignment.getSequenceAt(0);
1708     int startRes = seq.findPosition(viewport.startRes);
1709     // ShiftList shifts;
1710     // viewport.getAlignment().removeGaps(shifts=new ShiftList());
1711     // edit.alColumnChanges=shifts.getInverse();
1712     // if (viewport.hasHiddenColumns)
1713     // viewport.getColumnSelection().compensateForEdits(shifts);
1714     viewport.setStartRes(seq.findIndex(startRes) - 1);
1715     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
1716             .getSequences());
1717
1718   }
1719
1720   public void removeAllGapsMenuItem_actionPerformed()
1721   {
1722     int start = 0, end = viewport.alignment.getWidth() - 1;
1723
1724     SequenceI[] seqs;
1725     if (viewport.getSelectionGroup() != null)
1726     {
1727       seqs = viewport.getSelectionGroup().getSequencesAsArray(
1728               viewport.hiddenRepSequences);
1729       start = viewport.getSelectionGroup().getStartRes();
1730       end = viewport.getSelectionGroup().getEndRes();
1731     }
1732     else
1733     {
1734       seqs = viewport.alignment.getSequencesArray();
1735     }
1736
1737     // This is to maintain viewport position on first residue
1738     // of first sequence
1739     SequenceI seq = viewport.alignment.getSequenceAt(0);
1740     int startRes = seq.findPosition(viewport.startRes);
1741
1742     addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end,
1743             viewport.alignment));
1744
1745     viewport.setStartRes(seq.findIndex(startRes) - 1);
1746
1747     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
1748             .getSequences());
1749
1750   }
1751
1752   public void findMenuItem_actionPerformed()
1753   {
1754     new Finder(alignPanel);
1755   }
1756
1757   /**
1758    * create a new view derived from the current view
1759    * 
1760    * @param viewtitle
1761    * @return frame for the new view
1762    */
1763   public AlignFrame newView(String viewtitle)
1764   {
1765     AlignmentI newal;
1766     if (viewport.hasHiddenRows)
1767     {
1768       newal = new Alignment(viewport.getAlignment().getHiddenSequences()
1769               .getFullAlignment().getSequencesArray());
1770     }
1771     else
1772     {
1773       newal = new Alignment(viewport.alignment.getSequencesArray());
1774     }
1775
1776     if (viewport.alignment.getAlignmentAnnotation() != null)
1777     {
1778       for (int i = 0; i < viewport.alignment.getAlignmentAnnotation().length; i++)
1779       {
1780         if (!viewport.alignment.getAlignmentAnnotation()[i].autoCalculated)
1781         {
1782           newal
1783                   .addAnnotation(viewport.alignment
1784                           .getAlignmentAnnotation()[i]);
1785         }
1786       }
1787     }
1788
1789     AlignFrame newaf = new AlignFrame(newal, viewport.applet, "", false);
1790
1791     newaf.viewport.sequenceSetID = alignPanel.av.getSequenceSetId();
1792     PaintRefresher.Register(alignPanel, alignPanel.av.getSequenceSetId());
1793     PaintRefresher.Register(newaf.alignPanel, newaf.alignPanel.av
1794             .getSequenceSetId());
1795
1796     PaintRefresher.Register(newaf.alignPanel.idPanel.idCanvas,
1797             newaf.alignPanel.av.getSequenceSetId());
1798     PaintRefresher.Register(newaf.alignPanel.seqPanel.seqCanvas,
1799             newaf.alignPanel.av.getSequenceSetId());
1800
1801     Vector comps = (Vector) PaintRefresher.components.get(viewport
1802             .getSequenceSetId());
1803     int viewSize = -1;
1804     for (int i = 0; i < comps.size(); i++)
1805     {
1806       if (comps.elementAt(i) instanceof AlignmentPanel)
1807       {
1808         viewSize++;
1809       }
1810     }
1811
1812     String title = new String(this.getTitle());
1813     if (viewtitle != null)
1814     {
1815       title = viewtitle + " ( " + title + ")";
1816     }
1817     else
1818     {
1819       if (title.indexOf("(View") > -1)
1820       {
1821         title = title.substring(0, title.indexOf("(View"));
1822       }
1823       title += "(View " + viewSize + ")";
1824     }
1825
1826     newaf.setTitle(title.toString());
1827
1828     newaf.viewport.historyList = viewport.historyList;
1829     newaf.viewport.redoList = viewport.redoList;
1830     return newaf;
1831   }
1832
1833   /**
1834    * 
1835    * @return list of feature groups on the view
1836    */
1837   public String[] getFeatureGroups()
1838   {
1839     FeatureRenderer fr = null;
1840     if (alignPanel != null
1841             && (fr = alignPanel.getFeatureRenderer()) != null)
1842     {
1843       return fr.getGroups();
1844     }
1845     return null;
1846   }
1847
1848   /**
1849    * get sequence feature groups that are hidden or shown
1850    * 
1851    * @param visible
1852    *                true is visible
1853    * @return list
1854    */
1855   public String[] getFeatureGroupsOfState(boolean visible)
1856   {
1857     FeatureRenderer fr = null;
1858     if (alignPanel != null
1859             && (fr = alignPanel.getFeatureRenderer()) != null)
1860     {
1861       return fr.getGroups(visible);
1862     }
1863     return null;
1864   }
1865
1866   /**
1867    * Change the display state for the given feature groups
1868    * 
1869    * @param groups
1870    *                list of group strings
1871    * @param state
1872    *                visible or invisible
1873    */
1874   public void setFeatureGroupState(String[] groups, boolean state)
1875   {
1876     FeatureRenderer fr = null;
1877     this.sequenceFeatures.setState(true);
1878     viewport.showSequenceFeatures(true);
1879     if (alignPanel != null
1880             && (fr = alignPanel.getFeatureRenderer()) != null)
1881     {
1882       fr.setGroupState(groups, state);
1883       alignPanel.seqPanel.seqCanvas.repaint();
1884       if (alignPanel.overviewPanel != null)
1885       {
1886         alignPanel.overviewPanel.updateOverviewImage();
1887       }
1888     }
1889   }
1890
1891   public void seqLimits_itemStateChanged()
1892   {
1893     viewport.setShowJVSuffix(seqLimits.getState());
1894     alignPanel.fontChanged();
1895     alignPanel.paintAlignment(true);
1896   }
1897
1898   protected void colourTextMenuItem_actionPerformed()
1899   {
1900     viewport.setColourText(colourTextMenuItem.getState());
1901     alignPanel.paintAlignment(true);
1902   }
1903
1904   protected void wrapMenuItem_actionPerformed()
1905   {
1906     viewport.setWrapAlignment(wrapMenuItem.getState());
1907     alignPanel.setWrapAlignment(wrapMenuItem.getState());
1908     scaleAbove.setEnabled(wrapMenuItem.getState());
1909     scaleLeft.setEnabled(wrapMenuItem.getState());
1910     scaleRight.setEnabled(wrapMenuItem.getState());
1911     alignPanel.paintAlignment(true);
1912   }
1913
1914   public void overviewMenuItem_actionPerformed()
1915   {
1916     if (alignPanel.overviewPanel != null)
1917     {
1918       return;
1919     }
1920
1921     Frame frame = new Frame();
1922     OverviewPanel overview = new OverviewPanel(alignPanel);
1923     frame.add(overview);
1924     // +50 must allow for applet frame window
1925     jalview.bin.JalviewLite.addFrame(frame, "Overview " + this.getTitle(),
1926             overview.getPreferredSize().width,
1927             overview.getPreferredSize().height + 50);
1928
1929     frame.pack();
1930     frame.addWindowListener(new WindowAdapter()
1931     {
1932       public void windowClosing(WindowEvent e)
1933       {
1934         alignPanel.setOverviewPanel(null);
1935       };
1936     });
1937
1938     alignPanel.setOverviewPanel(overview);
1939
1940   }
1941
1942   void changeColour(ColourSchemeI cs)
1943   {
1944     int threshold = 0;
1945
1946     if (cs != null)
1947     {
1948       if (viewport.getAbovePIDThreshold())
1949       {
1950         threshold = SliderPanel.setPIDSliderSource(alignPanel, cs,
1951                 "Background");
1952
1953         cs.setThreshold(threshold, viewport.getIgnoreGapsConsensus());
1954
1955         viewport.setGlobalColourScheme(cs);
1956       }
1957       else
1958       {
1959         cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
1960       }
1961
1962       if (viewport.getConservationSelected())
1963       {
1964
1965         Alignment al = (Alignment) viewport.alignment;
1966         Conservation c = new Conservation("All",
1967                 ResidueProperties.propHash, 3, al.getSequences(), 0, al
1968                         .getWidth() - 1);
1969
1970         c.calculate();
1971         c.verdict(false, viewport.ConsPercGaps);
1972
1973         cs.setConservation(c);
1974
1975         cs.setConservationInc(SliderPanel.setConservationSlider(alignPanel,
1976                 cs, "Background"));
1977
1978       }
1979       else
1980       {
1981         cs.setConservation(null);
1982       }
1983
1984       cs.setConsensus(viewport.hconsensus);
1985
1986     }
1987     viewport.setGlobalColourScheme(cs);
1988
1989     if (viewport.getColourAppliesToAllGroups())
1990     {
1991       Vector groups = viewport.alignment.getGroups();
1992       for (int i = 0; i < groups.size(); i++)
1993       {
1994         SequenceGroup sg = (SequenceGroup) groups.elementAt(i);
1995
1996         if (cs == null)
1997         {
1998           sg.cs = null;
1999           continue;
2000         }
2001         if (cs instanceof ClustalxColourScheme)
2002         {
2003           sg.cs = new ClustalxColourScheme(sg
2004                   .getSequences(viewport.hiddenRepSequences), sg.getWidth());
2005         }
2006         else
2007         {
2008           try
2009           {
2010             sg.cs = (ColourSchemeI) cs.getClass().newInstance();
2011           } catch (Exception ex)
2012           {
2013             ex.printStackTrace();
2014             sg.cs = cs;
2015           }
2016         }
2017
2018         if (viewport.getAbovePIDThreshold()
2019                 || cs instanceof PIDColourScheme
2020                 || cs instanceof Blosum62ColourScheme)
2021         {
2022           sg.cs.setThreshold(threshold, viewport.getIgnoreGapsConsensus());
2023           sg.cs.setConsensus(AAFrequency.calculate(sg
2024                   .getSequences(viewport.hiddenRepSequences), 0, sg
2025                   .getWidth()));
2026         }
2027         else
2028         {
2029           sg.cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
2030         }
2031
2032         if (viewport.getConservationSelected())
2033         {
2034           Conservation c = new Conservation("Group",
2035                   ResidueProperties.propHash, 3, sg
2036                           .getSequences(viewport.hiddenRepSequences), 0,
2037                   viewport.alignment.getWidth() - 1);
2038           c.calculate();
2039           c.verdict(false, viewport.ConsPercGaps);
2040           sg.cs.setConservation(c);
2041         }
2042         else
2043         {
2044           sg.cs.setConservation(null);
2045           sg.cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
2046         }
2047
2048       }
2049     }
2050
2051     if (alignPanel.getOverviewPanel() != null)
2052     {
2053       alignPanel.getOverviewPanel().updateOverviewImage();
2054     }
2055
2056     jalview.structure.StructureSelectionManager
2057             .getStructureSelectionManager().sequenceColoursChanged(
2058                     alignPanel);
2059
2060     alignPanel.paintAlignment(true);
2061   }
2062
2063   protected void modifyPID_actionPerformed()
2064   {
2065     if (viewport.getAbovePIDThreshold()
2066             && viewport.globalColourScheme != null)
2067     {
2068       SliderPanel.setPIDSliderSource(alignPanel, viewport
2069               .getGlobalColourScheme(), "Background");
2070       SliderPanel.showPIDSlider();
2071     }
2072   }
2073
2074   protected void modifyConservation_actionPerformed()
2075   {
2076     if (viewport.getConservationSelected()
2077             && viewport.globalColourScheme != null)
2078     {
2079       SliderPanel.setConservationSlider(alignPanel,
2080               viewport.globalColourScheme, "Background");
2081       SliderPanel.showConservationSlider();
2082     }
2083   }
2084
2085   protected void conservationMenuItem_actionPerformed()
2086   {
2087     viewport.setConservationSelected(conservationMenuItem.getState());
2088
2089     viewport.setAbovePIDThreshold(false);
2090     abovePIDThreshold.setState(false);
2091
2092     changeColour(viewport.getGlobalColourScheme());
2093
2094     modifyConservation_actionPerformed();
2095   }
2096
2097   public void abovePIDThreshold_actionPerformed()
2098   {
2099     viewport.setAbovePIDThreshold(abovePIDThreshold.getState());
2100
2101     conservationMenuItem.setState(false);
2102     viewport.setConservationSelected(false);
2103
2104     changeColour(viewport.getGlobalColourScheme());
2105
2106     modifyPID_actionPerformed();
2107   }
2108
2109   public void sortPairwiseMenuItem_actionPerformed()
2110   {
2111     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
2112     AlignmentSorter.sortByPID(viewport.getAlignment(), viewport
2113             .getAlignment().getSequenceAt(0), null);
2114     addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
2115             viewport.alignment));
2116     alignPanel.paintAlignment(true);
2117   }
2118
2119   public void sortIDMenuItem_actionPerformed()
2120   {
2121     // addHistoryItem(new HistoryItem("ID Sort", viewport.alignment,
2122     // HistoryItem.SORT));
2123     AlignmentSorter.sortByID(viewport.getAlignment());
2124     alignPanel.paintAlignment(true);
2125   }
2126
2127   public void sortGroupMenuItem_actionPerformed()
2128   {
2129     // addHistoryItem(new HistoryItem("Group Sort", viewport.alignment,
2130     // HistoryItem.SORT));
2131     AlignmentSorter.sortByGroup(viewport.getAlignment());
2132     alignPanel.paintAlignment(true);
2133
2134   }
2135
2136   public void removeRedundancyMenuItem_actionPerformed()
2137   {
2138     new RedundancyPanel(alignPanel);
2139   }
2140
2141   public void pairwiseAlignmentMenuItem_actionPerformed()
2142   {
2143     if (viewport.getSelectionGroup() != null
2144             && viewport.getSelectionGroup().getSize() > 1)
2145     {
2146       Frame frame = new Frame();
2147       frame.add(new PairwiseAlignPanel(alignPanel));
2148       jalview.bin.JalviewLite.addFrame(frame, "Pairwise Alignment", 600,
2149               500);
2150     }
2151   }
2152
2153   public void PCAMenuItem_actionPerformed()
2154   {
2155     // are the sequences aligned?
2156     if (!viewport.alignment.isAligned())
2157     {
2158       SequenceI current;
2159       int Width = viewport.getAlignment().getWidth();
2160
2161       for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
2162       {
2163         current = viewport.getAlignment().getSequenceAt(i);
2164
2165         if (current.getLength() < Width)
2166         {
2167           current.insertCharAt(Width - 1, viewport.getGapCharacter());
2168         }
2169       }
2170       alignPanel.paintAlignment(true);
2171     }
2172
2173     if ((viewport.getSelectionGroup() != null
2174             && viewport.getSelectionGroup().getSize() < 4 && viewport
2175             .getSelectionGroup().getSize() > 0)
2176             || viewport.getAlignment().getHeight() < 4)
2177     {
2178       return;
2179     }
2180
2181     try
2182     {
2183       new PCAPanel(viewport);
2184     } catch (java.lang.OutOfMemoryError ex)
2185     {
2186     }
2187
2188   }
2189
2190   public void averageDistanceTreeMenuItem_actionPerformed()
2191   {
2192     NewTreePanel("AV", "PID", "Average distance tree using PID");
2193   }
2194
2195   public void neighbourTreeMenuItem_actionPerformed()
2196   {
2197     NewTreePanel("NJ", "PID", "Neighbour joining tree using PID");
2198   }
2199
2200   protected void njTreeBlosumMenuItem_actionPerformed()
2201   {
2202     NewTreePanel("NJ", "BL", "Neighbour joining tree using BLOSUM62");
2203   }
2204
2205   protected void avTreeBlosumMenuItem_actionPerformed()
2206   {
2207     NewTreePanel("AV", "BL", "Average distance tree using BLOSUM62");
2208   }
2209
2210   void NewTreePanel(String type, String pwType, String title)
2211   {
2212     // are the sequences aligned?
2213     if (!viewport.alignment.isAligned())
2214     {
2215       SequenceI current;
2216       int Width = viewport.getAlignment().getWidth();
2217
2218       for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
2219       {
2220         current = viewport.getAlignment().getSequenceAt(i);
2221
2222         if (current.getLength() < Width)
2223         {
2224           current.insertCharAt(Width - 1, viewport.getGapCharacter());
2225         }
2226       }
2227       alignPanel.paintAlignment(true);
2228
2229     }
2230
2231     if ((viewport.getSelectionGroup() != null && viewport
2232             .getSelectionGroup().getSize() > 1)
2233             || (viewport.getSelectionGroup() == null && viewport.alignment
2234                     .getHeight() > 1))
2235     {
2236       final TreePanel tp = new TreePanel(viewport, type, pwType);
2237
2238       addTreeMenuItem(tp, title);
2239
2240       jalview.bin.JalviewLite.addFrame(tp, title, 600, 500);
2241     }
2242   }
2243
2244   void loadTree_actionPerformed()
2245   {
2246     CutAndPasteTransfer cap = new CutAndPasteTransfer(true, this);
2247     cap.setText("Paste your Newick tree file here.");
2248     cap.setTreeImport();
2249     Frame frame = new Frame();
2250     frame.add(cap);
2251     jalview.bin.JalviewLite.addFrame(frame, "Paste Newick file ", 400, 300);
2252   }
2253
2254   public void loadTree(jalview.io.NewickFile tree, String treeFile)
2255   {
2256     TreePanel tp = new TreePanel(viewport, treeFile, "From File - ", tree);
2257     jalview.bin.JalviewLite.addFrame(tp, treeFile, 600, 500);
2258     addTreeMenuItem(tp, treeFile);
2259   }
2260
2261   void addTreeMenuItem(final TreePanel treePanel, String title)
2262   {
2263     final MenuItem item = new MenuItem(title);
2264     sortByTreeMenu.add(item);
2265     item.addActionListener(new java.awt.event.ActionListener()
2266     {
2267       public void actionPerformed(ActionEvent evt)
2268       {
2269         // addHistoryItem(new HistoryItem("Sort", viewport.alignment,
2270         // HistoryItem.SORT));
2271         AlignmentSorter.sortByTree(viewport.getAlignment(), treePanel
2272                 .getTree());
2273         alignPanel.paintAlignment(true);
2274       }
2275     });
2276
2277     treePanel.addWindowListener(new WindowAdapter()
2278     {
2279       public void windowClosing(WindowEvent e)
2280       {
2281         sortByTreeMenu.remove(item);
2282       };
2283     });
2284   }
2285
2286   protected void documentation_actionPerformed()
2287   {
2288     showURL("http://www.jalview.org/help.html", "HELP");
2289   }
2290
2291   protected void about_actionPerformed()
2292   {
2293
2294     class AboutPanel extends Canvas
2295     {
2296       String version;
2297
2298       public AboutPanel(String version)
2299       {
2300         this.version = version;
2301       }
2302
2303       public void paint(Graphics g)
2304       {
2305         g.setColor(Color.white);
2306         g.fillRect(0, 0, getSize().width, getSize().height);
2307         g.setFont(new Font("Helvetica", Font.PLAIN, 12));
2308         FontMetrics fm = g.getFontMetrics();
2309         int fh = fm.getHeight();
2310         int y = 5, x = 7;
2311         g.setColor(Color.black);
2312         // TODO: update this text for each release or centrally store it for
2313         // lite and application
2314         g.setFont(new Font("Helvetica", Font.BOLD, 14));
2315         g.drawString("JalviewLite - Release " + version, x, y += fh);
2316         g.setFont(new Font("Helvetica", Font.PLAIN, 12));
2317         g
2318                 .drawString(
2319                         "Authors:  Andrew Waterhouse, Jim Procter, Michele Clamp, James Cuff, Steve Searle,",
2320                         x, y += fh * 1.5);
2321         g.drawString("David Martin & Geoff Barton.", x + 50, y += fh);
2322         g
2323                 .drawString(
2324                         "Development managed by The Barton Group, University of Dundee, Scotland, UK.",
2325                         x, y += fh);
2326         g
2327                 .drawString(
2328                         "For help, see the FAQ at www.jalview.org and/or join the jalview-discuss@jalview.org mailing list",
2329                         x, y += fh);
2330         g.drawString("If  you use Jalview, please cite:", x, y += fh + 8);
2331         g.drawString(
2332                 "Waterhouse, A.M., Procter, J.B., Martin, D.M.A, Clamp, M. and Barton, G. J. (2009)",x,y+=fh);
2333         g.drawString("Jalview Version 2 - a multiple sequence alignment editor and analysis workbench",x,y+=fh);
2334         g.drawString("Bioinformatics doi: 10.1093/bioinformatics/btp033",x,y+=fh);
2335       }
2336     }
2337
2338     String version = "test";
2339     java.net.URL url = getClass().getResource("/.build_properties");
2340     if (url != null)
2341     {
2342       try
2343       {
2344         BufferedReader reader = new BufferedReader(new InputStreamReader(
2345                 url.openStream()));
2346         String line;
2347         while ((line = reader.readLine()) != null)
2348         {
2349           if (line.indexOf("VERSION") > -1)
2350           {
2351             version = line.substring(line.indexOf("=") + 1);
2352           }
2353         }
2354       } catch (Exception ex)
2355       {
2356         ex.printStackTrace();
2357       }
2358     }
2359
2360     Frame frame = new Frame();
2361     frame.add(new AboutPanel(version));
2362     jalview.bin.JalviewLite.addFrame(frame, "Jalview", 580, 220);
2363
2364   }
2365
2366   public void showURL(String url, String target)
2367   {
2368     if (viewport.applet == null)
2369     {
2370       System.out.println("Not running as applet - no browser available.");
2371     }
2372     else
2373     {
2374       try
2375       {
2376         if (url.indexOf(":")==-1)
2377         {
2378           // TODO: verify (Bas Vroling bug) prepend codebase or server URL to form valid URL
2379           if (url.indexOf("/")==0)
2380           {
2381             String codebase = viewport.applet.getCodeBase().toString();
2382             url = codebase.substring(0,codebase.length()-viewport.applet.getCodeBase().getFile().length())+url;
2383           } else {
2384             url = viewport.applet.getCodeBase()+url;
2385           }
2386           System.out.println("Show url (prepended codebase): " + url);
2387         } else {
2388           System.out.println("Show url: " + url);
2389         }
2390         viewport.applet.getAppletContext().showDocument(
2391                 new java.net.URL(url), target);
2392       } catch (Exception ex)
2393       {
2394         ex.printStackTrace();
2395       }
2396     }
2397   }
2398
2399   // ////////////////////////////////////////////////////////////////////////////////
2400   // JBuilder Graphics here
2401
2402   MenuBar alignFrameMenuBar = new MenuBar();
2403
2404   Menu fileMenu = new Menu("File");
2405
2406   MenuItem loadApplication = new MenuItem("View in Full Application");
2407
2408   MenuItem loadTree = new MenuItem("Load Associated Tree ...");
2409
2410   MenuItem loadAnnotations = new MenuItem("Load Features/Annotations ...");
2411
2412   MenuItem outputFeatures = new MenuItem("Export Features ...");
2413
2414   MenuItem outputAnnotations = new MenuItem("Export Annotations ...");
2415
2416   MenuItem closeMenuItem = new MenuItem("Close");
2417
2418   Menu editMenu = new Menu("Edit");
2419
2420   Menu viewMenu = new Menu("View");
2421
2422   Menu colourMenu = new Menu("Colour");
2423
2424   Menu calculateMenu = new Menu("Calculate");
2425
2426   MenuItem selectAllSequenceMenuItem = new MenuItem("Select all");
2427
2428   MenuItem deselectAllSequenceMenuItem = new MenuItem("Deselect All");
2429
2430   MenuItem invertSequenceMenuItem = new MenuItem("Invert Selection");
2431
2432   MenuItem remove2LeftMenuItem = new MenuItem();
2433
2434   MenuItem remove2RightMenuItem = new MenuItem();
2435
2436   MenuItem removeGappedColumnMenuItem = new MenuItem();
2437
2438   MenuItem removeAllGapsMenuItem = new MenuItem();
2439
2440   CheckboxMenuItem viewBoxesMenuItem = new CheckboxMenuItem();
2441
2442   CheckboxMenuItem viewTextMenuItem = new CheckboxMenuItem();
2443
2444   MenuItem sortPairwiseMenuItem = new MenuItem();
2445
2446   MenuItem sortIDMenuItem = new MenuItem();
2447
2448   MenuItem sortGroupMenuItem = new MenuItem();
2449
2450   MenuItem removeRedundancyMenuItem = new MenuItem();
2451
2452   MenuItem pairwiseAlignmentMenuItem = new MenuItem();
2453
2454   MenuItem PCAMenuItem = new MenuItem();
2455
2456   MenuItem averageDistanceTreeMenuItem = new MenuItem();
2457
2458   MenuItem neighbourTreeMenuItem = new MenuItem();
2459
2460   BorderLayout borderLayout1 = new BorderLayout();
2461
2462   public Label statusBar = new Label();
2463
2464   Menu outputTextboxMenu = new Menu();
2465
2466   MenuItem clustalColour = new MenuItem();
2467
2468   MenuItem zappoColour = new MenuItem();
2469
2470   MenuItem taylorColour = new MenuItem();
2471
2472   MenuItem hydrophobicityColour = new MenuItem();
2473
2474   MenuItem helixColour = new MenuItem();
2475
2476   MenuItem strandColour = new MenuItem();
2477
2478   MenuItem turnColour = new MenuItem();
2479
2480   MenuItem buriedColour = new MenuItem();
2481
2482   MenuItem userDefinedColour = new MenuItem();
2483
2484   MenuItem PIDColour = new MenuItem();
2485
2486   MenuItem BLOSUM62Colour = new MenuItem();
2487
2488   MenuItem njTreeBlosumMenuItem = new MenuItem();
2489
2490   MenuItem avDistanceTreeBlosumMenuItem = new MenuItem();
2491
2492   CheckboxMenuItem annotationPanelMenuItem = new CheckboxMenuItem();
2493
2494   CheckboxMenuItem colourTextMenuItem = new CheckboxMenuItem();
2495
2496   MenuItem alProperties = new MenuItem("Alignment Properties...");
2497
2498   MenuItem overviewMenuItem = new MenuItem();
2499
2500   MenuItem undoMenuItem = new MenuItem();
2501
2502   MenuItem redoMenuItem = new MenuItem();
2503
2504   CheckboxMenuItem conservationMenuItem = new CheckboxMenuItem();
2505
2506   MenuItem noColourmenuItem = new MenuItem();
2507
2508   CheckboxMenuItem wrapMenuItem = new CheckboxMenuItem();
2509
2510   CheckboxMenuItem renderGapsMenuItem = new CheckboxMenuItem();
2511
2512   MenuItem findMenuItem = new MenuItem();
2513
2514   CheckboxMenuItem abovePIDThreshold = new CheckboxMenuItem();
2515
2516   MenuItem nucleotideColour = new MenuItem();
2517
2518   MenuItem deleteGroups = new MenuItem();
2519
2520   MenuItem delete = new MenuItem();
2521
2522   MenuItem copy = new MenuItem();
2523
2524   MenuItem cut = new MenuItem();
2525
2526   Menu pasteMenu = new Menu();
2527
2528   MenuItem pasteNew = new MenuItem();
2529
2530   MenuItem pasteThis = new MenuItem();
2531
2532   CheckboxMenuItem applyToAllGroups = new CheckboxMenuItem();
2533
2534   MenuItem font = new MenuItem();
2535
2536   CheckboxMenuItem scaleAbove = new CheckboxMenuItem();
2537
2538   CheckboxMenuItem scaleLeft = new CheckboxMenuItem();
2539
2540   CheckboxMenuItem scaleRight = new CheckboxMenuItem();
2541
2542   MenuItem modifyPID = new MenuItem();
2543
2544   MenuItem modifyConservation = new MenuItem();
2545
2546   CheckboxMenuItem autoCalculate = new CheckboxMenuItem(
2547           "Autocalculate Consensus", true);
2548
2549   Menu sortByTreeMenu = new Menu();
2550
2551   Menu sort = new Menu();
2552
2553   Menu calculate = new Menu();
2554
2555   MenuItem inputText = new MenuItem();
2556
2557   Menu helpMenu = new Menu();
2558
2559   MenuItem documentation = new MenuItem();
2560
2561   MenuItem about = new MenuItem();
2562
2563   CheckboxMenuItem seqLimits = new CheckboxMenuItem();
2564
2565   CheckboxMenuItem centreColumnLabelFlag = new CheckboxMenuItem();
2566
2567   private void jbInit() throws Exception
2568   {
2569
2570     setMenuBar(alignFrameMenuBar);
2571
2572     MenuItem item;
2573
2574     // dynamically fill save as menu with available formats
2575     for (int i = 0; i < jalview.io.AppletFormatAdapter.WRITEABLE_FORMATS.length; i++)
2576     {
2577
2578       item = new MenuItem(
2579               jalview.io.AppletFormatAdapter.WRITEABLE_FORMATS[i]);
2580
2581       item.addActionListener(new java.awt.event.ActionListener()
2582       {
2583         public void actionPerformed(ActionEvent e)
2584         {
2585           outputText_actionPerformed(e);
2586         }
2587       });
2588
2589       outputTextboxMenu.add(item);
2590     }
2591     closeMenuItem.addActionListener(this);
2592     loadApplication.addActionListener(this);
2593
2594     loadTree.addActionListener(this);
2595     loadAnnotations.addActionListener(this);
2596     outputFeatures.addActionListener(this);
2597     outputAnnotations.addActionListener(this);
2598     selectAllSequenceMenuItem.addActionListener(this);
2599     deselectAllSequenceMenuItem.addActionListener(this);
2600     invertSequenceMenuItem.addActionListener(this);
2601     remove2LeftMenuItem.setLabel("Remove Left");
2602     remove2LeftMenuItem.addActionListener(this);
2603     remove2RightMenuItem.setLabel("Remove Right");
2604     remove2RightMenuItem.addActionListener(this);
2605     removeGappedColumnMenuItem.setLabel("Remove Empty Columns");
2606     removeGappedColumnMenuItem.addActionListener(this);
2607     removeAllGapsMenuItem.setLabel("Remove All Gaps");
2608     removeAllGapsMenuItem.addActionListener(this);
2609     viewBoxesMenuItem.setLabel("Boxes");
2610     viewBoxesMenuItem.setState(true);
2611     viewBoxesMenuItem.addItemListener(this);
2612     viewTextMenuItem.setLabel("Text");
2613     viewTextMenuItem.setState(true);
2614     viewTextMenuItem.addItemListener(this);
2615     sortPairwiseMenuItem.setLabel("by Pairwise Identity");
2616     sortPairwiseMenuItem.addActionListener(this);
2617     sortIDMenuItem.setLabel("by ID");
2618     sortIDMenuItem.addActionListener(this);
2619     sortGroupMenuItem.setLabel("by Group");
2620     sortGroupMenuItem.addActionListener(this);
2621     removeRedundancyMenuItem.setLabel("Remove Redundancy...");
2622     removeRedundancyMenuItem.addActionListener(this);
2623     pairwiseAlignmentMenuItem.setLabel("Pairwise Alignments...");
2624     pairwiseAlignmentMenuItem.addActionListener(this);
2625     PCAMenuItem.setLabel("Principal Component Analysis");
2626     PCAMenuItem.addActionListener(this);
2627     averageDistanceTreeMenuItem
2628             .setLabel("Average Distance Using % Identity");
2629     averageDistanceTreeMenuItem.addActionListener(this);
2630     neighbourTreeMenuItem.setLabel("Neighbour Joining Using % Identity");
2631     neighbourTreeMenuItem.addActionListener(this);
2632     statusBar.setBackground(Color.white);
2633     statusBar.setFont(new java.awt.Font("Verdana", 0, 11));
2634     statusBar.setText("Status bar");
2635     outputTextboxMenu.setLabel("Output to Textbox");
2636     clustalColour.setLabel("Clustalx");
2637
2638     clustalColour.addActionListener(this);
2639     zappoColour.setLabel("Zappo");
2640     zappoColour.addActionListener(this);
2641     taylorColour.setLabel("Taylor");
2642     taylorColour.addActionListener(this);
2643     hydrophobicityColour.setLabel("Hydrophobicity");
2644     hydrophobicityColour.addActionListener(this);
2645     helixColour.setLabel("Helix Propensity");
2646     helixColour.addActionListener(this);
2647     strandColour.setLabel("Strand Propensity");
2648     strandColour.addActionListener(this);
2649     turnColour.setLabel("Turn Propensity");
2650     turnColour.addActionListener(this);
2651     buriedColour.setLabel("Buried Index");
2652     buriedColour.addActionListener(this);
2653     userDefinedColour.setLabel("User Defined...");
2654     userDefinedColour.addActionListener(this);
2655     PIDColour.setLabel("Percentage Identity");
2656     PIDColour.addActionListener(this);
2657     BLOSUM62Colour.setLabel("BLOSUM62 Score");
2658     BLOSUM62Colour.addActionListener(this);
2659     avDistanceTreeBlosumMenuItem
2660             .setLabel("Average Distance Using BLOSUM62");
2661     avDistanceTreeBlosumMenuItem.addActionListener(this);
2662     njTreeBlosumMenuItem.setLabel("Neighbour Joining Using BLOSUM62");
2663     njTreeBlosumMenuItem.addActionListener(this);
2664     annotationPanelMenuItem.setLabel("Show Annotations");
2665     annotationPanelMenuItem.addItemListener(this);
2666     colourTextMenuItem.setLabel("Colour Text");
2667     colourTextMenuItem.addItemListener(this);
2668     alProperties.addActionListener(this);
2669     overviewMenuItem.setLabel("Overview Window");
2670     overviewMenuItem.addActionListener(this);
2671     undoMenuItem.setEnabled(false);
2672     undoMenuItem.setLabel("Undo");
2673     undoMenuItem.addActionListener(this);
2674     redoMenuItem.setEnabled(false);
2675     redoMenuItem.setLabel("Redo");
2676     redoMenuItem.addActionListener(this);
2677     conservationMenuItem.setLabel("by Conservation");
2678     conservationMenuItem.addItemListener(this);
2679     noColourmenuItem.setLabel("None");
2680     noColourmenuItem.addActionListener(this);
2681     wrapMenuItem.setLabel("Wrap");
2682     wrapMenuItem.addItemListener(this);
2683     renderGapsMenuItem.setLabel("Show Gaps");
2684     renderGapsMenuItem.setState(true);
2685     renderGapsMenuItem.addItemListener(this);
2686     findMenuItem.setLabel("Find...");
2687     findMenuItem.addActionListener(this);
2688     abovePIDThreshold.setLabel("Above Identity Threshold");
2689     abovePIDThreshold.addItemListener(this);
2690     nucleotideColour.setLabel("Nucleotide");
2691     nucleotideColour.addActionListener(this);
2692     deleteGroups.setLabel("Undefine Groups");
2693     deleteGroups.addActionListener(this);
2694     copy.setLabel("Copy");
2695     copy.addActionListener(this);
2696     cut.setLabel("Cut");
2697     cut.addActionListener(this);
2698     delete.setLabel("Delete");
2699     delete.addActionListener(this);
2700     pasteMenu.setLabel("Paste");
2701     pasteNew.setLabel("To New Alignment");
2702     pasteNew.addActionListener(this);
2703     pasteThis.setLabel("Add To This Alignment");
2704     pasteThis.addActionListener(this);
2705     applyToAllGroups.setLabel("Apply Colour To All Groups");
2706     applyToAllGroups.setState(true);
2707     applyToAllGroups.addItemListener(this);
2708     font.setLabel("Font...");
2709     font.addActionListener(this);
2710     scaleAbove.setLabel("Scale Above");
2711     scaleAbove.setState(true);
2712     scaleAbove.setEnabled(false);
2713     scaleAbove.addItemListener(this);
2714     scaleLeft.setEnabled(false);
2715     scaleLeft.setState(true);
2716     scaleLeft.setLabel("Scale Left");
2717     scaleLeft.addItemListener(this);
2718     scaleRight.setEnabled(false);
2719     scaleRight.setState(true);
2720     scaleRight.setLabel("Scale Right");
2721     scaleRight.addItemListener(this);
2722     modifyPID.setLabel("Modify Identity Threshold...");
2723     modifyPID.addActionListener(this);
2724     modifyConservation.setLabel("Modify Conservation Threshold...");
2725     modifyConservation.addActionListener(this);
2726     sortByTreeMenu.setLabel("By Tree Order");
2727     sort.setLabel("Sort");
2728     calculate.setLabel("Calculate Tree");
2729     autoCalculate.addItemListener(this);
2730     inputText.setLabel("Input from textbox");
2731     inputText.addActionListener(this);
2732     centreColumnLabelFlag.setLabel("Centre column labels");
2733     centreColumnLabelFlag.addItemListener(this);
2734
2735     helpMenu.setLabel("Help");
2736     documentation.setLabel("Documentation");
2737     documentation.addActionListener(this);
2738
2739     about.setLabel("About...");
2740     about.addActionListener(this);
2741     seqLimits.setState(true);
2742     seqLimits.setLabel("Show Sequence Limits");
2743     seqLimits.addItemListener(this);
2744     featureSettings.setLabel("Feature Settings...");
2745     featureSettings.addActionListener(this);
2746     sequenceFeatures.setLabel("Sequence Features");
2747     sequenceFeatures.addItemListener(this);
2748     sequenceFeatures.setState(false);
2749     annotationColour.setLabel("by Annotation...");
2750     annotationColour.addActionListener(this);
2751     invertSequenceMenuItem.setLabel("Invert Sequence Selection");
2752     invertColSel.setLabel("Invert Column Selection");
2753     menu1.setLabel("Show");
2754     showColumns.setLabel("All Columns ");
2755     showSeqs.setLabel("All Sequences");
2756     menu2.setLabel("Hide");
2757     hideColumns.setLabel("Selected Columns");
2758     hideSequences.setLabel("Selected Sequences");
2759     invertColSel.addActionListener(this);
2760     showColumns.addActionListener(this);
2761     showSeqs.addActionListener(this);
2762     hideColumns.addActionListener(this);
2763     hideSequences.addActionListener(this);
2764     formatMenu.setLabel("Format");
2765     selectMenu.setLabel("Select");
2766     newView.setLabel("New View");
2767     newView.addActionListener(this);
2768     alignFrameMenuBar.add(fileMenu);
2769     alignFrameMenuBar.add(editMenu);
2770     alignFrameMenuBar.add(selectMenu);
2771     alignFrameMenuBar.add(viewMenu);
2772     alignFrameMenuBar.add(formatMenu);
2773     alignFrameMenuBar.add(colourMenu);
2774     alignFrameMenuBar.add(calculateMenu);
2775     alignFrameMenuBar.add(helpMenu);
2776
2777     fileMenu.add(inputText);
2778     fileMenu.add(loadTree);
2779     fileMenu.add(loadAnnotations);
2780
2781     fileMenu.addSeparator();
2782     fileMenu.add(outputTextboxMenu);
2783     fileMenu.add(outputFeatures);
2784     fileMenu.add(outputAnnotations);
2785
2786     if (jalviewServletURL != null)
2787     {
2788       fileMenu.add(loadApplication);
2789     }
2790
2791     fileMenu.addSeparator();
2792     fileMenu.add(closeMenuItem);
2793
2794     editMenu.add(undoMenuItem);
2795     editMenu.add(redoMenuItem);
2796     editMenu.add(cut);
2797     editMenu.add(copy);
2798     editMenu.add(pasteMenu);
2799     editMenu.add(delete);
2800     editMenu.addSeparator();
2801     editMenu.add(remove2LeftMenuItem);
2802     editMenu.add(remove2RightMenuItem);
2803     editMenu.add(removeGappedColumnMenuItem);
2804     editMenu.add(removeAllGapsMenuItem);
2805     editMenu.add(removeRedundancyMenuItem);
2806     viewMenu.add(newView);
2807     viewMenu.addSeparator();
2808     viewMenu.add(menu1);
2809     viewMenu.add(menu2);
2810     viewMenu.addSeparator();
2811     viewMenu.add(annotationPanelMenuItem);
2812     viewMenu.addSeparator();
2813     viewMenu.add(sequenceFeatures);
2814     viewMenu.add(featureSettings);
2815     viewMenu.addSeparator();
2816     viewMenu.add(alProperties);
2817     viewMenu.addSeparator();
2818     viewMenu.add(overviewMenuItem);
2819     colourMenu.add(applyToAllGroups);
2820     colourMenu.addSeparator();
2821     colourMenu.add(noColourmenuItem);
2822     colourMenu.add(clustalColour);
2823     colourMenu.add(BLOSUM62Colour);
2824     colourMenu.add(PIDColour);
2825     colourMenu.add(zappoColour);
2826     colourMenu.add(taylorColour);
2827     colourMenu.add(hydrophobicityColour);
2828     colourMenu.add(helixColour);
2829     colourMenu.add(strandColour);
2830     colourMenu.add(turnColour);
2831     colourMenu.add(buriedColour);
2832     colourMenu.add(nucleotideColour);
2833     colourMenu.add(userDefinedColour);
2834     colourMenu.addSeparator();
2835     colourMenu.add(conservationMenuItem);
2836     colourMenu.add(modifyConservation);
2837     colourMenu.add(abovePIDThreshold);
2838     colourMenu.add(modifyPID);
2839     colourMenu.add(annotationColour);
2840     calculateMenu.add(sort);
2841     calculateMenu.add(calculate);
2842     calculateMenu.addSeparator();
2843     calculateMenu.add(pairwiseAlignmentMenuItem);
2844     calculateMenu.add(PCAMenuItem);
2845     calculateMenu.add(autoCalculate);
2846     this.add(statusBar, BorderLayout.SOUTH);
2847     pasteMenu.add(pasteNew);
2848     pasteMenu.add(pasteThis);
2849     sort.add(sortIDMenuItem);
2850     sort.add(sortByTreeMenu);
2851     sort.add(sortGroupMenuItem);
2852     sort.add(sortPairwiseMenuItem);
2853     calculate.add(averageDistanceTreeMenuItem);
2854     calculate.add(neighbourTreeMenuItem);
2855     calculate.add(avDistanceTreeBlosumMenuItem);
2856     calculate.add(njTreeBlosumMenuItem);
2857     helpMenu.add(documentation);
2858     helpMenu.add(about);
2859     menu1.add(showColumns);
2860     menu1.add(showSeqs);
2861     menu2.add(hideColumns);
2862     menu2.add(hideSequences);
2863     formatMenu.add(font);
2864     formatMenu.add(seqLimits);
2865     formatMenu.add(wrapMenuItem);
2866     formatMenu.add(scaleAbove);
2867     formatMenu.add(scaleLeft);
2868     formatMenu.add(scaleRight);
2869     formatMenu.add(viewBoxesMenuItem);
2870     formatMenu.add(viewTextMenuItem);
2871     formatMenu.add(colourTextMenuItem);
2872     formatMenu.add(renderGapsMenuItem);
2873     formatMenu.add(centreColumnLabelFlag);
2874     selectMenu.add(findMenuItem);
2875     selectMenu.addSeparator();
2876     selectMenu.add(selectAllSequenceMenuItem);
2877     selectMenu.add(deselectAllSequenceMenuItem);
2878     selectMenu.add(invertSequenceMenuItem);
2879     selectMenu.add(invertColSel);
2880     selectMenu.add(deleteGroups);
2881   }
2882
2883   MenuItem featureSettings = new MenuItem();
2884
2885   CheckboxMenuItem sequenceFeatures = new CheckboxMenuItem();
2886
2887   MenuItem annotationColour = new MenuItem();
2888
2889   MenuItem invertColSel = new MenuItem();
2890
2891   Menu menu1 = new Menu();
2892
2893   MenuItem showColumns = new MenuItem();
2894
2895   MenuItem showSeqs = new MenuItem();
2896
2897   Menu menu2 = new Menu();
2898
2899   MenuItem hideColumns = new MenuItem();
2900
2901   MenuItem hideSequences = new MenuItem();
2902
2903   Menu formatMenu = new Menu();
2904
2905   Menu selectMenu = new Menu();
2906
2907   MenuItem newView = new MenuItem();
2908
2909   /**
2910    * Attach the alignFrame panels after embedding menus, if necessary. This used
2911    * to be called setEmbedded, but is now creates the dropdown menus in a
2912    * platform independent manner to avoid OSX/Mac menu appendage daftness.
2913    * 
2914    * @param reallyEmbedded
2915    *                true to attach the view to the applet area on the page
2916    *                rather than in a new window
2917    */
2918   public void createAlignFrameWindow(boolean reallyEmbedded, String title)
2919   {
2920     if (reallyEmbedded)
2921     {
2922       // ////
2923       // Explicly build the embedded menu panel for the on-page applet
2924       //
2925       // view cannot be closed if its actually on the page
2926       fileMenu.remove(closeMenuItem);
2927       fileMenu.remove(3); // Remove Seperator
2928       embeddedMenu = makeEmbeddedPopupMenu(alignFrameMenuBar, "Arial",
2929               Font.PLAIN, 10, false); // use our own fonts.
2930       // and actually add the components to the applet area
2931       viewport.applet.setLayout(new BorderLayout());
2932       viewport.applet.add(embeddedMenu, BorderLayout.NORTH);
2933       viewport.applet.add(statusBar, BorderLayout.SOUTH);
2934       alignPanel.setSize(viewport.applet.getSize().width, viewport.applet
2935               .getSize().height
2936               - embeddedMenu.HEIGHT - statusBar.HEIGHT);
2937       viewport.applet.add(alignPanel, BorderLayout.CENTER);
2938       viewport.applet.validate();
2939     }
2940     else
2941     {
2942       // //////
2943       // test and embed menu bar if necessary.
2944       //
2945       if (embedMenuIfNeeded(alignPanel))
2946       {
2947         // adjust for status bar height too
2948         alignPanel.setSize(getSize().width, getSize().height
2949                 - statusBar.HEIGHT);
2950       }
2951       add(statusBar, BorderLayout.SOUTH);
2952       add(alignPanel, BorderLayout.CENTER);
2953       // and register with the applet so it can pass external API calls to us
2954       jalview.bin.JalviewLite.addFrame(this, title, DEFAULT_WIDTH,
2955               DEFAULT_HEIGHT);
2956     }
2957   }
2958 }