Merge branch 'patch/JAL-4345_pae_epas1_doubleclick' into develop
[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       if (comp instanceof AlignmentPanel)
116       {
117         if (validateSequences && source instanceof AlignmentPanel)
118         {
119           validateSequences(((AlignmentPanel) source).av.getAlignment(),
120                   ((AlignmentPanel) comp).av.getAlignment());
121         }
122         if (alignmentChanged)
123         {
124           ((AlignmentPanel) comp).alignmentChanged();
125         }
126       }
127       else if (comp instanceof IdCanvas)
128       {
129         // BH 2019.04.22 fixes JS problem of repaint() consolidation
130         // that occurs in JavaScript but not Java [JAL-3226]
131         ((IdCanvas) comp).fastPaint = false;
132       }
133       else if (comp instanceof SeqCanvas)
134       {
135         // BH 2019.04.22 fixes JS problem of repaint() consolidation
136         // that occurs in JavaScript but not Java [JAL-3226]
137         ((SeqCanvas) comp).fastPaint = false;
138       }
139       comp.repaint();
140     }
141   }
142
143   static void validateSequences(AlignmentI source, AlignmentI comp)
144   {
145     SequenceI[] a1;
146     if (source.getHiddenSequences().getSize() > 0)
147     {
148       a1 = source.getHiddenSequences().getFullAlignment()
149               .getSequencesArray();
150     }
151     else
152     {
153       a1 = source.getSequencesArray();
154     }
155
156     SequenceI[] a2;
157     if (comp.getHiddenSequences().getSize() > 0)
158     {
159       a2 = comp.getHiddenSequences().getFullAlignment().getSequencesArray();
160     }
161     else
162     {
163       a2 = comp.getSequencesArray();
164     }
165
166     int i, iSize = a1.length, j, jSize = a2.length;
167
168     if (iSize == jSize)
169     {
170       return;
171     }
172
173     boolean exists = false;
174     for (i = 0; i < iSize; i++)
175     {
176       exists = false;
177
178       for (j = 0; j < jSize; j++)
179       {
180         if (a2[j] == a1[i])
181         {
182           exists = true;
183           break;
184         }
185       }
186
187       if (!exists)
188       {
189         if (i < comp.getHeight())
190         {
191           // TODO: the following does not trigger any recalculation of
192           // height/etc, or maintain the dataset
193           if (comp.getDataset() != source.getDataset())
194           {
195             // raise an implementation warning here - not sure if this situation
196             // will ever occur
197             jalview.bin.Console.errPrintln(
198                     "IMPLEMENTATION PROBLEM: DATASET out of sync due to an insert whilst calling PaintRefresher.validateSequences(AlignmentI, ALignmentI)");
199           }
200           List<SequenceI> alsq = comp.getSequences();
201           synchronized (alsq)
202           {
203             alsq.add(i, a1[i]);
204           }
205         }
206         else
207         {
208           comp.addSequence(a1[i]);
209         }
210
211         if (comp.getHiddenSequences().getSize() > 0)
212         {
213           a2 = comp.getHiddenSequences().getFullAlignment()
214                   .getSequencesArray();
215         }
216         else
217         {
218           a2 = comp.getSequencesArray();
219         }
220
221         jSize = a2.length;
222       }
223     }
224
225     iSize = a1.length;
226     jSize = a2.length;
227
228     for (j = 0; j < jSize; j++)
229     {
230       exists = false;
231       for (i = 0; i < iSize; i++)
232       {
233         if (a2[j] == a1[i])
234         {
235           exists = true;
236           break;
237         }
238       }
239
240       if (!exists)
241       {
242         comp.deleteSequence(a2[j]);
243       }
244     }
245   }
246
247   static AlignmentPanel[] getAssociatedPanels(String id)
248   {
249     List<Component> comps = components.get(id);
250     if (comps == null)
251     {
252       return new AlignmentPanel[0];
253     }
254     List<AlignmentPanel> tmp = new ArrayList<>();
255     for (Component comp : comps)
256     {
257       if (comp instanceof AlignmentPanel)
258       {
259         tmp.add((AlignmentPanel) comp);
260       }
261     }
262     return tmp.toArray(new AlignmentPanel[tmp.size()]);
263   }
264
265 }