1 /* 2 * Jalview - A Sequence Alignment Editor and Viewer (2.11.1.4) 3 * Copyright (C) 2021 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.appletgui; 22 23 import jalview.api.FeatureColourI; 24 import jalview.api.FeatureSettingsControllerI; 25 import jalview.datamodel.AlignmentI; 26 import jalview.datamodel.SequenceI; 27 import jalview.util.MessageManager; 28 import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean; 29 30 import java.awt.BorderLayout; 31 import java.awt.Button; 32 import java.awt.Checkbox; 33 import java.awt.Color; 34 import java.awt.Component; 35 import java.awt.Dimension; 36 import java.awt.Font; 37 import java.awt.FontMetrics; 38 import java.awt.Frame; 39 import java.awt.Graphics; 40 import java.awt.GridLayout; 41 import java.awt.Image; 42 import java.awt.Label; 43 import java.awt.MenuItem; 44 import java.awt.Panel; 45 import java.awt.PopupMenu; 46 import java.awt.ScrollPane; 47 import java.awt.Scrollbar; 48 import java.awt.event.ActionEvent; 49 import java.awt.event.ActionListener; 50 import java.awt.event.AdjustmentEvent; 51 import java.awt.event.AdjustmentListener; 52 import java.awt.event.InputEvent; 53 import java.awt.event.ItemEvent; 54 import java.awt.event.ItemListener; 55 import java.awt.event.MouseEvent; 56 import java.awt.event.MouseListener; 57 import java.awt.event.MouseMotionListener; 58 import java.awt.event.WindowAdapter; 59 import java.awt.event.WindowEvent; 60 import java.util.ArrayList; 61 import java.util.Arrays; 62 import java.util.HashSet; 63 import java.util.List; 64 import java.util.Map; 65 import java.util.Set; 66 67 public class FeatureSettings extends Panel 68 implements ItemListener, MouseListener, MouseMotionListener, 69 AdjustmentListener, FeatureSettingsControllerI 70 { 71 FeatureRenderer fr; 72 73 AlignmentPanel ap; 74 75 AlignViewport av; 76 77 Frame frame; 78 79 Panel groupPanel; 80 81 Panel featurePanel = new Panel(); 82 83 ScrollPane scrollPane; 84 85 Image linkImage; 86 87 Scrollbar transparency; 88 FeatureSettings(final AlignmentPanel ap)89 public FeatureSettings(final AlignmentPanel ap) 90 { 91 this.ap = ap; 92 this.av = ap.av; 93 ap.av.featureSettings = this; 94 fr = ap.seqPanel.seqCanvas.getFeatureRenderer(); 95 96 transparency = new Scrollbar(Scrollbar.HORIZONTAL, 97 100 - (int) (fr.getTransparency() * 100), 1, 1, 100); 98 99 transparency.addAdjustmentListener(this); 100 101 java.net.URL url = getClass().getResource("/images/link.gif"); 102 if (url != null) 103 { 104 linkImage = java.awt.Toolkit.getDefaultToolkit().getImage(url); 105 } 106 107 if (av.isShowSequenceFeatures() || !fr.hasRenderOrder()) 108 { 109 fr.findAllFeatures(true); // was default - now true to make all visible 110 } 111 groupPanel = new Panel(); 112 113 discoverAllFeatureData(); 114 115 this.setLayout(new BorderLayout()); 116 scrollPane = new ScrollPane(); 117 scrollPane.add(featurePanel); 118 if (fr.getAllFeatureColours() != null 119 && fr.getAllFeatureColours().size() > 0) 120 { 121 add(scrollPane, BorderLayout.CENTER); 122 } 123 124 Button invert = new Button( 125 MessageManager.getString("label.invert_selection")); 126 invert.addActionListener(new ActionListener() 127 { 128 129 @Override 130 public void actionPerformed(ActionEvent e) 131 { 132 invertSelection(); 133 } 134 }); 135 136 Panel lowerPanel = new Panel(new GridLayout(2, 1, 5, 10)); 137 lowerPanel.add(invert); 138 139 Panel tPanel = new Panel(new BorderLayout()); 140 141 tPanel.add(transparency, BorderLayout.CENTER); 142 tPanel.add(new Label("Transparency"), BorderLayout.EAST); 143 144 lowerPanel.add(tPanel, BorderLayout.SOUTH); 145 146 add(lowerPanel, BorderLayout.SOUTH); 147 148 groupPanel.setLayout( 149 new GridLayout((fr.getFeatureGroupsSize()) / 4 + 1, 4)); // JBPNote 150 // - this 151 // was 152 // scaled 153 // on 154 // number 155 // of 156 // visible 157 // groups. 158 // seems 159 // broken 160 groupPanel.validate(); 161 162 add(groupPanel, BorderLayout.NORTH); 163 164 frame = new Frame(); 165 frame.add(this); 166 final FeatureSettings me = this; 167 frame.addWindowListener(new WindowAdapter() 168 { 169 @Override 170 public void windowClosing(WindowEvent e) 171 { 172 if (me.av.featureSettings == me) 173 { 174 me.av.featureSettings = null; 175 me.ap = null; 176 me.av = null; 177 } 178 } 179 }); 180 int height = featurePanel.getComponentCount() * 50 + 60; 181 182 height = Math.max(200, height); 183 height = Math.min(400, height); 184 int width = 300; 185 jalview.bin.JalviewLite.addFrame(frame, 186 MessageManager.getString("label.sequence_feature_settings"), 187 width, height); 188 } 189 190 @Override paint(Graphics g)191 public void paint(Graphics g) 192 { 193 g.setColor(Color.black); 194 g.drawString(MessageManager.getString( 195 "label.no_features_added_to_this_alignment"), 10, 20); 196 g.drawString(MessageManager.getString( 197 "label.features_can_be_added_from_searches_1"), 10, 40); 198 g.drawString(MessageManager.getString( 199 "label.features_can_be_added_from_searches_2"), 10, 60); 200 } 201 popupSort(final MyCheckbox check, final Map<String, float[][]> minmax, int x, int y)202 protected void popupSort(final MyCheckbox check, 203 final Map<String, float[][]> minmax, int x, int y) 204 { 205 final String type = check.type; 206 final FeatureColourI typeCol = fr.getFeatureStyle(type); 207 PopupMenu men = new PopupMenu(MessageManager 208 .formatMessage("label.settings_for_type", new String[] 209 { type })); 210 java.awt.MenuItem scr = new MenuItem( 211 MessageManager.getString("label.sort_by_score")); 212 men.add(scr); 213 final FeatureSettings me = this; 214 scr.addActionListener(new ActionListener() 215 { 216 217 @Override 218 public void actionPerformed(ActionEvent e) 219 { 220 me.ap.alignFrame.avc 221 .sortAlignmentByFeatureScore(Arrays.asList(new String[] 222 { type })); 223 } 224 225 }); 226 MenuItem dens = new MenuItem( 227 MessageManager.getString("label.sort_by_density")); 228 dens.addActionListener(new ActionListener() 229 { 230 231 @Override 232 public void actionPerformed(ActionEvent e) 233 { 234 me.ap.alignFrame.avc 235 .sortAlignmentByFeatureDensity(Arrays.asList(new String[] 236 { type })); 237 } 238 239 }); 240 men.add(dens); 241 242 if (minmax != null) 243 { 244 final float[][] typeMinMax = minmax.get(type); 245 /* 246 * final java.awt.CheckboxMenuItem chb = new 247 * java.awt.CheckboxMenuItem("Vary Height"); // this is broken at the 248 * moment chb.setState(minmax.get(type) != null); 249 * chb.addActionListener(new ActionListener() { 250 * 251 * public void actionPerformed(ActionEvent e) { 252 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type, 253 * null); } else { minmax.put(type, typeMinMax); } } 254 * 255 * }); men.add(chb); 256 */ 257 if (typeMinMax != null && typeMinMax[0] != null) 258 { 259 // graduated colourschemes for those where minmax exists for the 260 // positional features 261 MenuItem mxcol = new MenuItem( 262 (typeCol.isSimpleColour()) ? "Graduated Colour" 263 : "Single Colour"); 264 men.add(mxcol); 265 mxcol.addActionListener(new ActionListener() 266 { 267 268 @Override 269 public void actionPerformed(ActionEvent e) 270 { 271 if (typeCol.isSimpleColour()) 272 { 273 new FeatureColourChooser(me, type); 274 // write back the current colour object to update the table 275 check.updateColor(fr.getFeatureStyle(type)); 276 } 277 else 278 { 279 new UserDefinedColours(me, check.type, typeCol); 280 } 281 } 282 283 }); 284 } 285 } 286 287 MenuItem selectContaining = new MenuItem( 288 MessageManager.getString("label.select_columns_containing")); 289 selectContaining.addActionListener(new ActionListener() 290 { 291 @Override 292 public void actionPerformed(ActionEvent e) 293 { 294 me.ap.alignFrame.avc.markColumnsContainingFeatures(false, false, 295 false, type); 296 } 297 }); 298 men.add(selectContaining); 299 300 MenuItem selectNotContaining = new MenuItem(MessageManager 301 .getString("label.select_columns_not_containing")); 302 selectNotContaining.addActionListener(new ActionListener() 303 { 304 @Override 305 public void actionPerformed(ActionEvent e) 306 { 307 me.ap.alignFrame.avc.markColumnsContainingFeatures(true, false, 308 false, type); 309 } 310 }); 311 men.add(selectNotContaining); 312 313 MenuItem hideContaining = new MenuItem( 314 MessageManager.getString("label.hide_columns_containing")); 315 hideContaining.addActionListener(new ActionListener() 316 { 317 @Override 318 public void actionPerformed(ActionEvent e) 319 { 320 hideFeatureColumns(type, true); 321 } 322 }); 323 men.add(hideContaining); 324 325 MenuItem hideNotContaining = new MenuItem( 326 MessageManager.getString("label.hide_columns_not_containing")); 327 hideNotContaining.addActionListener(new ActionListener() 328 { 329 @Override 330 public void actionPerformed(ActionEvent e) 331 { 332 hideFeatureColumns(type, false); 333 } 334 }); 335 men.add(hideNotContaining); 336 337 this.featurePanel.add(men); 338 men.show(this.featurePanel, x, y); 339 } 340 341 @Override discoverAllFeatureData()342 public void discoverAllFeatureData() 343 { 344 if (fr.getAllFeatureColours() != null 345 && fr.getAllFeatureColours().size() > 0) 346 { 347 // rebuildGroups(); 348 349 } 350 resetTable(false); 351 } 352 353 /** 354 * Answers the visibility of the given group, and adds a checkbox for it if 355 * there is not one already 356 */ checkGroupState(String group)357 public boolean checkGroupState(String group) 358 { 359 boolean visible = fr.checkGroupVisibility(group, true); 360 361 /* 362 * is there already a checkbox for this group? 363 */ 364 for (int g = 0; g < groupPanel.getComponentCount(); g++) 365 { 366 if (((Checkbox) groupPanel.getComponent(g)).getLabel().equals(group)) 367 { 368 ((Checkbox) groupPanel.getComponent(g)).setState(visible); 369 return visible; 370 } 371 } 372 373 /* 374 * add a new checkbox 375 */ 376 Checkbox check = new MyCheckbox(group, visible, false); 377 check.addMouseListener(this); 378 check.setFont(new Font("Serif", Font.BOLD, 12)); 379 check.addItemListener(groupItemListener); 380 groupPanel.add(check); 381 382 groupPanel.validate(); 383 return visible; 384 } 385 386 // This routine adds and removes checkboxes depending on 387 // Group selection states resetTable(boolean groupsChanged)388 void resetTable(boolean groupsChanged) 389 { 390 List<String> displayableTypes = new ArrayList<>(); 391 Set<String> foundGroups = new HashSet<>(); 392 393 AlignmentI alignment = av.getAlignment(); 394 395 for (int i = 0; i < alignment.getHeight(); i++) 396 { 397 SequenceI seq = alignment.getSequenceAt(i); 398 399 /* 400 * get the sequence's groups for positional features 401 * and keep track of which groups are visible 402 */ 403 Set<String> groups = seq.getFeatures().getFeatureGroups(true); 404 Set<String> visibleGroups = new HashSet<>(); 405 for (String group : groups) 406 { 407 // if (group == null || fr.checkGroupVisibility(group, true)) 408 if (group == null || checkGroupState(group)) 409 { 410 visibleGroups.add(group); 411 } 412 } 413 foundGroups.addAll(groups); 414 415 /* 416 * get distinct feature types for visible groups 417 * record distinct visible types 418 */ 419 Set<String> types = seq.getFeatures().getFeatureTypesForGroups(true, 420 visibleGroups.toArray(new String[visibleGroups.size()])); 421 displayableTypes.addAll(types); 422 } 423 424 /* 425 * remove any checkboxes for groups not present 426 */ 427 pruneGroups(foundGroups); 428 429 Component[] comps; 430 int cSize = featurePanel.getComponentCount(); 431 MyCheckbox check; 432 // This will remove any checkboxes which shouldn't be 433 // visible 434 for (int i = 0; i < cSize; i++) 435 { 436 comps = featurePanel.getComponents(); 437 check = (MyCheckbox) comps[i]; 438 if (!displayableTypes.contains(check.type)) 439 { 440 featurePanel.remove(i); 441 cSize--; 442 i--; 443 } 444 } 445 446 if (fr.getRenderOrder() != null) 447 { 448 // First add the checks in the previous render order, 449 // in case the window has been closed and reopened 450 List<String> rol = fr.getRenderOrder(); 451 for (int ro = rol.size() - 1; ro > -1; ro--) 452 { 453 String item = rol.get(ro); 454 455 if (!displayableTypes.contains(item)) 456 { 457 continue; 458 } 459 460 displayableTypes.remove(item); 461 462 addCheck(false, item); 463 } 464 } 465 466 /* 467 * now add checkboxes which should be visible, 468 * if they have not already been added 469 */ 470 for (String type : displayableTypes) 471 { 472 addCheck(groupsChanged, type); 473 } 474 475 featurePanel.setLayout( 476 new GridLayout(featurePanel.getComponentCount(), 1, 10, 5)); 477 featurePanel.validate(); 478 479 if (scrollPane != null) 480 { 481 scrollPane.validate(); 482 } 483 484 itemStateChanged(null); 485 } 486 487 /** 488 * Remove from the groups panel any checkboxes for groups that are not in the 489 * foundGroups set. This enables removing a group from the display when the 490 * last feature in that group is deleted. 491 * 492 * @param foundGroups 493 */ pruneGroups(Set<String> foundGroups)494 protected void pruneGroups(Set<String> foundGroups) 495 { 496 for (int g = 0; g < groupPanel.getComponentCount(); g++) 497 { 498 Checkbox checkbox = (Checkbox) groupPanel.getComponent(g); 499 if (!foundGroups.contains(checkbox.getLabel())) 500 { 501 groupPanel.remove(checkbox); 502 } 503 } 504 } 505 506 /** 507 * update the checklist of feature types with the given type 508 * 509 * @param groupsChanged 510 * true means if the type is not in the display list then it will be 511 * added and displayed 512 * @param type 513 * feature type to be checked for in the list. 514 */ addCheck(boolean groupsChanged, String type)515 void addCheck(boolean groupsChanged, String type) 516 { 517 boolean addCheck; 518 Component[] comps = featurePanel.getComponents(); 519 MyCheckbox check; 520 addCheck = true; 521 for (int i = 0; i < featurePanel.getComponentCount(); i++) 522 { 523 check = (MyCheckbox) comps[i]; 524 if (check.type.equals(type)) 525 { 526 addCheck = false; 527 break; 528 } 529 } 530 531 if (addCheck) 532 { 533 boolean selected = false; 534 if (groupsChanged || av.getFeaturesDisplayed().isVisible(type)) 535 { 536 selected = true; 537 } 538 539 check = new MyCheckbox(type, selected, false, 540 fr.getFeatureStyle(type)); 541 542 check.addMouseListener(this); 543 check.addMouseMotionListener(this); 544 check.addItemListener(this); 545 if (groupsChanged) 546 { 547 // add at beginning of stack. 548 featurePanel.add(check, 0); 549 } 550 else 551 { 552 // add at end of stack. 553 featurePanel.add(check); 554 } 555 } 556 } 557 invertSelection()558 protected void invertSelection() 559 { 560 for (int i = 0; i < featurePanel.getComponentCount(); i++) 561 { 562 Checkbox check = (Checkbox) featurePanel.getComponent(i); 563 check.setState(!check.getState()); 564 } 565 selectionChanged(true); 566 } 567 568 private ItemListener groupItemListener = new ItemListener() 569 { 570 @Override 571 public void itemStateChanged(ItemEvent evt) 572 { 573 Checkbox source = (Checkbox) evt.getSource(); 574 fr.setGroupVisibility(source.getLabel(), source.getState()); 575 ap.seqPanel.seqCanvas.repaint(); 576 if (ap.overviewPanel != null) 577 { 578 ap.overviewPanel.updateOverviewImage(); 579 } 580 resetTable(true); 581 return; 582 }; 583 }; 584 585 @Override itemStateChanged(ItemEvent evt)586 public void itemStateChanged(ItemEvent evt) 587 { 588 selectionChanged(true); 589 } 590 selectionChanged(boolean updateOverview)591 void selectionChanged(boolean updateOverview) 592 { 593 Component[] comps = featurePanel.getComponents(); 594 int cSize = comps.length; 595 FeatureSettingsBean[] rowData = new FeatureSettingsBean[cSize]; 596 int i = 0; 597 for (Component comp : comps) 598 { 599 MyCheckbox check = (MyCheckbox) comp; 600 // feature filter set to null as not (yet) offered in applet 601 FeatureColourI colour = fr.getFeatureStyle(check.type); 602 rowData[i] = new FeatureSettingsBean(check.type, colour, null, 603 check.getState()); 604 i++; 605 } 606 607 fr.setFeaturePriority(rowData); 608 609 ap.paintAlignment(updateOverview, updateOverview); 610 } 611 612 MyCheckbox selectedCheck; 613 614 boolean dragging = false; 615 616 @Override mouseDragged(MouseEvent evt)617 public void mouseDragged(MouseEvent evt) 618 { 619 if (((Component) evt.getSource()).getParent() != featurePanel) 620 { 621 return; 622 } 623 dragging = true; 624 } 625 626 @Override mouseReleased(MouseEvent evt)627 public void mouseReleased(MouseEvent evt) 628 { 629 if (((Component) evt.getSource()).getParent() != featurePanel) 630 { 631 return; 632 } 633 634 Component comp = null; 635 Checkbox target = null; 636 637 int height = evt.getY() + evt.getComponent().getLocation().y; 638 639 if (height > featurePanel.getSize().height) 640 { 641 642 comp = featurePanel 643 .getComponent(featurePanel.getComponentCount() - 1); 644 } 645 else if (height < 0) 646 { 647 comp = featurePanel.getComponent(0); 648 } 649 else 650 { 651 comp = featurePanel.getComponentAt(evt.getX(), 652 evt.getY() + evt.getComponent().getLocation().y); 653 } 654 655 if (comp != null && comp instanceof Checkbox) 656 { 657 target = (Checkbox) comp; 658 } 659 660 if (selectedCheck != null && target != null && selectedCheck != target) 661 { 662 int targetIndex = -1; 663 for (int i = 0; i < featurePanel.getComponentCount(); i++) 664 { 665 if (target == featurePanel.getComponent(i)) 666 { 667 targetIndex = i; 668 break; 669 } 670 } 671 672 featurePanel.remove(selectedCheck); 673 featurePanel.add(selectedCheck, targetIndex); 674 featurePanel.validate(); 675 itemStateChanged(null); 676 } 677 } 678 setUserColour(String feature, FeatureColourI originalColour)679 public void setUserColour(String feature, FeatureColourI originalColour) 680 { 681 fr.setColour(feature, originalColour); 682 refreshTable(); 683 } 684 refreshTable()685 public void refreshTable() 686 { 687 featurePanel.removeAll(); 688 resetTable(false); 689 ap.paintAlignment(true, true); 690 } 691 692 @Override mouseEntered(MouseEvent evt)693 public void mouseEntered(MouseEvent evt) 694 { 695 } 696 697 @Override mouseExited(MouseEvent evt)698 public void mouseExited(MouseEvent evt) 699 { 700 } 701 702 @Override mouseClicked(MouseEvent evt)703 public void mouseClicked(MouseEvent evt) 704 { 705 MyCheckbox check = (MyCheckbox) evt.getSource(); 706 if ((evt.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0) 707 { 708 this.popupSort(check, fr.getMinMax(), evt.getX(), evt.getY()); 709 } 710 711 if (check.getParent() != featurePanel) 712 { 713 return; 714 } 715 716 if (evt.getClickCount() > 1) 717 { 718 FeatureColourI fcol = fr.getFeatureStyle(check.type); 719 if (fcol.isSimpleColour()) 720 { 721 new UserDefinedColours(this, check.type, fcol.getColour()); 722 } 723 else 724 { 725 new FeatureColourChooser(this, check.type); 726 // write back the current colour object to update the table 727 check.updateColor(fr.getFeatureStyle(check.type)); 728 } 729 } 730 } 731 732 @Override mouseMoved(MouseEvent evt)733 public void mouseMoved(MouseEvent evt) 734 { 735 } 736 737 @Override adjustmentValueChanged(AdjustmentEvent evt)738 public void adjustmentValueChanged(AdjustmentEvent evt) 739 { 740 fr.setTransparency((100 - transparency.getValue()) / 100f); 741 ap.paintAlignment(true, true); 742 } 743 744 class MyCheckbox extends Checkbox 745 { 746 public String type; 747 748 public int stringWidth; 749 750 boolean hasLink; 751 752 FeatureColourI col; 753 updateColor(FeatureColourI newcol)754 public void updateColor(FeatureColourI newcol) 755 { 756 col = newcol; 757 if (col.isSimpleColour()) 758 { 759 setBackground(col.getColour()); 760 } 761 else 762 { 763 String vlabel = type; 764 if (col.isAboveThreshold()) 765 { 766 vlabel += " (>)"; 767 } 768 else if (col.isBelowThreshold()) 769 { 770 vlabel += " (<)"; 771 } 772 if (col.isColourByLabel()) 773 { 774 setBackground(Color.white); 775 vlabel += " (by Label)"; 776 } 777 else 778 { 779 setBackground(col.getMinColour()); 780 } 781 this.setLabel(vlabel); 782 } 783 repaint(); 784 } 785 MyCheckbox(String label, boolean checked, boolean haslink)786 public MyCheckbox(String label, boolean checked, boolean haslink) 787 { 788 super(label, checked); 789 type = label; 790 FontMetrics fm = av.nullFrame.getFontMetrics(av.nullFrame.getFont()); 791 stringWidth = fm.stringWidth(label); 792 this.hasLink = haslink; 793 } 794 MyCheckbox(String type, boolean selected, boolean b, FeatureColourI featureStyle)795 public MyCheckbox(String type, boolean selected, boolean b, 796 FeatureColourI featureStyle) 797 { 798 this(type, selected, b); 799 updateColor(featureStyle); 800 } 801 802 @Override paint(Graphics g)803 public void paint(Graphics g) 804 { 805 Dimension d = getSize(); 806 if (col != null) 807 { 808 if (col.isColourByLabel()) 809 { 810 g.setColor(Color.white); 811 g.fillRect(d.width / 2, 0, d.width / 2, d.height); 812 /* 813 * g.setColor(Color.black); Font f=g.getFont().deriveFont(9); 814 * g.setFont(f); 815 * 816 * // g.setFont(g.getFont().deriveFont( // 817 * AffineTransform.getScaleInstance( // 818 * width/g.getFontMetrics().stringWidth("Label"), // 819 * height/g.getFontMetrics().getHeight()))); g.drawString("Label", 820 * width/2, 0); 821 */ 822 823 } 824 else if (col.isGraduatedColour()) 825 { 826 Color maxCol = col.getMaxColour(); 827 g.setColor(maxCol); 828 g.fillRect(d.width / 2, 0, d.width / 2, d.height); 829 830 } 831 } 832 833 if (hasLink) 834 { 835 g.drawImage(linkImage, stringWidth + 25, 836 (getSize().height - linkImage.getHeight(this)) / 2, this); 837 } 838 } 839 } 840 841 /** 842 * Hide columns containing (or not containing) a given feature type 843 * 844 * @param type 845 * @param columnsContaining 846 */ hideFeatureColumns(final String type, boolean columnsContaining)847 void hideFeatureColumns(final String type, boolean columnsContaining) 848 { 849 if (ap.alignFrame.avc.markColumnsContainingFeatures(columnsContaining, 850 false, false, type)) 851 { 852 if (ap.alignFrame.avc.markColumnsContainingFeatures( 853 !columnsContaining, false, false, type)) 854 { 855 ap.alignFrame.viewport.hideSelectedColumns(); 856 } 857 } 858 } 859 860 @Override mousePressed(MouseEvent e)861 public void mousePressed(MouseEvent e) 862 { 863 // TODO Auto-generated method stub 864 865 } 866 867 } 868