2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
3 * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 import java.awt.event.*;
27 import jalview.commands.*;
28 import jalview.datamodel.*;
29 import jalview.schemes.*;
30 import jalview.structure.*;
38 public class SeqPanel extends JPanel implements MouseListener,
39 MouseMotionListener, MouseWheelListener, SequenceListener
43 public SeqCanvas seqCanvas;
46 public AlignmentPanel ap;
48 protected int lastres;
50 protected int startseq;
52 protected AlignViewport av;
54 ScrollThread scrollThread = null;
56 boolean mouseDragging = false;
58 boolean editingSeqs = false;
60 boolean groupEditing = false;
62 // ////////////////////////////////////////
63 // ///Everything below this is for defining the boundary of the rubberband
64 // ////////////////////////////////////////
67 boolean changeEndSeq = false;
69 boolean changeStartSeq = false;
71 boolean changeEndRes = false;
73 boolean changeStartRes = false;
75 SequenceGroup stretchGroup = null;
77 boolean remove = false;
81 boolean mouseWheelPressed = false;
83 StringBuffer keyboardNo1;
85 StringBuffer keyboardNo2;
87 java.net.URL linkImageURL;
89 StringBuffer tooltipText = new StringBuffer("<html>");
93 EditCommand editCommand;
95 StructureSelectionManager ssm;
98 * Creates a new SeqPanel object.
105 public SeqPanel(AlignViewport av, AlignmentPanel ap)
107 linkImageURL = getClass().getResource("/images/link.gif");
108 ToolTipManager.sharedInstance().registerComponent(this);
109 ToolTipManager.sharedInstance().setInitialDelay(0);
110 ToolTipManager.sharedInstance().setDismissDelay(10000);
112 setBackground(Color.white);
114 seqCanvas = new SeqCanvas(ap);
115 setLayout(new BorderLayout());
116 add(seqCanvas, BorderLayout.CENTER);
122 addMouseMotionListener(this);
123 addMouseListener(this);
124 addMouseWheelListener(this);
125 ssm = StructureSelectionManager.getStructureSelectionManager();
126 ssm.addStructureViewerListener(this);
130 int startWrapBlock = -1;
132 int wrappedBlock = -1;
134 int findRes(MouseEvent evt)
139 if (av.wrapAlignment)
142 int hgap = av.charHeight;
143 if (av.scaleAboveWrapped)
145 hgap += av.charHeight;
148 int cHeight = av.getAlignment().getHeight() * av.charHeight + hgap
149 + seqCanvas.getAnnotationHeight();
153 x -= seqCanvas.LABEL_WEST;
155 int cwidth = seqCanvas.getWrappedCanvasWidth(this.getWidth());
161 wrappedBlock = y / cHeight;
162 wrappedBlock += av.getStartRes() / cwidth;
164 res = wrappedBlock * cwidth + x / av.getCharWidth();
169 res = (x / av.getCharWidth()) + av.getStartRes();
172 if (av.hasHiddenColumns)
174 res = av.getColumnSelection().adjustForHiddenColumns(res);
181 int findSeq(MouseEvent evt)
186 if (av.wrapAlignment)
188 int hgap = av.charHeight;
189 if (av.scaleAboveWrapped)
191 hgap += av.charHeight;
194 int cHeight = av.getAlignment().getHeight() * av.charHeight + hgap
195 + seqCanvas.getAnnotationHeight();
199 seq = Math.min((y % cHeight) / av.getCharHeight(), av.alignment
204 seq = Math.min((y / av.getCharHeight()) + av.getStartSeq(),
205 av.alignment.getHeight() - 1);
211 SequenceFeature[] findFeaturesAtRes(SequenceI sequence, int res)
213 Vector tmp = new Vector();
214 SequenceFeature[] features = sequence.getSequenceFeatures();
215 if (features != null)
217 for (int i = 0; i < features.length; i++)
219 if (av.featuresDisplayed == null
220 || !av.featuresDisplayed.containsKey(features[i].getType()))
225 if (features[i].featureGroup != null
226 && seqCanvas.fr.featureGroups != null
227 && seqCanvas.fr.featureGroups
228 .containsKey(features[i].featureGroup)
229 && !((Boolean) seqCanvas.fr.featureGroups
230 .get(features[i].featureGroup)).booleanValue())
233 if ((features[i].getBegin() <= res)
234 && (features[i].getEnd() >= res))
236 tmp.addElement(features[i]);
241 features = new SequenceFeature[tmp.size()];
242 tmp.copyInto(features);
249 if (editCommand != null && editCommand.getSize() > 0)
251 ap.alignFrame.addHistoryItem(editCommand);
252 av.firePropertyChange("alignment", null, av.getAlignment()
259 groupEditing = false;
267 seqCanvas.cursorY = getKeyboardNo1() - 1;
271 void setCursorColumn()
273 seqCanvas.cursorX = getKeyboardNo1() - 1;
277 void setCursorRowAndColumn()
279 if (keyboardNo2 == null)
281 keyboardNo2 = new StringBuffer();
285 seqCanvas.cursorX = getKeyboardNo1() - 1;
286 seqCanvas.cursorY = getKeyboardNo2() - 1;
291 void setCursorPosition()
293 SequenceI sequence = (Sequence) av.getAlignment().getSequenceAt(
296 seqCanvas.cursorX = sequence.findIndex(getKeyboardNo1() - 1);
300 void moveCursor(int dx, int dy)
302 seqCanvas.cursorX += dx;
303 seqCanvas.cursorY += dy;
304 if (av.hasHiddenColumns && !av.colSel.isVisible(seqCanvas.cursorX))
306 int original = seqCanvas.cursorX - dx;
307 int maxWidth = av.alignment.getWidth();
309 while (!av.colSel.isVisible(seqCanvas.cursorX)
310 && seqCanvas.cursorX < maxWidth && seqCanvas.cursorX > 0)
312 seqCanvas.cursorX += dx;
315 if (seqCanvas.cursorX >= maxWidth
316 || !av.colSel.isVisible(seqCanvas.cursorX))
318 seqCanvas.cursorX = original;
325 void scrollToVisible()
327 if (seqCanvas.cursorX < 0)
329 seqCanvas.cursorX = 0;
331 else if (seqCanvas.cursorX > av.alignment.getWidth() - 1)
333 seqCanvas.cursorX = av.alignment.getWidth() - 1;
336 if (seqCanvas.cursorY < 0)
338 seqCanvas.cursorY = 0;
340 else if (seqCanvas.cursorY > av.alignment.getHeight() - 1)
342 seqCanvas.cursorY = av.alignment.getHeight() - 1;
346 if (av.wrapAlignment)
348 ap.scrollToWrappedVisible(seqCanvas.cursorX);
352 while (seqCanvas.cursorY < av.startSeq)
356 while (seqCanvas.cursorY + 1 > av.endSeq)
360 if (!av.wrapAlignment)
362 while (seqCanvas.cursorX < av.colSel
363 .adjustForHiddenColumns(av.startRes))
365 if (!ap.scrollRight(false))
370 while (seqCanvas.cursorX > av.colSel
371 .adjustForHiddenColumns(av.endRes))
373 if (!ap.scrollRight(true))
380 setStatusMessage(av.alignment.getSequenceAt(seqCanvas.cursorY),
381 seqCanvas.cursorX, seqCanvas.cursorY);
386 void setSelectionAreaAtCursor(boolean topLeft)
388 SequenceI sequence = (Sequence) av.getAlignment().getSequenceAt(
391 if (av.getSelectionGroup() != null)
393 SequenceGroup sg = av.selectionGroup;
394 // Find the top and bottom of this group
395 int min = av.alignment.getHeight(), max = 0;
396 for (int i = 0; i < sg.getSize(); i++)
398 int index = av.alignment.findIndex(sg.getSequenceAt(i));
413 sg.setStartRes(seqCanvas.cursorX);
414 if (sg.getEndRes() < seqCanvas.cursorX)
416 sg.setEndRes(seqCanvas.cursorX);
419 min = seqCanvas.cursorY;
423 sg.setEndRes(seqCanvas.cursorX);
424 if (sg.getStartRes() > seqCanvas.cursorX)
426 sg.setStartRes(seqCanvas.cursorX);
429 max = seqCanvas.cursorY + 1;
434 // Only the user can do this
435 av.setSelectionGroup(null);
439 // Now add any sequences between min and max
440 sg.getSequences(null).clear();
441 for (int i = min; i < max; i++)
443 sg.addSequence(av.alignment.getSequenceAt(i), false);
448 if (av.getSelectionGroup() == null)
450 SequenceGroup sg = new SequenceGroup();
451 sg.setStartRes(seqCanvas.cursorX);
452 sg.setEndRes(seqCanvas.cursorX);
453 sg.addSequence(sequence, false);
454 av.setSelectionGroup(sg);
457 ap.paintAlignment(false);
460 void insertGapAtCursor(boolean group)
462 groupEditing = group;
463 startseq = seqCanvas.cursorY;
464 lastres = seqCanvas.cursorX;
465 editSequence(true, seqCanvas.cursorX + getKeyboardNo1());
469 void deleteGapAtCursor(boolean group)
471 groupEditing = group;
472 startseq = seqCanvas.cursorY;
473 lastres = seqCanvas.cursorX + getKeyboardNo1();
474 editSequence(false, seqCanvas.cursorX);
478 void numberPressed(char value)
480 if (keyboardNo1 == null)
482 keyboardNo1 = new StringBuffer();
485 if (keyboardNo2 != null)
487 keyboardNo2.append(value);
491 keyboardNo1.append(value);
497 if (keyboardNo1 == null)
501 int value = Integer.parseInt(keyboardNo1.toString());
509 if (keyboardNo2 == null)
513 int value = Integer.parseInt(keyboardNo2.toString());
525 public void mouseReleased(MouseEvent evt)
527 mouseDragging = false;
528 mouseWheelPressed = false;
532 doMouseReleasedDefineMode(evt);
545 public void mousePressed(MouseEvent evt)
547 lastMousePress = evt.getPoint();
549 if (javax.swing.SwingUtilities.isMiddleMouseButton(evt))
551 mouseWheelPressed = true;
555 if (evt.isShiftDown() || evt.isAltDown() || evt.isControlDown())
557 if (evt.isAltDown() || evt.isControlDown())
565 doMousePressedDefineMode(evt);
569 int seq = findSeq(evt);
570 int res = findRes(evt);
572 if (seq < 0 || res < 0)
577 if ((seq < av.getAlignment().getHeight())
578 && (res < av.getAlignment().getSequenceAt(seq).getLength()))
594 public void mouseOverSequence(SequenceI sequence, int index, int pos)
596 String tmp = sequence.hashCode() + " " + index + " " + pos;
598 if (lastMessage == null || !lastMessage.equals(tmp))
600 // System.err.println("mouseOver Sequence: "+tmp);
601 ssm.mouseOverSequence(sequence, index, pos);
606 public void highlightSequence(SearchResults results)
608 seqCanvas.highlightSearchResults(results);
611 public void updateColours(SequenceI seq, int index)
613 System.out.println("update the seqPanel colours");
623 public void mouseMoved(MouseEvent evt)
627 // This is because MacOSX creates a mouseMoved
628 // If control is down, other platforms will not.
632 int res = findRes(evt);
633 int seq = findSeq(evt);
635 if (res < 0 || seq < 0 || seq >= av.getAlignment().getHeight())
640 SequenceI sequence = av.getAlignment().getSequenceAt(seq);
642 if (res >= sequence.getLength())
647 pos = setStatusMessage(sequence, res, seq);
648 if (ssm != null && pos > -1)
649 mouseOverSequence(sequence, res, pos);
651 tooltipText.setLength(6); // Cuts the buffer back to <html>
653 SequenceGroup[] groups = av.alignment.findAllGroups(sequence);
656 for (int g = 0; g < groups.length; g++)
658 if (groups[g].getStartRes() <= res && groups[g].getEndRes() >= res)
660 if (tooltipText.length() > 6)
662 tooltipText.append("<br>");
665 if (!groups[g].getName().startsWith("JTreeGroup")
666 && !groups[g].getName().startsWith("JGroup"))
668 tooltipText.append(groups[g].getName());
671 if (groups[g].getDescription() != null)
673 tooltipText.append(": " + groups[g].getDescription());
679 // use aa to see if the mouse pointer is on a
680 if (av.showSequenceFeatures)
682 SequenceFeature[] features = findFeaturesAtRes(sequence
683 .getDatasetSequence(), sequence.findPosition(res));
685 if (features != null)
687 for (int i = 0; i < features.length; i++)
689 if (features[i].getType().equals("disulfide bond"))
691 if (features[i].getBegin() == sequence.findPosition(res)
692 || features[i].getEnd() == sequence.findPosition(res))
694 if (tooltipText.length() > 6)
696 tooltipText.append("<br>");
698 tooltipText.append("disulfide bond " + features[i].getBegin()
699 + ":" + features[i].getEnd());
700 if (features[i].links != null)
702 tooltipText.append(" <img src=\"" + linkImageURL + "\">");
708 if (tooltipText.length() > 6)
710 tooltipText.append("<br>");
713 tooltipText.append(features[i].getType() + " "
714 + features[i].begin);
715 if (features[i].begin != features[i].end)
717 tooltipText.append(" " + features[i].end);
720 if (features[i].getDescription() != null
721 && !features[i].description.equals(features[i]
724 tmpString = features[i].getDescription();
725 int startTag = tmpString.toUpperCase().indexOf("<HTML>");
728 tmpString = tmpString.substring(startTag + 6);
730 int endTag = tmpString.toUpperCase().indexOf("</BODY>");
733 tmpString = tmpString.substring(0, endTag);
735 endTag = tmpString.toUpperCase().indexOf("</HTML>");
738 tmpString = tmpString.substring(0, endTag);
743 tooltipText.append("; " + tmpString);
747 if (tmpString.indexOf("<") > -1
748 || tmpString.indexOf(">") > -1)
750 // The description does not specify html is to
751 // be used, so we must remove < > symbols
752 tmpString = tmpString.replaceAll("<", "<");
753 tmpString = tmpString.replaceAll(">", ">");
755 tooltipText.append("; ");
756 tooltipText.append(tmpString);
761 tooltipText.append("; " + tmpString);
765 if (features[i].getValue("status") != null)
767 String status = features[i].getValue("status").toString();
768 if (status.length() > 0)
770 tooltipText.append("; (" + features[i].getValue("status")
775 if (features[i].links != null)
777 tooltipText.append(" <img src=\"" + linkImageURL + "\">");
785 if (tooltipText.length() == 6) // <html></html>
787 setToolTipText(null);
791 tooltipText.append("</html>");
792 if (lastTooltip == null
793 || !lastTooltip.equals(tooltipText.toString()))
794 setToolTipText(tooltipText.toString());
796 lastTooltip = tooltipText.toString();
804 * Set status message in alignment panel
807 * aligned sequence object
811 * index of sequence in alignment
812 * @return position of res in sequence
814 int setStatusMessage(SequenceI sequence, int res, int seq)
817 StringBuffer text = new StringBuffer("Sequence " + (seq + 1) + " ID: "
818 + sequence.getName());
821 if (av.alignment.isNucleotide())
823 obj = ResidueProperties.nucleotideName.get(sequence.getCharAt(res)
827 text.append(" Nucleotide: ");
832 obj = ResidueProperties.aa2Triplet.get(sequence.getCharAt(res) + "");
835 text.append(" Residue: ");
841 pos = sequence.findPosition(res);
844 text.append(obj + " (" + pos + ")");
847 ap.alignFrame.statusBar.setText(text.toString());
857 public void mouseDragged(MouseEvent evt)
859 if (mouseWheelPressed)
861 int oldWidth = av.charWidth;
863 // Which is bigger, left-right or up-down?
864 if (Math.abs(evt.getY() - lastMousePress.getY()) > Math.abs(evt
866 - lastMousePress.getX()))
868 int fontSize = av.font.getSize();
870 if (evt.getY() < lastMousePress.getY())
874 else if (evt.getY() > lastMousePress.getY())
885 .setFont(new Font(av.font.getName(), av.font.getStyle(),
887 av.charWidth = oldWidth;
892 if (evt.getX() < lastMousePress.getX() && av.charWidth > 1)
896 else if (evt.getX() > lastMousePress.getX())
901 ap.paintAlignment(false);
904 FontMetrics fm = getFontMetrics(av.getFont());
905 av.validCharWidth = fm.charWidth('M') <= av.charWidth;
907 lastMousePress = evt.getPoint();
914 doMouseDraggedDefineMode(evt);
918 int res = findRes(evt);
925 if ((lastres == -1) || (lastres == res))
930 if ((res < av.getAlignment().getWidth()) && (res < lastres))
932 // dragLeft, delete gap
933 editSequence(false, res);
937 editSequence(true, res);
940 mouseDragging = true;
941 if (scrollThread != null)
943 scrollThread.setEvent(evt);
947 synchronized void editSequence(boolean insertGap, int startres)
951 boolean fixedColumns = false;
952 SequenceGroup sg = av.getSelectionGroup();
954 SequenceI seq = av.alignment.getSequenceAt(startseq);
956 // No group, but the sequence may represent a group
957 if (!groupEditing && av.hasHiddenRows)
959 if (av.hiddenRepSequences != null
960 && av.hiddenRepSequences.containsKey(seq))
962 sg = (SequenceGroup) av.hiddenRepSequences.get(seq);
967 StringBuffer message = new StringBuffer();
970 message.append("Edit group:");
971 if (editCommand == null)
973 editCommand = new EditCommand("Edit Group");
978 message.append("Edit sequence: " + seq.getName());
979 String label = seq.getName();
980 if (label.length() > 10)
982 label = label.substring(0, 10);
984 if (editCommand == null)
986 editCommand = new EditCommand("Edit " + label);
992 message.append(" insert ");
996 message.append(" delete ");
999 message.append(Math.abs(startres - lastres) + " gaps.");
1000 ap.alignFrame.statusBar.setText(message.toString());
1002 // Are we editing within a selection group?
1004 || (sg != null && sg.getSequences(av.hiddenRepSequences)
1007 fixedColumns = true;
1009 // sg might be null as the user may only see 1 sequence,
1010 // but the sequence represents a group
1013 if (av.hiddenRepSequences == null
1014 || !av.hiddenRepSequences.containsKey(seq))
1019 sg = (SequenceGroup) av.hiddenRepSequences.get(seq);
1022 fixedLeft = sg.getStartRes();
1023 fixedRight = sg.getEndRes();
1025 if ((startres < fixedLeft && lastres >= fixedLeft)
1026 || (startres >= fixedLeft && lastres < fixedLeft)
1027 || (startres > fixedRight && lastres <= fixedRight)
1028 || (startres <= fixedRight && lastres > fixedRight))
1034 if (fixedLeft > startres)
1036 fixedRight = fixedLeft - 1;
1039 else if (fixedRight < startres)
1041 fixedLeft = fixedRight;
1046 if (av.hasHiddenColumns)
1048 fixedColumns = true;
1049 int y1 = av.getColumnSelection().getHiddenBoundaryLeft(startres);
1050 int y2 = av.getColumnSelection().getHiddenBoundaryRight(startres);
1052 if ((insertGap && startres > y1 && lastres < y1)
1053 || (!insertGap && startres < y2 && lastres > y2))
1059 // System.out.print(y1+" "+y2+" "+fixedLeft+" "+fixedRight+"~~");
1060 // Selection spans a hidden region
1061 if (fixedLeft < y1 && (fixedRight > y2 || fixedRight == -1))
1069 fixedRight = y2 - 1;
1076 Vector vseqs = sg.getSequences(av.hiddenRepSequences);
1077 int g, groupSize = vseqs.size();
1078 SequenceI[] groupSeqs = new SequenceI[groupSize];
1079 for (g = 0; g < groupSeqs.length; g++)
1081 groupSeqs[g] = (SequenceI) vseqs.elementAt(g);
1087 // If the user has selected the whole sequence, and is dragging to
1088 // the right, we can still extend the alignment and selectionGroup
1089 if (sg.getStartRes() == 0 && sg.getEndRes() == fixedRight
1090 && sg.getEndRes() == av.alignment.getWidth() - 1)
1092 sg.setEndRes(av.alignment.getWidth() + startres - lastres);
1093 fixedRight = sg.getEndRes();
1096 // Is it valid with fixed columns??
1097 // Find the next gap before the end
1098 // of the visible region boundary
1099 boolean blank = false;
1100 for (fixedRight = fixedRight; fixedRight > lastres; fixedRight--)
1104 for (g = 0; g < groupSize; g++)
1106 for (int j = 0; j < startres - lastres; j++)
1108 if (!jalview.util.Comparison.isGap(groupSeqs[g]
1109 .getCharAt(fixedRight - j)))
1124 if (sg.getSize() == av.alignment.getHeight())
1126 if ((av.hasHiddenColumns && startres < av.getColumnSelection()
1127 .getHiddenBoundaryRight(startres)))
1133 int alWidth = av.alignment.getWidth();
1134 if (av.hasHiddenRows)
1136 int hwidth = av.alignment.getHiddenSequences().getWidth();
1137 if (hwidth > alWidth)
1142 // We can still insert gaps if the selectionGroup
1143 // contains all the sequences
1144 sg.setEndRes(sg.getEndRes() + startres - lastres);
1145 fixedRight = alWidth + startres - lastres;
1156 else if (!insertGap)
1158 // / Are we able to delete?
1159 // ie are all columns blank?
1161 for (g = 0; g < groupSize; g++)
1163 for (int j = startres; j < lastres; j++)
1165 if (groupSeqs[g].getLength() <= j)
1170 if (!jalview.util.Comparison.isGap(groupSeqs[g].getCharAt(j)))
1172 // Not a gap, block edit not valid
1182 // dragging to the right
1183 if (fixedColumns && fixedRight != -1)
1185 for (int j = lastres; j < startres; j++)
1187 insertChar(j, groupSeqs, fixedRight);
1192 editCommand.appendEdit(EditCommand.INSERT_GAP, groupSeqs,
1193 startres, startres - lastres, av.alignment, true);
1198 // dragging to the left
1199 if (fixedColumns && fixedRight != -1)
1201 for (int j = lastres; j > startres; j--)
1203 deleteChar(startres, groupSeqs, fixedRight);
1208 editCommand.appendEdit(EditCommand.DELETE_GAP, groupSeqs,
1209 startres, lastres - startres, av.alignment, true);
1215 // ///Editing a single sequence///////////
1219 // dragging to the right
1220 if (fixedColumns && fixedRight != -1)
1222 for (int j = lastres; j < startres; j++)
1224 insertChar(j, new SequenceI[]
1225 { seq }, fixedRight);
1230 editCommand.appendEdit(EditCommand.INSERT_GAP, new SequenceI[]
1231 { seq }, lastres, startres - lastres, av.alignment, true);
1236 // dragging to the left
1237 if (fixedColumns && fixedRight != -1)
1239 for (int j = lastres; j > startres; j--)
1241 if (!jalview.util.Comparison.isGap(seq.getCharAt(startres)))
1246 deleteChar(startres, new SequenceI[]
1247 { seq }, fixedRight);
1252 // could be a keyboard edit trying to delete none gaps
1254 for (int m = startres; m < lastres; m++)
1256 if (!jalview.util.Comparison.isGap(seq.getCharAt(m)))
1265 editCommand.appendEdit(EditCommand.DELETE_GAP, new SequenceI[]
1266 { seq }, startres, max, av.alignment, true);
1273 seqCanvas.repaint();
1276 void insertChar(int j, SequenceI[] seq, int fixedColumn)
1278 int blankColumn = fixedColumn;
1279 for (int s = 0; s < seq.length; s++)
1281 // Find the next gap before the end of the visible region boundary
1282 // If lastCol > j, theres a boundary after the gap insertion
1284 for (blankColumn = fixedColumn; blankColumn > j; blankColumn--)
1286 if (jalview.util.Comparison.isGap(seq[s].getCharAt(blankColumn)))
1288 // Theres a space, so break and insert the gap
1293 if (blankColumn <= j)
1295 blankColumn = fixedColumn;
1301 editCommand.appendEdit(EditCommand.DELETE_GAP, seq, blankColumn, 1,
1302 av.alignment, true);
1304 editCommand.appendEdit(EditCommand.INSERT_GAP, seq, j, 1, av.alignment,
1309 void deleteChar(int j, SequenceI[] seq, int fixedColumn)
1312 editCommand.appendEdit(EditCommand.DELETE_GAP, seq, j, 1, av.alignment,
1315 editCommand.appendEdit(EditCommand.INSERT_GAP, seq, fixedColumn, 1,
1316 av.alignment, true);
1325 public void mouseEntered(MouseEvent e)
1332 if (scrollThread != null)
1334 scrollThread.running = false;
1335 scrollThread = null;
1345 public void mouseExited(MouseEvent e)
1347 if (av.getWrapAlignment())
1354 scrollThread = new ScrollThread();
1358 public void mouseClicked(MouseEvent evt)
1360 SequenceI sequence = av.alignment.getSequenceAt(findSeq(evt));
1361 if (evt.getClickCount() > 1)
1363 if (av.getSelectionGroup().getSize() == 1
1364 && av.getSelectionGroup().getEndRes()
1365 - av.getSelectionGroup().getStartRes() < 2)
1367 av.setSelectionGroup(null);
1370 SequenceFeature[] features = findFeaturesAtRes(sequence
1371 .getDatasetSequence(), sequence.findPosition(findRes(evt)));
1373 if (features != null && features.length > 0)
1375 SearchResults highlight = new SearchResults();
1376 highlight.addResult(sequence, features[0].getBegin(), features[0]
1378 seqCanvas.highlightSearchResults(highlight);
1380 if (features != null && features.length > 0)
1382 seqCanvas.getFeatureRenderer().amendFeatures(new SequenceI[]
1383 { sequence }, features, false, ap);
1385 seqCanvas.highlightSearchResults(null);
1390 public void mouseWheelMoved(MouseWheelEvent e)
1393 if (e.getWheelRotation() > 0)
1409 public void doMousePressedDefineMode(MouseEvent evt)
1411 int res = findRes(evt);
1412 int seq = findSeq(evt);
1415 startWrapBlock = wrappedBlock;
1417 if (av.wrapAlignment && seq > av.alignment.getHeight())
1419 JOptionPane.showInternalMessageDialog(Desktop.desktop,
1420 "Cannot edit annotations in wrapped view.",
1421 "Wrapped view - no edit", JOptionPane.WARNING_MESSAGE);
1425 if (seq < 0 || res < 0)
1430 SequenceI sequence = (Sequence) av.getAlignment().getSequenceAt(seq);
1432 if ((sequence == null) || (res > sequence.getLength()))
1437 stretchGroup = av.getSelectionGroup();
1439 if (stretchGroup == null)
1441 stretchGroup = av.alignment.findGroup(sequence);
1443 if ((stretchGroup != null) && (res > stretchGroup.getStartRes())
1444 && (res < stretchGroup.getEndRes()))
1446 av.setSelectionGroup(stretchGroup);
1450 stretchGroup = null;
1453 else if (!stretchGroup.getSequences(null).contains(sequence)
1454 || (stretchGroup.getStartRes() > res)
1455 || (stretchGroup.getEndRes() < res))
1457 stretchGroup = null;
1459 SequenceGroup[] allGroups = av.alignment.findAllGroups(sequence);
1461 if (allGroups != null)
1463 for (int i = 0; i < allGroups.length; i++)
1465 if ((allGroups[i].getStartRes() <= res)
1466 && (allGroups[i].getEndRes() >= res))
1468 stretchGroup = allGroups[i];
1474 av.setSelectionGroup(stretchGroup);
1478 if (javax.swing.SwingUtilities.isRightMouseButton(evt))
1480 SequenceFeature[] allFeatures = findFeaturesAtRes(sequence
1481 .getDatasetSequence(), sequence.findPosition(res));
1482 Vector links = new Vector();
1483 for (int i = 0; i < allFeatures.length; i++)
1485 if (allFeatures[i].links != null)
1487 for (int j = 0; j < allFeatures[i].links.size(); j++)
1489 links.addElement(allFeatures[i].links.elementAt(j));
1494 jalview.gui.PopupMenu pop = new jalview.gui.PopupMenu(ap, null, links);
1495 pop.show(this, evt.getX(), evt.getY());
1501 seqCanvas.cursorX = findRes(evt);
1502 seqCanvas.cursorY = findSeq(evt);
1503 seqCanvas.repaint();
1507 if (stretchGroup == null)
1509 // Only if left mouse button do we want to change group sizes
1511 // define a new group here
1512 SequenceGroup sg = new SequenceGroup();
1513 sg.setStartRes(res);
1515 sg.addSequence(sequence, false);
1516 av.setSelectionGroup(sg);
1519 if (av.getConservationSelected())
1521 SliderPanel.setConservationSlider(ap, av.getGlobalColourScheme(),
1525 if (av.getAbovePIDThreshold())
1527 SliderPanel.setPIDSliderSource(ap, av.getGlobalColourScheme(),
1530 if ((stretchGroup != null) && (stretchGroup.getEndRes() == res))
1532 // Edit end res position of selected group
1533 changeEndRes = true;
1535 else if ((stretchGroup != null)
1536 && (stretchGroup.getStartRes() == res))
1538 // Edit end res position of selected group
1539 changeStartRes = true;
1541 stretchGroup.getWidth();
1544 seqCanvas.repaint();
1553 public void doMouseReleasedDefineMode(MouseEvent evt)
1555 if (stretchGroup == null)
1560 if (stretchGroup.cs != null)
1562 if (stretchGroup.cs instanceof ClustalxColourScheme)
1564 ((ClustalxColourScheme) stretchGroup.cs).resetClustalX(stretchGroup
1565 .getSequences(av.hiddenRepSequences), stretchGroup
1569 if (stretchGroup.cs instanceof Blosum62ColourScheme
1570 || stretchGroup.cs instanceof PIDColourScheme
1571 || stretchGroup.cs.conservationApplied()
1572 || stretchGroup.cs.getThreshold() > 0)
1574 stretchGroup.recalcConservation();
1577 if (stretchGroup.cs.conservationApplied())
1579 SliderPanel.setConservationSlider(ap, stretchGroup.cs, stretchGroup
1584 SliderPanel.setPIDSliderSource(ap, stretchGroup.cs, stretchGroup
1587 PaintRefresher.Refresh(this, av.getSequenceSetId());
1588 ap.paintAlignment(true);
1591 changeEndRes = false;
1592 changeStartRes = false;
1593 stretchGroup = null;
1603 public void doMouseDraggedDefineMode(MouseEvent evt)
1605 int res = findRes(evt);
1606 int y = findSeq(evt);
1608 if (wrappedBlock != startWrapBlock)
1613 if (stretchGroup == null)
1618 if (res >= av.alignment.getWidth())
1620 res = av.alignment.getWidth() - 1;
1623 if (stretchGroup.getEndRes() == res)
1625 // Edit end res position of selected group
1626 changeEndRes = true;
1628 else if (stretchGroup.getStartRes() == res)
1630 // Edit start res position of selected group
1631 changeStartRes = true;
1634 if (res < av.getStartRes())
1636 res = av.getStartRes();
1641 if (res > (stretchGroup.getStartRes() - 1))
1643 stretchGroup.setEndRes(res);
1646 else if (changeStartRes)
1648 if (res < (stretchGroup.getEndRes() + 1))
1650 stretchGroup.setStartRes(res);
1654 int dragDirection = 0;
1660 else if (y < oldSeq)
1665 while ((y != oldSeq) && (oldSeq > -1) && (y < av.alignment.getHeight()))
1667 // This routine ensures we don't skip any sequences, as the
1668 // selection is quite slow.
1669 Sequence seq = (Sequence) av.getAlignment().getSequenceAt(oldSeq);
1671 oldSeq += dragDirection;
1678 Sequence nextSeq = (Sequence) av.getAlignment().getSequenceAt(oldSeq);
1680 if (stretchGroup.getSequences(null).contains(nextSeq))
1682 stretchGroup.deleteSequence(seq, false);
1688 stretchGroup.addSequence(seq, false);
1691 stretchGroup.addSequence(nextSeq, false);
1700 mouseDragging = true;
1702 if (scrollThread != null)
1704 scrollThread.setEvent(evt);
1707 seqCanvas.repaint();
1710 void scrollCanvas(MouseEvent evt)
1714 if (scrollThread != null)
1716 scrollThread.running = false;
1717 scrollThread = null;
1719 mouseDragging = false;
1723 if (scrollThread == null)
1725 scrollThread = new ScrollThread();
1728 mouseDragging = true;
1729 scrollThread.setEvent(evt);
1734 // this class allows scrolling off the bottom of the visible alignment
1735 class ScrollThread extends Thread
1739 boolean running = false;
1741 public ScrollThread()
1746 public void setEvent(MouseEvent e)
1751 public void stopScrolling()
1764 if (mouseDragging && (evt.getY() < 0) && (av.getStartSeq() > 0))
1766 running = ap.scrollUp(true);
1769 if (mouseDragging && (evt.getY() >= getHeight())
1770 && (av.alignment.getHeight() > av.getEndSeq()))
1772 running = ap.scrollUp(false);
1775 if (mouseDragging && (evt.getX() < 0))
1777 running = ap.scrollRight(false);
1779 else if (mouseDragging && (evt.getX() >= getWidth()))
1781 running = ap.scrollRight(true);
1788 } catch (Exception ex)