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