boolean cutIsInternal = cutPositions != null
&& sequence.getStart() != cutPositions
.getBegin() && sequence.getEnd() != cutPositions.getEnd();
+
+ /*
+ * perform the cut; if this results in a new dataset sequence, add
+ * that to the alignment dataset
+ */
+ SequenceI ds = sequence.getDatasetSequence();
sequence.deleteChars(command.position, command.position
+ command.number);
+ SequenceI newDs = sequence.getDatasetSequence();
+ if (newDs != ds && command.al != null
+ && command.al.getDataset() != null
+ && !command.al.getDataset().getSequences().contains(newDs))
+ {
+ command.al.getDataset().addSequence(newDs);
+ }
if (command.oldds != null && command.oldds[i] != null)
{
{
command.oldds = new SequenceI[command.seqs.length];
}
- command.oldds[i] = oldds;
+ command.oldds[i] = oldds;// todo not if !cutIsInternal?
+ // do we need to edit sequence features for new sequence ?
+ if (oldds != sequence.getDatasetSequence()
+ || (cutIsInternal
+ && sequence.getFeatures().hasFeatures()))
+ // todo or just test cutIsInternal && cutPositions != null ?
+ {
if (cutPositions != null)
{
cutFeatures(command, sequence, cutPositions.getBegin(),
{
boolean newDSWasNeeded = command.oldds != null
&& command.oldds[i] != null;
+ boolean newStartEndWasNeeded = command.oldStartEnd!=null && command.oldStartEnd[i]!=null;
/**
* cut addHistoryItem(new EditCommand("Cut Sequences", EditCommand.CUT,
* EditCommand.PASTE, sequences, 0, alignment.getWidth(), alignment) );
*
*/
+
+ Range beforeEditedPositions = command.seqs[i].findPositions(1, start);
+ Range afterEditedPositions = command.seqs[i]
+ .findPositions(start + end + 1, command.seqs[i].getLength());
+
oldstring = command.seqs[i].getSequenceAsString();
tmp = new StringBuffer(oldstring.substring(0, start));
tmp.append(command.string[i]);
new String(command.string[i]));
int ipos = command.seqs[i].findPosition(start)
- command.seqs[i].getStart();
- tmp.append(oldstring.substring(end));
+ if (end < oldstring.length())
+ {
+ tmp.append(oldstring.substring(end));
+ }
command.seqs[i].setSequence(tmp.toString());
- command.string[i] = oldstring.substring(start, end).toCharArray();
+ command.string[i] = oldstring
+ .substring(start, Math.min(end, oldstring.length()))
+ .toCharArray();
String nogapold = AlignSeq.extractGaps(Comparison.GapChars,
new String(command.string[i]));
+
if (!nogaprep.toLowerCase().equals(nogapold.toLowerCase()))
{
+ // probably need a new dataset sequence
if (newDSWasNeeded)
{
+ // then just switch the dataset sequence
SequenceI oldds = command.seqs[i].getDatasetSequence();
command.seqs[i].setDatasetSequence(command.oldds[i]);
command.oldds[i] = oldds;
}
else
+ if (newStartEndWasNeeded)
{
- 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();
+ Range newStart = command.oldStartEnd[i];
+ command.oldStartEnd[i] = new Range(command.seqs[i].getStart(),
+ command.seqs[i].getEnd());
+ command.seqs[i].setStart(newStart.getBegin());
+ command.seqs[i].setEnd(newStart.getEnd());
+ }
+ else
+ {
+ // first edit the original dataset sequence string
+ SequenceI oldds = command.seqs[i].getDatasetSequence();
+ String fullseq, osp = oldds.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);
+ // and check if new sequence data is different..
+ if (!fullseq.equalsIgnoreCase(osp))
+ {
+ // old ds and edited ds are different, so
+ // create the new dataset sequence
+ SequenceI newds = new Sequence(oldds);
+ newds.setSequence(fullseq.toUpperCase());
+
+ if (command.oldds == null)
+ {
+ command.oldds = new SequenceI[command.seqs.length];
+ }
+ command.oldds[i] = command.seqs[i].getDatasetSequence();
+ // 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);
+ }
+ else
+ {
+ if (command.oldStartEnd == null)
+ {
+ command.oldStartEnd = new Range[command.seqs.length];
+ }
+ command.oldStartEnd[i] = new Range(command.seqs[i].getStart(),
+ command.seqs[i].getEnd());
+ if (beforeEditedPositions != null
+ && afterEditedPositions == null)
+ {
+ // modification at end
+ command.seqs[i].setEnd(
+ beforeEditedPositions.getEnd() + nogaprep.length());
+ }
+ else if (afterEditedPositions != null
+ && beforeEditedPositions == null)
+ {
+ // modification at start
+ command.seqs[i].setStart(
+ afterEditedPositions.getBegin() - nogaprep.length());
+ }
+ else
+ {
+ // edit covered both start and end. Here we can only guess the
+ // new
+ // start/end
+ String nogapalseq = jalview.analysis.AlignSeq.extractGaps(
+ jalview.util.Comparison.GapChars,
+ command.seqs[i].getSequenceAsString().toUpperCase());
+ int newStart = command.seqs[i].getDatasetSequence()
+ .getSequenceAsString().indexOf(nogapalseq);
+ if (newStart == -1)
+ {
+ throw new Error(
+ "Implementation Error: could not locate start/end "
+ + "in dataset sequence after an edit of the sequence string");
+ }
+ int newEnd = newStart + nogapalseq.length() - 1;
+ command.seqs[i].setStart(newStart);
+ command.seqs[i].setEnd(newEnd);
+ }
+ }
}
}
tmp = null;
{
public SequenceI[] oldds;
+ /**
+ * start and end of sequence prior to edit
+ */
+ public Range[] oldStartEnd;
+
boolean fullAlignmentHeight = false;
Map<SequenceI, AlignmentAnnotation[]> deletedAnnotationRows;
* <li>features right of the cut are shifted left</li>
* <li>features internal to the cut region are deleted</li>
* <li>features that overlap or span the cut are shortened</li>
- * <li>the originals of any deleted or shorted features are saved, to re-add
+ * <li>the originals of any deleted or shortened features are saved, to re-add
* on Undo</li>
* <li>any added (shortened) features are saved, to delete on Undo</li>
* </ul>
protected static void cutFeatures(Edit command, SequenceI seq,
int fromPosition, int toPosition, boolean cutIsInternal)
{
+ /*
+ * if the cut is at start or end of sequence
+ * then we don't modify the sequence feature store
+ */
if (!cutIsInternal)
{
return;
/*
* and left shift any features lying to the right of the cut region
- * (but not if the cut is at start or end of sequence)
*/
- if (cutIsInternal)
- {
- featureStore.shiftFeatures(cutEndPos + 1, -cutWidth);
- }
+
+ featureStore.shiftFeatures(cutEndPos + 1, -cutWidth);
}
/*