X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fcommands%2FEditCommand.java;h=aff8595b99cb90981ff9730c7fbb089892e85145;hb=ab43013b7e357b84b4abade0dba949668dfb2a0e;hp=a8aa8860e1b6c23e6c6196b46908e71ed3856c2f;hpb=d6509fcf3a8cc90616e18cb22cec97f85c722bb8;p=jalview.git diff --git a/src/jalview/commands/EditCommand.java b/src/jalview/commands/EditCommand.java index a8aa886..aff8595 100644 --- a/src/jalview/commands/EditCommand.java +++ b/src/jalview/commands/EditCommand.java @@ -1,25 +1,36 @@ /* - * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7) - * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, G Barton, M Clamp, S Searle + * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2b1) + * Copyright (C) 2014 The Jalview Authors * * This file is part of Jalview. * * Jalview 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 3 of the License, or (at your option) any later version. - * + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * * Jalview 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 Jalview. If not, see . + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. */ package jalview.commands; -import java.util.*; +import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.Annotation; +import jalview.datamodel.Sequence; +import jalview.datamodel.SequenceFeature; +import jalview.datamodel.SequenceI; -import jalview.datamodel.*; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; +import java.util.ListIterator; /** * @@ -45,19 +56,12 @@ import jalview.datamodel.*; */ 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; - - public static final int INSERT_NUC=5; + public enum Action + { + INSERT_GAP, DELETE_GAP, CUT, PASTE, REPLACE, INSERT_NUC + }; - Edit[] edits; + private List edits = new ArrayList(); String description; @@ -70,45 +74,95 @@ public class EditCommand implements CommandI this.description = description; } - public EditCommand(String description, int command, SequenceI[] seqs, + public EditCommand(String description, Action command, SequenceI[] seqs, int position, int number, AlignmentI al) { this.description = description; - if (command == CUT || command == PASTE) + if (command == Action.CUT || command == Action.PASTE) { - edits = new Edit[] - { new Edit(command, seqs, position, number, al) }; + setEdit(new Edit(command, seqs, position, number, al)); } performEdit(0, null); } - public EditCommand(String description, int command, String replace, + public EditCommand(String description, Action command, String replace, SequenceI[] seqs, int position, int number, AlignmentI al) { this.description = description; - if (command == REPLACE) + if (command == Action.REPLACE) { - edits = new Edit[] - { new Edit(command, seqs, position, number, al, replace) }; + setEdit(new Edit(command, seqs, position, number, al, replace)); } performEdit(0, null); } + /** + * Set the list of edits to the specified item (only). + * + * @param e + */ + protected void setEdit(Edit e) + { + edits.clear(); + edits.add(e); + } + + /** + * Add the given edit command to the stored list of commands. + * + * @param e + */ + protected void addEdit(Edit e) + { + edits.add(e); + } + + /** + * Clear the list of stored edit commands. + * + */ + protected void clearEdits() + { + edits.clear(); + } + + /** + * Returns the i'th stored Edit command. + * + * @param i + * @return + */ + protected Edit getEdit(int i) + { + if (i >= 0 && i < edits.size()) + { + return edits.get(i); + } + return null; + } + + @Override final public String getDescription() { return description; } + @Override public int getSize() { - return edits == null ? 0 : edits.length; + return edits.size(); } + /** + * Return the alignment for the first edit (or null if no edit). + * + * @return + */ final public AlignmentI getAlignment() { - return edits[0].al; + return (edits.isEmpty() ? null : edits.get(0).al); } /** @@ -124,7 +178,8 @@ public class EditCommand implements CommandI * @param al * @param performEdit */ - final public void appendEdit(int command, SequenceI[] seqs, int position, + final public void appendEdit(Action command, SequenceI[] seqs, + int position, int number, AlignmentI al, boolean performEdit) { appendEdit(command, seqs, position, number, al, performEdit, null); @@ -142,7 +197,8 @@ public class EditCommand implements CommandI * @param performEdit * @param views */ - final public void appendEdit(int command, SequenceI[] seqs, int position, + final public void appendEdit(Action command, SequenceI[] seqs, + int position, int number, AlignmentI al, boolean performEdit, AlignmentI[] views) { Edit edit = new Edit(command, seqs, position, number, @@ -153,112 +209,146 @@ public class EditCommand implements CommandI 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 }; - } + edits.add(edit); if (performEdit) { - performEdit(edits.length - 1, views); + performEdit(edit, views); } } + /** + * Execute all the edit commands, starting at the given commandIndex + * + * @param commandIndex + * @param views + */ final void performEdit(int commandIndex, AlignmentI[] views) { - int eSize = edits.length; - for (int e = commandIndex; e < eSize; e++) + ListIterator iterator = edits.listIterator(commandIndex); + while (iterator.hasNext()) { - 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; - //TODO:add deleteNuc for UNDO -// case INSERT_NUC: -// insertNuc(edits[e]); -// break; - } + Edit edit = iterator.next(); + performEdit(edit, views); } } + /** + * Execute one edit command in all the specified alignment views + * + * @param edit + * @param views + */ + protected void performEdit(Edit edit, AlignmentI[] views) + { + switch (edit.command) + { + case INSERT_GAP: + insertGap(edit); + break; + case DELETE_GAP: + deleteGap(edit); + break; + case CUT: + cut(edit, views); + break; + case PASTE: + paste(edit, views); + break; + case REPLACE: + replace(edit); + break; + case INSERT_NUC: + // TODO:add deleteNuc for UNDO + // case INSERT_NUC: + // insertNuc(edits[e]); + break; + default: + break; + } + } + + @Override final public void doCommand(AlignmentI[] views) { performEdit(0, views); } + /** + * Undo the stored list of commands, in reverse order. + */ + @Override final public void undoCommand(AlignmentI[] views) - { - int e = 0, eSize = edits.length; - for (e = eSize - 1; e > -1; e--) + { + ListIterator iterator = edits.listIterator(edits.size()); + while (iterator.hasPrevious()) { - switch (edits[e].command) + Edit e = iterator.previous(); + switch (e.command) { case INSERT_GAP: - deleteGap(edits[e]); + deleteGap(e); break; case DELETE_GAP: - insertGap(edits[e]); + insertGap(e); break; case CUT: - paste(edits[e], views); + paste(e, views); break; case PASTE: - cut(edits[e], views); + cut(e, views); break; case REPLACE: - replace(edits[e]); + replace(e); break; - } + case INSERT_NUC: + // not implemented + break; + default: + break; + } } } - final void insertGap(Edit command) + /** + * Insert gap(s) in sequences as specified by the command, and adjust + * annotations. + * + * @param command + */ + final private void insertGap(Edit command) { for (int s = 0; s < command.seqs.length; s++) { command.seqs[s].insertCharAt(command.position, command.number, command.gapChar); -// System.out.println("pos: "+command.position+" number: "+command.number); + // System.out.println("pos: "+command.position+" number: "+command.number); } adjustAnnotations(command, true, false, null); } -// -// final void insertNuc(Edit command) -// { -// -// for (int s = 0; s < command.seqs.length; s++) -// { -// System.out.println("pos: "+command.position+" number: "+command.number); -// command.seqs[s].insertCharAt(command.position, command.number,'A'); -// } -// -// adjustAnnotations(command, true, false, null); -// } - - final void deleteGap(Edit command) + + // + // final void insertNuc(Edit command) + // { + // + // for (int s = 0; s < command.seqs.length; s++) + // { + // System.out.println("pos: "+command.position+" number: "+command.number); + // command.seqs[s].insertCharAt(command.position, command.number,'A'); + // } + // + // adjustAnnotations(command, true, false, null); + // } + + /** + * Delete gap(s) in sequences as specified by the command, and adjust + * annotations. + * + * @param command + */ + final private void deleteGap(Edit command) { for (int s = 0; s < command.seqs.length; s++) { @@ -269,6 +359,13 @@ public class EditCommand implements CommandI adjustAnnotations(command, false, false, null); } + /** + * Carry out a Cut action. The cut characters are saved in case Undo is + * requested. + * + * @param command + * @param views + */ void cut(Edit command, AlignmentI[] views) { boolean seqDeleted = false; @@ -276,29 +373,30 @@ public class EditCommand implements CommandI for (int i = 0; i < command.seqs.length; i++) { - if (command.seqs[i].getLength() > command.position) + final SequenceI sequence = command.seqs[i]; + if (sequence.getLength() > command.position) { - command.string[i] = command.seqs[i].getSequence(command.position, + command.string[i] = sequence.getSequence(command.position, command.position + command.number); - SequenceI oldds = command.seqs[i].getDatasetSequence(); + SequenceI oldds = sequence.getDatasetSequence(); if (command.oldds != null && command.oldds[i] != null) { // we are redoing an undone cut. - command.seqs[i].setDatasetSequence(null); + sequence.setDatasetSequence(null); } - command.seqs[i].deleteChars(command.position, command.position + sequence.deleteChars(command.position, command.position + command.number); if (command.oldds != null && command.oldds[i] != null) { // oldds entry contains the cut dataset sequence. - command.seqs[i].setDatasetSequence(command.oldds[i]); + sequence.setDatasetSequence(command.oldds[i]); command.oldds[i] = oldds; } else { // modify the oldds if necessary - if (oldds != command.seqs[i].getDatasetSequence() - || command.seqs[i].getSequenceFeatures() != null) + if (oldds != sequence.getDatasetSequence() + || sequence.getSequenceFeatures() != null) { if (command.oldds == null) { @@ -308,16 +406,16 @@ public class EditCommand implements CommandI adjustFeatures( command, i, - command.seqs[i].findPosition(command.position), - command.seqs[i].findPosition(command.position + sequence.findPosition(command.position), + sequence.findPosition(command.position + command.number), false); } } } - if (command.seqs[i].getLength() < 1) + if (sequence.getLength() < 1) { - command.al.deleteSequence(command.seqs[i]); + command.al.deleteSequence(sequence); seqDeleted = true; } } @@ -325,6 +423,13 @@ public class EditCommand implements CommandI adjustAnnotations(command, false, seqDeleted, views); } + /** + * Perform the given Paste command. This may be to add cut or copied sequences + * to an alignment, or to undo a 'Cut' action on a region of the alignment. + * + * @param command + * @param views + */ void paste(Edit command, AlignmentI[] views) { StringBuffer tmp; @@ -345,8 +450,12 @@ public class EditCommand implements CommandI if (command.alIndex[i] < command.al.getHeight()) { List sequences; - synchronized (sequences=command.al.getSequences()) { - sequences.add(command.alIndex[i], command.seqs[i]); + synchronized (sequences = command.al.getSequences()) + { + if (!(command.alIndex[i] < 0)) + { + sequences.add(command.alIndex[i], command.seqs[i]); + } } } else @@ -389,9 +498,13 @@ public class EditCommand implements CommandI + command.number); } if (command.seqs[i].getStart() == start) + { newstart--; + } else + { newend++; + } } } command.string[i] = null; @@ -448,6 +561,9 @@ public class EditCommand implements CommandI command.number = start + command.string[0].length; for (int i = 0; i < command.seqs.length; i++) { + boolean newDSWasNeeded = command.oldds != null + && command.oldds[i] != null; + /** * cut addHistoryItem(new EditCommand("Cut Sequences", EditCommand.CUT, * cut, sg.getStartRes(), sg.getEndRes()-sg.getStartRes()+1, @@ -462,9 +578,48 @@ public class EditCommand implements CommandI oldstring = command.seqs[i].getSequenceAsString(); tmp = new StringBuffer(oldstring.substring(0, start)); tmp.append(command.string[i]); + String nogaprep = jalview.analysis.AlignSeq.extractGaps( + jalview.util.Comparison.GapChars, new String( + command.string[i])); + int ipos = command.seqs[i].findPosition(start) + - command.seqs[i].getStart(); tmp.append(oldstring.substring(end)); command.seqs[i].setSequence(tmp.toString()); command.string[i] = oldstring.substring(start, end).toCharArray(); + String nogapold = jalview.analysis.AlignSeq.extractGaps( + jalview.util.Comparison.GapChars, new String( + command.string[i])); + if (!nogaprep.toLowerCase().equals(nogapold.toLowerCase())) + { + if (newDSWasNeeded) + { + SequenceI oldds = command.seqs[i].getDatasetSequence(); + command.seqs[i].setDatasetSequence(command.oldds[i]); + command.oldds[i] = oldds; + } + else + { + if (command.oldds == null) + { + command.oldds = new SequenceI[command.seqs.length]; + } + command.oldds[i] = command.seqs[i].getDatasetSequence(); + SequenceI newds = new Sequence( + command.seqs[i].getDatasetSequence()); + String fullseq, osp = newds.getSequenceAsString(); + fullseq = osp.substring(0, ipos) + nogaprep + + osp.substring(ipos + nogaprep.length()); + newds.setSequence(fullseq.toUpperCase()); + // TODO: JAL-1131 ensure newly created dataset sequence is added to + // the set of + // dataset sequences associated with the alignment. + // TODO: JAL-1131 fix up any annotation associated with new dataset + // sequence to ensure that original sequence/annotation relationships + // are preserved. + command.seqs[i].setDatasetSequence(newds); + + } + } tmp = null; oldstring = null; } @@ -478,7 +633,7 @@ public class EditCommand implements CommandI if (modifyVisibility && !insert) { // only occurs if a sequence was added or deleted. - command.deletedAnnotationRows = new Hashtable(); + command.deletedAnnotationRows = new Hashtable(); } if (command.fullAlignmentHeight) { @@ -562,7 +717,7 @@ public class EditCommand implements CommandI && command.deletedAnnotationRows .containsKey(command.seqs[s])) { - AlignmentAnnotation[] revealed = (AlignmentAnnotation[]) command.deletedAnnotationRows + AlignmentAnnotation[] revealed = command.deletedAnnotationRows .get(command.seqs[s]); command.seqs[s].setAlignmentAnnotation(revealed); if (revealed != null) @@ -633,7 +788,7 @@ public class EditCommand implements CommandI if (!insert) { - command.deletedAnnotations = new Hashtable(); + command.deletedAnnotations = new Hashtable(); } int aSize; @@ -653,10 +808,12 @@ public class EditCommand implements CommandI { temp = new Annotation[aSize + command.number]; if (annotations[a].padGaps) + { for (int aa = 0; aa < temp.length; aa++) { temp[aa] = new Annotation(command.gapChar + "", null, ' ', 0); } + } } else { @@ -694,7 +851,7 @@ public class EditCommand implements CommandI && command.deletedAnnotations .containsKey(annotations[a].annotationId)) { - Annotation[] restore = (Annotation[]) command.deletedAnnotations + Annotation[] restore = command.deletedAnnotations .get(annotations[a].annotationId); System.arraycopy(restore, 0, temp, command.position, @@ -712,7 +869,7 @@ public class EditCommand implements CommandI && command.deletedAnnotations .containsKey(annotations[a].annotationId)) { - Annotation[] restore = (Annotation[]) command.deletedAnnotations + Annotation[] restore = command.deletedAnnotations .get(annotations[a].annotationId); temp = new Annotation[annotations[a].annotations.length @@ -735,8 +892,10 @@ public class EditCommand implements CommandI int copylen = Math.min(command.position, annotations[a].annotations.length); if (copylen > 0) + { System.arraycopy(annotations[a].annotations, 0, temp, 0, copylen); // command.position); + } Annotation[] deleted = new Annotation[command.number]; if (copylen >= command.position) @@ -805,7 +964,7 @@ public class EditCommand implements CommandI if (command.editedFeatures != null && command.editedFeatures.containsKey(seq)) { - sequence.setSequenceFeatures((SequenceFeature[]) command.editedFeatures + sequence.setSequenceFeatures(command.editedFeatures .get(seq)); } @@ -861,7 +1020,7 @@ public class EditCommand implements CommandI if (command.editedFeatures == null) { - command.editedFeatures = new Hashtable(); + command.editedFeatures = new Hashtable(); } command.editedFeatures.put(seq, oldsf); @@ -874,15 +1033,15 @@ public class EditCommand implements CommandI boolean fullAlignmentHeight = false; - Hashtable deletedAnnotationRows; + Hashtable deletedAnnotationRows; - Hashtable deletedAnnotations; + Hashtable deletedAnnotations; - Hashtable editedFeatures; + Hashtable editedFeatures; AlignmentI al; - int command; + Action command; char[][] string; @@ -894,7 +1053,7 @@ public class EditCommand implements CommandI char gapChar; - Edit(int command, SequenceI[] seqs, int position, int number, + Edit(Action command, SequenceI[] seqs, int position, int number, char gapChar) { this.command = command; @@ -904,7 +1063,7 @@ public class EditCommand implements CommandI this.gapChar = gapChar; } - Edit(int command, SequenceI[] seqs, int position, int number, + Edit(Action command, SequenceI[] seqs, int position, int number, AlignmentI al) { this.gapChar = al.getGapCharacter(); @@ -923,7 +1082,7 @@ public class EditCommand implements CommandI fullAlignmentHeight = (al.getHeight() == seqs.length); } - Edit(int command, SequenceI[] seqs, int position, int number, + Edit(Action command, SequenceI[] seqs, int position, int number, AlignmentI al, String replace) { this.command = command;