54fe488449c98e1708f66c89b969e922c2247cca
[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.Iterator;
30 import java.util.List;
31 import java.util.Map;
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<>();
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<>();
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     if (components == null)
78     {
79       return;
80     }
81
82     Iterator<String> it = components.keySet().iterator();
83     while (it.hasNext())
84     {
85       List<Component> comps = components.get(it.next());
86       comps.remove(comp);
87       if (comps.isEmpty())
88       {
89         it.remove();
90       }
91     }
92   }
93
94   public static void Refresh(Component source, String id)
95   {
96     Refresh(source, id, false, false);
97   }
98
99   public static void Refresh(Component source, String id,
100           boolean alignmentChanged, boolean validateSequences)
101   {
102     List<Component> comps = components.get(id);
103
104     if (comps == null)
105     {
106       return;
107     }
108
109     for (Component comp : comps)
110     {
111       if (comp == source)
112       {
113         continue;
114       }
115
116       if (validateSequences && comp instanceof AlignmentPanel
117               && source instanceof AlignmentPanel)
118       {
119         validateSequences(((AlignmentPanel) source).av.getAlignment(),
120                 ((AlignmentPanel) comp).av.getAlignment());
121       }
122
123       if (comp instanceof AlignmentPanel && alignmentChanged)
124       {
125         ((AlignmentPanel) comp).alignmentChanged();
126       }
127
128       comp.repaint();
129     }
130   }
131
132   static void validateSequences(AlignmentI source, AlignmentI comp)
133   {
134     SequenceI[] a1;
135     if (source.getHiddenSequences().getSize() > 0)
136     {
137       a1 = source.getHiddenSequences().getFullAlignment()
138               .getSequencesArray();
139     }
140     else
141     {
142       a1 = source.getSequencesArray();
143     }
144
145     SequenceI[] a2;
146     if (comp.getHiddenSequences().getSize() > 0)
147     {
148       a2 = comp.getHiddenSequences().getFullAlignment().getSequencesArray();
149     }
150     else
151     {
152       a2 = comp.getSequencesArray();
153     }
154
155     int i, iSize = a1.length, j, jSize = a2.length;
156
157     if (iSize == jSize)
158     {
159       return;
160     }
161
162     boolean exists = false;
163     for (i = 0; i < iSize; i++)
164     {
165       exists = false;
166
167       for (j = 0; j < jSize; j++)
168       {
169         if (a2[j] == a1[i])
170         {
171           exists = true;
172           break;
173         }
174       }
175
176       if (!exists)
177       {
178         if (i < comp.getHeight())
179         {
180           // TODO: the following does not trigger any recalculation of
181           // height/etc, or maintain the dataset
182           if (comp.getDataset() != source.getDataset())
183           {
184             // raise an implementation warning here - not sure if this situation
185             // will ever occur
186             System.err.println(
187                     "IMPLEMENTATION PROBLEM: DATASET out of sync due to an insert whilst calling PaintRefresher.validateSequences(AlignmentI, ALignmentI)");
188           }
189           List<SequenceI> alsq = comp.getSequences();
190           synchronized (alsq)
191           {
192             alsq.add(i, a1[i]);
193           }
194         }
195         else
196         {
197           comp.addSequence(a1[i]);
198         }
199
200         if (comp.getHiddenSequences().getSize() > 0)
201         {
202           a2 = comp.getHiddenSequences().getFullAlignment()
203                   .getSequencesArray();
204         }
205         else
206         {
207           a2 = comp.getSequencesArray();
208         }
209
210         jSize = a2.length;
211       }
212     }
213
214     iSize = a1.length;
215     jSize = a2.length;
216
217     for (j = 0; j < jSize; j++)
218     {
219       exists = false;
220       for (i = 0; i < iSize; i++)
221       {
222         if (a2[j] == a1[i])
223         {
224           exists = true;
225           break;
226         }
227       }
228
229       if (!exists)
230       {
231         comp.deleteSequence(a2[j]);
232       }
233     }
234   }
235
236   static AlignmentPanel[] getAssociatedPanels(String id)
237   {
238     List<Component> comps = components.get(id);
239     if (comps == null)
240     {
241       return new AlignmentPanel[0];
242     }
243     List<AlignmentPanel> tmp = new ArrayList<>();
244     for (Component comp : comps)
245     {
246       if (comp instanceof AlignmentPanel)
247       {
248         tmp.add((AlignmentPanel) comp);
249       }
250     }
251     return tmp.toArray(new AlignmentPanel[tmp.size()]);
252   }
253
254 }