/* * Jalview - A Sequence Alignment Editor and Viewer * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package jalview.commands; import jalview.datamodel.*; import java.util.Hashtable; /** * *

Title: EditCommmand

* *

Description: Essential information for performing * undo and redo for cut/paste insert/delete gap * which can be stored in the HistoryList

* *

Copyright: Copyright (c) 2006

* *

Company: Dundee University

* * @author not attributable * @version 1.0 */ public class EditCommand implements CommandI { public static final int INSERT_GAP = 0; public static final int DELETE_GAP = 1; public static final int CUT = 2; public static final int PASTE = 3; Edit[] edits; String description; public EditCommand() {} public EditCommand(String description) { this.description = description; } public EditCommand( String description, int command, SequenceI[] seqs, int position, int number, AlignmentI al) { this.description = description; if ( command==CUT || command==PASTE) { edits = new Edit[]{new Edit(command, seqs, position, number, al)}; } performEdit(0); } final public String getDescription() { return description; } public int getSize() { return edits==null?0:edits.length; } final public AlignmentI getAlignment() { return edits[0].al; } final public void appendEdit(int command, SequenceI[] seqs, int position, int number, AlignmentI al, boolean performEdit) { Edit edit = new Edit(command, seqs, position, number, al.getGapCharacter()); if(al.getHeight()==seqs.length) { edit.al = al; edit.fullAlignmentHeight = true; } if (edits != null) { Edit[] temp = new Edit[edits.length + 1]; System.arraycopy(edits, 0, temp, 0, edits.length); edits = temp; edits[edits.length - 1] = edit; } else edits = new Edit[] { edit }; if (performEdit) performEdit(edits.length - 1); } final void performEdit(int commandIndex) { int eSize = edits.length; for (int e = commandIndex; e < eSize; e++) { if (edits[e].command==INSERT_GAP) { insertGap(edits[e]); } else if (edits[e].command==DELETE_GAP) { deleteGap(edits[e]); } else if(edits[e].command==CUT) { cut(edits[e]); } else if(edits[e].command==PASTE) { paste(edits[e]); } } } final public void doCommand() { performEdit(0); } final public void undoCommand() { int e = 0, eSize = edits.length; for (e = eSize-1; e > -1; e--) { if (edits[e].command==INSERT_GAP) { deleteGap(edits[e]); } else if (edits[e].command==DELETE_GAP) { insertGap(edits[e]); } else if (edits[e].command==CUT) { paste(edits[e]); } else if (edits[e].command==PASTE) { cut(edits[e]); } } } final void insertGap(Edit command) { for(int s=0; scommand.position) { command.string[i] = command.seqs[i].getSequence(command.position, command.position + command.number); if(command.seqs[i].getDatasetSequence()!=null || command.seqs[i].getSequenceFeatures()!=null) { for (int s = command.position; s < command.position + command.number; s++) { if (jalview.schemes.ResidueProperties .aaIndex[command.seqs[i].getCharAt(s)] != 23) { adjustFeatures(command, i, command.seqs[i].findPosition(command.position), command.seqs[i].findPosition(command.position + command.number), false); break; } } } command.seqs[i].deleteChars(command.position, command.position + command.number); } if(command.seqs[i].getLength()<1) { command.al.deleteSequence(command.seqs[i]); } } adjustAnnotations(command, false); } void paste(Edit command) { StringBuffer tmp; boolean newDSNeeded; int start=0, end=0; for(int i=0; i=tmp.length()) { //This occurs if padding is on, and residues //are removed from end of alignment int length = command.position-tmp.length(); while (length > 0) { tmp.append(command.gapChar); length--; } } tmp.insert(command.position, command.string[i]); for (int s = 0; s < command.string[i].length; s++) { if (jalview.schemes.ResidueProperties.aaIndex[command.string[i][s]] != 23) { newDSNeeded = true; start = command.seqs[i].findPosition(command.position); end = command.seqs[i].findPosition(command.position+command.number); break; } } command.string[i] = null; } command.seqs[i].setSequence(tmp.toString()); if(newDSNeeded) { if (command.seqs[i].getDatasetSequence() != null) { Sequence ds = new Sequence(command.seqs[i].getName(), jalview.analysis.AlignSeq.extractGaps( jalview.util.Comparison.GapChars, command.seqs[i].getSequenceAsString() ), command.seqs[i].getStart(), command.seqs[i].getEnd()); ds.setDescription(command.seqs[i].getDescription()); command.seqs[i].setDatasetSequence(ds); } adjustFeatures(command, i, start, end, true); } } adjustAnnotations(command, true); command.string = null; } final void adjustAnnotations(Edit command, boolean insert) { AlignmentAnnotation [] annotations = null; if (command.fullAlignmentHeight) { annotations = command.al.getAlignmentAnnotation(); } else { int aSize = 0; AlignmentAnnotation [] tmp; for(int s=0; s 0) temp = new Annotation[aSize - command.number + command.position]; else temp = new Annotation[aSize]; } else temp = new Annotation[aSize]; } if(insert) { if(command.position < annotations[a].annotations.length) { System.arraycopy(annotations[a].annotations, 0, temp, 0, command.position); if (command.deletedAnnotations != null && command.deletedAnnotations.containsKey(annotations[a].annotationId)) { Annotation[] restore = (Annotation[]) command.deletedAnnotations.get(annotations[a].annotationId); System.arraycopy(restore, 0, temp, command.position, command.number); } System.arraycopy(annotations[a].annotations, command.position, temp, command.position + command.number, aSize - command.position); } else temp = annotations[a].annotations; } else { if(command.position < aSize && aSize - command.number+command.position>0) { System.arraycopy(annotations[a].annotations, 0, temp, 0, command.position); Annotation[] deleted = new Annotation[command.number]; System.arraycopy(annotations[a].annotations, command.position, deleted, 0, command.number); command.deletedAnnotations.put(annotations[a].annotationId, deleted); System.arraycopy(annotations[a].annotations, command.position + command.number, temp, command.position, aSize - command.position - command.number); } else temp = annotations[a].annotations; } annotations[a].annotations = temp; } } final void adjustFeatures(Edit command, int index, int i, int j, boolean insert) { SequenceI seq = command.seqs[index]; SequenceI sequence = seq.getDatasetSequence(); if(sequence==null) sequence = seq; if(insert) { if (command.editedFeatures != null && command.editedFeatures.containsKey(seq)) sequence.setSequenceFeatures( (SequenceFeature[]) command.editedFeatures.get(seq) ); return; } SequenceFeature [] sf = sequence.getSequenceFeatures(); if(sf==null) { return; } SequenceFeature [] oldsf = new SequenceFeature[sf.length]; int cSize = j - i; for (int s = 0; s < sf.length; s++) { SequenceFeature copy = new SequenceFeature(sf[s]); oldsf[s] = copy; if (sf[s].getEnd() < i) continue; if (sf[s].getBegin() > j) { sf[s].setBegin(copy.getBegin() - cSize); sf[s].setEnd(copy.getEnd() - cSize); continue; } if (sf[s].getBegin() >= i) sf[s].setBegin(i); if (sf[s].getEnd() < j) sf[s].setEnd(j - 1); sf[s].setEnd(sf[s].getEnd() - (cSize)); if (sf[s].getBegin() > sf[s].getEnd()) sequence.deleteFeature(sf[s]); } if (command.editedFeatures == null) command.editedFeatures = new Hashtable(); command.editedFeatures.put(seq, oldsf); } class Edit { boolean fullAlignmentHeight = false; Hashtable deletedAnnotations; Hashtable editedFeatures; AlignmentI al; int command; char [][] string; SequenceI[] seqs; int [] alIndex; int position, number; char gapChar; Edit(int command, SequenceI[] seqs, int position, int number, char gapChar) { this.command = command; this.seqs = seqs; this.position = position; this.number = number; this.gapChar = gapChar; } Edit(int command, SequenceI[] seqs, int position, int number, AlignmentI al) { this.gapChar = al.getGapCharacter(); this.command = command; this.seqs = seqs; this.position = position; this.number = number; this.al = al; alIndex = new int[seqs.length]; for(int i=0; i