/* * Jalview - A Sequence Alignment Editor and Viewer * Copyright (C) 2007 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 java.util.*; import jalview.datamodel.*; /** * *
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; public static final int REPLACE = 4; 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, null); } public EditCommand(String description, int command, String replace, SequenceI[] seqs, int position, int number, AlignmentI al) { this.description = description; if (command == REPLACE) { edits = new Edit[] { new Edit(command, seqs, position, number, al, replace)}; } performEdit(0, null); } final public String getDescription() { return description; } public int getSize() { return edits == null ? 0 : edits.length; } final public AlignmentI getAlignment() { return edits[0].al; } /** * append a new editCommand * Note. this shouldn't be called if the edit is an operation affects more alignment objects than the one referenced * in al (for example, cut or pasting whole sequences). Use the form with an additional AlignmentI[] views parameter. * @param command * @param seqs * @param position * @param number * @param al * @param performEdit */ final public void appendEdit(int command, SequenceI[] seqs, int position, int number, AlignmentI al, boolean performEdit) { appendEdit(command, seqs, position, number, al, performEdit, null); } /** * append a new edit command with a set of alignment views that may be operated on * @param command * @param seqs * @param position * @param number * @param al * @param performEdit * @param views */ final public void appendEdit(int command, SequenceI[] seqs, int position, int number, AlignmentI al, boolean performEdit, AlignmentI[] views) { 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, views); } } final void performEdit(int commandIndex, AlignmentI[] views) { int eSize = edits.length; for (int e = commandIndex; e < eSize; e++) { switch(edits[e].command) { case INSERT_GAP: insertGap(edits[e]); break; case DELETE_GAP: deleteGap(edits[e]); break; case CUT: cut(edits[e], views); break; case PASTE: paste(edits[e], views); break; case REPLACE: replace(edits[e]); break; } } } final public void doCommand(AlignmentI[] views) { performEdit(0,views); } final public void undoCommand(AlignmentI[] views) { int e = 0, eSize = edits.length; for (e = eSize - 1; e > -1; e--) { switch (edits[e].command) { case INSERT_GAP: deleteGap(edits[e]); break; case DELETE_GAP: insertGap(edits[e]); break; case CUT: paste(edits[e], views); break; case PASTE: cut(edits[e], views); break; case REPLACE: replace(edits[e]); break; } } } final void insertGap(Edit command) { for (int s = 0; s < command.seqs.length; s++) { command.seqs[s].insertCharAt(command.position, command.number, command.gapChar); } adjustAnnotations(command, true, false, null); } final void deleteGap(Edit command) { for (int s = 0; s < command.seqs.length; s++) { command.seqs[s].deleteChars(command.position, command.position + command.number); } adjustAnnotations(command, false, false, null); } void cut(Edit command, AlignmentI[] views) { boolean seqDeleted=false; command.string = new char[command.seqs.length][]; for (int i = 0; i < command.seqs.length; i++) { if (command.seqs[i].getLength() > command.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]); seqDeleted=true; } } adjustAnnotations(command, false, seqDeleted, views); } void paste(Edit command, AlignmentI[] views) { StringBuffer tmp; boolean newDSNeeded; boolean seqWasDeleted=false; int start = 0, end = 0; for (int i = 0; i < command.seqs.length; i++) { newDSNeeded = false; if (command.seqs[i].getLength() < 1) { // ie this sequence was deleted, we need to // read it to the alignment if (command.alIndex[i] < command.al.getHeight()) { command.al.getSequences().insertElementAt(command.seqs[i], command.alIndex[i]); } else { command.al.addSequence(command.seqs[i]); } seqWasDeleted=true; } tmp = new StringBuffer(); tmp.append(command.seqs[i].getSequence()); if (command.string != null && command.string[i] != null) { if (command.position >= 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) { // use new ds mechanism here 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, seqWasDeleted, views); command.string = null; } void replace(Edit command) { StringBuffer tmp; String oldstring; int start = command.position; int end = command.number; command.number = start + command.string[0].length; for (int i = 0; i < command.seqs.length; i++) { oldstring = command.seqs[i].getSequenceAsString(); tmp = new StringBuffer(oldstring.substring(0, start)); tmp.append(command.string[i]); tmp.append(oldstring.substring(end)); command.seqs[i].setSequence(tmp.toString()); command.string[i] = oldstring.substring(start, end).toCharArray(); tmp = null; oldstring = null; } } final void adjustAnnotations(Edit command, boolean insert, boolean modifyVisibility, AlignmentI[] views) { AlignmentAnnotation[] annotations = null; if (modifyVisibility && !insert) { // only occurs if a sequence was added or deleted. command.deletedAnnotationRows = new Hashtable(); } if (command.fullAlignmentHeight) { annotations = command.al.getAlignmentAnnotation(); } else { int aSize = 0; AlignmentAnnotation[] tmp; for (int s = 0; s < command.seqs.length; s++) { if (modifyVisibility) { // Rows are only removed or added to sequence object. if (!insert) { // remove rows tmp = command.seqs[s].getAnnotation(); if (tmp!=null) { int alen=tmp.length; for (int aa =0; aa