Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
ColumnSelection | 36 | 153 | 104 | ||
ColumnSelection.IntList | 41 | 61 | 33 |
1 | /* | |
2 | * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) | |
3 | * Copyright (C) $$Year-Rel$$ The Jalview Authors | |
4 | * | |
5 | * This file is part of Jalview. | |
6 | * | |
7 | * Jalview is free software: you can redistribute it and/or | |
8 | * modify it under the terms of the GNU General Public License | |
9 | * as published by the Free Software Foundation, either version 3 | |
10 | * of the License, or (at your option) any later version. | |
11 | * | |
12 | * Jalview is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty | |
14 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR | |
15 | * PURPOSE. See the GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with Jalview. If not, see <http://www.gnu.org/licenses/>. | |
19 | * The Jalview Authors are detailed in the 'AUTHORS' file. | |
20 | */ | |
21 | package jalview.datamodel; | |
22 | ||
23 | import java.util.ArrayList; | |
24 | import java.util.BitSet; | |
25 | import java.util.Collections; | |
26 | import java.util.List; | |
27 | import java.util.regex.PatternSyntaxException; | |
28 | ||
29 | import jalview.viewmodel.annotationfilter.AnnotationFilterParameter; | |
30 | import jalview.viewmodel.annotationfilter.AnnotationFilterParameter.SearchableAnnotationField; | |
31 | ||
32 | /** | |
33 | * Data class holding the selected columns and hidden column ranges for a view. | |
34 | * Ranges are base 1. | |
35 | */ | |
36 | public class ColumnSelection | |
37 | { | |
38 | /** | |
39 | * A class to hold an efficient representation of selected columns | |
40 | */ | |
41 | private class IntList | |
42 | { | |
43 | /* | |
44 | * list of selected columns (ordered by selection order, not column order) | |
45 | */ | |
46 | private List<Integer> order; | |
47 | ||
48 | /* | |
49 | * an unmodifiable view of the selected columns list | |
50 | */ | |
51 | private List<Integer> _uorder; | |
52 | ||
53 | /** | |
54 | * bitfield for column selection - allows quick lookup | |
55 | */ | |
56 | private BitSet selected; | |
57 | ||
58 | /** | |
59 | * Constructor | |
60 | */ | |
61 | 680 | IntList() |
62 | { | |
63 | 680 | order = new ArrayList<>(); |
64 | 680 | _uorder = Collections.unmodifiableList(order); |
65 | 680 | selected = new BitSet(); |
66 | } | |
67 | ||
68 | /** | |
69 | * Copy constructor | |
70 | * | |
71 | * @param other | |
72 | */ | |
73 | 24 | IntList(IntList other) |
74 | { | |
75 | 24 | this(); |
76 | 24 | if (other != null) |
77 | { | |
78 | 24 | int j = other.size(); |
79 | 39 | for (int i = 0; i < j; i++) |
80 | { | |
81 | 15 | add(other.elementAt(i)); |
82 | } | |
83 | } | |
84 | } | |
85 | ||
86 | /** | |
87 | * adds a new column i to the selection - only if i is not already selected | |
88 | * | |
89 | * @param i | |
90 | */ | |
91 | 2870 | void add(int i) |
92 | { | |
93 | 2870 | if (!selected.get(i)) |
94 | { | |
95 | 2621 | order.add(Integer.valueOf(i)); |
96 | 2621 | selected.set(i); |
97 | } | |
98 | } | |
99 | ||
100 | 55 | void clear() |
101 | { | |
102 | 55 | order.clear(); |
103 | 55 | selected.clear(); |
104 | } | |
105 | ||
106 | 48 | void remove(int col) |
107 | { | |
108 | ||
109 | 48 | Integer colInt = Integer.valueOf(col); |
110 | ||
111 | 48 | if (selected.get(col)) |
112 | { | |
113 | // if this ever changes to List.remove(), ensure Integer not int | |
114 | // argument | |
115 | // as List.remove(int i) removes the i'th item which is wrong | |
116 | 32 | order.remove(colInt); |
117 | 32 | selected.clear(col); |
118 | } | |
119 | } | |
120 | ||
121 | 0 | boolean contains(Integer colInt) |
122 | { | |
123 | 0 | return selected.get(colInt); |
124 | } | |
125 | ||
126 | 206 | boolean isEmpty() |
127 | { | |
128 | 206 | return order.isEmpty(); |
129 | } | |
130 | ||
131 | /** | |
132 | * Returns a read-only view of the selected columns list | |
133 | * | |
134 | * @return | |
135 | */ | |
136 | 2474 | List<Integer> getList() |
137 | { | |
138 | 2474 | return _uorder; |
139 | } | |
140 | ||
141 | 33 | int size() |
142 | { | |
143 | 33 | return order.size(); |
144 | } | |
145 | ||
146 | /** | |
147 | * gets the column that was selected first, second or i'th | |
148 | * | |
149 | * @param i | |
150 | * @return | |
151 | */ | |
152 | 15 | int elementAt(int i) |
153 | { | |
154 | 15 | return order.get(i); |
155 | } | |
156 | ||
157 | 0 | protected boolean pruneColumnList(final List<int[]> shifts) |
158 | { | |
159 | 0 | int s = 0, t = shifts.size(); |
160 | 0 | int[] sr = shifts.get(s++); |
161 | 0 | boolean pruned = false; |
162 | 0 | int i = 0, j = order.size(); |
163 | 0 | while (i < j && s <= t) |
164 | { | |
165 | 0 | int c = order.get(i++).intValue(); |
166 | 0 | if (sr[0] <= c) |
167 | { | |
168 | 0 | if (sr[1] + sr[0] >= c) |
169 | { // sr[1] -ve means inseriton. | |
170 | 0 | order.remove(--i); |
171 | 0 | selected.clear(c); |
172 | 0 | j--; |
173 | } | |
174 | else | |
175 | { | |
176 | 0 | if (s < t) |
177 | { | |
178 | 0 | sr = shifts.get(s); |
179 | } | |
180 | 0 | s++; |
181 | } | |
182 | } | |
183 | } | |
184 | 0 | return pruned; |
185 | } | |
186 | ||
187 | /** | |
188 | * shift every selected column at or above start by change | |
189 | * | |
190 | * @param start | |
191 | * - leftmost column to be shifted | |
192 | * @param change | |
193 | * - delta for shift | |
194 | */ | |
195 | 0 | void compensateForEdits(int start, int change) |
196 | { | |
197 | 0 | BitSet mask = new BitSet(); |
198 | 0 | for (int i = 0; i < order.size(); i++) |
199 | { | |
200 | 0 | int temp = order.get(i); |
201 | ||
202 | 0 | if (temp >= start) |
203 | { | |
204 | // clear shifted bits and update List of selected columns | |
205 | 0 | selected.clear(temp); |
206 | 0 | mask.set(temp - change); |
207 | 0 | order.set(i, Integer.valueOf(temp - change)); |
208 | } | |
209 | } | |
210 | // lastly update the bitfield all at once | |
211 | 0 | selected.or(mask); |
212 | } | |
213 | ||
214 | 555187 | boolean isSelected(int column) |
215 | { | |
216 | 555187 | return selected.get(column); |
217 | } | |
218 | ||
219 | 4 | int getMaxColumn() |
220 | { | |
221 | 4 | return selected.length() - 1; |
222 | } | |
223 | ||
224 | 3 | int getMinColumn() |
225 | { | |
226 | 3 | return selected.get(0) ? 0 : selected.nextSetBit(0); |
227 | } | |
228 | ||
229 | /** | |
230 | * @return a series of selection intervals along the range | |
231 | */ | |
232 | 8 | List<int[]> getRanges() |
233 | { | |
234 | 8 | List<int[]> rlist = new ArrayList<>(); |
235 | 8 | if (selected.isEmpty()) |
236 | { | |
237 | 0 | return rlist; |
238 | } | |
239 | 8 | int next = selected.nextSetBit(0), clear = -1; |
240 | 23 | while (next != -1) |
241 | { | |
242 | 15 | clear = selected.nextClearBit(next); |
243 | 15 | rlist.add(new int[] { next, clear - 1 }); |
244 | 15 | next = selected.nextSetBit(clear); |
245 | } | |
246 | 8 | return rlist; |
247 | } | |
248 | ||
249 | 28 | @Override |
250 | public int hashCode() | |
251 | { | |
252 | // TODO Auto-generated method stub | |
253 | 28 | return selected.hashCode(); |
254 | } | |
255 | ||
256 | 9 | @Override |
257 | public boolean equals(Object obj) | |
258 | { | |
259 | 9 | if (obj instanceof IntList) |
260 | { | |
261 | 9 | return ((IntList) obj).selected.equals(selected); |
262 | } | |
263 | 0 | return false; |
264 | } | |
265 | } | |
266 | ||
267 | private IntList selection = new IntList(); | |
268 | ||
269 | /** | |
270 | * Add a column to the selection | |
271 | * | |
272 | * @param col | |
273 | * index of column | |
274 | */ | |
275 | 2853 | public void addElement(int col) |
276 | { | |
277 | 2853 | selection.add(col); |
278 | } | |
279 | ||
280 | /** | |
281 | * add a series of start,end (inclusive) ranges to the column selection | |
282 | * | |
283 | * @param rng | |
284 | * [start_0, end_0, start_1, end_1, ... ] | |
285 | * @param baseOne | |
286 | * - when true, ranges are base 1 and will be mapped to base 0 | |
287 | */ | |
288 | 0 | public void addRangeOfElements(int[] rng, boolean baseOne) |
289 | { | |
290 | 0 | int base = baseOne ? -1 : 0; |
291 | 0 | for (int c = 0; c < rng.length; c += 2) |
292 | { | |
293 | 0 | for (int p = rng[c]; p <= rng[c + 1]; p++) |
294 | { | |
295 | 0 | selection.add(base + p); |
296 | } | |
297 | } | |
298 | ||
299 | } | |
300 | ||
301 | /** | |
302 | * clears column selection | |
303 | */ | |
304 | 50 | public void clear() |
305 | { | |
306 | 50 | selection.clear(); |
307 | } | |
308 | ||
309 | /** | |
310 | * Removes value 'col' from the selection (not the col'th item) | |
311 | * | |
312 | * @param col | |
313 | * index of column to be removed | |
314 | */ | |
315 | 48 | public void removeElement(int col) |
316 | { | |
317 | 48 | selection.remove(col); |
318 | } | |
319 | ||
320 | /** | |
321 | * removes a range of columns from the selection | |
322 | * | |
323 | * @param start | |
324 | * int - first column in range to be removed | |
325 | * @param end | |
326 | * int - last col | |
327 | */ | |
328 | 0 | public void removeElements(int start, int end) |
329 | { | |
330 | 0 | Integer colInt; |
331 | 0 | for (int i = start; i < end; i++) |
332 | { | |
333 | 0 | colInt = Integer.valueOf(i); |
334 | 0 | if (selection.contains(colInt)) |
335 | { | |
336 | 0 | selection.remove(colInt); |
337 | } | |
338 | } | |
339 | } | |
340 | ||
341 | /** | |
342 | * Returns a read-only view of the (possibly empty) list of selected columns | |
343 | * (base 1) | |
344 | * <p> | |
345 | * The list contains no duplicates but is not necessarily ordered. Columns are | |
346 | * reported in alignment coordinates (base 1), so may also include columns | |
347 | * hidden from the current view. To modify (for example sort) the list, you | |
348 | * should first make a copy. | |
349 | * <p> | |
350 | * The list is not thread-safe: iterating over it could result in | |
351 | * ConcurrentModificationException if it is modified by another thread. | |
352 | */ | |
353 | 2474 | public List<Integer> getSelected() |
354 | { | |
355 | 2474 | return selection.getList(); |
356 | } | |
357 | ||
358 | /** | |
359 | * @return list of int arrays containing start and end column position for | |
360 | * runs of selected columns ordered from right to left. | |
361 | */ | |
362 | 3 | public List<int[]> getSelectedRanges() |
363 | { | |
364 | 3 | return selection.getRanges(); |
365 | } | |
366 | ||
367 | /** | |
368 | * | |
369 | * @param col | |
370 | * index to search for in column selection | |
371 | * | |
372 | * @return true if col is selected | |
373 | */ | |
374 | 8185 | public boolean contains(int col) |
375 | { | |
376 | 8185 | return (col > -1) ? selection.isSelected(col) : false; |
377 | } | |
378 | ||
379 | /** | |
380 | * | |
381 | */ | |
382 | 142091 | public boolean intersects(int from, int to) |
383 | { | |
384 | // TODO: do this in a more efficient bitwise way | |
385 | 689102 | for (int f = from; f <= to; f++) |
386 | { | |
387 | 547016 | if (selection.isSelected(f)) |
388 | { | |
389 | 4 | return true; |
390 | } | |
391 | } | |
392 | 142088 | return false; |
393 | } | |
394 | ||
395 | /** | |
396 | * Answers true if no columns are selected, else false | |
397 | */ | |
398 | 199 | public boolean isEmpty() |
399 | { | |
400 | 199 | return selection == null || selection.isEmpty(); |
401 | } | |
402 | ||
403 | /** | |
404 | * rightmost selected column | |
405 | * | |
406 | * @return rightmost column in alignment that is selected | |
407 | */ | |
408 | 4 | public int getMax() |
409 | { | |
410 | 4 | if (selection.isEmpty()) |
411 | { | |
412 | 0 | return -1; |
413 | } | |
414 | 4 | return selection.getMaxColumn(); |
415 | } | |
416 | ||
417 | /** | |
418 | * Leftmost column in selection | |
419 | * | |
420 | * @return column index of leftmost column in selection | |
421 | */ | |
422 | 3 | public int getMin() |
423 | { | |
424 | 3 | if (selection.isEmpty()) |
425 | { | |
426 | 0 | return 1000000000; |
427 | } | |
428 | 3 | return selection.getMinColumn(); |
429 | } | |
430 | ||
431 | 5 | public void hideSelectedColumns(AlignmentI al) |
432 | { | |
433 | 5 | synchronized (selection) |
434 | { | |
435 | 5 | for (int[] selregions : selection.getRanges()) |
436 | { | |
437 | 8 | al.getHiddenColumns().hideColumns(selregions[0], selregions[1]); |
438 | } | |
439 | 5 | selection.clear(); |
440 | } | |
441 | ||
442 | } | |
443 | ||
444 | /** | |
445 | * Hides the specified column and any adjacent selected columns | |
446 | * | |
447 | * @param res | |
448 | * int | |
449 | */ | |
450 | 17 | public void hideSelectedColumns(int col, HiddenColumns hidden) |
451 | { | |
452 | /* | |
453 | * deselect column (whether selected or not!) | |
454 | */ | |
455 | 17 | removeElement(col); |
456 | ||
457 | /* | |
458 | * find adjacent selected columns | |
459 | */ | |
460 | 17 | int min = col - 1, max = col + 1; |
461 | 24 | while (contains(min)) |
462 | { | |
463 | 7 | removeElement(min); |
464 | 7 | min--; |
465 | } | |
466 | ||
467 | 21 | while (contains(max)) |
468 | { | |
469 | 4 | removeElement(max); |
470 | 4 | max++; |
471 | } | |
472 | ||
473 | /* | |
474 | * min, max are now the closest unselected columns | |
475 | */ | |
476 | 17 | min++; |
477 | 17 | max--; |
478 | 17 | if (min > max) |
479 | { | |
480 | 0 | min = max; |
481 | } | |
482 | ||
483 | 17 | hidden.hideColumns(min, max); |
484 | } | |
485 | ||
486 | /** | |
487 | * Copy constructor | |
488 | * | |
489 | * @param copy | |
490 | */ | |
491 | 24 | public ColumnSelection(ColumnSelection copy) |
492 | { | |
493 | 24 | if (copy != null) |
494 | { | |
495 | 24 | selection = new IntList(copy.selection); |
496 | } | |
497 | } | |
498 | ||
499 | /** | |
500 | * ColumnSelection | |
501 | */ | |
502 | 630 | public ColumnSelection() |
503 | { | |
504 | } | |
505 | ||
506 | /** | |
507 | * Invert the column selection from first to end-1. leaves hiddenColumns | |
508 | * untouched (and unselected) | |
509 | * | |
510 | * @param first | |
511 | * @param end | |
512 | */ | |
513 | 2 | public void invertColumnSelection(int first, int width, AlignmentI al) |
514 | { | |
515 | 2 | boolean hasHidden = al.getHiddenColumns().hasHiddenColumns(); |
516 | 17 | for (int i = first; i < width; i++) |
517 | { | |
518 | 15 | if (contains(i)) |
519 | { | |
520 | 6 | removeElement(i); |
521 | } | |
522 | else | |
523 | { | |
524 | 9 | if (!hasHidden || al.getHiddenColumns().isVisible(i)) |
525 | { | |
526 | 6 | addElement(i); |
527 | } | |
528 | } | |
529 | } | |
530 | } | |
531 | ||
532 | /** | |
533 | * set the selected columns to the given column selection, excluding any | |
534 | * columns that are hidden. | |
535 | * | |
536 | * @param colsel | |
537 | */ | |
538 | 2 | public void setElementsFrom(ColumnSelection colsel, |
539 | HiddenColumns hiddenColumns) | |
540 | { | |
541 | 2 | selection = new IntList(); |
542 | 2 | if (colsel.selection != null && colsel.selection.size() > 0) |
543 | { | |
544 | 2 | if (hiddenColumns.hasHiddenColumns()) |
545 | { | |
546 | // only select visible columns in this columns selection | |
547 | 1 | for (Integer col : colsel.getSelected()) |
548 | { | |
549 | 3 | if (hiddenColumns != null |
550 | && hiddenColumns.isVisible(col.intValue())) | |
551 | { | |
552 | 2 | selection.add(col); |
553 | } | |
554 | } | |
555 | } | |
556 | else | |
557 | { | |
558 | // add everything regardless | |
559 | 1 | for (Integer col : colsel.getSelected()) |
560 | { | |
561 | 3 | addElement(col); |
562 | } | |
563 | } | |
564 | } | |
565 | } | |
566 | ||
567 | /** | |
568 | * | |
569 | * @return true if there are columns marked | |
570 | */ | |
571 | 7 | public boolean hasSelectedColumns() |
572 | { | |
573 | 7 | return (selection != null && selection.size() > 0); |
574 | } | |
575 | ||
576 | /** | |
577 | * Selects columns where the given annotation matches the provided filter | |
578 | * condition(s). Any existing column selections are first cleared. Answers the | |
579 | * number of columns added. | |
580 | * | |
581 | * @param annotations | |
582 | * @param filterParams | |
583 | * @return | |
584 | */ | |
585 | 11 | public int filterAnnotations(AlignmentAnnotation ann_row, |
586 | AnnotationFilterParameter filterParams) | |
587 | { | |
588 | 11 | Annotation[] annotations = ann_row.annotations; |
589 | // JBPNote - this method needs to be refactored to become independent of | |
590 | // viewmodel package | |
591 | 11 | this.clear(); |
592 | ||
593 | 11 | if (ann_row.graph == AlignmentAnnotation.CONTACT_MAP && (filterParams |
594 | .getThresholdType() == AnnotationFilterParameter.ThresholdType.ABOVE_THRESHOLD | |
595 | || filterParams | |
596 | .getThresholdType() == AnnotationFilterParameter.ThresholdType.BELOW_THRESHOLD)) | |
597 | { | |
598 | 0 | float tVal = filterParams.getThresholdValue(); |
599 | 0 | if (ann_row.sequenceRef != null) |
600 | { | |
601 | // TODO - get ContactList from AlignmentView for non-seq-ref associatd | |
602 | 0 | for (int column = 0; column < annotations.length; column++) |
603 | { | |
604 | 0 | if (ann_row.annotations[column] == null) |
605 | { | |
606 | 0 | continue; |
607 | } | |
608 | ||
609 | 0 | int cpos = ann_row.sequenceRef.findPosition(column) - 1; |
610 | 0 | ContactListI clist = ann_row.sequenceRef |
611 | .getContactListFor(ann_row, cpos); | |
612 | 0 | for (int row = column + 8, rowEnd = clist |
613 | 0 | .getContactHeight(); row < rowEnd; row++) |
614 | { | |
615 | 0 | if (filterParams |
616 | .getThresholdType() == AnnotationFilterParameter.ThresholdType.ABOVE_THRESHOLD | |
617 | ? (clist.getContactAt(row) > tVal) | |
618 | : (clist.getContactAt(row) < tVal)) | |
619 | { | |
620 | 0 | addElement(column); |
621 | 0 | break; |
622 | // int column_forrowpos = ann_row.sequenceRef.findIndex(row + 1); | |
623 | // addElement(column_forrowpos); | |
624 | } | |
625 | } | |
626 | } | |
627 | } | |
628 | 0 | return selection.size(); |
629 | } | |
630 | ||
631 | 11 | int addedCount = 0; |
632 | 11 | int column = 0; |
633 | 11 | do |
634 | { | |
635 | 55 | Annotation ann = annotations[column]; |
636 | 55 | if (ann != null) |
637 | { | |
638 | 45 | float value = ann.value; |
639 | 45 | boolean matched = false; |
640 | ||
641 | /* | |
642 | * filter may have multiple conditions - | |
643 | * these are or'd until a match is found | |
644 | */ | |
645 | 45 | if (filterParams |
646 | .getThresholdType() == AnnotationFilterParameter.ThresholdType.ABOVE_THRESHOLD | |
647 | && value > filterParams.getThresholdValue()) | |
648 | { | |
649 | 2 | matched = true; |
650 | } | |
651 | ||
652 | 45 | if (!matched && filterParams |
653 | .getThresholdType() == AnnotationFilterParameter.ThresholdType.BELOW_THRESHOLD | |
654 | && value < filterParams.getThresholdValue()) | |
655 | { | |
656 | 3 | matched = true; |
657 | } | |
658 | ||
659 | 45 | if (!matched && filterParams.isFilterAlphaHelix() |
660 | && ann.secondaryStructure == 'H') | |
661 | { | |
662 | 3 | matched = true; |
663 | } | |
664 | ||
665 | 45 | if (!matched && filterParams.isFilterBetaSheet() |
666 | && ann.secondaryStructure == 'E') | |
667 | { | |
668 | 2 | matched = true; |
669 | } | |
670 | ||
671 | 45 | if (!matched && filterParams.isFilterTurn() |
672 | && ann.secondaryStructure == 'S') | |
673 | { | |
674 | 1 | matched = true; |
675 | } | |
676 | ||
677 | 45 | String regexSearchString = filterParams.getRegexString(); |
678 | 45 | if (!matched && regexSearchString != null) |
679 | { | |
680 | 4 | List<SearchableAnnotationField> fields = filterParams |
681 | .getRegexSearchFields(); | |
682 | 4 | for (SearchableAnnotationField field : fields) |
683 | { | |
684 | 4 | String compareTo = field == SearchableAnnotationField.DISPLAY_STRING |
685 | ? ann.displayCharacter // match 'Label' | |
686 | : ann.description; // and/or 'Description' | |
687 | 4 | if (compareTo != null) |
688 | { | |
689 | 4 | try |
690 | { | |
691 | 2 | if (compareTo.matches(regexSearchString)) |
692 | { | |
693 | 1 | matched = true; |
694 | } | |
695 | } catch (PatternSyntaxException pse) | |
696 | { | |
697 | 2 | if (compareTo.equals(regexSearchString)) |
698 | { | |
699 | 2 | matched = true; |
700 | } | |
701 | } | |
702 | 4 | if (matched) |
703 | { | |
704 | 3 | break; |
705 | } | |
706 | } | |
707 | } | |
708 | } | |
709 | ||
710 | 45 | if (matched) |
711 | { | |
712 | 14 | this.addElement(column); |
713 | 14 | addedCount++; |
714 | } | |
715 | } | |
716 | 55 | column++; |
717 | 55 | } while (column < annotations.length); |
718 | ||
719 | 11 | return addedCount; |
720 | } | |
721 | ||
722 | /** | |
723 | * Returns a hashCode built from selected columns ranges | |
724 | */ | |
725 | 28 | @Override |
726 | public int hashCode() | |
727 | { | |
728 | 28 | return selection.hashCode(); |
729 | } | |
730 | ||
731 | /** | |
732 | * Answers true if comparing to a ColumnSelection with the same selected | |
733 | * columns and hidden columns, else false | |
734 | */ | |
735 | 9 | @Override |
736 | public boolean equals(Object obj) | |
737 | { | |
738 | 9 | if (!(obj instanceof ColumnSelection)) |
739 | { | |
740 | 0 | return false; |
741 | } | |
742 | 9 | ColumnSelection that = (ColumnSelection) obj; |
743 | ||
744 | /* | |
745 | * check columns selected are either both null, or match | |
746 | */ | |
747 | 9 | if (this.selection == null) |
748 | { | |
749 | 0 | if (that.selection != null) |
750 | { | |
751 | 0 | return false; |
752 | } | |
753 | } | |
754 | 9 | if (!this.selection.equals(that.selection)) |
755 | { | |
756 | 2 | return false; |
757 | } | |
758 | ||
759 | 7 | return true; |
760 | } | |
761 | ||
762 | /** | |
763 | * Updates the column selection depending on the parameters, and returns true | |
764 | * if any change was made to the selection | |
765 | * | |
766 | * @param markedColumns | |
767 | * a set identifying marked columns (base 0) | |
768 | * @param startCol | |
769 | * the first column of the range to operate over (base 0) | |
770 | * @param endCol | |
771 | * the last column of the range to operate over (base 0) | |
772 | * @param invert | |
773 | * if true, deselect marked columns and select unmarked | |
774 | * @param extendCurrent | |
775 | * if true, extend rather than replacing the current column selection | |
776 | * @param toggle | |
777 | * if true, toggle the selection state of marked columns | |
778 | * | |
779 | * @return | |
780 | */ | |
781 | 16 | public boolean markColumns(BitSet markedColumns, int startCol, int endCol, |
782 | boolean invert, boolean extendCurrent, boolean toggle) | |
783 | { | |
784 | 16 | boolean changed = false; |
785 | 16 | if (!extendCurrent && !toggle) |
786 | { | |
787 | 14 | changed = !this.isEmpty(); |
788 | 14 | clear(); |
789 | } | |
790 | 16 | if (invert) |
791 | { | |
792 | // invert only in the currently selected sequence region | |
793 | 7 | int i = markedColumns.nextClearBit(startCol); |
794 | 7 | int ibs = markedColumns.nextSetBit(startCol); |
795 | 35 | while (i >= startCol && i <= endCol) |
796 | { | |
797 | 28 | if (ibs < 0 || i < ibs) |
798 | { | |
799 | 23 | changed = true; |
800 | 23 | if (toggle && contains(i)) |
801 | { | |
802 | 0 | removeElement(i++); |
803 | } | |
804 | else | |
805 | { | |
806 | 23 | addElement(i++); |
807 | } | |
808 | } | |
809 | else | |
810 | { | |
811 | 5 | i = markedColumns.nextClearBit(ibs); |
812 | 5 | ibs = markedColumns.nextSetBit(i); |
813 | } | |
814 | } | |
815 | } | |
816 | else | |
817 | { | |
818 | 9 | int i = markedColumns.nextSetBit(startCol); |
819 | 1963 | while (i >= startCol && i <= endCol) |
820 | { | |
821 | 1954 | changed = true; |
822 | 1954 | if (toggle && contains(i)) |
823 | { | |
824 | 1 | removeElement(i); |
825 | } | |
826 | else | |
827 | { | |
828 | 1953 | addElement(i); |
829 | } | |
830 | 1954 | i = markedColumns.nextSetBit(i + 1); |
831 | } | |
832 | } | |
833 | 16 | return changed; |
834 | } | |
835 | ||
836 | /** | |
837 | * Adjusts column selections, and the given selection group, to match the | |
838 | * range of a stretch (e.g. mouse drag) operation | |
839 | * <p> | |
840 | * Method refactored from ScalePanel.mouseDragged | |
841 | * | |
842 | * @param res | |
843 | * current column position, adjusted for hidden columns | |
844 | * @param sg | |
845 | * current selection group | |
846 | * @param min | |
847 | * start position of the stretch group | |
848 | * @param max | |
849 | * end position of the stretch group | |
850 | */ | |
851 | 9 | public void stretchGroup(int res, SequenceGroup sg, int min, int max) |
852 | { | |
853 | 9 | if (!contains(res)) |
854 | { | |
855 | 4 | addElement(res); |
856 | } | |
857 | ||
858 | 9 | if (res > sg.getStartRes()) |
859 | { | |
860 | // expand selection group to the right | |
861 | 5 | sg.setEndRes(res); |
862 | } | |
863 | 9 | if (res < sg.getStartRes()) |
864 | { | |
865 | // expand selection group to the left | |
866 | 0 | sg.setStartRes(res); |
867 | } | |
868 | ||
869 | /* | |
870 | * expand or shrink column selection to match the | |
871 | * range of the drag operation | |
872 | */ | |
873 | 45 | for (int col = min; col <= max; col++) |
874 | { | |
875 | 36 | if (col < sg.getStartRes() || col > sg.getEndRes()) |
876 | { | |
877 | // shrinking drag - remove from selection | |
878 | 1 | removeElement(col); |
879 | } | |
880 | else | |
881 | { | |
882 | // expanding drag - add to selection | |
883 | 35 | addElement(col); |
884 | } | |
885 | } | |
886 | } | |
887 | } |