Fixed bug in trim right annotation adjust
[jalview.git] / src / jalview / commands / EditCommand.java
index a53798a..7effdfb 100644 (file)
@@ -20,6 +20,8 @@ package jalview.commands;
 \r
 import jalview.datamodel.*;\r
 \r
+import java.util.Hashtable;\r
+\r
 /**\r
  *\r
  * <p>Title: EditCommmand</p>\r
@@ -37,10 +39,10 @@ import jalview.datamodel.*;
  */\r
 public class EditCommand implements CommandI\r
 {\r
-  public static String INSERT_GAP = "InsertGap";\r
-  public static String DELETE_GAP = "DeleteGap";\r
-  public static String CUT = "Cut";\r
-  public static String PASTE = "Paste";\r
+  public static final int INSERT_GAP = 0;\r
+  public static final int DELETE_GAP = 1;\r
+  public static final int CUT = 2;\r
+  public static final int PASTE = 3;\r
 \r
   Edit[] edits;\r
 \r
@@ -54,33 +56,15 @@ public class EditCommand implements CommandI
     this.description = description;\r
   }\r
 \r
-  public EditCommand(String description,\r
-                     String command,\r
-                     SequenceI[] seqs,\r
-                     int position,\r
-                     int number,\r
-                     char gapChar)\r
-  {\r
-    this.description = description;\r
-\r
-    if (command.equalsIgnoreCase(INSERT_GAP)\r
-        || command.equalsIgnoreCase(DELETE_GAP))\r
-    {\r
-      edits = new Edit[] { new Edit(command, seqs, position, number, gapChar)};\r
-    }\r
-\r
-    performEdit(0);\r
-  }\r
-\r
   public EditCommand( String description,\r
-                      String command,\r
+                      int command,\r
                       SequenceI[] seqs,\r
                       int position,\r
                       int number,\r
                       AlignmentI al)\r
    {\r
      this.description = description;\r
-     if ( command.equalsIgnoreCase(CUT) || command.equalsIgnoreCase(PASTE))\r
+     if ( command==CUT || command==PASTE)\r
      {\r
        edits = new Edit[]{new Edit(command, seqs, position, number, al)};\r
      }\r
@@ -89,7 +73,7 @@ public class EditCommand implements CommandI
   }\r
 \r
 \r
-  public String getDescription()\r
+  final public String getDescription()\r
   {\r
     return description;\r
   }\r
@@ -99,15 +83,25 @@ public class EditCommand implements CommandI
     return edits==null?0:edits.length;\r
   }\r
 \r
+  final public AlignmentI getAlignment()\r
+  {\r
+    return edits[0].al;\r
+  }\r
+\r
 \r
