1 package jalview.structures.models;
3 import jalview.api.StructureSelectionManagerProvider;
4 import jalview.datamodel.PDBEntry;
5 import jalview.datamodel.SequenceI;
6 import jalview.structure.AtomSpec;
7 import jalview.structure.StructureListener;
8 import jalview.structure.StructureSelectionManager;
9 import jalview.util.MessageManager;
11 import java.util.ArrayList;
12 import java.util.List;
16 * A base class to hold common function for protein structure model binding.
17 * Initial version created by refactoring JMol and Chimera binding models, but
18 * other structure viewers could in principle be accommodated in future.
23 public abstract class AAStructureBindingModel extends
24 SequenceStructureBindingModel implements StructureListener,
25 StructureSelectionManagerProvider
28 private StructureSelectionManager ssm;
30 private PDBEntry[] pdbEntry;
33 * sequences mapped to each pdbentry
35 private SequenceI[][] sequence;
38 * array of target chains for sequences - tied to pdbentry and sequence[]
40 private String[][] chains;
43 * datasource protocol for access to PDBEntrylatest
45 String protocol = null;
47 protected boolean colourBySequence = true;
55 public AAStructureBindingModel(StructureSelectionManager ssm,
71 public AAStructureBindingModel(StructureSelectionManager ssm,
72 PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String[][] chains,
76 this.sequence = sequenceIs;
78 this.pdbEntry = pdbentry;
79 this.protocol = protocol;
82 this.chains = new String[pdbentry.length][];
86 public StructureSelectionManager getSsm()
92 * Returns the i'th PDBEntry (or null)
97 public PDBEntry getPdbEntry(int i)
99 return (pdbEntry != null && pdbEntry.length > i) ? pdbEntry[i] : null;
103 * Returns the number of modelled PDB file entries.
107 public int getPdbCount()
109 return pdbEntry == null ? 0 : pdbEntry.length;
112 public SequenceI[][] getSequence()
117 public String[][] getChains()
122 public String getProtocol()
127 // TODO may remove this if calling methods can be pulled up here
128 protected void setPdbentry(PDBEntry[] pdbentry)
130 this.pdbEntry = pdbentry;
133 protected void setSequence(SequenceI[][] sequence)
135 this.sequence = sequence;
138 protected void setChains(String[][] chains)
140 this.chains = chains;
144 * Construct a title string for the viewer window based on the data Jalview
146 * @param viewerName TODO
151 public String getViewerTitle(String viewerName, boolean verbose)
153 if (getSequence() == null || getSequence().length < 1
155 || getSequence()[0].length < 1)
157 return ("Jalview " + viewerName + " Window");
159 // TODO: give a more informative title when multiple structures are
161 StringBuilder title = new StringBuilder(64);
162 final PDBEntry pdbEntry = getPdbEntry(0);
163 title.append(viewerName + " view for " + getSequence()[0][0].getName()
169 if (pdbEntry.getProperty() != null)
171 if (pdbEntry.getProperty().get("method") != null)
173 title.append(" Method: ");
174 title.append(pdbEntry.getProperty().get("method"));
176 if (pdbEntry.getProperty().get("chains") != null)
178 title.append(" Chain:");
179 title.append(pdbEntry.getProperty().get("chains"));
183 return title.toString();
187 * Called by after closeViewer is called, to release any resources and
188 * references so they can be garbage collected. Override if needed.
190 protected void releaseUIResources()
195 public boolean isColourBySequence()
197 return colourBySequence;
200 public void setColourBySequence(boolean colourBySequence)
202 this.colourBySequence = colourBySequence;
205 protected void addSequenceAndChain(int pe, SequenceI[] seq,
208 if (pe < 0 || pe >= getPdbCount())
210 throw new Error(MessageManager.formatMessage(
211 "error.implementation_error_no_pdbentry_from_index",
213 { Integer.valueOf(pe).toString() }));
215 final String nullChain = "TheNullChain";
216 List<SequenceI> s = new ArrayList<SequenceI>();
217 List<String> c = new ArrayList<String>();
218 if (getChains() == null)
220 setChains(new String[getPdbCount()][]);
222 if (getSequence()[pe] != null)
224 for (int i = 0; i < getSequence()[pe].length; i++)
226 s.add(getSequence()[pe][i]);
227 if (getChains()[pe] != null)
229 if (i < getChains()[pe].length)
231 c.add(getChains()[pe][i]);
240 if (tchain != null && tchain.length > 0)
247 for (int i = 0; i < seq.length; i++)
249 if (!s.contains(seq[i]))
252 if (tchain != null && i < tchain.length)
254 c.add(tchain[i] == null ? nullChain : tchain[i]);
258 SequenceI[] tmp = s.toArray(new SequenceI[s.size()]);
259 getSequence()[pe] = tmp;
262 String[] tch = c.toArray(new String[c.size()]);
263 for (int i = 0; i < tch.length; i++)
265 if (tch[i] == nullChain)
270 getChains()[pe] = tch;
274 getChains()[pe] = null;
279 * add structures and any known sequence associations
281 * @returns the pdb entries added to the current set.
283 public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe, SequenceI[][] seq,
286 List<PDBEntry> v = new ArrayList<PDBEntry>();
287 List<int[]> rtn = new ArrayList<int[]>();
288 for (int i = 0; i < getPdbCount(); i++)
290 v.add(getPdbEntry(i));
292 for (int i = 0; i < pdbe.length; i++)
294 int r = v.indexOf(pdbe[i]);
295 if (r == -1 || r >= getPdbCount())
303 // just make sure the sequence/chain entries are all up to date
304 addSequenceAndChain(r, seq[i], chns[i]);
307 pdbe = v.toArray(new PDBEntry[v.size()]);
311 // expand the tied sequence[] and string[] arrays
312 SequenceI[][] sqs = new SequenceI[getPdbCount()][];
313 String[][] sch = new String[getPdbCount()][];
314 System.arraycopy(getSequence(), 0, sqs, 0, getSequence().length);
315 System.arraycopy(getChains(), 0, sch, 0, this.getChains().length);
318 pdbe = new PDBEntry[rtn.size()];
319 for (int r = 0; r < pdbe.length; r++)
321 int[] stri = (rtn.get(r));
322 // record the pdb file as a new addition
323 pdbe[r] = getPdbEntry(stri[0]);
324 // and add the new sequence/chain entries
325 addSequenceAndChain(stri[0], seq[stri[1]], chns[stri[1]]);
336 * Add sequences to the pe'th pdbentry's sequence set.
341 public void addSequence(int pe, SequenceI[] seq)
343 addSequenceAndChain(pe, seq, null);
347 * add the given sequences to the mapping scope for the given pdb file handle
350 * - pdbFile identifier
352 * - set of sequences it can be mapped to
354 public void addSequenceForStructFile(String pdbFile, SequenceI[] seq)
356 for (int pe = 0; pe < getPdbCount(); pe++)
358 if (getPdbEntry(pe).getFile().equals(pdbFile))
360 addSequence(pe, seq);
366 public void highlightAtoms(List<AtomSpec> atoms)
370 for (AtomSpec atom : atoms)
372 highlightAtom(atom.getAtomIndex(), atom.getPdbResNum(),
373 atom.getChain(), atom.getPdbFile());
378 // TODO Jmol and Chimera seem to expect pdbFile, javascript listener pdbId
379 protected abstract void highlightAtom(int atomIndex, int pdbResNum,
380 String chain, String pdbFile);