refactored do and undo() method to take array of alignments for operations that resul...
[jalview.git] / src / jalview / gui / RedundancyPanel.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer
3  * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
4  *
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.
9  *
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.
14  *
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
18  */
19 package jalview.gui;
20
21 import java.util.*;
22
23 import java.awt.event.*;
24 import javax.swing.*;
25 import javax.swing.event.*;
26
27 import jalview.commands.*;
28 import jalview.datamodel.*;
29 import jalview.jbgui.*;
30 import jalview.util.*;
31
32 /**
33  * DOCUMENT ME!
34  *
35  * @author $author$
36  * @version $Revision$
37  */
38 public class RedundancyPanel
39     extends GSliderPanel implements Runnable
40 {
41   AlignFrame af;
42   AlignmentPanel ap;
43   Stack historyList = new Stack(); // simpler than synching with alignFrame.
44   float[] redundancy;
45   SequenceI[] originalSequences;
46   JInternalFrame frame;
47   Vector redundantSeqs;
48
49   /**
50    * Creates a new RedundancyPanel object.
51    *
52    * @param ap DOCUMENT ME!
53    * @param af DOCUMENT ME!
54    */
55   public RedundancyPanel(final AlignmentPanel ap, AlignFrame af)
56   {
57     this.ap = ap;
58     this.af = af;
59     redundantSeqs = new Vector();
60
61     slider.addChangeListener(new ChangeListener()
62     {
63       public void stateChanged(ChangeEvent evt)
64       {
65         valueField.setText(slider.getValue() + "");
66         sliderValueChanged();
67       }
68     });
69
70     applyButton.setText("Remove");
71     allGroupsCheck.setVisible(false);
72     slider.setMinimum(0);
73     slider.setMaximum(100);
74     slider.setValue(100);
75
76     Thread worker = new Thread(this);
77     worker.start();
78
79     frame = new JInternalFrame();
80     frame.setContentPane(this);
81     Desktop.addInternalFrame(frame, "Redundancy threshold selection", 400,
82                              100, false);
83     frame.addInternalFrameListener(new InternalFrameAdapter()
84     {
85       public void internalFrameClosing(InternalFrameEvent evt)
86       {
87         ap.idPanel.idCanvas.setHighlighted(null);
88       }
89     }
90     );
91
92   }
93
94   /**
95    * This is a copy of remove redundancy in jalivew.datamodel.Alignment
96    * except we dont want to remove redundancy, just calculate once
97    * so we can use the slider to dynamically hide redundant sequences
98    *
99    * @param threshold DOCUMENT ME!
100    * @param sel DOCUMENT ME!
101    *
102    * @return DOCUMENT ME!
103    */
104   public void run()
105   {
106     JProgressBar progress = new JProgressBar();
107     progress.setIndeterminate(true);
108     southPanel.add(progress, java.awt.BorderLayout.SOUTH);
109
110     label.setText("Calculating....");
111
112     slider.setVisible(false);
113     applyButton.setEnabled(false);
114     valueField.setVisible(false);
115
116     validate();
117
118     String[] omitHidden = null;
119
120     SequenceGroup sg = ap.av.getSelectionGroup();
121     int height;
122
123     int start, end;
124
125     if ( (sg != null) && (sg.getSize() >= 1))
126     {
127       originalSequences = sg.getSequencesInOrder(ap.av.alignment);
128       start = sg.getStartRes();
129       end = sg.getEndRes();
130     }
131     else
132     {
133       originalSequences = ap.av.alignment.getSequencesArray();
134       start = 0;
135       end = ap.av.alignment.getWidth();
136     }
137
138     height = originalSequences.length;
139
140     redundancy = new float[height];
141     for (int i = 0; i < height; i++)
142     {
143       redundancy[i] = 0f;
144     }
145
146     if (ap.av.hasHiddenColumns)
147     {
148       omitHidden = ap.av.getViewAsString(sg != null);
149     }
150
151     // long start = System.currentTimeMillis();
152
153     float pid;
154     String seqi, seqj;
155     for (int i = 0; i < height; i++)
156     {
157
158       for (int j = 0; j < i; j++)
159       {
160         if (i == j)
161         {
162           continue;
163         }
164
165         if (omitHidden == null)
166         {
167           seqi = originalSequences[i].getSequenceAsString(start, end);
168           seqj = originalSequences[j].getSequenceAsString(start, end);
169         }
170         else
171         {
172           seqi = omitHidden[i];
173           seqj = omitHidden[j];
174         }
175
176         pid = Comparison.PID(seqi, seqj);
177
178         if (seqj.length() < seqi.length())
179         {
180           redundancy[j] = Math.max(pid, redundancy[j]);
181         }
182         else
183         {
184           redundancy[i] = Math.max(pid, redundancy[i]);
185         }
186
187       }
188     }
189
190     progress.setIndeterminate(false);
191     progress.setVisible(false);
192     progress = null;
193
194     label.setText("Enter the redundancy threshold");
195     slider.setVisible(true);
196     applyButton.setEnabled(true);
197     valueField.setVisible(true);
198
199     validate();
200     // System.out.println((System.currentTimeMillis()-start));
201   }
202
203   void sliderValueChanged()
204   {
205     if (redundancy == null)
206     {
207       return;
208     }
209
210     float value = slider.getValue();
211
212     for (int i = 0; i < redundancy.length; i++)
213     {
214       if (value > redundancy[i])
215       {
216         redundantSeqs.remove(originalSequences[i]);
217       }
218       else if (!redundantSeqs.contains(originalSequences[i]))
219       {
220         redundantSeqs.add(originalSequences[i]);
221       }
222
223     }
224
225     ap.idPanel.idCanvas.setHighlighted(redundantSeqs);
226   }
227
228   /**
229    * DOCUMENT ME!
230    *
231    * @param e DOCUMENT ME!
232    */
233   public void applyButton_actionPerformed(ActionEvent e)
234   {
235     Vector del = new Vector();
236
237     undoButton.setEnabled(true);
238
239     float value = slider.getValue();
240     SequenceGroup sg = ap.av.getSelectionGroup();
241
242     for (int i = 0; i < redundancy.length; i++)
243     {
244       if (value <= redundancy[i])
245       {
246         del.addElement(originalSequences[i]);
247       }
248     }
249
250     // This has to be done before the restoreHistoryItem method of alignFrame will
251     // actually restore these sequences.
252     if (del.size() > 0)
253     {
254       SequenceI[] deleted = new SequenceI[del.size()];
255
256       int width = 0;
257       for (int i = 0; i < del.size(); i++)
258       {
259         deleted[i] = (SequenceI) del.elementAt(i);
260         if (deleted[i].getLength() > width)
261         {
262           width = deleted[i].getLength();
263         }
264       }
265
266       EditCommand cut = new EditCommand("Remove Redundancy",
267                                         EditCommand.CUT, deleted, 0, width,
268                                         ap.av.alignment);
269
270       for (int i = 0; i < del.size(); i++)
271       {
272         ap.av.alignment.deleteSequence(deleted[i]);
273         PaintRefresher.Refresh(this,
274                                ap.av.getSequenceSetId(),
275                                true,
276                                true);
277         if (sg != null)
278         {
279           sg.deleteSequence(deleted[i], false);
280         }
281       }
282
283       historyList.push(cut);
284
285       ap.alignFrame.addHistoryItem(cut);
286
287       ap.av.firePropertyChange("alignment", null,
288                                ap.av.getAlignment().getSequences());
289     }
290
291   }
292
293   /**
294    * DOCUMENT ME!
295    *
296    * @param e DOCUMENT ME!
297    */
298   public void undoButton_actionPerformed(ActionEvent e)
299   {
300     CommandI command = (CommandI) historyList.pop();
301     command.undoCommand(af.getViewAlignments());
302
303     if (ap.av.historyList.contains(command))
304     {
305       ap.av.historyList.remove(command);
306       af.updateEditMenuBar();
307     }
308
309     ap.paintAlignment(true);
310
311     if (historyList.size() == 0)
312     {
313       undoButton.setEnabled(false);
314     }
315   }
316
317   /**
318    * DOCUMENT ME!
319    *
320    * @param e DOCUMENT ME!
321    */
322   public void valueField_actionPerformed(ActionEvent e)
323   {
324     try
325     {
326       int i = Integer.parseInt(valueField.getText());
327       slider.setValue(i);
328     }
329     catch (Exception ex)
330     {
331       valueField.setText(slider.getValue() + "");
332     }
333   }
334
335 }