-  public void appendEdit(String command,\r
+  final public void appendEdit(int command,\r
                          SequenceI[] seqs,\r
                          int position,\r
                          int number,\r
-                         char gapChar,\r
+                         AlignmentI al,\r
                          boolean performEdit)\r
   {\r
-    Edit edit = new Edit(command, seqs, position, number, gapChar);\r
+    Edit edit = new Edit(command, seqs, position, number, al.getGapCharacter());\r
+    if(al.getHeight()==seqs.length)\r
+    {\r
+      edit.al = al;\r
+      edit.fullAlignmentHeight = true;\r
+    }\r
 \r
     if (edits != null)\r
     {\r
@@ -123,60 +117,60 @@ public class EditCommand implements CommandI
       performEdit(edits.length - 1);\r
   }\r
 \r
-  void performEdit(int commandIndex)\r
+  final void performEdit(int commandIndex)\r
   {\r
     int eSize = edits.length;\r
     for (int e = commandIndex; e < eSize; e++)\r
     {\r
-      if (edits[e].command.equals(INSERT_GAP))\r
+      if (edits[e].command==INSERT_GAP)\r
       {\r
         insertGap(edits[e]);\r
       }\r
-      else if (edits[e].command.equals(DELETE_GAP))\r
+      else if (edits[e].command==DELETE_GAP)\r
       {\r
         deleteGap(edits[e]);\r
       }\r
-      else if(edits[e].command.equals(CUT))\r
+      else if(edits[e].command==CUT)\r
       {\r
         cut(edits[e]);\r
       }\r
-      else if(edits[e].command.equals(PASTE))\r
+      else if(edits[e].command==PASTE)\r
       {\r
         paste(edits[e]);\r
       }\r
     }\r
   }\r
 \r
-  public void doCommand()\r
+  final public void doCommand()\r
   {\r
     performEdit(0);\r
   }\r
 \r
-  public void undoCommand()\r
+  final public void undoCommand()\r
   {\r
     int e = 0, eSize = edits.length;\r
     for (e = eSize-1; e > -1; e--)\r
     {\r
-      if (edits[e].command.equals(INSERT_GAP))\r
+      if (edits[e].command==INSERT_GAP)\r
       {\r
         deleteGap(edits[e]);\r
       }\r
-      else if (edits[e].command.equals(DELETE_GAP))\r
+      else if (edits[e].command==DELETE_GAP)\r
       {\r
         insertGap(edits[e]);\r
       }\r
-      else if (edits[e].command.equals(CUT))\r
+      else if (edits[e].command==CUT)\r
       {\r
         paste(edits[e]);\r
       }\r
-      else if (edits[e].command.equals(PASTE))\r
+      else if (edits[e].command==PASTE)\r
       {\r
         cut(edits[e]);\r
       }\r
     }\r
   }\r
 \r
-  void insertGap(Edit command)\r
+  final void insertGap(Edit command)\r
   {\r
     for(int s=0; s<command.seqs.length; s++)\r
     {\r
@@ -184,40 +178,70 @@ public class EditCommand implements CommandI
                                      command.number,\r
                                      command.gapChar);\r
     }\r
+\r
+    adjustAnnotations(command, true);\r
   }\r
 \r
-  void deleteGap(Edit command)\r
+  final void deleteGap(Edit command)\r
   {\r
     for (int s = 0; s < command.seqs.length; s++)\r
     {\r
       command.seqs[s].deleteChars(command.position, command.position+command.number);\r
     }\r
+\r
+    adjustAnnotations(command, false);\r
   }\r
 \r
   void cut(Edit command)\r
   {\r
-    command.string = new String [command.seqs.length];\r
+    command.string = new char [command.seqs.length][];\r
 \r
     for(int i=0; i<command.seqs.length; i++)\r
     {\r
-      command.string[i] = command.seqs[i].getSequence(command.position,\r
-                                           command.position + command.number);\r
-\r
-      command.seqs[i].deleteChars(command.position,\r
-                                  command.position+command.number);\r
+      if(command.seqs[i].getLength()>command.position)\r
+      {\r
+        command.string[i] = command.seqs[i].getSequence(command.position,\r
+            command.position + command.number);\r
+\r
+        if(command.seqs[i].getDatasetSequence()!=null\r
+        || command.seqs[i].getSequenceFeatures()!=null)\r
+        {\r
+          for (int s = command.position; s < command.position + command.number; s++)\r
+          {\r
+            if (jalview.schemes.ResidueProperties\r
+                .aaIndex[command.seqs[i].getCharAt(s)] != 23)\r
+            {\r
+              adjustFeatures(command, i,\r
+                             command.seqs[i].findPosition(command.position),\r
+                             command.seqs[i].findPosition(command.position +\r
+                                                          command.number),\r
+                             false);\r
+              break;\r
+            }\r
+          }\r
+        }\r
+        command.seqs[i].deleteChars(command.position,\r
+                                    command.position + command.number);\r
+      }\r
 \r
       if(command.seqs[i].getLength()<1)\r
       {\r
         command.al.deleteSequence(command.seqs[i]);\r
       }\r
     }\r
+\r
+    adjustAnnotations(command, false);\r
   }\r
 \r
   void paste(Edit command)\r
   {\r
     StringBuffer tmp;\r
+    boolean newDSNeeded;\r
+    int start=0, end=0;\r
+\r
     for(int i=0; i<command.seqs.length; i++)\r
     {\r
+      newDSNeeded = false;\r
       if(command.seqs[i].getLength()<1)\r
       {\r
         // ie this sequence was deleted, we need to\r
@@ -228,29 +252,274 @@ public class EditCommand implements CommandI
         else\r
           command.al.addSequence(command.seqs[i]);\r
       }\r
-      tmp = new StringBuffer(command.seqs[i].getSequence());\r
-      if(command.string!=null)\r
+      tmp = new StringBuffer();\r
+      tmp.append(command.seqs[i].getSequence());\r
+\r
+      if(command.string!=null && command.string[i]!=null)\r
       {\r
+        if(command.position>=tmp.length())\r
+        {\r
+          //This occurs if padding is on, and residues\r
+          //are removed from end of alignment\r
+          int length = command.position-tmp.length();\r
+          while (length > 0)\r
+          {\r
+            tmp.append(command.gapChar);\r
+            length--;\r
+          }\r
+        }\r
         tmp.insert(command.position, command.string[i]);\r
+\r
+        for (int s = 0; s < command.string[i].length; s++)\r
+        {\r
+          if (jalview.schemes.ResidueProperties.aaIndex[command.string[i][s]] != 23)\r
+          {\r
+            newDSNeeded = true;\r
+            start = command.seqs[i].findPosition(command.position);\r
+            end = command.seqs[i].findPosition(command.position+command.number);\r
+            break;\r
+          }\r
+        }\r
         command.string[i] = null;\r
       }\r
+\r
+\r
       command.seqs[i].setSequence(tmp.toString());\r
+\r
+      if(newDSNeeded)\r
+      {\r
+        if (command.seqs[i].getDatasetSequence() != null)\r
+        {\r
+          Sequence ds = new Sequence(command.seqs[i].getName(),\r
+                                     jalview.analysis.AlignSeq.extractGaps(\r
+                                         jalview.util.Comparison.GapChars,\r
+                                         command.seqs[i].getSequenceAsString()\r
+                                     ),\r
+                                     command.seqs[i].getStart(),\r
+                                     command.seqs[i].getEnd());\r
+          ds.setDescription(command.seqs[i].getDescription());\r
+          command.seqs[i].setDatasetSequence(ds);\r
+        }\r
+\r
+        adjustFeatures(command, i, start, end, true);\r
+      }\r
     }\r
 \r
+\r
+    adjustAnnotations(command, true);\r
+\r
     command.string = null;\r
   }\r
 \r
+\r
+  final void adjustAnnotations(Edit command, boolean insert)\r
+  {\r
+\r
+    AlignmentAnnotation [] annotations = null;\r
+\r
+    if (command.fullAlignmentHeight)\r
+    {\r
+      annotations = command.al.getAlignmentAnnotation();\r
+    }\r
+    else\r
+    {\r
+      int aSize = 0;\r
+      AlignmentAnnotation [] tmp;\r
+      for(int s=0; s<command.seqs.length; s++)\r
+      {\r
+        if(command.seqs[s].getAnnotation()==null)\r
+          continue;\r
+\r
+        if (aSize == 0)\r
+            annotations = command.seqs[s].getAnnotation();\r
+        else\r
+        {\r
+          tmp = new AlignmentAnnotation\r
+              [aSize + command.seqs[s].getAnnotation().length];\r
+\r
+          System.arraycopy(annotations,0,tmp,0,aSize);\r
+\r
+          System.arraycopy(command.seqs[s].getAnnotation(),\r
+              0,tmp,aSize,command.seqs[s].getAnnotation().length);\r
+\r
+          annotations = tmp;\r
+        }\r
+\r
+\r
+        aSize = annotations.length;\r
+      }\r
+    }\r
+\r
+    if(annotations==null)\r
+      return;\r
+\r
+\r
+      if(!insert)\r
+        command.deletedAnnotations = new Hashtable();\r
+\r
+      int aSize;\r
+      Annotation [] temp;\r
+      for (int a = 0; a < annotations.length; a++)\r
+      {\r
+        if(annotations[a].autoCalculated)\r
+        {\r
+          continue;\r
+        }\r
+\r
+        aSize = annotations[a].annotations.length;\r
+        if(insert)\r
+          temp = new Annotation[aSize + command.number];\r
+        else\r
+        {\r
+          if(command.position<aSize)\r
+          {\r
+            if (aSize - command.number + command.position > 0)\r
+              temp = new Annotation[aSize - command.number + command.position];\r
+            else\r
+              temp = new Annotation[aSize];\r
+          }\r
+          else\r
+            temp = new Annotation[aSize];\r
+        }\r
+\r
+        if(insert)\r
+        {\r
+          if(command.position < annotations[a].annotations.length)\r
+          {\r
+            System.arraycopy(annotations[a].annotations,\r
+                             0, temp, 0, command.position);\r
+\r
+            if (command.deletedAnnotations != null\r
+                &&\r
+                command.deletedAnnotations.containsKey(annotations[a].annotationId))\r
+            {\r
+              Annotation[] restore = (Annotation[])\r
+                  command.deletedAnnotations.get(annotations[a].annotationId);\r
+\r
+              System.arraycopy(restore,\r
+                               0,\r
+                               temp,\r
+                               command.position,\r
+                               command.number);\r
+\r
+            }\r
+\r
+            System.arraycopy(annotations[a].annotations,\r
+                             command.position, temp,\r
+                             command.position + command.number,\r
+                             aSize - command.position);\r
+          }\r
+          else\r
+            temp = annotations[a].annotations;\r
+        }\r
+        else\r
+        {\r
+          if(command.position < aSize &&  aSize - command.number+command.position>0)\r
+          {\r
+            System.arraycopy(annotations[a].annotations,\r
+                             0, temp, 0, command.position);\r
+\r
+            Annotation[] deleted = new Annotation[command.number];\r
+            System.arraycopy(annotations[a].annotations,\r
+                             command.position, deleted, 0, command.number);\r
+\r
+            command.deletedAnnotations.put(annotations[a].annotationId,\r
+                                           deleted);\r
+\r
+            System.arraycopy(annotations[a].annotations,\r
+                             command.position + command.number,\r
+                             temp, command.position,\r
+                             aSize - command.position - command.number);\r
+          }\r
+          else\r
+            temp = annotations[a].annotations;\r
+        }\r
+\r
+        annotations[a].annotations = temp;\r
+     }\r
+  }\r
+\r
+  final void adjustFeatures(Edit command, int index, int i, int j, boolean insert)\r
+  {\r
+    SequenceI seq = command.seqs[index];\r
+    SequenceI sequence = seq.getDatasetSequence();\r
+    if(sequence==null)\r
+      sequence = seq;\r
+\r
+    if(insert)\r
+    {\r
+      if (command.editedFeatures != null\r
+          && command.editedFeatures.containsKey(seq))\r
+        sequence.setSequenceFeatures(\r
+            (SequenceFeature[]) command.editedFeatures.get(seq)\r
+            );\r
+\r
+      return;\r
+    }\r
+\r
+\r
+    SequenceFeature [] sf = sequence.getSequenceFeatures();\r
+\r
+\r
+    if(sf==null)\r
+    {\r
+      return;\r
+    }\r
+\r
+    SequenceFeature [] oldsf = new SequenceFeature[sf.length];\r
+\r
+    int cSize = j - i;\r
+\r
+    for (int s = 0; s < sf.length; s++)\r
+    {\r
+      SequenceFeature copy = new SequenceFeature(sf[s]);\r
+\r
+      oldsf[s] = copy;\r
+\r
+      if (sf[s].getEnd() < i)\r
+        continue;\r
+\r
+      if (sf[s].getBegin() > j)\r
+      {\r
+        sf[s].setBegin(copy.getBegin() - cSize);\r
+        sf[s].setEnd(copy.getEnd() - cSize);\r
+        continue;\r
+      }\r
+\r
+      if (sf[s].getBegin() >= i)\r
+        sf[s].setBegin(i);\r
+\r
+      if (sf[s].getEnd() < j)\r
+        sf[s].setEnd(j - 1);\r
+\r
+      sf[s].setEnd(sf[s].getEnd() - (cSize));\r
+\r
+      if (sf[s].getBegin() > sf[s].getEnd())\r
+        sequence.deleteFeature(sf[s]);\r
+    }\r
+\r
+    if (command.editedFeatures == null)\r
+      command.editedFeatures = new Hashtable();\r
+\r
+    command.editedFeatures.put(seq, oldsf);\r
+\r
+  }\r
+\r
+\r
   class Edit\r
   {\r
+    boolean fullAlignmentHeight = false;\r
+    Hashtable deletedAnnotations;\r
+    Hashtable editedFeatures;\r
     AlignmentI al;\r
-    String command;\r
-    String [] string;\r
+    int command;\r
+    char [][] string;\r
     SequenceI[] seqs;\r
     int [] alIndex;\r
     int position, number;\r
     char gapChar;\r
 \r
-    Edit(String command,\r
+    Edit(int command,\r
          SequenceI[] seqs,\r
          int position,\r
          int number,\r
@@ -264,22 +533,27 @@ public class EditCommand implements CommandI
     }\r
 \r
 \r
-    Edit(String command,\r
+    Edit(int command,\r
          SequenceI[] seqs,\r
          int position,\r
          int number,\r
          AlignmentI al)\r
     {\r
+      this.gapChar = al.getGapCharacter();\r
       this.command = command;\r
       this.seqs = seqs;\r
       this.position = position;\r
       this.number = number;\r
       this.al = al;\r
+\r
       alIndex = new int[seqs.length];\r
       for(int i=0; i<seqs.length; i++)\r
+      {\r
         alIndex[i] = al.findIndex(seqs[i]);\r
-    }\r
+      }\r
 \r
+      fullAlignmentHeight = (al.getHeight()==seqs.length);\r
+    }\r
   }\r
 \r
 }\r