Merge branch 'patch/JAL-4345_pae_epas1_doubleclick' into develop
[jalview.git] / src / jalview / gui / RedundancyPanel.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.gui;
22
23 import java.awt.event.ActionEvent;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.Stack;
27 import java.util.Vector;
28
29 import javax.swing.JInternalFrame;
30 import javax.swing.JProgressBar;
31 import javax.swing.event.ChangeEvent;
32 import javax.swing.event.ChangeListener;
33 import javax.swing.event.InternalFrameAdapter;
34 import javax.swing.event.InternalFrameEvent;
35
36 import jalview.analysis.AlignSeq;
37 import jalview.commands.CommandI;
38 import jalview.commands.EditCommand;
39 import jalview.commands.EditCommand.Action;
40 import jalview.datamodel.SequenceGroup;
41 import jalview.datamodel.SequenceI;
42 import jalview.jbgui.GSliderPanel;
43 import jalview.util.MessageManager;
44
45 /**
46  * DOCUMENT ME!
47  * 
48  * @author $author$
49  * @version $Revision$
50  */
51 public class RedundancyPanel extends GSliderPanel implements Runnable
52 {
53   AlignFrame af;
54
55   AlignmentPanel ap;
56
57   Stack<CommandI> historyList = new Stack<>();
58
59   // simpler than synching with alignFrame.
60
61   float[] redundancy;
62
63   SequenceI[] originalSequences;
64
65   JInternalFrame frame;
66
67   Vector redundantSeqs;
68
69   /**
70    * Creates a new RedundancyPanel object.
71    * 
72    * @param ap
73    *          DOCUMENT ME!
74    * @param af
75    *          DOCUMENT ME!
76    */
77   public RedundancyPanel(final AlignmentPanel ap, AlignFrame af)
78   {
79     this.ap = ap;
80     this.af = af;
81     redundantSeqs = new Vector();
82
83     slider.addChangeListener(new ChangeListener()
84     {
85       @Override
86       public void stateChanged(ChangeEvent evt)
87       {
88         valueField.setText(slider.getValue() + "");
89         sliderValueChanged();
90       }
91     });
92
93     applyButton.setText(MessageManager.getString("action.remove"));
94     allGroupsCheck.setVisible(false);
95     slider.setMinimum(0);
96     slider.setMaximum(100);
97     slider.setValue(100);
98
99     Thread worker = new Thread(this);
100     worker.start();
101
102     frame = new JInternalFrame();
103     frame.setFrameIcon(null);
104     frame.setContentPane(this);
105     Desktop.addInternalFrame(frame,
106             MessageManager
107                     .getString("label.redundancy_threshold_selection"),
108             true, FRAME_WIDTH, FRAME_HEIGHT, false, true);
109     frame.addInternalFrameListener(new InternalFrameAdapter()
110     {
111       @Override
112       public void internalFrameClosing(InternalFrameEvent evt)
113       {
114         ap.getIdPanel().getIdCanvas().setHighlighted(null);
115       }
116     });
117
118   }
119
120   /**
121    * This is a copy of remove redundancy in jalivew.datamodel.Alignment except
122    * we dont want to remove redundancy, just calculate once so we can use the
123    * slider to dynamically hide redundant sequences
124    * 
125    * @param threshold
126    *          DOCUMENT ME!
127    * @param sel
128    *          DOCUMENT ME!
129    * 
130    * @return DOCUMENT ME!
131    */
132   @Override
133   public void run()
134   {
135     JProgressBar progress = new JProgressBar();
136     progress.setIndeterminate(true);
137     southPanel.add(progress, java.awt.BorderLayout.SOUTH);
138
139     label.setText(MessageManager.getString("label.calculating"));
140
141     slider.setVisible(false);
142     applyButton.setEnabled(false);
143     valueField.setVisible(false);
144
145     validate();
146
147     String[] omitHidden = null;
148
149     SequenceGroup sg = ap.av.getSelectionGroup();
150     int height;
151
152     int start, end;
153
154     if ((sg != null) && (sg.getSize() >= 1))
155     {
156       originalSequences = sg.getSequencesInOrder(ap.av.getAlignment());
157       start = sg.getStartRes();
158       end = sg.getEndRes();
159     }
160     else
161     {
162       originalSequences = ap.av.getAlignment().getSequencesArray();
163       start = 0;
164       end = ap.av.getAlignment().getWidth();
165     }
166
167     height = originalSequences.length;
168     if (ap.av.hasHiddenColumns())
169     {
170       omitHidden = ap.av.getViewAsString(sg != null);
171     }
172     redundancy = AlignSeq.computeRedundancyMatrix(originalSequences,
173             omitHidden, start, end, false);
174
175     progress.setIndeterminate(false);
176     progress.setVisible(false);
177     progress = null;
178
179     label.setText(
180             MessageManager.getString("label.enter_redundancy_threshold"));
181     slider.setVisible(true);
182     applyButton.setEnabled(true);
183     valueField.setVisible(true);
184
185     validate();
186     sliderValueChanged();
187     // jalview.bin.Console.outPrintln((System.currentTimeMillis()-start));
188   }
189
190   void sliderValueChanged()
191   {
192     if (redundancy == null)
193     {
194       return;
195     }
196
197     float value = slider.getValue();
198     List<SequenceI> redundantSequences = new ArrayList<>();
199     for (int i = 0; i < redundancy.length; i++)
200     {
201       if (value <= redundancy[i])
202       {
203         redundantSequences.add(originalSequences[i]);
204       }
205     }
206     ap.getIdPanel().getIdCanvas().setHighlighted(redundantSequences);
207   }
208
209   /**
210    * DOCUMENT ME!
211    * 
212    * @param e
213    *          DOCUMENT ME!
214    */
215   @Override
216   public void applyButton_actionPerformed(ActionEvent e)
217   {
218     List<SequenceI> del = new ArrayList<>();
219
220     undoButton.setEnabled(true);
221
222     float value = slider.getValue();
223     SequenceGroup sg = ap.av.getSelectionGroup();
224
225     for (int i = 0; i < redundancy.length; i++)
226     {
227       if (value <= redundancy[i])
228       {
229         del.add(originalSequences[i]);
230       }
231     }
232
233     // This has to be done before the restoreHistoryItem method of alignFrame
234     // will actually restore these sequences.
235     if (del.size() > 0)
236     {
237       SequenceI[] deleted = new SequenceI[del.size()];
238
239       int width = 0;
240       for (int i = 0; i < del.size(); i++)
241       {
242         deleted[i] = del.get(i);
243         if (deleted[i].getLength() > width)
244         {
245           width = deleted[i].getLength();
246         }
247       }
248
249       EditCommand cut = new EditCommand(
250               MessageManager.getString("action.remove_redundancy"),
251               Action.CUT, deleted, 0, width, ap.av.getAlignment());
252
253       for (int i = 0; i < del.size(); i++)
254       {
255         ap.av.getAlignment().deleteSequence(deleted[i]);
256         if (sg != null)
257         {
258           sg.deleteSequence(deleted[i], false);
259         }
260       }
261
262       historyList.push(cut);
263
264       ap.alignFrame.addHistoryItem(cut);
265
266       PaintRefresher.Refresh(this, ap.av.getSequenceSetId(), true, true);
267       ap.av.firePropertyChange("alignment", null,
268               ap.av.getAlignment().getSequences());
269     }
270
271   }
272
273   /**
274    * DOCUMENT ME!
275    * 
276    * @param e
277    *          DOCUMENT ME!
278    */
279   @Override
280   public void undoButton_actionPerformed(ActionEvent e)
281   {
282     if (historyList == null || historyList.isEmpty())
283     {
284       undoButton.setEnabled(false);
285       return;
286     }
287
288     CommandI command = historyList.pop();
289     if (ap.av.getHistoryList().contains(command))
290     {
291       command.undoCommand(af.getViewAlignments());
292       ap.av.getHistoryList().remove(command);
293       ap.av.firePropertyChange("alignment", null,
294               ap.av.getAlignment().getSequences());
295       af.updateEditMenuBar();
296     }
297
298     ap.paintAlignment(true, true);
299
300     if (historyList.size() == 0)
301     {
302       undoButton.setEnabled(false);
303     }
304   }
305
306 }