Jalview 2.6 source licence
[jalview.git] / src / jalview / commands / EditCommand.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
3  * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
10  * 
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.commands;
19
20 import java.util.*;
21
22 import jalview.datamodel.*;
23
24 /**
25  * 
26  * <p>
27  * Title: EditCommmand
28  * </p>
29  * 
30  * <p>
31  * Description: Essential information for performing undo and redo for cut/paste
32  * insert/delete gap which can be stored in the HistoryList
33  * </p>
34  * 
35  * <p>
36  * Copyright: Copyright (c) 2006
37  * </p>
38  * 
39  * <p>
40  * Company: Dundee University
41  * </p>
42  * 
43  * @author not attributable
44  * @version 1.0
45  */
46 public class EditCommand implements CommandI
47 {
48   public static final int INSERT_GAP = 0;
49
50   public static final int DELETE_GAP = 1;
51
52   public static final int CUT = 2;
53
54   public static final int PASTE = 3;
55
56   public static final int REPLACE = 4;
57
58   Edit[] edits;
59
60   String description;
61
62   public EditCommand()
63   {
64   }
65
66   public EditCommand(String description)
67   {
68     this.description = description;
69   }
70
71   public EditCommand(String description, int command, SequenceI[] seqs,
72           int position, int number, AlignmentI al)
73   {
74     this.description = description;
75     if (command == CUT || command == PASTE)
76     {
77       edits = new Edit[]
78       { new Edit(command, seqs, position, number, al) };
79     }
80
81     performEdit(0, null);
82   }
83
84   public EditCommand(String description, int command, String replace,
85           SequenceI[] seqs, int position, int number, AlignmentI al)
86   {
87     this.description = description;
88     if (command == REPLACE)
89     {
90       edits = new Edit[]
91       { new Edit(command, seqs, position, number, al, replace) };
92     }
93
94     performEdit(0, null);
95   }
96
97   final public String getDescription()
98   {
99     return description;
100   }
101
102   public int getSize()
103   {
104     return edits == null ? 0 : edits.length;
105   }
106
107   final public AlignmentI getAlignment()
108   {
109     return edits[0].al;
110   }
111
112   /**
113    * append a new editCommand Note. this shouldn't be called if the edit is an
114    * operation affects more alignment objects than the one referenced in al (for
115    * example, cut or pasting whole sequences). Use the form with an additional
116    * AlignmentI[] views parameter.
117    * 
118    * @param command
119    * @param seqs
120    * @param position
121    * @param number
122    * @param al
123    * @param performEdit
124    */
125   final public void appendEdit(int command, SequenceI[] seqs, int position,
126           int number, AlignmentI al, boolean performEdit)
127   {
128     appendEdit(command, seqs, position, number, al, performEdit, null);
129   }
130
131   /**
132    * append a new edit command with a set of alignment views that may be
133    * operated on
134    * 
135    * @param command
136    * @param seqs
137    * @param position
138    * @param number
139    * @param al
140    * @param performEdit
141    * @param views
142    */
143   final public void appendEdit(int command, SequenceI[] seqs, int position,
144           int number, AlignmentI al, boolean performEdit, AlignmentI[] views)
145   {
146     Edit edit = new Edit(command, seqs, position, number, al
147             .getGapCharacter());
148     if (al.getHeight() == seqs.length)
149     {
150       edit.al = al;
151       edit.fullAlignmentHeight = true;
152     }
153
154     if (edits != null)
155     {
156       Edit[] temp = new Edit[edits.length + 1];
157       System.arraycopy(edits, 0, temp, 0, edits.length);
158       edits = temp;
159       edits[edits.length - 1] = edit;
160     }
161     else
162     {
163       edits = new Edit[]
164       { edit };
165     }
166
167     if (performEdit)
168     {
169       performEdit(edits.length - 1, views);
170     }
171   }
172
173   final void performEdit(int commandIndex, AlignmentI[] views)
174   {
175     int eSize = edits.length;
176     for (int e = commandIndex; e < eSize; e++)
177     {
178       switch (edits[e].command)
179       {
180       case INSERT_GAP:
181         insertGap(edits[e]);
182         break;
183       case DELETE_GAP:
184         deleteGap(edits[e]);
185         break;
186       case CUT:
187         cut(edits[e], views);
188         break;
189       case PASTE:
190         paste(edits[e], views);
191         break;
192       case REPLACE:
193         replace(edits[e]);
194         break;
195       }
196     }
197   }
198
199   final public void doCommand(AlignmentI[] views)
200   {
201     performEdit(0, views);
202   }
203
204   final public void undoCommand(AlignmentI[] views)
205   {
206     int e = 0, eSize = edits.length;
207     for (e = eSize - 1; e > -1; e--)
208     {
209       switch (edits[e].command)
210       {
211       case INSERT_GAP:
212         deleteGap(edits[e]);
213         break;
214       case DELETE_GAP:
215         insertGap(edits[e]);
216         break;
217       case CUT:
218         paste(edits[e], views);
219         break;
220       case PASTE:
221         cut(edits[e], views);
222         break;
223       case REPLACE:
224         replace(edits[e]);
225         break;
226       }
227     }
228   }
229
230   final void insertGap(Edit command)
231   {
232
233     for (int s = 0; s < command.seqs.length; s++)
234     {
235       command.seqs[s].insertCharAt(command.position, command.number,
236               command.gapChar);
237     }
238
239     adjustAnnotations(command, true, false, null);
240   }
241
242   final void deleteGap(Edit command)
243   {
244     for (int s = 0; s < command.seqs.length; s++)
245     {
246       command.seqs[s].deleteChars(command.position, command.position
247               + command.number);
248     }
249
250     adjustAnnotations(command, false, false, null);
251   }
252
253   void cut(Edit command, AlignmentI[] views)
254   {
255     boolean seqDeleted = false;
256     command.string = new char[command.seqs.length][];
257
258     for (int i = 0; i < command.seqs.length; i++)
259     {
260       if (command.seqs[i].getLength() > command.position)
261       {
262         command.string[i] = command.seqs[i].getSequence(command.position,
263                 command.position + command.number);
264         SequenceI oldds = command.seqs[i].getDatasetSequence();
265         if (command.oldds != null && command.oldds[i] != null)
266         {
267           // we are redoing an undone cut.
268           command.seqs[i].setDatasetSequence(null);
269         }
270         command.seqs[i].deleteChars(command.position, command.position
271                 + command.number);
272         if (command.oldds != null && command.oldds[i] != null)
273         {
274           // oldds entry contains the cut dataset sequence.
275           command.seqs[i].setDatasetSequence(command.oldds[i]);
276           command.oldds[i] = oldds;
277         }
278         else
279         {
280           // modify the oldds if necessary
281           if (oldds != command.seqs[i].getDatasetSequence()
282                   || command.seqs[i].getSequenceFeatures() != null)
283           {
284             if (command.oldds == null)
285             {
286               command.oldds = new SequenceI[command.seqs.length];
287             }
288             command.oldds[i] = oldds;
289             adjustFeatures(command, i, command.seqs[i]
290                     .findPosition(command.position), command.seqs[i]
291                     .findPosition(command.position + command.number), false);
292           }
293         }
294       }
295
296       if (command.seqs[i].getLength() < 1)
297       {
298         command.al.deleteSequence(command.seqs[i]);
299         seqDeleted = true;
300       }
301     }
302
303     adjustAnnotations(command, false, seqDeleted, views);
304   }
305
306   void paste(Edit command, AlignmentI[] views)
307   {
308     StringBuffer tmp;
309     boolean newDSNeeded;
310     boolean newDSWasNeeded;
311     int newstart, newend;
312     boolean seqWasDeleted = false;
313     int start = 0, end = 0;
314
315     for (int i = 0; i < command.seqs.length; i++)
316     {
317       newDSNeeded = false;
318       newDSWasNeeded = command.oldds != null && command.oldds[i] != null;
319       if (command.seqs[i].getLength() < 1)
320       {
321         // ie this sequence was deleted, we need to
322         // read it to the alignment
323         if (command.alIndex[i] < command.al.getHeight())
324         {
325           command.al.getSequences().insertElementAt(command.seqs[i],
326                   command.alIndex[i]);
327         }
328         else
329         {
330           command.al.addSequence(command.seqs[i]);
331         }
332         seqWasDeleted = true;
333       }
334       newstart = command.seqs[i].getStart();
335       newend = command.seqs[i].getEnd();
336
337       tmp = new StringBuffer();
338       tmp.append(command.seqs[i].getSequence());
339       // Undo of a delete does not replace original dataset sequence on to
340       // alignment sequence.
341
342       if (command.string != null && command.string[i] != null)
343       {
344         if (command.position >= tmp.length())
345         {
346           // This occurs if padding is on, and residues
347           // are removed from end of alignment
348           int length = command.position - tmp.length();
349           while (length > 0)
350           {
351             tmp.append(command.gapChar);
352             length--;
353           }
354         }
355         tmp.insert(command.position, command.string[i]);
356         for (int s = 0; s < command.string[i].length; s++)
357         {
358           if (jalview.schemes.ResidueProperties.aaIndex[command.string[i][s]] != 23)
359           {
360             if (!newDSNeeded)
361             {
362               newDSNeeded = true;
363               start = command.seqs[i].findPosition(command.position);
364               end = command.seqs[i].findPosition(command.position
365                       + command.number);
366             }
367             if (command.seqs[i].getStart() == start)
368               newstart--;
369             else
370               newend++;
371           }
372         }
373         command.string[i] = null;
374       }
375
376       command.seqs[i].setSequence(tmp.toString());
377       command.seqs[i].setStart(newstart);
378       command.seqs[i].setEnd(newend);
379       if (newDSNeeded)
380       {
381         if (command.seqs[i].getDatasetSequence() != null)
382         {
383           SequenceI ds;
384           if (newDSWasNeeded)
385           {
386             ds = command.oldds[i];
387           }
388           else
389           {
390             // make a new DS sequence
391             // use new ds mechanism here
392             ds = new Sequence(command.seqs[i].getName(),
393                     jalview.analysis.AlignSeq.extractGaps(
394                             jalview.util.Comparison.GapChars,
395                             command.seqs[i].getSequenceAsString()),
396                     command.seqs[i].getStart(), command.seqs[i].getEnd());
397             ds.setDescription(command.seqs[i].getDescription());
398           }
399           if (command.oldds == null)
400           {
401             command.oldds = new SequenceI[command.seqs.length];
402           }
403           command.oldds[i] = command.seqs[i].getDatasetSequence();
404           command.seqs[i].setDatasetSequence(ds);
405         }
406         adjustFeatures(command, i, start, end, true);
407       }
408     }
409     adjustAnnotations(command, true, seqWasDeleted, views);
410
411     command.string = null;
412   }
413
414   void replace(Edit command)
415   {
416     StringBuffer tmp;
417     String oldstring;
418     int start = command.position;
419     int end = command.number;
420     // TODO TUTORIAL - Fix for replacement with different length of sequence (or
421     // whole sequence)
422     // TODO Jalview 2.4 bugfix change to an aggregate command - original
423     // sequence string is cut, new string is pasted in.
424     command.number = start + command.string[0].length;
425     for (int i = 0; i < command.seqs.length; i++)
426     {
427       /**
428        * cut addHistoryItem(new EditCommand("Cut Sequences", EditCommand.CUT,
429        * cut, sg.getStartRes(), sg.getEndRes()-sg.getStartRes()+1,
430        * viewport.alignment));
431        * 
432        */
433       /**
434        * then addHistoryItem(new EditCommand( "Add sequences",
435        * EditCommand.PASTE, sequences, 0, alignment.getWidth(), alignment) );
436        * 
437        */
438       oldstring = command.seqs[i].getSequenceAsString();
439       tmp = new StringBuffer(oldstring.substring(0, start));
440       tmp.append(command.string[i]);
441       tmp.append(oldstring.substring(end));
442       command.seqs[i].setSequence(tmp.toString());
443       command.string[i] = oldstring.substring(start, end).toCharArray();
444       tmp = null;
445       oldstring = null;
446     }
447   }
448
449   final void adjustAnnotations(Edit command, boolean insert,
450           boolean modifyVisibility, AlignmentI[] views)
451   {
452     AlignmentAnnotation[] annotations = null;
453
454     if (modifyVisibility && !insert)
455     {
456       // only occurs if a sequence was added or deleted.
457       command.deletedAnnotationRows = new Hashtable();
458     }
459     if (command.fullAlignmentHeight)
460     {
461       annotations = command.al.getAlignmentAnnotation();
462     }
463     else
464     {
465       int aSize = 0;
466       AlignmentAnnotation[] tmp;
467       for (int s = 0; s < command.seqs.length; s++)
468       {
469         if (modifyVisibility)
470         {
471           // Rows are only removed or added to sequence object.
472           if (!insert)
473           {
474             // remove rows
475             tmp = command.seqs[s].getAnnotation();
476             if (tmp != null)
477             {
478               int alen = tmp.length;
479               for (int aa = 0; aa < tmp.length; aa++)
480               {
481                 if (!command.al.deleteAnnotation(tmp[aa]))
482                 {
483                   // strip out annotation not in the current al (will be put
484                   // back on insert in all views)
485                   tmp[aa] = null;
486                   alen--;
487                 }
488               }
489               command.seqs[s].setAlignmentAnnotation(null);
490               if (alen != tmp.length)
491               {
492                 // save the non-null annotation references only
493                 AlignmentAnnotation[] saved = new AlignmentAnnotation[alen];
494                 for (int aa = 0, aapos = 0; aa < tmp.length; aa++)
495                 {
496                   if (tmp[aa] != null)
497                   {
498                     saved[aapos++] = tmp[aa];
499                     tmp[aa] = null;
500                   }
501                 }
502                 tmp = saved;
503                 command.deletedAnnotationRows.put(command.seqs[s], saved);
504                 // and then remove any annotation in the other views
505                 for (int alview = 0; views != null && alview < views.length; alview++)
506                 {
507                   if (views[alview] != command.al)
508                   {
509                     AlignmentAnnotation[] toremove = views[alview]
510                             .getAlignmentAnnotation();
511                     if (toremove == null || toremove.length == 0)
512                     {
513                       continue;
514                     }
515                     // remove any alignment annotation on this sequence that's
516                     // on that alignment view.
517                     for (int aa = 0; aa < toremove.length; aa++)
518                     {
519                       if (toremove[aa].sequenceRef == command.seqs[s])
520                       {
521                         views[alview].deleteAnnotation(toremove[aa]);
522                       }
523                     }
524                   }
525                 }
526               }
527               else
528               {
529                 // save all the annotation
530                 command.deletedAnnotationRows.put(command.seqs[s], tmp);
531               }
532             }
533           }
534           else
535           {
536             // recover rows
537             if (command.deletedAnnotationRows != null
538                     && command.deletedAnnotationRows
539                             .containsKey(command.seqs[s]))
540             {
541               AlignmentAnnotation[] revealed = (AlignmentAnnotation[]) command.deletedAnnotationRows
542                       .get(command.seqs[s]);
543               command.seqs[s].setAlignmentAnnotation(revealed);
544               if (revealed != null)
545               {
546                 for (int aa = 0; aa < revealed.length; aa++)
547                 {
548                   // iterate through al adding original annotation
549                   command.al.addAnnotation(revealed[aa]);
550                 }
551                 for (int aa = 0; aa < revealed.length; aa++)
552                 {
553                   command.al.setAnnotationIndex(revealed[aa], aa);
554                 }
555                 // and then duplicate added annotation on every other alignment
556                 // view
557                 for (int vnum = 0; views != null && vnum < views.length; vnum++)
558                 {
559                   if (views[vnum] != command.al)
560                   {
561                     int avwidth = views[vnum].getWidth() + 1;
562                     // duplicate in this view
563                     for (int a = 0; a < revealed.length; a++)
564                     {
565                       AlignmentAnnotation newann = new AlignmentAnnotation(
566                               revealed[a]);
567                       command.seqs[s].addAlignmentAnnotation(newann);
568                       newann.padAnnotation(avwidth);
569                       views[vnum].addAnnotation(newann);
570                       views[vnum].setAnnotationIndex(newann, a);
571                     }
572                   }
573                 }
574               }
575             }
576           }
577           continue;
578         }
579
580         if (command.seqs[s].getAnnotation() == null)
581         {
582           continue;
583         }
584
585         if (aSize == 0)
586         {
587           annotations = command.seqs[s].getAnnotation();
588         }
589         else
590         {
591           tmp = new AlignmentAnnotation[aSize
592                   + command.seqs[s].getAnnotation().length];
593
594           System.arraycopy(annotations, 0, tmp, 0, aSize);
595
596           System.arraycopy(command.seqs[s].getAnnotation(), 0, tmp, aSize,
597                   command.seqs[s].getAnnotation().length);
598
599           annotations = tmp;
600         }
601         aSize = annotations.length;
602       }
603     }
604
605     if (annotations == null)
606     {
607       return;
608     }
609
610     if (!insert)
611     {
612       command.deletedAnnotations = new Hashtable();
613     }
614
615     int aSize;
616     Annotation[] temp;
617     for (int a = 0; a < annotations.length; a++)
618     {
619       if (annotations[a].autoCalculated
620               || annotations[a].annotations == null)
621       {
622         continue;
623       }
624
625       int tSize = 0;
626
627       aSize = annotations[a].annotations.length;
628       if (insert)
629       {
630         temp = new Annotation[aSize + command.number];
631         if (annotations[a].padGaps)
632           for (int aa = 0; aa < temp.length; aa++)
633           {
634             temp[aa] = new Annotation(command.gapChar + "", null, ' ', 0);
635           }
636       }
637       else
638       {
639         if (command.position < aSize)
640         {
641           if (command.position + command.number >= aSize)
642           {
643             tSize = aSize;
644           }
645           else
646           {
647             tSize = aSize - command.number;
648           }
649         }
650         else
651         {
652           tSize = aSize;
653         }
654
655         if (tSize < 0)
656         {
657           tSize = aSize;
658         }
659         temp = new Annotation[tSize];
660       }
661
662       if (insert)
663       {
664         if (command.position < annotations[a].annotations.length)
665         {
666           System.arraycopy(annotations[a].annotations, 0, temp, 0,
667                   command.position);
668
669           if (command.deletedAnnotations != null
670                   && command.deletedAnnotations
671                           .containsKey(annotations[a].annotationId))
672           {
673             Annotation[] restore = (Annotation[]) command.deletedAnnotations
674                     .get(annotations[a].annotationId);
675
676             System.arraycopy(restore, 0, temp, command.position,
677                     command.number);
678
679           }
680
681           System.arraycopy(annotations[a].annotations, command.position,
682                   temp, command.position + command.number, aSize
683                           - command.position);
684         }
685         else
686         {
687           if (command.deletedAnnotations != null
688                   && command.deletedAnnotations
689                           .containsKey(annotations[a].annotationId))
690           {
691             Annotation[] restore = (Annotation[]) command.deletedAnnotations
692                     .get(annotations[a].annotationId);
693
694             temp = new Annotation[annotations[a].annotations.length
695                     + restore.length];
696             System.arraycopy(annotations[a].annotations, 0, temp, 0,
697                     annotations[a].annotations.length);
698             System.arraycopy(restore, 0, temp,
699                     annotations[a].annotations.length, restore.length);
700           }
701           else
702           {
703             temp = annotations[a].annotations;
704           }
705         }
706       }
707       else
708       {
709         if (tSize != aSize || command.position < 2)
710         {
711           int copylen = Math.min(command.position,
712                   annotations[a].annotations.length);
713           if (copylen > 0)
714             System.arraycopy(annotations[a].annotations, 0, temp, 0,
715                     copylen); // command.position);
716
717           Annotation[] deleted = new Annotation[command.number];
718           if (copylen >= command.position)
719           {
720             copylen = Math.min(command.number,
721                     annotations[a].annotations.length - command.position);
722             if (copylen > 0)
723             {
724               System.arraycopy(annotations[a].annotations,
725                       command.position, deleted, 0, copylen); // command.number);
726             }
727           }
728
729           command.deletedAnnotations.put(annotations[a].annotationId,
730                   deleted);
731           if (annotations[a].annotations.length > command.position
732                   + command.number)
733           {
734             System.arraycopy(annotations[a].annotations, command.position
735                     + command.number, temp, command.position,
736                     annotations[a].annotations.length - command.position
737                             - command.number); // aSize
738           }
739         }
740         else
741         {
742           int dSize = aSize - command.position;
743
744           if (dSize > 0)
745           {
746             Annotation[] deleted = new Annotation[command.number];
747             System.arraycopy(annotations[a].annotations, command.position,
748                     deleted, 0, dSize);
749
750             command.deletedAnnotations.put(annotations[a].annotationId,
751                     deleted);
752
753             tSize = Math.min(annotations[a].annotations.length,
754                     command.position);
755             temp = new Annotation[tSize];
756             System.arraycopy(annotations[a].annotations, 0, temp, 0, tSize);
757           }
758           else
759           {
760             temp = annotations[a].annotations;
761           }
762         }
763       }
764
765       annotations[a].annotations = temp;
766     }
767   }
768
769   final void adjustFeatures(Edit command, int index, int i, int j,
770           boolean insert)
771   {
772     SequenceI seq = command.seqs[index];
773     SequenceI sequence = seq.getDatasetSequence();
774     if (sequence == null)
775     {
776       sequence = seq;
777     }
778
779     if (insert)
780     {
781       if (command.editedFeatures != null
782               && command.editedFeatures.containsKey(seq))
783       {
784         sequence
785                 .setSequenceFeatures((SequenceFeature[]) command.editedFeatures
786                         .get(seq));
787       }
788
789       return;
790     }
791
792     SequenceFeature[] sf = sequence.getSequenceFeatures();
793
794     if (sf == null)
795     {
796       return;
797     }
798
799     SequenceFeature[] oldsf = new SequenceFeature[sf.length];
800
801     int cSize = j - i;
802
803     for (int s = 0; s < sf.length; s++)
804     {
805       SequenceFeature copy = new SequenceFeature(sf[s]);
806
807       oldsf[s] = copy;
808
809       if (sf[s].getEnd() < i)
810       {
811         continue;
812       }
813
814       if (sf[s].getBegin() > j)
815       {
816         sf[s].setBegin(copy.getBegin() - cSize);
817         sf[s].setEnd(copy.getEnd() - cSize);
818         continue;
819       }
820
821       if (sf[s].getBegin() >= i)
822       {
823         sf[s].setBegin(i);
824       }
825
826       if (sf[s].getEnd() < j)
827       {
828         sf[s].setEnd(j - 1);
829       }
830
831       sf[s].setEnd(sf[s].getEnd() - (cSize));
832
833       if (sf[s].getBegin() > sf[s].getEnd())
834       {
835         sequence.deleteFeature(sf[s]);
836       }
837     }
838
839     if (command.editedFeatures == null)
840     {
841       command.editedFeatures = new Hashtable();
842     }
843
844     command.editedFeatures.put(seq, oldsf);
845
846   }
847
848   class Edit
849   {
850     public SequenceI[] oldds;
851
852     boolean fullAlignmentHeight = false;
853
854     Hashtable deletedAnnotationRows;
855
856     Hashtable deletedAnnotations;
857
858     Hashtable editedFeatures;
859
860     AlignmentI al;
861
862     int command;
863
864     char[][] string;
865
866     SequenceI[] seqs;
867
868     int[] alIndex;
869
870     int position, number;
871
872     char gapChar;
873
874     Edit(int command, SequenceI[] seqs, int position, int number,
875             char gapChar)
876     {
877       this.command = command;
878       this.seqs = seqs;
879       this.position = position;
880       this.number = number;
881       this.gapChar = gapChar;
882     }
883
884     Edit(int command, SequenceI[] seqs, int position, int number,
885             AlignmentI al)
886     {
887       this.gapChar = al.getGapCharacter();
888       this.command = command;
889       this.seqs = seqs;
890       this.position = position;
891       this.number = number;
892       this.al = al;
893
894       alIndex = new int[seqs.length];
895       for (int i = 0; i < seqs.length; i++)
896       {
897         alIndex[i] = al.findIndex(seqs[i]);
898       }
899
900       fullAlignmentHeight = (al.getHeight() == seqs.length);
901     }
902
903     Edit(int command, SequenceI[] seqs, int position, int number,
904             AlignmentI al, String replace)
905     {
906       this.command = command;
907       this.seqs = seqs;
908       this.position = position;
909       this.number = number;
910       this.al = al;
911       this.gapChar = al.getGapCharacter();
912       string = new char[seqs.length][];
913       for (int i = 0; i < seqs.length; i++)
914       {
915         string[i] = replace.toCharArray();
916       }
917
918       fullAlignmentHeight = (al.getHeight() == seqs.length);
919     }
920   }
921 }