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