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