Annotation adjustment moved to EditCommand
[jalview.git] / src / jalview / commands / EditCommand.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\r
5  * This program is free software; you can redistribute it and/or\r
6  * modify it under the terms of the GNU General Public License\r
7  * as published by the Free Software Foundation; either version 2\r
8  * of the License, or (at your option) any later version.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  * You should have received a copy of the GNU General Public License\r
16  * along with this program; if not, write to the Free Software\r
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18  */\r
19 package jalview.commands;\r
20 \r
21 import jalview.datamodel.*;\r
22 \r
23 import java.util.Hashtable;\r
24 \r
25 /**\r
26  *\r
27  * <p>Title: EditCommmand</p>\r
28  *\r
29  * <p>Description: Essential information for performing\r
30  * undo and redo for cut/paste insert/delete gap\r
31  * which can be stored in the HistoryList </p>\r
32  *\r
33  * <p>Copyright: Copyright (c) 2006</p>\r
34  *\r
35  * <p>Company: Dundee University</p>\r
36  *\r
37  * @author not attributable\r
38  * @version 1.0\r
39  */\r
40 public class EditCommand implements CommandI\r
41 {\r
42   public static final int INSERT_GAP = 0;\r
43   public static final int DELETE_GAP = 1;\r
44   public static final int CUT = 2;\r
45   public static final int PASTE = 3;\r
46 \r
47   Edit[] edits;\r
48 \r
49   String description;\r
50 \r
51   public EditCommand()\r
52   {}\r
53 \r
54   public EditCommand(String description)\r
55   {\r
56     this.description = description;\r
57   }\r
58 \r
59   public EditCommand( String description,\r
60                       int command,\r
61                       SequenceI[] seqs,\r
62                       int position,\r
63                       int number,\r
64                       AlignmentI al)\r
65    {\r
66      this.description = description;\r
67      if ( command==CUT || command==PASTE)\r
68      {\r
69        edits = new Edit[]{new Edit(command, seqs, position, number, al)};\r
70      }\r
71 \r
72      performEdit(0);\r
73   }\r
74 \r
75 \r
76   public String getDescription()\r
77   {\r
78     return description;\r
79   }\r
80 \r
81   public int getSize()\r
82   {\r
83     return edits==null?0:edits.length;\r
84   }\r
85 \r
86   public AlignmentI getAlignment()\r
87   {\r
88     return edits[0].al;\r
89   }\r
90 \r
91 \r
92   public void appendEdit(int command,\r
93                          SequenceI[] seqs,\r
94                          int position,\r
95                          int number,\r
96                          AlignmentI al,\r
97                          boolean performEdit)\r
98   {\r
99     Edit edit = new Edit(command, seqs, position, number, al.getGapCharacter());\r
100     if(al.getHeight()==seqs.length)\r
101     {\r
102       edit.al = al;\r
103       edit.fullAlignmentHeight = true;\r
104     }\r
105 \r
106     if (edits != null)\r
107     {\r
108       Edit[] temp = new Edit[edits.length + 1];\r
109       System.arraycopy(edits, 0, temp, 0, edits.length);\r
110       edits = temp;\r
111       edits[edits.length - 1] = edit;\r
112     }\r
113     else\r
114       edits = new Edit[] {  edit  };\r
115 \r
116     if (performEdit)\r
117       performEdit(edits.length - 1);\r
118   }\r
119 \r
120   void performEdit(int commandIndex)\r
121   {\r
122     int eSize = edits.length;\r
123     for (int e = commandIndex; e < eSize; e++)\r
124     {\r
125       if (edits[e].command==INSERT_GAP)\r
126       {\r
127         insertGap(edits[e]);\r
128       }\r
129       else if (edits[e].command==DELETE_GAP)\r
130       {\r
131         deleteGap(edits[e]);\r
132       }\r
133       else if(edits[e].command==CUT)\r
134       {\r
135         cut(edits[e]);\r
136       }\r
137       else if(edits[e].command==PASTE)\r
138       {\r
139         paste(edits[e]);\r
140       }\r
141     }\r
142   }\r
143 \r
144   public void doCommand()\r
145   {\r
146     performEdit(0);\r
147   }\r
148 \r
149   public void undoCommand()\r
150   {\r
151     int e = 0, eSize = edits.length;\r
152     for (e = eSize-1; e > -1; e--)\r
153     {\r
154       if (edits[e].command==INSERT_GAP)\r
155       {\r
156         deleteGap(edits[e]);\r
157       }\r
158       else if (edits[e].command==DELETE_GAP)\r
159       {\r
160         insertGap(edits[e]);\r
161       }\r
162       else if (edits[e].command==CUT)\r
163       {\r
164         paste(edits[e]);\r
165       }\r
166       else if (edits[e].command==PASTE)\r
167       {\r
168         cut(edits[e]);\r
169       }\r
170     }\r
171   }\r
172 \r
173   void insertGap(Edit command)\r
174   {\r
175     for(int s=0; s<command.seqs.length; s++)\r
176     {\r
177         command.seqs[s].insertCharAt(command.position,\r
178                                      command.number,\r
179                                      command.gapChar);\r
180     }\r
181 \r
182     if (command.fullAlignmentHeight)\r
183     {\r
184       adjustAnnotations(command, true);\r
185     }\r
186   }\r
187 \r
188   void deleteGap(Edit command)\r
189   {\r
190     for (int s = 0; s < command.seqs.length; s++)\r
191     {\r
192       command.seqs[s].deleteChars(command.position, command.position+command.number);\r
193     }\r
194 \r
195     if (command.fullAlignmentHeight)\r
196     {\r
197       adjustAnnotations(command, false);\r
198     }\r
199   }\r
200 \r
201   void cut(Edit command)\r
202   {\r
203     command.string = new char [command.seqs.length][];\r
204 \r
205     for(int i=0; i<command.seqs.length; i++)\r
206     {\r
207       if(command.seqs[i].getLength()>command.position)\r
208       {\r
209         command.string[i] = command.seqs[i].getSequence(command.position,\r
210             command.position + command.number);\r
211 \r
212         command.seqs[i].deleteChars(command.position,\r
213                                     command.position + command.number);\r
214       }\r
215 \r
216       if(command.seqs[i].getLength()<1)\r
217       {\r
218         command.al.deleteSequence(command.seqs[i]);\r
219       }\r
220     }\r
221 \r
222     if (command.fullAlignmentHeight)\r
223     {\r
224       adjustAnnotations(command, false);\r
225     }\r
226 \r
227   }\r
228 \r
229   void paste(Edit command)\r
230   {\r
231     StringBuffer tmp;\r
232     for(int i=0; i<command.seqs.length; i++)\r
233     {\r
234       if(command.seqs[i].getLength()<1)\r
235       {\r
236         // ie this sequence was deleted, we need to\r
237         // read it to the alignment\r
238         if (command.alIndex[i] < command.al.getHeight())\r
239           command.al.getSequences().insertElementAt(command.seqs[i],\r
240               command.alIndex[i]);\r
241         else\r
242           command.al.addSequence(command.seqs[i]);\r
243       }\r
244       tmp = new StringBuffer();\r
245       tmp.append(command.seqs[i].getSequence());\r
246 \r
247       if(command.string!=null && command.string[i]!=null)\r
248       {\r
249         if(command.position>=tmp.length())\r
250         {\r
251           //This occurs if padding is on, and residues\r
252           //are removed from end of alignment\r
253           int length = command.position-tmp.length();\r
254           while (length > 0)\r
255           {\r
256             tmp.append(command.gapChar);\r
257             length--;\r
258           }\r
259         }\r
260         tmp.insert(command.position, command.string[i]);\r
261         command.string[i] = null;\r
262       }\r
263       command.seqs[i].setSequence(tmp.toString());\r
264     }\r
265 \r
266     if (command.fullAlignmentHeight)\r
267     {\r
268       adjustAnnotations(command, true);\r
269     }\r
270 \r
271     command.string = null;\r
272   }\r
273 \r
274 \r
275   void adjustAnnotations(Edit command, boolean insert)\r
276   {\r
277     AlignmentAnnotation [] annotations = command.al.getAlignmentAnnotation();\r
278     if(annotations!=null)\r
279     {\r
280       if(!insert)\r
281         command.deletedAnnotations = new Hashtable();\r
282 \r
283       int aSize, tSize;\r
284       Annotation [] temp;\r
285       for (int a = 0; a < annotations.length; a++)\r
286       {\r
287         if(annotations[a].autoCalculated)\r
288         {\r
289           continue;\r
290         }\r
291 \r
292         aSize = annotations[a].annotations.length;\r
293         if(insert)\r
294           tSize = aSize + command.number;\r
295         else\r
296           tSize = aSize - command.number;\r
297 \r
298         temp = new Annotation[tSize];\r
299 \r
300         if(insert)\r
301         {\r
302           System.arraycopy(annotations[a].annotations,\r
303               0, temp, 0, command.position);\r
304 \r
305           if(command.deletedAnnotations!=null\r
306              && command.deletedAnnotations.containsKey(annotations[a].annotationId))\r
307           {\r
308             Annotation [] restore = (Annotation [])\r
309                 command.deletedAnnotations.get(annotations[a].annotationId);\r
310 \r
311             System.arraycopy(restore,\r
312                              0,\r
313                              temp,\r
314                              command.position,\r
315                              command.number);\r
316 \r
317           }\r
318 \r
319           System.arraycopy(annotations[a].annotations,\r
320               command.position, temp,\r
321               command.position+command.number,\r
322               aSize - command.position);\r
323         }\r
324         else\r
325         {\r
326           if(command.position < annotations[a].annotations.length)\r
327           {\r
328             System.arraycopy(annotations[a].annotations,\r
329                              0, temp, 0, command.position);\r
330 \r
331             Annotation[] deleted = new Annotation[command.number];\r
332             System.arraycopy(annotations[a].annotations,\r
333                              command.position, deleted, 0, command.number);\r
334 \r
335             command.deletedAnnotations.put(annotations[a].annotationId,\r
336                                            deleted);\r
337 \r
338             System.arraycopy(annotations[a].annotations,\r
339                              command.position + command.number,\r
340                              temp, command.position,\r
341                              aSize - command.position - command.number);\r
342           }\r
343           else\r
344             temp = annotations[a].annotations;\r
345         }\r
346 \r
347         annotations[a].annotations = temp;\r
348      }\r
349     }\r
350   }\r
351 \r
352 \r
353   class Edit\r
354   {\r
355     boolean fullAlignmentHeight = false;\r
356     Hashtable deletedAnnotations;\r
357     AlignmentI al;\r
358     int command;\r
359     char [][] string;\r
360     SequenceI[] seqs;\r
361     int [] alIndex;\r
362     int position, number;\r
363     char gapChar;\r
364 \r
365     Edit(int command,\r
366          SequenceI[] seqs,\r
367          int position,\r
368          int number,\r
369          char gapChar)\r
370     {\r
371       this.command = command;\r
372       this.seqs = seqs;\r
373       this.position = position;\r
374       this.number = number;\r
375       this.gapChar = gapChar;\r
376     }\r
377 \r
378 \r
379     Edit(int command,\r
380          SequenceI[] seqs,\r
381          int position,\r
382          int number,\r
383          AlignmentI al)\r
384     {\r
385       this.gapChar = al.getGapCharacter();\r
386       this.command = command;\r
387       this.seqs = seqs;\r
388       this.position = position;\r
389       this.number = number;\r
390       this.al = al;\r
391 \r
392       alIndex = new int[seqs.length];\r
393       for(int i=0; i<seqs.length; i++)\r
394         alIndex[i] = al.findIndex(seqs[i]);\r
395 \r
396       fullAlignmentHeight = (al.getHeight()==seqs.length);\r
397 \r
398     }\r
399 \r
400   }\r
401 \r
402 }\r