1 /* $RCSfile$
2  * $Author: hansonr $
3  * $Date: 2019-05-28 14:45:56 -0500 (Tue, 28 May 2019) $
4  * $Revision: 21972 $
5  *
6  * Copyright (C) 2003-2005  Miguel, Jmol Development
7  *
8  * Contact: jmol-developers@lists.sf.net, jmol-developers@lists.sf.net
9  *
10  *  This library is free software; you can redistribute it and/or
11  *  modify it under the terms of the GNU Lesser General Public
12  *  License as published by the Free Software Foundation; either
13  *  version 2.1 of the License, or (at your option) any later version.
14  *
15  *  This library is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  *  Lesser General Public License for more details.
19  *
20  *  You should have received a copy of the GNU Lesser General Public
21  *  License along with this library; if not, write to the Free Software
22  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24 package org.jmol.viewer;
25 
26 import org.jmol.script.T;
27 import org.jmol.util.BSUtil;
28 
29 import javajs.util.AU;
30 
31 
32 import org.jmol.api.JmolSelectionListener;
33 import org.jmol.i18n.GT;
34 import javajs.util.BS;
35 import org.jmol.modelset.ModelSet;
36 
37 public class SelectionManager {
38 
39   private Viewer vwr;
40 
41   private JmolSelectionListener[] listeners = new JmolSelectionListener[0];
42 
SelectionManager(Viewer vwr)43   SelectionManager(Viewer vwr) {
44     this.vwr = vwr;
45   }
46 
47   final BS bsHidden = new BS();
48   private final BS bsSelection = new BS();
49   final BS bsFixed = new BS();
50 
51   public BS bsSubset;
52   public BS bsDeleted;
53   public Boolean noneSelected;
54 
55 
56 //  void deleteModelAtoms(BS bsDeleted) {
57 //    BSUtil.deleteBits(bsHidden, bsDeleted);
58 //    BSUtil.deleteBits(bsSelection, bsDeleted);
59 //    BSUtil.deleteBits(bsSubset, bsDeleted);
60 //    BSUtil.deleteBits(bsFixed, bsDeleted);
61 //    BSUtil.deleteBits(this.bsDeleted, bsDeleted);
62 //  }
63 
processDeletedModelAtoms(BS bsAtoms)64   void processDeletedModelAtoms(BS bsAtoms) {
65     BSUtil.deleteBits(bsDeleted, bsAtoms);
66     BSUtil.deleteBits(bsSubset, bsAtoms);
67     BSUtil.deleteBits(bsFixed, bsAtoms);
68     BSUtil.deleteBits(bsHidden, bsAtoms);
69     BS bs = BSUtil.copy(bsSelection);
70     BSUtil.deleteBits(bs, bsAtoms);
71     setSelectionSet(bs, 0);
72     selectionChanged(false);
73   }
74 
75 
76   // this is a tri-state. the value -1 means unknown
77   private final static int TRUE = 1;
78   private final static int FALSE = 0;
79   private final static int UNKNOWN = -1;
80   private int empty = TRUE;
81 
82   boolean hideNotSelected;
83 
clear()84   void clear() {
85     clearSelection(true);
86     setSelectionSubset(null);
87     hide(null, null, 0, true);
88     bsDeleted = null;
89     setMotionFixedAtoms(null);
90   }
91 
display(ModelSet modelSet, BS bs, int addRemove, boolean isQuiet)92   void display(ModelSet modelSet, BS bs, int addRemove, boolean isQuiet) {
93     switch (addRemove) {
94     default:
95       BS bsNotSubset = (bsSubset == null ? null : BSUtil.andNot(BSUtil.copy(bsHidden), bsSubset));
96       BS bsAll = modelSet.getModelAtomBitSetIncludingDeleted(-1, false);
97       bsHidden.or(bsAll);
98       if (bsNotSubset != null) {
99         bsHidden.and(bsSubset);
100         bsHidden.or(bsNotSubset);
101       }
102       //$FALL-THROUGH$
103     case T.add:
104       if (bs != null)
105         bsHidden.andNot(bs);
106       break;
107     case T.remove:
108       if (bs != null)
109         bsHidden.or(bs);
110       break;
111     }
112     BSUtil.andNot(bsHidden, bsDeleted);
113     modelSet.setBsHidden(bsHidden);
114     if (!isQuiet)
115       vwr.reportSelection(GT.i(GT.$("{0} atoms hidden"), bsHidden.cardinality()));
116   }
117 
hide(ModelSet modelSet, BS bs, int addRemove, boolean isQuiet)118   void hide(ModelSet modelSet, BS bs, int addRemove, boolean isQuiet) {
119     BS bsNotSubset = (addRemove == 0 || bsSubset == null ? null : BSUtil.andNot(BSUtil.copy(bsHidden), bsSubset));
120     setBitSet(bsHidden, bs, addRemove);
121     if (bsNotSubset != null)
122       bsHidden.or(bsNotSubset);
123     if (modelSet != null)
124       modelSet.setBsHidden(bsHidden);
125     if (!isQuiet)
126       vwr.reportSelection(GT.i(GT.$("{0} atoms hidden"), bsHidden.cardinality()));
127   }
128 
setSelectionSet(BS set, int addRemove)129   void setSelectionSet(BS set, int addRemove) {
130     setBitSet(bsSelection, set, addRemove);
131     empty = UNKNOWN;
132   }
133 
setBitSet(BS bsWhat, BS bs, int addRemove)134   private static void setBitSet(BS bsWhat, BS bs, int addRemove) {
135     switch (addRemove) {
136     default:
137       bsWhat.clearAll();
138       //$FALL-THROUGH$
139     case T.add:
140       if (bs != null)
141         bsWhat.or(bs);
142       break;
143     case T.remove:
144       if (bs != null)
145         bsWhat.andNot(bs);
146       break;
147     }
148   }
149 
getHiddenSet()150   public BS getHiddenSet() {
151     return bsHidden;
152   }
153 
getHideNotSelected()154   boolean getHideNotSelected() {
155     return hideNotSelected;
156   }
157 
setHideNotSelected(boolean TF)158   void setHideNotSelected(boolean TF) {
159     hideNotSelected = TF;
160     if (TF)
161       selectionChanged(false);
162   }
163 
isSelected(int atomIndex)164   public boolean isSelected(int atomIndex) {
165     return (atomIndex >= 0 && bsSelection.get(atomIndex));
166   }
167 
select(BS bs, int addRemove, boolean isQuiet)168   void select(BS bs, int addRemove, boolean isQuiet) {
169     if (bs == null) {
170       selectAll(true);
171       if (!vwr.getBoolean(T.hydrogen))
172         excludeSelectionSet(vwr.ms.getAtoms(T.hydrogen, null));
173       if (!vwr.getBoolean(T.hetero))
174         excludeSelectionSet(vwr.ms.getAtoms(T.hetero, null));
175     } else {
176       setSelectionSet(bs, addRemove);
177       if (!vwr.getBoolean(T.hydrogen))
178         excludeSelectionSet(vwr.ms.getAtoms(T.hydrogen, null));
179       if (!vwr.getBoolean(T.hetero))
180         excludeSelectionSet(vwr.ms.getAtoms(T.hetero, null));
181 
182     }
183     selectionChanged(false);
184     boolean reportChime = vwr.getBoolean(T.messagestylechime);
185     if (!reportChime && isQuiet)
186       return;
187     int n = getSelectionCount();
188     if (reportChime)
189       vwr.getChimeMessenger().reportSelection(n);
190     else if (!isQuiet)
191       vwr.reportSelection(GT.i(GT.$("{0} atoms selected"), n));
192   }
193 
selectAll(boolean isQuiet)194   void selectAll(boolean isQuiet) {
195     int count = vwr.ms.ac;
196     empty = (count == 0) ? TRUE : FALSE;
197     for (int i = count; --i >= 0;)
198       bsSelection.set(i);
199     BSUtil.andNot(bsSelection, bsDeleted);
200     selectionChanged(isQuiet);
201   }
202 
clearSelection(boolean isQuiet)203   void clearSelection(boolean isQuiet) {
204     setHideNotSelected(false);
205     bsSelection.clearAll();
206     empty = TRUE;
207     selectionChanged(isQuiet);
208   }
209 
isAtomSelected(int atomIndex)210   public boolean isAtomSelected(int atomIndex) {
211     return (
212         (bsSubset == null || bsSubset.get(atomIndex))
213         && bsDeleted == null || !bsDeleted.get(atomIndex))
214         && bsSelection.get(atomIndex);
215   }
216 
setSelectedAtom(int atomIndex, boolean TF)217   public void setSelectedAtom(int atomIndex, boolean TF) {
218     if (atomIndex < 0) {
219       selectionChanged(true);
220       return;
221     }
222     if (bsSubset != null && !bsSubset.get(atomIndex)
223         || bsDeleted != null && bsDeleted.get(atomIndex))
224       return;
225     bsSelection.setBitTo(atomIndex, TF);
226     if (TF)
227       empty = FALSE;
228     else
229       empty = UNKNOWN;
230   }
231 
setSelectionSubset(BS bs)232   public void setSelectionSubset(BS bs) {
233     bsSubset = bs;
234   }
235 
isInSelectionSubset(int atomIndex)236   boolean isInSelectionSubset(int atomIndex) {
237     return (atomIndex < 0 || bsSubset == null || bsSubset.get(atomIndex));
238   }
239 
invertSelection()240   void invertSelection() {
241     BSUtil.invertInPlace(bsSelection, vwr.ms.ac);
242     empty = (bsSelection.length() > 0 ? FALSE : TRUE);
243     selectionChanged(false);
244   }
245 
excludeSelectionSet(BS setExclude)246   private void excludeSelectionSet(BS setExclude) {
247     if (setExclude == null || empty == TRUE)
248       return;
249     bsSelection.andNot(setExclude);
250     empty = UNKNOWN;
251   }
252 
253   private final BS bsTemp = new BS();
254 
getSelectionCount()255   public int getSelectionCount() {
256     if (empty == TRUE)
257       return 0;
258     empty = TRUE;
259     BS bs;
260     if (bsSubset == null) {
261       bs = bsSelection;
262     } else {
263       bsTemp.clearAll();
264       bsTemp.or(bsSubset);
265       bsTemp.and(bsSelection);
266       bs = bsTemp;
267    }
268     int count = bs.cardinality();
269     if (count > 0)
270       empty = FALSE;
271     return count;
272   }
273 
addListener(JmolSelectionListener listener)274   void addListener(JmolSelectionListener listener) {
275     for (int i = listeners.length; --i >= 0;)
276       if (listeners[i] == listener) {
277         listeners[i] = null;
278         break;
279       }
280     int len = listeners.length;
281     for (int i = len; --i >= 0;)
282       if (listeners[i] == null) {
283         listeners[i] = listener;
284         return;
285       }
286     if (listeners.length == 0)
287       listeners = new JmolSelectionListener[1];
288     else
289       listeners = (JmolSelectionListener[]) AU.doubleLength(listeners);
290     listeners[len] = listener;
291   }
292 
selectionChanged(boolean isQuiet)293   private void selectionChanged(boolean isQuiet) {
294     if (hideNotSelected)
295       hide(vwr.ms, BSUtil.copyInvert(bsSelection, vwr.ms.ac), 0, isQuiet);
296     if (isQuiet || listeners.length == 0)
297       return;
298     for (int i = listeners.length; --i >= 0;)
299       if (listeners[i] != null)
300         listeners[i].selectionChanged(bsSelection);
301   }
302 
deleteAtoms(BS bs)303   int deleteAtoms(BS bs) {
304     BS bsNew = BSUtil.copy(bs);
305     if (bsDeleted == null) {
306       bsDeleted = bsNew;
307     } else {
308       bsNew.andNot(bsDeleted);
309       bsDeleted.or(bs);
310     }
311     bsHidden.andNot(bsDeleted);
312     bsSelection.andNot(bsDeleted);
313     return bsNew.cardinality();
314   }
315 
getSelectedAtoms()316   BS getSelectedAtoms() {
317     if (bsSubset == null)
318       return bsSelection;
319     BS bs = BSUtil.copy(bsSelection);
320     bs.and(bsSubset);
321     return bs;
322   }
323 
getSelectedAtomsNoSubset()324   BS getSelectedAtomsNoSubset() {
325     return BSUtil.copy(bsSelection);
326   }
327 
excludeAtoms(BS bs, boolean ignoreSubset)328   public BS excludeAtoms(BS bs, boolean ignoreSubset) {
329     if (bsDeleted != null)
330       bs.andNot(bsDeleted);
331     if (!ignoreSubset && bsSubset != null)
332       (bs = BSUtil.copy(bs)).and(bsSubset);
333     return bs;
334   }
335 
setMotionFixedAtoms(BS bs)336   void setMotionFixedAtoms(BS bs) {
337     bsFixed.clearAll();
338     if (bs != null)
339       bsFixed.or(bs);
340   }
341 
getMotionFixedAtoms()342   public BS getMotionFixedAtoms() {
343     return bsFixed;
344   }
345 
346 }
347