JAL-2416 allow space in score matrix name
[jalview.git] / src / jalview / gui / PaintRefresher.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 jalview.datamodel.AlignmentI;
24 import jalview.datamodel.SequenceI;
25
26 import java.awt.Component;
27 import java.util.ArrayList;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Map.Entry;
32
33 /**
34  * Route datamodel/view update events for a sequence set to any display
35  * components involved TODO: JV3 refactor to abstract gui/view package
36  * 
37  * @author $author$
38  * @version $Revision$
39  */
40 public class PaintRefresher
41 {
42   static Map<String, List<Component>> components = new HashMap<String, List<Component>>();
43
44   /**
45    * Add the given component to those registered under the given sequence set
46    * id. Does nothing if already added.
47    * 
48    * @param comp
49    * @param al
50    */
51   public static void Register(Component comp, String seqSetId)
52   {
53     if (components.containsKey(seqSetId))
54     {
55       List<Component> comps = components.get(seqSetId);
56       if (!comps.contains(comp))
57       {
58         comps.add(comp);
59       }
60     }
61     else
62     {
63       List<Component> vcoms = new ArrayList<Component>();
64       vcoms.add(comp);
65       components.put(seqSetId, vcoms);
66     }
67   }
68
69   /**
70    * Remove this component from all registrations. Also removes a registered
71    * sequence set id if there are no remaining components registered against it.
72    * 
73    * @param comp
74    */
75   public static void RemoveComponent(Component comp)
76   {
77     List<String> emptied = new ArrayList<String>();
78     for (Entry<String, List<Component>> registered : components.entrySet())
79     {
80       String id = registered.getKey();
81       List<Component> comps = components.get(id);
82       comps.remove(comp);
83       if (comps.isEmpty())
84       {
85         emptied.add(id);
86       }
87     }
88
89     /*
90      * Remove now empty ids after the above (to avoid
91      * ConcurrentModificationException).
92      */
93     for (String id : emptied)
94     {
95       components.remove(id);
96     }
97   }
98
99   public static void Refresh(Component source, String id)
100   {
101     Refresh(source, id, false, false);
102   }
103
104   public static void Refresh(Component source, String id,
105           boolean alignmentChanged, boolean validateSequences)
106   {
107     List<Component> comps = components.get(id);
108
109     if (comps == null)
110     {
111       return;
112     }
113
114     for (Component comp : comps)
115     {
116       if (comp == source)
117       {
118         continue;
119       }
120
121       if (validateSequences && comp instanceof AlignmentPanel
122               && source instanceof AlignmentPanel)
123       {
124         validateSequences(((AlignmentPanel) source).av.getAlignment(),
125                 ((AlignmentPanel) comp).av.getAlignment());
126       }
127
128       if (comp instanceof AlignmentPanel && alignmentChanged)
129       {
130         ((AlignmentPanel) comp).alignmentChanged();
131       }
132
133       comp.repaint();
134     }
135   }
136
137   static void validateSequences(AlignmentI source, AlignmentI comp)
138   {
139     SequenceI[] a1;
140     if (source.getHiddenSequences().getSize() > 0)
141     {
142       a1 = source.getHiddenSequences().getFullAlignment()
143               .getSequencesArray();
144     }
145     else
146     {
147       a1 = source.getSequencesArray();
148     }
149
150     SequenceI[] a2;
151     if (comp.getHiddenSequences().getSize() > 0)
152     {
153       a2 = comp.getHiddenSequences().getFullAlignment().getSequencesArray();
154     }
155     else
156     {
157       a2 = comp.getSequencesArray();
158     }
159
160     int i, iSize = a1.length, j, jSize = a2.length;
161
162     if (iSize == jSize)
163     {
164       return;
165     }
166
167     boolean exists = false;
168     for (i = 0; i < iSize; i++)
169     {
170       exists = false;
171
172       for (j = 0; j < jSize; j++)
173       {
174         if (a2[j] == a1[i])
175         {
176           exists = true;
177           break;
178         }
179       }
180
181       if (!exists)
182       {
183         if (i < comp.getHeight())
184         {
185           // TODO: the following does not trigger any recalculation of
186           // height/etc, or maintain the dataset
187           if (comp.getDataset() != source.getDataset())
188           {
189             // raise an implementation warning here - not sure if this situation
190             // will ever occur
191             System.err
192                     .println("IMPLEMENTATION PROBLEM: DATASET out of sync due to an insert whilst calling PaintRefresher.validateSequences(AlignmentI, ALignmentI)");
193           }
194           List<SequenceI> alsq;
195           synchronized (alsq = comp.getSequences())
196           {
197             alsq.add(i, a1[i]);
198           }
199         }
200         else
201         {
202           comp.addSequence(a1[i]);
203         }
204
205         if (comp.getHiddenSequences().getSize() > 0)
206         {
207           a2 = comp.getHiddenSequences().getFullAlignment()
208                   .getSequencesArray();
209         }
210         else
211         {
212           a2 = comp.getSequencesArray();
213         }
214
215         jSize = a2.length;
216       }
217     }
218
219     iSize = a1.length;
220     jSize = a2.length;
221
222     for (j = 0; j < jSize; j++)
223     {
224       exists = false;
225       for (i = 0; i < iSize; i++)
226       {
227         if (a2[j] == a1[i])
228         {
229           exists = true;
230           break;
231         }
232       }
233
234       if (!exists)
235       {
236         comp.deleteSequence(a2[j]);
237       }
238     }
239   }
240
241   static AlignmentPanel[] getAssociatedPanels(String id)
242   {
243     List<Component> comps = components.get(id);
244     if (comps == null)
245     {
246       return new AlignmentPanel[0];
247     }
248     List<AlignmentPanel> tmp = new ArrayList<AlignmentPanel>();
249     for (Component comp : comps)
250     {
251       if (comp instanceof AlignmentPanel)
252       {
253         tmp.add((AlignmentPanel) comp);
254       }
255     }
256     return tmp.toArray(new AlignmentPanel[tmp.size()]);
257   }
258
259 }