53108387753d9be0650dff00b8d25ec80c42baf4
[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,
147             al.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(
290                     command,
291                     i,
292                     command.seqs[i].findPosition(command.position),
293                     command.seqs[i].findPosition(command.position
294                             + command.number), false);
295           }
296         }
297       }
298
299       if (command.seqs[i].getLength() < 1)
300       {
301         command.al.deleteSequence(command.seqs[i]);
302         seqDeleted = true;
303       }
304     }
305
306     adjustAnnotations(command, false, seqDeleted, views);
307   }
308
309   void paste(Edit command, AlignmentI[] views)
310   {
311     StringBuffer tmp;
312     boolean newDSNeeded;
313     boolean newDSWasNeeded;
314     int newstart, newend;
315     boolean seqWasDeleted = false;
316     int start = 0, end = 0;
317
318     for (int i = 0; i < command.seqs.length; i++)
319     {
320       newDSNeeded = false;
321       newDSWasNeeded = command.oldds != null && command.oldds[i] != null;
322       if (command.seqs[i].getLength() < 1)
323       {
324         // ie this sequence was deleted, we need to
325         // read it to the alignment
326         if (command.alIndex[i] < command.al.getHeight())
327         {
328           command.al.getSequences().insertElementAt(command.seqs[i],
329                   command.alIndex[i]);
330         }
331         else
332         {
333           command.al.addSequence(command.seqs[i]);
334         }
335         seqWasDeleted = true;
336       }
337       newstart = command.seqs[i].getStart();
338       newend = command.seqs[i].getEnd();
339
340       tmp = new StringBuffer();
341       tmp.append(command.seqs[i].getSequence());
342       // Undo of a delete does not replace original dataset sequence on to
343       // alignment sequence.
344
345       if (command.string != null && command.string[i] != null)
346       {
347         if (command.position >= tmp.length())
348         {
349           // This occurs if padding is on, and residues
350           // are removed from end of alignment
351           int length = command.position - tmp.length();
352           while (length > 0)
353           {
354             tmp.append(command.gapChar);
355             length--;
356           }
357         }
358         tmp.insert(command.position, command.string[i]);
359         for (int s = 0; s < command.string[i].length; s++)
360         {
361           if (jalview.schemes.ResidueProperties.aaIndex[command.string[i][s]] != 23)
362           {
363             if (!newDSNeeded)
364             {
365               newDSNeeded = true;
366               start = command.seqs[i].findPosition(command.position);
367               end = command.seqs[i].findPosition(command.position
368                       + command.number);
369             }
370             if (command.seqs[i].getStart() == start)
371               newstart--;
372             else
373               newend++;
374           }
375         }
376         command.string[i] = null;
377       }
378
379       command.seqs[i].setSequence(tmp.toString());
380       command.seqs[i].setStart(newstart);
381       command.seqs[i].setEnd(newend);
382       if (newDSNeeded)
383       {
384         if (command.seqs[i].getDatasetSequence() != null)
385         {
386           SequenceI ds;
387           if (newDSWasNeeded)
388           {
389             ds = command.oldds[i];
390           }
391           else
392           {
393             // make a new DS sequence
394             // use new ds mechanism here
395             ds = new Sequence(command.seqs[i].getName(),
396                     jalview.analysis.AlignSeq.extractGaps(
397                             jalview.util.Comparison.GapChars,
398                             command.seqs[i].getSequenceAsString()),
399                     command.seqs[i].getStart(), command.seqs[i].getEnd());
400             ds.setDescription(command.seqs[i].getDescription());
401           }
402           if (command.oldds == null)
403           {
404             command.oldds = new SequenceI[command.seqs.length];
405           }
406           command.oldds[i] = command.seqs[i].getDatasetSequence();
407           command.seqs[i].setDatasetSequence(ds);
408         }
409         adjustFeatures(command, i, start, end, true);
410       }
411     }
412     adjustAnnotations(command, true, seqWasDeleted, views);
413
414     command.string = null;
415   }
416
417   void replace(Edit command)
418   {
419     StringBuffer tmp;
420     String oldstring;
421     int start = command.position;
422     int end = command.number;
423     // TODO TUTORIAL - Fix for replacement with different length of sequence (or
424     // whole sequence)
425     // TODO Jalview 2.4 bugfix change to an aggregate command - original
426     // sequence string is cut, new string is pasted in.
427     command.number = start + command.string[0].length;
428     for (int i = 0; i < command.seqs.length; i++)
429     {
430       /**
431        * cut addHistoryItem(new EditCommand("Cut Sequences", EditCommand.CUT,
432        * cut, sg.getStartRes(), sg.getEndRes()-sg.getStartRes()+1,
433        * viewport.alignment));
434        * 
435        */
436       /**
437        * then addHistoryItem(new EditCommand( "Add sequences",
438        * EditCommand.PASTE, sequences, 0, alignment.getWidth(), alignment) );
439        * 
440        */
441       oldstring = command.seqs[i].getSequenceAsString();
442       tmp = new StringBuffer(oldstring.substring(0, start));
443       tmp.append(command.string[i]);
444       tmp.append(oldstring.substring(end));
445       command.seqs[i].setSequence(tmp.toString());
446       command.string[i] = oldstring.substring(start, end).toCharArray();
447       tmp = null;
448       oldstring = null;
449     }
450   }
451
452   final void adjustAnnotations(Edit command, boolean insert,
453           boolean modifyVisibility, AlignmentI[] views)
454   {
455     AlignmentAnnotation[] annotations = null;
456
457     if (modifyVisibility && !insert)
458     {
459       // only occurs if a sequence was added or deleted.
460       command.deletedAnnotationRows = new Hashtable();
461     }
462     if (command.fullAlignmentHeight)
463     {
464       annotations = command.al.getAlignmentAnnotation();
465     }
466     else
467     {
468       int aSize = 0;
469       AlignmentAnnotation[] tmp;
470       for (int s = 0; s < command.seqs.length; s++)
471       {
472         if (modifyVisibility)
473         {
474           // Rows are only removed or added to sequence object.
475           if (!insert)
476           {
477             // remove rows
478             tmp = command.seqs[s].getAnnotation();
479             if (tmp != null)
480             {
481               int alen = tmp.length;
482               for (int aa = 0; aa < tmp.length; aa++)
483               {
484                 if (!command.al.deleteAnnotation(tmp[aa]))
485                 {
486                   // strip out annotation not in the current al (will be put
487                   // back on insert in all views)
488                   tmp[aa] = null;
489                   alen--;
490                 }
491               }
492               command.seqs[s].setAlignmentAnnotation(null);
493               if (alen != tmp.length)
494               {
495                 // save the non-null annotation references only
496                 AlignmentAnnotation[] saved = new AlignmentAnnotation[alen];
497                 for (int aa = 0, aapos = 0; aa < tmp.length; aa++)
498                 {
499                   if (tmp[aa] != null)
500                   {
501                     saved[aapos++] = tmp[aa];
502                     tmp[aa] = null;
503                   }
504                 }
505                 tmp = saved;
506                 command.deletedAnnotationRows.put(command.seqs[s], saved);
507                 // and then remove any annotation in the other views
508                 for (int alview = 0; views != null && alview < views.length; alview++)
509                 {
510                   if (views[alview] != command.al)
511                   {
512                     AlignmentAnnotation[] toremove = views[alview]
513                             .getAlignmentAnnotation();
514                     if (toremove == null || toremove.length == 0)
515                     {
516                       continue;
517                     }
518                     // remove any alignment annotation on this sequence that's
519                     // on that alignment view.
520                     for (int aa = 0; aa < toremove.length; aa++)
521                     {
522                       if (toremove[aa].sequenceRef == command.seqs[s])
523                       {
524                         views[alview].deleteAnnotation(toremove[aa]);
525                       }
526                     }
527                   }
528                 }
529               }
530               else
531               {
532                 // save all the annotation
533                 command.deletedAnnotationRows.put(command.seqs[s], tmp);
534               }
535             }
536           }
537           else
538           {
539             // recover rows
540             if (command.deletedAnnotationRows != null
541                     && command.deletedAnnotationRows
542                             .containsKey(command.seqs[s]))
543             {
544               AlignmentAnnotation[] revealed = (AlignmentAnnotation[]) command.deletedAnnotationRows
545                       .get(command.seqs[s]);
546               command.seqs[s].setAlignmentAnnotation(revealed);
547               if (revealed != null)
548               {
549                 for (int aa = 0; aa < revealed.length; aa++)
550                 {
551                   // iterate through al adding original annotation
552                   command.al.addAnnotation(revealed[aa]);
553                 }
554                 for (int aa = 0; aa < revealed.length; aa++)
555                 {
556                   command.al.setAnnotationIndex(revealed[aa], aa);
557                 }
558                 // and then duplicate added annotation on every other alignment
559                 // view
560                 for (int vnum = 0; views != null && vnum < views.length; vnum++)
561                 {
562                   if (views[vnum] != command.al)
563                   {
564                     int avwidth = views[vnum].getWidth() + 1;
565                     // duplicate in this view
566                     for (int a = 0; a < revealed.length; a++)
567                     {
568                       AlignmentAnnotation newann = new AlignmentAnnotation(
569                               revealed[a]);
570                       command.seqs[s].addAlignmentAnnotation(newann);
571                       newann.padAnnotation(avwidth);
572                       views[vnum].addAnnotation(newann);
573                       views[vnum].setAnnotationIndex(newann, a);
574                     }
575                   }
576                 }
577               }
578             }
579           }
580           continue;
581         }
582
583         if (command.seqs[s].getAnnotation() == null)
584         {
585           continue;
586         }
587
588         if (aSize == 0)
589         {
590           annotations = command.seqs[s].getAnnotation();
591         }
592         else
593         {
594           tmp = new AlignmentAnnotation[aSize
595                   + command.seqs[s].getAnnotation().length];
596
597           System.arraycopy(annotations, 0, tmp, 0, aSize);
598
599           System.arraycopy(command.seqs[s].getAnnotation(), 0, tmp, aSize,
600                   command.seqs[s].getAnnotation().length);
601
602           annotations = tmp;
603         }
604         aSize = annotations.length;
605       }
606     }
607
608     if (annotations == null)
609     {
610       return;
611     }
612
613     if (!insert)
614     {
615       command.deletedAnnotations = new Hashtable();
616     }
617
618     int aSize;
619     Annotation[] temp;
620     for (int a = 0; a < annotations.length; a++)
621     {
622       if (annotations[a].autoCalculated
623               || annotations[a].annotations == null)
624       {
625         continue;
626       }
627
628       int tSize = 0;
629
630       aSize = annotations[a].annotations.length;
631       if (insert)
632       {
633         temp = new Annotation[aSize + command.number];
634         if (annotations[a].padGaps)
635           for (int aa = 0; aa < temp.length; aa++)
636           {
637             temp[aa] = new Annotation(command.gapChar + "", null, ' ', 0);
638           }
639       }
640       else
641       {
642         if (command.position < aSize)
643         {
644           if (command.position + command.number >= aSize)
645           {
646             tSize = aSize;
647           }
648           else
649           {
650             tSize = aSize - command.number;
651           }
652         }
653         else
654         {
655           tSize = aSize;
656         }
657
658         if (tSize < 0)
659         {
660           tSize = aSize;
661         }
662         temp = new Annotation[tSize];
663       }
664
665       if (insert)
666       {
667         if (command.position < annotations[a].annotations.length)
668         {
669           System.arraycopy(annotations[a].annotations, 0, temp, 0,
670                   command.position);
671
672           if (command.deletedAnnotations != null
673                   && command.deletedAnnotations
674                           .containsKey(annotations[a].annotationId))
675           {
676             Annotation[] restore = (Annotation[]) command.deletedAnnotations
677                     .get(annotations[a].annotationId);
678
679             System.arraycopy(restore, 0, temp, command.position,
680                     command.number);
681
682           }
683
684           System.arraycopy(annotations[a].annotations, command.position,
685                   temp, command.position + command.number, aSize
686                           - command.position);
687         }
688         else
689         {
690           if (command.deletedAnnotations != null
691                   && command.deletedAnnotations
692                           .containsKey(annotations[a].annotationId))
693           {
694             Annotation[] restore = (Annotation[]) command.deletedAnnotations
695                     .get(annotations[a].annotationId);
696
697             temp = new Annotation[annotations[a].annotations.length
698                     + restore.length];
699             System.arraycopy(annotations[a].annotations, 0, temp, 0,
700                     annotations[a].annotations.length);
701             System.arraycopy(restore, 0, temp,
702                     annotations[a].annotations.length, restore.length);
703           }
704           else
705           {
706             temp = annotations[a].annotations;
707           }
708         }
709       }
710       else
711       {
712         if (tSize != aSize || command.position < 2)
713         {
714           int copylen = Math.min(command.position,
715                   annotations[a].annotations.length);
716           if (copylen > 0)
717             System.arraycopy(annotations[a].annotations, 0, temp, 0,
718                     copylen); // command.position);
719
720           Annotation[] deleted = new Annotation[command.number];
721           if (copylen >= command.position)
722           {
723             copylen = Math.min(command.number,
724                     annotations[a].annotations.length - command.position);
725             if (copylen > 0)
726             {
727               System.arraycopy(annotations[a].annotations,
728                       command.position, deleted, 0, copylen); // command.number);
729             }
730           }
731
732           command.deletedAnnotations.put(annotations[a].annotationId,
733                   deleted);
734           if (annotations[a].annotations.length > command.position
735                   + command.number)
736           {
737             System.arraycopy(annotations[a].annotations, command.position
738                     + command.number, temp, command.position,
739                     annotations[a].annotations.length - command.position
740                             - command.number); // aSize
741           }
742         }
743         else
744         {
745           int dSize = aSize - command.position;
746
747           if (dSize > 0)
748           {
749             Annotation[] deleted = new Annotation[command.number];
750             System.arraycopy(annotations[a].annotations, command.position,
751                     deleted, 0, dSize);
752
753             command.deletedAnnotations.put(annotations[a].annotationId,
754                     deleted);
755
756             tSize = Math.min(annotations[a].annotations.length,
757                     command.position);
758             temp = new Annotation[tSize];
759             System.arraycopy(annotations[a].annotations, 0, temp, 0, tSize);
760           }
761           else
762           {
763             temp = annotations[a].annotations;
764           }
765         }
766       }
767
768       annotations[a].annotations = temp;
769     }
770   }
771
772   final void adjustFeatures(Edit command, int index, int i, int j,
773           boolean insert)
774   {
775     SequenceI seq = command.seqs[index];
776     SequenceI sequence = seq.getDatasetSequence();
777     if (sequence == null)
778     {
779       sequence = seq;
780     }
781
782     if (insert)
783     {
784       if (command.editedFeatures != null
785               && command.editedFeatures.containsKey(seq))
786       {
787         sequence.setSequenceFeatures((SequenceFeature[]) command.editedFeatures
788                 .get(seq));
789       }
790
791       return;
792     }
793
794     SequenceFeature[] sf = sequence.getSequenceFeatures();
795
796     if (sf == null)
797     {
798       return;
799     }
800
801     SequenceFeature[] oldsf = new SequenceFeature[sf.length];
802
803     int cSize = j - i;
804
805     for (int s = 0; s < sf.length; s++)
806     {
807       SequenceFeature copy = new SequenceFeature(sf[s]);
808
809       oldsf[s] = copy;
810
811       if (sf[s].getEnd() < i)
812       {
813         continue;
814       }
815
816       if (sf[s].getBegin() > j)
817       {
818         sf[s].setBegin(copy.getBegin() - cSize);
819         sf[s].setEnd(copy.getEnd() - cSize);
820         continue;
821       }
822
823       if (sf[s].getBegin() >= i)
824       {
825         sf[s].setBegin(i);
826       }
827
828       if (sf[s].getEnd() < j)
829       {
830         sf[s].setEnd(j - 1);
831       }
832
833       sf[s].setEnd(sf[s].getEnd() - (cSize));
834
835       if (sf[s].getBegin() > sf[s].getEnd())
836       {
837         sequence.deleteFeature(sf[s]);
838       }
839     }
840
841     if (command.editedFeatures == null)
842     {
843       command.editedFeatures = new Hashtable();
844     }
845
846     command.editedFeatures.put(seq, oldsf);
847
848   }
849
850   class Edit
851   {
852     public SequenceI[] oldds;
853
854     boolean fullAlignmentHeight = false;
855
856     Hashtable deletedAnnotationRows;
857
858     Hashtable deletedAnnotations;
859
860     Hashtable editedFeatures;
861
862     AlignmentI al;
863
864     int command;
865
866     char[][] string;
867
868     SequenceI[] seqs;
869
870     int[] alIndex;
871
872     int position, number;
873
874     char gapChar;
875
876     Edit(int command, SequenceI[] seqs, int position, int number,
877             char gapChar)
878     {
879       this.command = command;
880       this.seqs = seqs;
881       this.position = position;
882       this.number = number;
883       this.gapChar = gapChar;
884     }
885
886     Edit(int command, SequenceI[] seqs, int position, int number,
887             AlignmentI al)
888     {
889       this.gapChar = al.getGapCharacter();
890       this.command = command;
891       this.seqs = seqs;
892       this.position = position;
893       this.number = number;
894       this.al = al;
895
896       alIndex = new int[seqs.length];
897       for (int i = 0; i < seqs.length; i++)
898       {
899         alIndex[i] = al.findIndex(seqs[i]);
900       }
901
902       fullAlignmentHeight = (al.getHeight() == seqs.length);
903     }
904
905     Edit(int command, SequenceI[] seqs, int position, int number,
906             AlignmentI al, String replace)
907     {
908       this.command = command;
909       this.seqs = seqs;
910       this.position = position;
911       this.number = number;
912       this.al = al;
913       this.gapChar = al.getGapCharacter();
914       string = new char[seqs.length][];
915       for (int i = 0; i < seqs.length; i++)
916       {
917         string[i] = replace.toCharArray();
918       }
919
920       fullAlignmentHeight = (al.getHeight() == seqs.length);
921     }
922   }
923 }