[Git][java-team/openchemlib][upstream] New upstream version 2021.10.0+dfsg
Andrius Merkys (@merkys)
gitlab at salsa.debian.org
Mon Oct 4 07:50:43 BST 2021
Andrius Merkys pushed to branch upstream at Debian Java Maintainers / openchemlib
Commits:
f63e99bf by Andrius Merkys at 2021-10-04T02:16:25-04:00
New upstream version 2021.10.0+dfsg
- - - - -
29 changed files:
- pom.xml
- src/main/java/com/actelion/research/chem/Canonizer.java
- src/main/java/com/actelion/research/chem/ExtendedMolecule.java
- src/main/java/com/actelion/research/chem/IsomericSmilesCreator.java
- src/main/java/com/actelion/research/chem/SmilesParser.java
- src/main/java/com/actelion/research/chem/StereoIsomerEnumerator.java
- src/main/java/com/actelion/research/chem/TautomerHelper.java
- src/main/java/com/actelion/research/chem/coords/CoordinateInventor.java
- src/main/java/com/actelion/research/chem/descriptor/flexophore/generator/CreatorMolDistHistViz.java
- src/main/java/com/actelion/research/chem/docking/DockingEngine.java
- src/main/java/com/actelion/research/chem/docking/LigandPose.java
- src/main/java/com/actelion/research/chem/docking/scoring/AbstractScoringEngine.java
- src/main/java/com/actelion/research/chem/docking/scoring/ChemPLP.java
- src/main/java/com/actelion/research/chem/docking/scoring/IdoScore.java
- src/main/java/com/actelion/research/chem/io/Mol2FileParser.java
- src/main/java/com/actelion/research/chem/properties/complexity/ContainerFragBondsSolutions.java
- src/main/java/com/actelion/research/chem/properties/complexity/ExhaustiveFragmentsStatistics.java
- src/main/java/com/actelion/research/chem/reaction/mapping/MappingScorer.java
- src/main/java/com/actelion/research/chem/reaction/mapping/RootAtomPairSource.java
- src/main/java/com/actelion/research/chem/reaction/mapping/SimilarityGraphBasedReactionMapper.java
- src/main/java/com/actelion/research/gui/JDrawDialog.java
- src/main/java/com/actelion/research/gui/JEditableChemistryView.java
- src/main/java/com/actelion/research/gui/clipboard/ClipboardHandler.java
- + src/main/java/com/actelion/research/gui/dock/DividerChangeListener.java
- src/main/java/com/actelion/research/gui/dock/JDockingPanel.java
- src/main/java/com/actelion/research/gui/dock/TreeFork.java
- src/main/java/com/actelion/research/gui/dock/TreeLeaf.java
- src/main/java/com/actelion/research/gui/dock/TreeRoot.java
- src/main/java/com/actelion/research/util/ConstantsDWAR.java
Changes:
=====================================
pom.xml
=====================================
@@ -8,7 +8,7 @@
Please follow the naming scheme YEAR.MONTH.RELEASE_NO_OF_MONTH
(eg. 2016.4.1 for second release in Apr 2016)
-->
- <version>2021.9.0</version>
+ <version>2021.10.0</version>
<name>OpenChemLib</name>
<description>Open Source Chemistry Library</description>
@@ -195,7 +195,7 @@
<connection>scm:git:git at github.com:Actelion/openchemlib.git</connection>
<developerConnection>scm:git:git at github.com:Actelion/openchemlib.git</developerConnection>
<url>https://github.com/Actelion/openchemlib</url>
- <tag>openchemlib-2021.9.0</tag>
+ <tag>openchemlib-2021.10.0</tag>
</scm>
<distributionManagement>
=====================================
src/main/java/com/actelion/research/chem/Canonizer.java
=====================================
@@ -245,9 +245,10 @@ public class Canonizer {
/**
* Locate those tetrahedral nitrogen atoms with at least 3 neighbors that
* qualify for tetrahedral parity calculation because:<br>
- * - they are quarternary nitrogen atoms<br>
- * or - their configuration inversion is hindered in a polycyclic structure<br>
- * or - flag ASSIGN_PARITIES_TO_TETRAHEDRAL_N is set
+ * - being a quarternary nitrogen atom<br>
+ * - being an aziridin nitrogen atom<br>
+ * - the configuration inversion is hindered in a polycyclic structure<br>
+ * - flag ASSIGN_PARITIES_TO_TETRAHEDRAL_N is set
*/
private void canFindNitrogenQualifyingForParity() {
mNitrogenQualifiesForParity = new boolean[mMol.getAtoms()];
@@ -258,6 +259,11 @@ public class Canonizer {
continue;
}
if (mMol.getConnAtoms(atom) == 3) {
+ if (mMol.getAtomRingSize(atom) == 3) {
+ mNitrogenQualifiesForParity[atom] = true;
+ continue;
+ }
+
if (mMol.getAtomCharge(atom) == 1) {
mNitrogenQualifiesForParity[atom] = true;
continue;
=====================================
src/main/java/com/actelion/research/chem/ExtendedMolecule.java
=====================================
@@ -232,7 +232,7 @@ public class ExtendedMolecule extends Molecule implements Serializable {
* The neighbours (connected atoms) of any atom are sorted by their relevance:<br>
* 1. non-hydrogen atoms (bond order 1 and above) and unusual hydrogen atoms (non natural abundance isotops, custom labelled hydrogen, etc.)<br>
* 2. plain-hydrogen atoms (natural abundance, bond order 1)<br>
- * 3. loosely connected atoms (bond order 0, i.e. metall ligand bond)<br>
+ * 3. loosely connected atoms (bond order 0, i.e. metal ligand bond)<br>
* Only valid after calling ensureHelperArrays(cHelperNeighbours or higher);
* @param atom
* @return count of category 1 & 2 neighbour atoms (excludes neighbours connected with zero bond order)
@@ -3141,13 +3141,13 @@ public class ExtendedMolecule extends Molecule implements Serializable {
return getHandleHydrogenAtomMap(findSimpleHydrogens());
}
- /**
- * If ensureHelperArrays() (and with it handleHydrogens()) was not called yet
- * on a fresh molecule and if the molecule contains simple hydrogen atoms within
- * non-hydrogens atoms, then this function returns a map from current atom indexes
- * to those new atom indexes that would result from a call to handleHydrogens.
- * @return
- */
+ /**
+ * If ensureHelperArrays() (and with it handleHydrogens()) was not called yet
+ * on a fresh molecule and if the molecule contains simple hydrogen atoms within
+ * non-hydrogens atoms, then this function returns a map from current atom indexes
+ * to those new atom indexes that would result from a call to handleHydrogens.
+ * @return
+ */
public int[] getHandleHydrogenAtomMap(boolean[] isSimpleHydrogen) {
int[] map = new int[mAllAtoms];
for (int i=0; i<mAllAtoms; i++)
@@ -3163,6 +3163,11 @@ public class ExtendedMolecule extends Molecule implements Serializable {
map[i] = map[lastNonHAtom];
map[lastNonHAtom] = tempIndex;
+ // swap simple H flags also
+ boolean temp = isSimpleHydrogen[i];
+ isSimpleHydrogen[i] = isSimpleHydrogen[lastNonHAtom];
+ isSimpleHydrogen[lastNonHAtom] = temp;
+
do lastNonHAtom--;
while (isSimpleHydrogen[lastNonHAtom]);
}
=====================================
src/main/java/com/actelion/research/chem/IsomericSmilesCreator.java
=====================================
@@ -50,12 +50,10 @@ public class IsomericSmilesCreator {
private int[] mAtomRank;
private int[] mClosureNumber;
private int[] mSmilesIndex;
- private int[] mClosureBuffer;
private int[][] mKnownTHCountInESRGroup;
private List<SmilesAtom> mGraphAtomList;
private boolean[] mAtomUsed;
private boolean[] mBondUsed;
- private boolean[] mClosureOpened;
private boolean[] mPseudoStereoGroupInversion;
private boolean[] mPseudoStereoGroupInitialized;
@@ -205,33 +203,56 @@ public class IsomericSmilesCreator {
}
private void findRingClosures() {
- boolean[] closureNumberUsed = new boolean[mMol.getBonds()];
- mClosureNumber = new int[mMol.getBonds()];
-
+ // find closure neighbours of every atom and put them in canonical order. i.e. order of appearance in SMILES
for (SmilesAtom smilesAtom:mGraphAtomList) {
- for (int i=0; i<mMol.getConnAtoms(smilesAtom.atom); i++) {
- int bond = mMol.getConnBond(smilesAtom.atom, i);
- closureNumberUsed[mClosureNumber[bond]] = false;
- }
-
- int index = getUnusedConnBondIndex(smilesAtom.atom);
- while (index != -1) {
- int closureBond = mMol.getConnBond(smilesAtom.atom, index);
- mBondUsed[closureBond] = true;
-
- int closureNumber = 1;
- while (closureNumberUsed[closureNumber])
- closureNumber++;
-
- mClosureNumber[closureBond] = closureNumber;
- closureNumberUsed[closureNumber] = true;
+ int closureCount = 0;
+ for (int i=0; i<mMol.getConnAtoms(smilesAtom.atom); i++)
+ if (!mBondUsed[mMol.getConnBond(smilesAtom.atom, i)])
+ closureCount++;
+
+ if (closureCount != 0) {
+ smilesAtom.closureNeighbour = new int[closureCount];
+
+ closureCount = 0;
+ for (int i=0; i<mMol.getConnAtoms(smilesAtom.atom); i++) {
+ if (!mBondUsed[mMol.getConnBond(smilesAtom.atom, i)]) {
+ int neighbour = mMol.getConnAtom(smilesAtom.atom, i);
+ smilesAtom.closureNeighbour[closureCount++] = (mSmilesIndex[neighbour] << 16) | neighbour;
+ }
+ }
- index = getUnusedConnBondIndex(smilesAtom.atom);
+ Arrays.sort(smilesAtom.closureNeighbour);
+ for (int i=0; i<smilesAtom.closureNeighbour.length; i++)
+ smilesAtom.closureNeighbour[i] = 0x0000FFFF & smilesAtom.closureNeighbour[i];
}
}
- mClosureOpened = new boolean[mMol.getBonds()];
- mClosureBuffer = new int[8];
+ // assign closure digits to closure bonds
+ boolean[] closureNumberUsed = new boolean[mMol.getBonds()];
+ mClosureNumber = new int[mMol.getBonds()];
+ for (SmilesAtom smilesAtom:mGraphAtomList) {
+ if (smilesAtom.closureNeighbour != null) {
+ for (int neighbour:smilesAtom.closureNeighbour) {
+ for (int i=0; i<mMol.getConnAtoms(smilesAtom.atom); i++) {
+ if (neighbour == mMol.getConnAtom(smilesAtom.atom, i)) {
+ int bond = mMol.getConnBond(smilesAtom.atom, i);
+ if (!mBondUsed[bond]) { // opening closure bond
+ mBondUsed[bond] = true;
+
+ // assign and allocation closure digit
+ mClosureNumber[bond] = 1;
+ while (closureNumberUsed[mClosureNumber[bond]])
+ mClosureNumber[bond]++;
+ closureNumberUsed[mClosureNumber[bond]] = true;
+ }
+ else { // closing closure bond: release closure digit
+ closureNumberUsed[mClosureNumber[bond]] = false;
+ }
+ }
+ }
+ }
+ }
+ }
}
private void calculateEZBonds() {
@@ -391,16 +412,6 @@ public class IsomericSmilesCreator {
return bestIndex;
}
- private int getUnusedConnBondIndex(int atom) {
- int bestIndex = -1;
- for (int i=0; i<mMol.getConnAtoms(atom); i++)
- if (!mBondUsed[mMol.getConnBond(atom, i)]
- && (bestIndex == -1 || mAtomRank[mMol.getConnAtom(atom, bestIndex)] < mAtomRank[mMol.getConnAtom(atom, i)]))
- bestIndex = i;
-
- return bestIndex;
- }
-
private void addToGraph(SmilesAtom smilesAtom, int listIndex) {
mGraphAtomList.add(listIndex, smilesAtom);
mAtomUsed[smilesAtom.atom] = true;
@@ -444,7 +455,7 @@ public class IsomericSmilesCreator {
int isotop = mMol.getAtomMass(atom);
int mapNo = (mMode & MODE_INCLUDE_MAPPING) != 0 ? mMol.getAtomMapNo(atom) : 0;
- String smartsFeatures = (mMode & MODE_CREATE_SMARTS) != 0 ? getAtomSMARTSFeatures(atom, buffer) : "";
+ String smartsFeatures = (mMode & MODE_CREATE_SMARTS) != 0 ? getAtomSMARTSFeatures(atom, buffer) : null;
boolean useBrackets =
(!isAnyAtom && !isOrganic(mMol.getAtomicNo(atom)))
@@ -456,7 +467,7 @@ public class IsomericSmilesCreator {
|| mapNo != 0
|| mMol.getAtomAbnormalValence(atom) != -1
|| mMol.getAtomRadical(atom) != Molecule.cAtomRadicalStateNone
- || smartsFeatures.length() != 0;
+ || smartsFeatures != null;
if (useBrackets)
builder.append('[');
@@ -483,6 +494,9 @@ public class IsomericSmilesCreator {
builder.append(Math.abs(charge));
}
+ if (smartsFeatures != null)
+ builder.append(smartsFeatures);
+
if (mapNo != 0) {
builder.append(':');
builder.append(mapNo);
@@ -589,7 +603,8 @@ public class IsomericSmilesCreator {
}
int ringSize = (queryFeatures & Molecule.cAtomQFRingSize) >> Molecule.cAtomQFRingSizeShift;
- buffer.append(";r"+(ringSize == 0 ? 0 : ringSize-2));
+ if (ringSize != 0)
+ buffer.append(";r"+ringSize);
int neighbourFeatures = queryFeatures & Molecule.cAtomQFNeighbours;
switch (neighbourFeatures) {
@@ -625,7 +640,7 @@ public class IsomericSmilesCreator {
if ((queryFeatures & Molecule.cAtomQFMoreNeighbours) != 0)
buffer.append(";!D"+mMol.getConnAtoms(atom)); // Convert into exact explicit neighbour count 'D'
- return buffer.toString();
+ return buffer.length() == 0 ? null : buffer.toString();
}
/**
@@ -647,31 +662,47 @@ public class IsomericSmilesCreator {
}
private void appendClosureBonds(SmilesAtom smilesAtom, StringBuilder builder) {
- int closureCount = 0;
- for (int i=0; i<mMol.getConnAtoms(smilesAtom.atom); i++) {
- int bond = mMol.getConnBond(smilesAtom.atom, i);
- if (mClosureNumber[bond] != 0) {
- int isOpenFlag = mClosureOpened[bond] ? 0 : 0x40000000;
- mClosureBuffer[closureCount++] = isOpenFlag | (mClosureNumber[bond] << 20) | bond;
- }
- }
- if (closureCount != 0) {
- // when sorting, then put and handle open closures first
- Arrays.sort(mClosureBuffer, 0, closureCount); // we must sort to be canonical
- for (int i=0; i<closureCount; i++) {
- int bond = mClosureBuffer[i] & 0x0003FFFF;
- int closureNumber = ((mClosureBuffer[i] & 0x3FFC0000) >> 20);
- if (!mClosureOpened[bond]) {
- mClosureOpened[bond] = true;
- appendBondOrderSymbol(bond, smilesAtom.atom, builder);
+ if (smilesAtom.closureNeighbour != null) {
+ for (int neighbour:smilesAtom.closureNeighbour) {
+ for (int i=0; i<mMol.getConnAtoms(smilesAtom.atom); i++) {
+ if (neighbour == mMol.getConnAtom(smilesAtom.atom, i)) {
+ int bond = mMol.getConnBond(smilesAtom.atom, i);
+ appendBondOrderSymbol(bond, smilesAtom.atom, builder);
+ if (mClosureNumber[bond] > 9)
+ builder.append('%');
+ builder.append(mClosureNumber[bond]);
+ }
}
- if (closureNumber > 9)
- builder.append('%');
- builder.append(closureNumber);
}
}
}
+// private void appendClosureBonds(SmilesAtom smilesAtom, StringBuilder builder) {
+// int closureCount = 0;
+// for (int i=0; i<mMol.getConnAtoms(smilesAtom.atom); i++) {
+// int bond = mMol.getConnBond(smilesAtom.atom, i);
+// if (mClosureNumber[bond] != 0) {
+// int isOpenFlag = mClosureOpened[bond] ? 0 : 0x40000000;
+// mClosureBuffer[closureCount++] = isOpenFlag | (mClosureNumber[bond] << 20) | bond;
+// }
+// }
+// if (closureCount != 0) {
+// // when sorting, then put and handle open closures first
+// Arrays.sort(mClosureBuffer, 0, closureCount); // we must sort to be canonical
+// for (int i=0; i<closureCount; i++) {
+// int bond = mClosureBuffer[i] & 0x0003FFFF;
+// int closureNumber = ((mClosureBuffer[i] & 0x3FFC0000) >> 20);
+// if (!mClosureOpened[bond]) {
+// mClosureOpened[bond] = true;
+// appendBondOrderSymbol(bond, smilesAtom.atom, builder);
+// }
+// if (closureNumber > 9)
+// builder.append('%');
+// builder.append(closureNumber);
+// }
+// }
+// }
+
private void appendBondOrderSymbol(SmilesAtom smilesAtom, StringBuilder builder) {
if (smilesAtom.ezHalfParity != 0) {
builder.append(smilesAtom.ezHalfParity == 1 ? '/' : '\\');
@@ -814,23 +845,24 @@ public class IsomericSmilesCreator {
/**
* @param atom for which to return a neighbor's smiles rank
- * @param neighborIndex index for getConnAtoms() to get neighbor atom and bond
+ * @param neighbourIndex index for getConnAtoms() to get neighbor atom and bond
* @return neighbor's position rank in smiles from a perspective of atom using closure digit positions for closure neighbors
*/
- private int getSmilesRank(int atom, int neighborIndex) {
- int bond = mMol.getConnBond(atom, neighborIndex);
+ private int getSmilesRank(int atom, int neighbourIndex) {
+ int bond = mMol.getConnBond(atom, neighbourIndex);
+ int neighbour = mMol.getConnAtom(atom, neighbourIndex);
if (mClosureNumber[bond] != 0) {
- // if neighbor is attached via a closure digit, then the rank is based primarily on atom's position
+ // if neighbour is attached via a closure digit, then the rank is based primarily on atom's position
// in the smiles and secondary on the count of other closures at atom that precede this closure
int rank = 8 * mSmilesIndex[atom] + 1;
- for (int i=0; i<neighborIndex; i++)
- if (mClosureNumber[mMol.getConnAtom(atom, i)] != 0)
- rank++;
+ int[] closureNeighbour = mGraphAtomList.get(mSmilesIndex[atom]).closureNeighbour;
+ for (int i=0; i<closureNeighbour.length && neighbour != closureNeighbour[i]; i++)
+ rank++;
return rank;
}
- // if the neighbor is not a closure return a rank based on its atom index in the smiles
- return 8 * mSmilesIndex[mMol.getConnAtom(atom, neighborIndex)];
+ // if the neighbour is not a closure return a rank based on its atom index in the smiles
+ return 8 * mSmilesIndex[neighbour];
}
private boolean isOrganic (int atomicNo) {
@@ -844,6 +876,7 @@ public class IsomericSmilesCreator {
class SmilesAtom {
public int atom,parent,ezHalfParity;
public boolean isSideChainStart,isSideChainEnd;
+ public int[] closureNeighbour;
public SmilesAtom(int atom, int parent, boolean isSideChainStart, boolean isSideChainEnd) {
this.atom = atom;
=====================================
src/main/java/com/actelion/research/chem/SmilesParser.java
=====================================
@@ -38,16 +38,22 @@ import com.actelion.research.chem.reaction.Reaction;
import com.actelion.research.util.ArrayUtils;
import com.actelion.research.util.SortedList;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.TreeMap;
public class SmilesParser {
+ private static final int SMARTS_MODE_MASK = 3;
public static final int SMARTS_MODE_IS_SMILES = 0;
public static final int SMARTS_MODE_GUESS = 1;
public static final int SMARTS_MODE_IS_SMARTS = 2;
+ public static final int MODE_SKIP_COORDINATE_TEMPLATES = 4;
+
+ private static final int INITIAL_CONNECTIONS = 16;
+ private static final int MAX_CONNECTIONS = 100; // largest allowed one in SMILES is 99
private static final int MAX_BRACKET_LEVELS = 64;
- private static final int MAX_RE_CONNECTIONS = 64;
private static final int MAX_AROMATIC_RING_SIZE = 15;
private static final int HYDROGEN_ANY = -1;
@@ -58,8 +64,8 @@ public class SmilesParser {
private StereoMolecule mMol;
private boolean[] mIsAromaticBond;
- private int mAromaticAtoms,mAromaticBonds,mSmartsMode;
- private boolean mCreateSmartsWarnings;
+ private int mAromaticAtoms,mAromaticBonds,mSmartsMode,mCoordinateMode;
+ private boolean mCreateSmartsWarnings,mSkipTemplates;
private StringBuilder mSmartsWarningBuffer;
/**
@@ -79,12 +85,39 @@ public class SmilesParser {
* single bond and without any implicit hydrogen atoms. If smartsMode is SMARTS_MODE_IS_GUESS,
* then
* molecules is never set.
- * @param smartsMode one of SMARTS_MODE...
+ * @param mode one of SMARTS_MODE... and optionally other mode flags
* @param createSmartsWarnings if true, then getSmartsWarning() may be used after parsing a SMILES or SMARTS
*/
- public SmilesParser(int smartsMode, boolean createSmartsWarnings) {
- mSmartsMode = smartsMode;
+ public SmilesParser(int mode, boolean createSmartsWarnings) {
+ mSmartsMode = mode & SMARTS_MODE_MASK;
mCreateSmartsWarnings = createSmartsWarnings;
+ mCoordinateMode = CoordinateInventor.MODE_DEFAULT;
+ if ((mode & MODE_SKIP_COORDINATE_TEMPLATES) != 0)
+ mCoordinateMode |= CoordinateInventor.MODE_SKIP_DEFAULT_TEMPLATES;
+
+ mSkipTemplates = ((mode & MODE_SKIP_COORDINATE_TEMPLATES) != 0);
+ }
+
+ public StereoMolecule parseMolecule(String smiles) {
+ return smiles == null ? null : parseMolecule(smiles.getBytes());
+ }
+
+ /**
+ * Convenience method to quickly obtain a StereoMolecule from a SMILES string.
+ * If you process many SMILES, then the parse() methods are preferred, because
+ * they avoid the steady instantiation new StereoMolecules.
+ * @param smiles
+ * @return
+ */
+ public StereoMolecule parseMolecule(byte[] smiles) {
+ StereoMolecule mol = new StereoMolecule();
+ try {
+ parse(mol, smiles);
+ }
+ catch (Exception e) {
+ return null;
+ }
+ return mol;
}
public Reaction parseReaction(String smiles) throws Exception {
@@ -207,17 +240,17 @@ public class SmilesParser {
int[] baseAtom = new int[MAX_BRACKET_LEVELS];
baseAtom[0] = -1;
- int[] ringClosureAtom = new int[MAX_RE_CONNECTIONS];
- int[] ringClosurePosition = new int[MAX_RE_CONNECTIONS];
- int[] ringClosureBondType = new int[MAX_RE_CONNECTIONS];
- int[] ringClosureBondQueryFeatures = new int[MAX_RE_CONNECTIONS];
- for (int i=0; i<MAX_RE_CONNECTIONS; i++)
+ int[] ringClosureAtom = new int[INITIAL_CONNECTIONS];
+ int[] ringClosurePosition = new int[INITIAL_CONNECTIONS];
+ int[] ringClosureBondType = new int[INITIAL_CONNECTIONS];
+ int[] ringClosureBondQueryFeatures = new int[INITIAL_CONNECTIONS];
+ for (int i = 0; i<INITIAL_CONNECTIONS; i++)
ringClosureAtom[i] = -1;
int atomMass = 0;
int fromAtom = -1;
boolean squareBracketOpen = false;
- boolean percentFound = false;
+ boolean isDoubleDigit = false;
boolean smartsFeatureFound = false;
int bracketLevel = 0;
int bondType = Molecule.cBondTypeSingle;
@@ -409,8 +442,11 @@ public class SmilesParser {
if (smiles[position] == 'D') { // non-H-neighbours
position++;
- int neighbours = smiles[position] - '0';
- position++;
+ int neighbours = 1;
+ if (Character.isDigit(smiles[position])) {
+ neighbours = smiles[position] - '0';
+ position++;
+ }
int qf = (neighbours == 0) ? Molecule.cAtomQFNot0Neighbours
: (neighbours == 1) ? Molecule.cAtomQFNot1Neighbour
: (neighbours == 2) ? Molecule.cAtomQFNot2Neighbours
@@ -432,15 +468,17 @@ public class SmilesParser {
if (smiles[position] == 'R') {
position++;
- int ringCount = -1;
- if (Character.isDigit(smiles[position])) {
- ringCount = smiles[position] - '0';
- position++;
+ if (!Character.isDigit(smiles[position])) {
+ if (isNot)
+ atomQueryFeatures |= Molecule.cBondQFRingState & ~Molecule.cAtomQFNotChain;
+ else
+ atomQueryFeatures |= Molecule.cAtomQFNotChain;
+ continue;
}
+ int ringCount = smiles[position] - '0';
+ position++;
if (isNot) {
- if (ringCount == -1)
- atomQueryFeatures |= Molecule.cAtomQFRingState & ~Molecule.cAtomQFNotChain;
- else if (ringCount == 0)
+ if (ringCount == 0)
atomQueryFeatures |= Molecule.cAtomQFNotChain;
else if (ringCount == 1)
atomQueryFeatures |= Molecule.cAtomQFNot2RingBonds;
@@ -454,9 +492,7 @@ public class SmilesParser {
else {
if (ringCount >= 3)
ringCount = 3;
- if (ringCount == -1)
- atomQueryFeatures |= Molecule.cAtomQFNotChain;
- else if (ringCount == 0)
+ if (ringCount == 0)
atomQueryFeatures |= Molecule.cAtomQFRingState & ~Molecule.cAtomQFNotChain;
else if (ringCount == 1)
atomQueryFeatures |= Molecule.cAtomQFRingState & ~Molecule.cAtomQFNot2RingBonds;
@@ -472,11 +508,17 @@ public class SmilesParser {
if (smiles[position] == 'r') {
position++;
+ if (!Character.isDigit(smiles[position])) {
+ if (isNot)
+ atomQueryFeatures |= Molecule.cBondQFRingState & ~Molecule.cAtomQFNotChain;
+ else
+ atomQueryFeatures |= Molecule.cAtomQFNotChain;
+ continue;
+ }
int ringSize = smiles[position] - '0';
- int ringCode = (ringSize >= 3) ? ringSize-2 : 0;
position++;
- if (!isNot && ringCode <= 7)
- atomQueryFeatures |= (ringCode << Molecule.cAtomQFRingSizeShift);
+ if (!isNot && ringSize >= 3 && ringSize <= 7)
+ atomQueryFeatures |= (ringSize << Molecule.cAtomQFRingSizeShift);
else
smartsWarning((isNot ? "!r" : "r") + ringSize);
continue;
@@ -582,6 +624,9 @@ public class SmilesParser {
// mark aromatic atoms
if (Character.isLowerCase(theChar)) {
+ if (atomicNo != 5 && atomicNo != 6 && atomicNo != 7 && atomicNo != 8 && atomicNo != 15 &&atomicNo != 16)
+ throw new Exception("SmilesParser: atomicNo "+atomicNo+" must not be aromatic");
+
mMol.setAtomMarker(atom, true);
mAromaticAtoms++;
}
@@ -626,7 +671,7 @@ public class SmilesParser {
// using position as hydrogenPosition is close enough
int hydrogenCount = (explicitHydrogens == HYDROGEN_IMPLICIT_ZERO) ? 0 : explicitHydrogens;
- parityMap.put(atom, new THParity(atom, fromAtom, hydrogenCount, position, isClockwise));
+ parityMap.put(atom, new THParity(atom, fromAtom, hydrogenCount, position-1, isClockwise));
}
}
@@ -739,15 +784,29 @@ public class SmilesParser {
|| smiles[position-2] == '#'
|| smiles[position-2] == ':'
|| smiles[position-2] == '>');
- if (percentFound
+ if (isDoubleDigit
&& position < endIndex
&& Character.isDigit(smiles[position])) {
number = 10 * number + smiles[position] - '0';
+ isDoubleDigit = false;
position++;
}
- percentFound = false;
- if (number >= MAX_RE_CONNECTIONS)
- throw new Exception("SmilesParser: ringClosureAtom number out of range");
+ if (number >= ringClosureAtom.length) {
+ if (number >=MAX_CONNECTIONS)
+ throw new Exception("SmilesParser: ringClosureAtom number out of range");
+
+ int oldSize = ringClosureAtom.length;
+ int newSize = ringClosureAtom.length;
+ while (newSize <= number)
+ newSize = Math.min(MAX_CONNECTIONS, newSize + INITIAL_CONNECTIONS);
+
+ ringClosureAtom = Arrays.copyOf(ringClosureAtom, newSize);
+ ringClosurePosition = Arrays.copyOf(ringClosurePosition, newSize);
+ ringClosureBondType = Arrays.copyOf(ringClosureBondType, newSize);
+ ringClosureBondQueryFeatures = Arrays.copyOf(ringClosureBondQueryFeatures, newSize);
+ for (int i=oldSize; i<newSize; i++)
+ ringClosureAtom[i] = -1;
+ }
if (ringClosureAtom[number] == -1) {
ringClosureAtom[number] = baseAtom[bracketLevel];
ringClosurePosition[number] = position-1;
@@ -816,7 +875,7 @@ public class SmilesParser {
}
if (theChar == '%') {
- percentFound = true;
+ isDoubleDigit = true;
continue;
}
@@ -835,8 +894,8 @@ public class SmilesParser {
// Check for unsatisfied open bonds
if (bondType != Molecule.cBondTypeSingle)
throw new Exception("SmilesParser: dangling open bond");
- for (int i=0; i<MAX_RE_CONNECTIONS; i++)
- if (ringClosureAtom[i] != -1)
+ for (int rca:ringClosureAtom)
+ if (rca != -1)
throw new Exception("SmilesParser: dangling ring closure");
int[] handleHydrogenAtomMap = mMol.getHandleHydrogenMap();
@@ -921,7 +980,7 @@ public class SmilesParser {
mMol.setParitiesValid(0);
if (createCoordinates) {
- new CoordinateInventor().invent(mMol);
+ new CoordinateInventor(mCoordinateMode).invent(mMol);
if (readStereoFeatures)
mMol.setUnknownParitiesToExplicitlyUnknown();
@@ -1456,11 +1515,21 @@ public class SmilesParser {
return paritiesFound;
}
+ private class ParityNeighbour {
+ int mAtom,mPosition;
+ boolean mIsHydrogen;
+
+ public ParityNeighbour(int atom, int position, boolean isHydrogen) {
+ mAtom = atom;
+ mPosition = position;
+ mIsHydrogen = isHydrogen;
+ }
+ }
+
private class THParity {
- int mCentralAtom,mImplicitHydrogen,mFromAtom,mNeighborCount;
- int[] mNeighborAtom,mNeighborPosition;
- boolean[] mNeighborIsHydrogen;
+ int mCentralAtom,mImplicitHydrogen,mFromAtom;
boolean mIsClockwise,mError;
+ ArrayList<ParityNeighbour> mNeighbourList;
/**
* Instantiates a new parity object during smiles traversal.
@@ -1472,26 +1541,23 @@ public class SmilesParser {
public THParity(int centralAtom, int fromAtom, int implicitHydrogen, int hydrogenPosition, boolean isClockwise) {
if (implicitHydrogen != 0 && implicitHydrogen != 1) {
mError = true;
- }
+ }
else {
mCentralAtom = centralAtom;
mFromAtom = fromAtom;
mImplicitHydrogen = implicitHydrogen;
mIsClockwise = isClockwise;
- mNeighborCount = 0;
- mNeighborIsHydrogen = new boolean[4];
- mNeighborAtom = new int[4];
- mNeighborPosition = new int[4];
+ mNeighbourList = new ArrayList<>();
// If we have a fromAtom and we have an implicit hydrogen,
- // then make the implicit hydrogen a normal neighbor.
+ // then make the implicit hydrogen a normal neighbour.
if (fromAtom != -1 && implicitHydrogen == 1) {
// We put it at the end of the atom list with MAX_VALUE
addNeighbor(Integer.MAX_VALUE, hydrogenPosition, true);
mImplicitHydrogen = 0;
- }
}
}
+ }
/**
* Adds a currently traversed neighbor or ring closure to parity object,
@@ -1505,19 +1571,14 @@ public class SmilesParser {
* @param isHydrogen
*/
public void addNeighbor(int atom, int position, boolean isHydrogen) {
- if (mError)
- return;
+ if (!mError) {
+ if (mNeighbourList.size() == 4 || (mNeighbourList.size() == 3 && mFromAtom != -1)) {
+ mError = true;
+ return;
+ }
- if (mNeighborCount == 4
- || (mNeighborCount == 3 && mFromAtom != -1)) {
- mError = true;
- return;
+ mNeighbourList.add(new ParityNeighbour(atom, position, isHydrogen));
}
-
- mNeighborIsHydrogen[mNeighborCount] = isHydrogen;
- mNeighborAtom[mNeighborCount] = atom;
- mNeighborPosition[mNeighborCount] = position;
- mNeighborCount++;
}
public int calculateParity(int[] handleHydrogenAtomMap) {
@@ -1528,71 +1589,66 @@ public class SmilesParser {
// uses after calling handleHydrogens, which is called from ensureHelperArrays().
if (mFromAtom != -1)
mFromAtom = handleHydrogenAtomMap[mFromAtom];
- for (int i=0; i<mNeighborCount; i++)
- if (mNeighborAtom[i] != Integer.MAX_VALUE)
- mNeighborAtom[i] = handleHydrogenAtomMap[mNeighborAtom[i]];
+ for (ParityNeighbour neighbour:mNeighbourList)
+ if (neighbour.mAtom != Integer.MAX_VALUE)
+ neighbour.mAtom = handleHydrogenAtomMap[neighbour.mAtom];
if (mFromAtom == -1 && mImplicitHydrogen == 0) {
// If we have no implicit hydrogen and the central atom is the first atom in the smiles,
// then we assume that we have to take the first neighbor as from-atom (not described in Daylight theory manual).
// Assumption: take the first neighbor as front atom, i.e. skip it when comparing positions
int minPosition = Integer.MAX_VALUE;
- int minIndex = -1;
- for (int i=0; i<mNeighborCount; i++) {
- if (minPosition > mNeighborPosition[i]) {
- minPosition = mNeighborPosition[i];
- minIndex = i;
+ ParityNeighbour minNeighbour = null;
+ for (ParityNeighbour neighbour:mNeighbourList) {
+ if (minPosition > neighbour.mPosition) {
+ minPosition = neighbour.mPosition;
+ minNeighbour = neighbour;
}
}
- mFromAtom = mNeighborAtom[minIndex];
- for (int i=minIndex+1; i<mNeighborCount; i++) {
- mNeighborAtom[i-1] = mNeighborAtom[i];
- mNeighborPosition[i-1] = mNeighborPosition[i];
- mNeighborIsHydrogen[i-1] = mNeighborIsHydrogen[i];
- }
- mNeighborCount--;
+ mFromAtom = minNeighbour.mAtom;
+ mNeighbourList.remove(minNeighbour);
}
- int totalNeighborCount = (mFromAtom == -1? 0 : 1) + mImplicitHydrogen + mNeighborCount;
+ int totalNeighborCount = (mFromAtom == -1? 0 : 1) + mImplicitHydrogen + mNeighbourList.size();
if (totalNeighborCount > 4 || totalNeighborCount < 3)
return Molecule.cAtomParityUnknown;
// We look from the hydrogen towards the central carbon if the fromAtom is a hydrogen or
// if there is no fromAtom but the central atom has an implicit hydrogen.
boolean fromAtomIsHydrogen = (mFromAtom == -1 && mImplicitHydrogen == 1)
- || (mFromAtom != -1 && mMol.isSimpleHydrogen(mFromAtom));
+ || (mFromAtom != -1 && mMol.isSimpleHydrogen(mFromAtom));
- int hydrogenNeighborIndex = -1;
- for (int i=0; i<mNeighborCount; i++) {
- if (mNeighborIsHydrogen[i]) {
- if (hydrogenNeighborIndex != -1 || fromAtomIsHydrogen)
+ ParityNeighbour hydrogenNeighbour = null;
+ for (ParityNeighbour neighbour:mNeighbourList) {
+ if (neighbour.mIsHydrogen) {
+ if (hydrogenNeighbour != null || fromAtomIsHydrogen)
return Molecule.cAtomParityUnknown;
- hydrogenNeighborIndex = i;
- }
+ hydrogenNeighbour = neighbour;
}
+ }
// hydrogens are moved to the end of the atom list. If the hydrogen passes an odd number of
// neighbor atoms on its way to the list end, we are effectively inverting the atom order.
boolean isHydrogenTraversalInversion = false;
- if (hydrogenNeighborIndex != -1)
- for (int i=0; i<mNeighborCount; i++)
- if (!mNeighborIsHydrogen[i]
- && mNeighborAtom[hydrogenNeighborIndex] < mNeighborAtom[i])
+ if (hydrogenNeighbour != null)
+ for (ParityNeighbour neighbour:mNeighbourList)
+ if (neighbour != hydrogenNeighbour
+ && hydrogenNeighbour.mAtom < neighbour.mAtom)
isHydrogenTraversalInversion = !isHydrogenTraversalInversion;
// If fromAtom is not a hydrogen, we consider it moved to highest atom index,
// because
boolean fromAtomTraversalInversion = false;
if (mFromAtom != -1 && !fromAtomIsHydrogen)
- for (int i=0; i<mNeighborCount; i++)
- if (mFromAtom < mNeighborAtom[i])
+ for (ParityNeighbour neighbour:mNeighbourList)
+ if (mFromAtom < neighbour.mAtom)
fromAtomTraversalInversion = !fromAtomTraversalInversion;
int parity = (mIsClockwise
- ^ isInverseOrder(mNeighborAtom, mNeighborPosition, mNeighborCount)
- ^ fromAtomTraversalInversion
- ^ isHydrogenTraversalInversion) ?
- Molecule.cAtomParity2 : Molecule.cAtomParity1;
+ ^ isInverseOrder()
+ ^ fromAtomTraversalInversion
+ ^ isHydrogenTraversalInversion) ?
+ Molecule.cAtomParity2 : Molecule.cAtomParity1;
/*
System.out.println();
System.out.println("central:"+mCentralAtom+(mIsClockwise?" @@":" @")+" from:"
@@ -1606,19 +1662,19 @@ System.out.println("parity:"+parity);
return parity;
}
- private boolean isInverseOrder(int[] atom, int[] position, int count) {
+ private boolean isInverseOrder() {
boolean inversion = false;
- for (int i=1; i<count; i++) {
+ for (int i=1; i<mNeighbourList.size(); i++) {
for (int j=0; j<i; j++) {
- if (atom[j] > atom[i])
+ if (mNeighbourList.get(j).mAtom > mNeighbourList.get(i).mAtom)
inversion = !inversion;
- if (position[j] > position[i])
+ if (mNeighbourList.get(j).mPosition > mNeighbourList.get(i).mPosition)
inversion = !inversion;
- }
}
- return inversion;
}
+ return inversion;
}
+ }
private static void testStereo() {
final String[][] data = { { "F/C=C/I", "F/C=C/I" },
=====================================
src/main/java/com/actelion/research/chem/StereoIsomerEnumerator.java
=====================================
@@ -28,11 +28,11 @@ public class StereoIsomerEnumerator {
private boolean[][] mAtomIsParity1,mBondIsParity1;
/**
- * If the passed molecules has stereo-chemically undefined configurations
+ * If the passed molecule has stereo-chemically undefined configurations
* (double bonds, stereo centers) or/and one or more AND/OR groups of
* defined relative stereo configurations, then it represents multiple
* stereo isomers. The StereoIsomerEnumerator generates all individual
- * stereo isomers of the passes molecule. If the passed molecule does
+ * stereo isomers of the passed molecule. If the passed molecule does
* not include absolute stereo centers (or atrop isomeric configuration),
* but unknown stereo centers or groups with defined relative configuration,
* then we have pairs of enantiomers. In this case the StereoIsomerEnumerator
=====================================
src/main/java/com/actelion/research/chem/TautomerHelper.java
=====================================
@@ -42,6 +42,8 @@ import java.util.TreeSet;
public class TautomerHelper {
private static final int MAX_TAUTOMERS = 100000;
+ private static int sMaxTautomers = MAX_TAUTOMERS;
+ private static boolean sSuppressWarning = false;
private StereoMolecule mOriginalMol;
private boolean[] mIsTautomerBond;
@@ -54,6 +56,14 @@ public class TautomerHelper {
private TreeSet<BondOrders> mBondOrderSet;
private ArrayDeque<BondOrders> mBondOrderDeque;
+ public static void setMaxTautomers(int maxTautomers) {
+ sMaxTautomers = maxTautomers;
+ }
+
+ public static void setSuppressWarning(boolean suppressWarning) {
+ sSuppressWarning = suppressWarning;
+ }
+
/**
* @param mol
*/
@@ -284,8 +294,9 @@ public class TautomerHelper {
mBondOrderDeque.poll().copyToTautomer(tautomer);
addAllTautomers(tautomer);
- if (mBondOrderSet.size() >= MAX_TAUTOMERS) {
- System.out.println("Tautomer count exceeds maximum: "+new Canonizer(mOriginalMol).getIDCode());
+ if (mBondOrderSet.size() >= sMaxTautomers) {
+ if (!sSuppressWarning)
+ System.out.println("Tautomer count exceeds maximum: "+new Canonizer(mOriginalMol).getIDCode());
break;
}
}
=====================================
src/main/java/com/actelion/research/chem/coords/CoordinateInventor.java
=====================================
@@ -43,6 +43,7 @@ public class CoordinateInventor {
public static final int MODE_KEEP_MARKED_ATOM_COORDS = 4;
public static final int MODE_PREFER_MARKED_ATOM_COORDS = 8;
protected static final int MODE_CONSIDER_MARKED_ATOMS = MODE_KEEP_MARKED_ATOM_COORDS | MODE_PREFER_MARKED_ATOM_COORDS;
+ public static final int MODE_DEFAULT = MODE_REMOVE_HYDROGEN;
private static final byte FLIP_AS_LAST_RESORT = 1;
private static final byte FLIP_POSSIBLE = 2;
@@ -79,7 +80,7 @@ public class CoordinateInventor {
* polycyclic structures from these templates (adamantanes, cubane, etc.).
*/
public CoordinateInventor () {
- this(MODE_REMOVE_HYDROGEN);
+ this(MODE_DEFAULT);
}
@@ -372,7 +373,7 @@ public class CoordinateInventor {
private void locateInitialFragments() {
// take every atom with more than 4 neighbours including first neighbour shell
- for (int atom=0; atom<mMol.getAllAtoms(); atom++) {
+ for (int atom=0; atom<mMol.getAtoms(); atom++) {
if (mMol.getAllConnAtoms(atom) > 4) {
InventorFragment f = new InventorFragment(mMol, 1+mMol.getAllConnAtoms(atom), mMode);
@@ -437,7 +438,7 @@ public class CoordinateInventor {
}
// take every large ring that has ring bonds that are not member of a fragment added already
- for (int bond=0; bond<mMol.getAllBonds(); bond++) {
+ for (int bond=0; bond<mMol.getBonds(); bond++) {
if (mMol.isRingBond(bond) && !mBondHandled[bond]) {
InventorChain theRing = getSmallestRingFromBond(bond);
int[] ringAtom = theRing.getRingAtoms();
@@ -1183,9 +1184,7 @@ public class CoordinateInventor {
int current = 1;
int highest = 1;
while (current <= highest) {
-// if (graphLevel[graphAtom[current]] > RingCollection.MAX_LARGE_RING_SIZE)
-// return null; // disabled ring size limit; TLS 20130613
- for (int i=0; i<mMol.getAllConnAtoms(graphAtom[current]); i++) {
+ for (int i=0; i<mMol.getConnAtoms(graphAtom[current]); i++) {
int candidate = mMol.getConnAtom(graphAtom[current], i);
if ((current > 1) && candidate == atom1) {
InventorChain theRing = new InventorChain(graphLevel[graphAtom[current]]);
@@ -1222,9 +1221,7 @@ public class CoordinateInventor {
int current = 1;
int highest = 1;
while (current <= highest) {
-// if (graphLevel[graphAtom[current]] > RingCollection.MAX_LARGE_RING_SIZE)
-// return 0; // disabled ring size limit; TLS 20130613
- for (int i=0; i<mMol.getAllConnAtoms(graphAtom[current]); i++) {
+ for (int i=0; i<mMol.getConnAtoms(graphAtom[current]); i++) {
int candidate = mMol.getConnAtom(graphAtom[current], i);
if (candidate == atom3)
return 1 + graphLevel[graphAtom[current]];
=====================================
src/main/java/com/actelion/research/chem/descriptor/flexophore/generator/CreatorMolDistHistViz.java
=====================================
@@ -9,6 +9,7 @@ import com.actelion.research.chem.descriptor.flexophore.redgraph.SubGraphExtract
import com.actelion.research.chem.descriptor.flexophore.redgraph.SubGraphIndices;
import com.actelion.research.chem.interactionstatistics.InteractionAtomTypeCalculator;
import org.openmolecules.chem.conf.gen.ConformerGenerator;
+import org.openmolecules.chem.conf.gen.RigidFragmentCache;
import java.util.ArrayList;
import java.util.Date;
@@ -60,6 +61,7 @@ public class CreatorMolDistHistViz {
subGraphExtractor = new SubGraphExtractor();
conformerGenerator = new ConformerGenerator(seed, false);
+ RigidFragmentCache.getDefaultInstance().loadDefaultCache();
conformationMode = CONF_GEN_TS;
=====================================
src/main/java/com/actelion/research/chem/docking/DockingEngine.java
=====================================
@@ -17,6 +17,7 @@ import org.openmolecules.chem.conf.gen.ConformerGenerator;
import com.actelion.research.calc.ThreadMaster;
import com.actelion.research.chem.Canonizer;
import com.actelion.research.chem.Coordinates;
+import com.actelion.research.chem.IDCodeParser;
import com.actelion.research.chem.IDCodeParserWithoutCoordinateInvention;
import com.actelion.research.chem.Molecule;
import com.actelion.research.chem.Molecule3D;
@@ -121,7 +122,7 @@ public class DockingEngine {
threadMaster = tm;
}
- private double getStartingPositions(StereoMolecule mol, List<Conformer> initialPos) {
+ private double getStartingPositions(StereoMolecule mol, List<Conformer> initialPos) throws DockingFailedException {
double eMin = Double.MAX_VALUE;
Map<String, Object> ffOptions = new HashMap<String, Object>();
@@ -140,7 +141,14 @@ public class DockingEngine {
if(c!=null) {
StereoMolecule conf = c.toMolecule();
conf.ensureHelperArrays(Molecule.cHelperParities);
- ForceFieldMMFF94 mmff = new ForceFieldMMFF94(conf, ForceFieldMMFF94.MMFF94SPLUS, ffOptions);
+
+ ForceFieldMMFF94 mmff;
+ try {
+ mmff = new ForceFieldMMFF94(conf, ForceFieldMMFF94.MMFF94SPLUS, ffOptions);
+ }
+ catch(Exception e) {
+ throw new DockingFailedException("could not assess atom types");
+ }
PositionConstraint constraint = new PositionConstraint(conf,50,0.2);
mmff.addEnergyTerm(constraint);
mmff.minimise();
@@ -170,6 +178,7 @@ public class DockingEngine {
ForceFieldMMFF94.initialize(ForceFieldMMFF94.MMFF94SPLUS);
List<Conformer> startPoints = new ArrayList<>();
double eMin = getStartingPositions(mol, startPoints);
+ Map<String,Double> contributions = null;
for(Conformer ligConf : startPoints) {
for(double[] transform : PheSAAlignment.initialTransform(0)) {
Conformer newLigConf = new Conformer(ligConf);
@@ -191,6 +200,7 @@ public class DockingEngine {
if(energy<bestEnergy) {
bestEnergy = energy;
bestPose = pose.getLigConf();
+ contributions = pose.getContributions();
}
if(threadMaster!=null && threadMaster.threadMustDie())
break;
@@ -202,8 +212,7 @@ public class DockingEngine {
Translation translate = new Translation(new double[] {origCOM.x, origCOM.y, origCOM.z});
rot.apply(best);
translate.apply(best);
-
- return new DockingResult(best,bestEnergy);
+ return new DockingResult(best,bestEnergy,contributions);
}
else {
throw new DockingFailedException("docking failed");
@@ -265,7 +274,6 @@ public class DockingEngine {
}
pose.setState(bestState);
- engine.getScore();
return bestEnergy;
}
@@ -391,11 +399,16 @@ public class DockingEngine {
public static class DockingResult implements Comparable<DockingResult> {
private double score;
private StereoMolecule pose;
+ private Map<String,Double> contributions;
private static final String DELIMITER = ";";
+ private static final String DELIMITER2 = ":";
+ private static final String DELIMITER3 = "%";
+ private static final String NULL_CONTRIBUTION = "#";
- public DockingResult(StereoMolecule pose, double score) {
+ public DockingResult(StereoMolecule pose, double score, Map<String,Double> contributions) {
this.score = score;
this.pose = pose;
+ this.contributions = contributions;
}
public double getScore() {
@@ -406,6 +419,11 @@ public class DockingEngine {
return pose;
}
+ public Map<String,Double> getContributions() {
+ return contributions;
+ }
+
+
public String encode() {
Encoder encoder = Base64.getEncoder();
StringBuilder sb = new StringBuilder();
@@ -417,6 +435,19 @@ public class DockingEngine {
sb.append(idcoords);
sb.append(DELIMITER);
sb.append(encoder.encodeToString(EncodeFunctions.doubleToByteArray(score)));
+ sb.append(DELIMITER);
+ if(contributions==null || contributions.keySet().size()==0)
+ sb.append(NULL_CONTRIBUTION);
+ else {
+ for(String name : contributions.keySet()) {
+ sb.append(name);
+ sb.append(DELIMITER3);
+ sb.append(encoder.encodeToString(EncodeFunctions.doubleToByteArray(contributions.get(name))));
+ sb.append(DELIMITER2);
+ }
+ sb.setLength(sb.length() - 1);
+ }
+
return sb.toString();
}
@@ -430,7 +461,19 @@ public class DockingEngine {
parser.parse(pose, idcode, idcoords);
pose.ensureHelperArrays(Molecule.cHelperCIP);
double score = EncodeFunctions.byteArrayToDouble(decoder.decode(s[2].getBytes()));
- DockingResult dockingResult = new DockingResult(pose,score);
+ Map<String,Double> contributions = null;
+ if(!s[3].equals(NULL_CONTRIBUTION)) {
+ contributions = new HashMap<String,Double>();
+ String[] splitted = s[3].split(DELIMITER2);
+ for(String contr : splitted) {
+ String[] splitted2 = contr.split(DELIMITER3);
+ String name = splitted2[0];
+ double value = EncodeFunctions.byteArrayToDouble(decoder.decode(splitted2[1].getBytes()));
+ contributions.put(name, value);
+ }
+ }
+
+ DockingResult dockingResult = new DockingResult(pose,score,contributions);
return dockingResult;
}
@@ -444,6 +487,8 @@ public class DockingEngine {
}
}
+
+
=====================================
src/main/java/com/actelion/research/chem/docking/LigandPose.java
=====================================
@@ -136,6 +136,10 @@ public class LigandPose implements Evaluable{
}
+ public Map<String,Double> getContributions() {
+ return engine.getContributions();
+ }
+
public void setInitialState() {
int elements = 3+3+torsionHelper.getRotatableBonds().length; //3 translational, 3 rotational, 3 torsion
state = new double[elements];
=====================================
src/main/java/com/actelion/research/chem/docking/scoring/AbstractScoringEngine.java
=====================================
@@ -3,6 +3,8 @@ package com.actelion.research.chem.docking.scoring;
import java.util.Set;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+
import com.actelion.research.chem.Coordinates;
import com.actelion.research.chem.Molecule3D;
import com.actelion.research.chem.StereoMolecule;
@@ -78,6 +80,8 @@ public abstract class AbstractScoringEngine {
public abstract double getFGValue(double[] grad);
public abstract double getScore();
+
+ public abstract Map<String,Double> getContributions();
public Conformer getReceptorConf() {
return receptorConf;
=====================================
src/main/java/com/actelion/research/chem/docking/scoring/ChemPLP.java
=====================================
@@ -98,7 +98,7 @@ public class ChemPLP extends AbstractScoringEngine {
ff.setState(candidatePose.getCartState());
double ffEnergy = ff.getTotalEnergy();
if((ffEnergy-e0)>STRAIN_CUTOFF) {
- energy+=ffEnergy;
+ energy+=ffEnergy-e0;
ff.addGradient(grad);
}
for(PotentialEnergyTerm term : constraints)
@@ -498,6 +498,34 @@ public class ChemPLP extends AbstractScoringEngine {
}
+ @Override
+ public Map<String, Double> getContributions() {
+ Map<String,Double> contributions = new HashMap<String,Double>();
+ double[] grad = new double[3*candidatePose.getLigConf().getMolecule().getAllAtoms()];
+ double hbond = 0.0;
+ for(PotentialEnergyTerm term : chemscoreHbond)
+ hbond+=term.getFGValue(grad);
+ contributions.put("HBOND", hbond);
+ double metal = 0.0;
+ for(PotentialEnergyTerm term : chemscoreMetal)
+ metal+=term.getFGValue(grad);
+ contributions.put("METAL", metal);
+ double plpContr = 0.0;
+ for(PotentialEnergyTerm term : plp)
+ plpContr+=term.getFGValue(grad);
+ contributions.put("PLP", plpContr);
+ double strain = 0.0;
+ ff.setState(candidatePose.getCartState());
+ double ffEnergy = ff.getTotalEnergy();
+ if((ffEnergy-e0)>STRAIN_CUTOFF) {
+ strain+=ffEnergy;
+ ff.addGradient(grad);
+ }
+ contributions.put("STRAIN", strain);
+ return contributions;
+ }
+
+
=====================================
src/main/java/com/actelion/research/chem/docking/scoring/IdoScore.java
=====================================
@@ -140,6 +140,12 @@ public class IdoScore extends AbstractScoringEngine {
}
+ @Override
+ public Map<String, Double> getContributions() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
=====================================
src/main/java/com/actelion/research/chem/io/Mol2FileParser.java
=====================================
@@ -243,8 +243,9 @@ public class Mol2FileParser extends AbstractParser {
int a = m.addAtom(atomicNo);
m.setAtomX(a, x);
- m.setAtomY(a, y);
- m.setAtomZ(a, z);
+ //invert y and z coordinates for compatibility with Java coordinate system (analogously to Molfileparser)
+ m.setAtomY(a, -y);
+ m.setAtomZ(a, -z);
m.setAtomName(a, atomName);
m.setAtomChainId(a, chainId);
m.setAtomAmino(a, amino);
=====================================
src/main/java/com/actelion/research/chem/properties/complexity/ContainerFragBondsSolutions.java
=====================================
@@ -197,7 +197,7 @@ public class ContainerFragBondsSolutions {
}
if(ELUSIVE)
- System.out.println("ContainerFragBondsSolutions maximumNumberBondsInFragment " + maximumNumberBondsInFragment);
+ System.out.println("ContainerFragBondsSolutions maximum number of bonds in a single fragment " + maximumNumberBondsInFragment + ".");
return arrCapacity;
}
=====================================
src/main/java/com/actelion/research/chem/properties/complexity/ExhaustiveFragmentsStatistics.java
=====================================
@@ -115,7 +115,7 @@ public class ExhaustiveFragmentsStatistics {
efg = new ExhaustiveFragmentGeneratorBonds(bits, totalCapacity);
- System.out.println("ExhaustiveFragmentsStatistics init(...) max capacity bonds in fragment " + efg.getMaximumCapacityBondsInFragment());
+ System.out.println("ExhaustiveFragmentsStatistics init(...) max number of bonds in a fragment " + efg.getMaximumCapacityBondsInFragment());
minNumBondsFragment = MINLEN_FRAG;
=====================================
src/main/java/com/actelion/research/chem/reaction/mapping/MappingScorer.java
=====================================
@@ -52,7 +52,8 @@ public class MappingScorer {
// we add/remove fractional bond orders for new/broken bonds and
// we add fractional bond order changes of changed bonds
// to reflect the corresponding change in implicit hydrogen bond counts.
- float[] hydrogenBondPenalty = new float[mProduct.getAtoms()];
+ float[] hydrogenBondPenalty = SCORE_HYDROGEN ? new float[mProduct.getAtoms()] : null;
+
boolean[] isAssignedProductAtom = new boolean[mProduct.getAtoms()];
for (int atom:reactantToProductAtom)
if (atom != -1)
@@ -71,24 +72,32 @@ public class MappingScorer {
if (pAtom1 != -1 || pAtom2 != -1)
penalty += getBondCreateOrBreakPenalty(mReactant, rBond);
- if (pAtom1 != -1)
- hydrogenBondPenalty[pAtom1] += rBondOrder;
- if (pAtom2 != -1)
- hydrogenBondPenalty[pAtom2] += rBondOrder;
+ if (SCORE_HYDROGEN) {
+ if (pAtom1 != -1)
+ hydrogenBondPenalty[pAtom1] += rBondOrder;
+ if (pAtom2 != -1)
+ hydrogenBondPenalty[pAtom2] += rBondOrder;
+ }
continue;
}
int pBond = mProduct.getBond(pAtom1, pAtom2);
if (pBond == -1) {
penalty += getBondCreateOrBreakPenalty(mReactant, rBond);
- hydrogenBondPenalty[pAtom1] += rBondOrder;
- hydrogenBondPenalty[pAtom2] += rBondOrder;
+
+ if (SCORE_HYDROGEN) {
+ hydrogenBondPenalty[pAtom1] += rBondOrder;
+ hydrogenBondPenalty[pAtom2] += rBondOrder;
+ }
+
continue;
}
- float bondOrderChange = rBondOrder - getFractionalBondOrder(mProduct, pBond);
- hydrogenBondPenalty[pAtom1] += bondOrderChange;
- hydrogenBondPenalty[pAtom2] += bondOrderChange;
+ if (SCORE_HYDROGEN) {
+ float bondOrderChange = rBondOrder - getFractionalBondOrder(mProduct, pBond);
+ hydrogenBondPenalty[pAtom1] += bondOrderChange;
+ hydrogenBondPenalty[pAtom2] += bondOrderChange;
+ }
productBondHandled[pBond] = true;
penalty += getBondChangePenalty(rBond, pBond);
@@ -97,13 +106,16 @@ public class MappingScorer {
for (int pBond=0; pBond<mProduct.getBonds(); pBond++) {
if (!productBondHandled[pBond]) {
penalty += getBondCreateOrBreakPenalty(mProduct, pBond);
- float pBondOrder = getFractionalBondOrder(mProduct, pBond);
- int pAtom1 = mProduct.getBondAtom(0, pBond);
- int pAtom2 = mProduct.getBondAtom(1, pBond);
- if (isAssignedProductAtom[pAtom1])
- hydrogenBondPenalty[pAtom1] -= pBondOrder;
- if (isAssignedProductAtom[pAtom2])
- hydrogenBondPenalty[pAtom2] -= pBondOrder;
+
+ if (SCORE_HYDROGEN) {
+ float pBondOrder = getFractionalBondOrder(mProduct, pBond);
+ int pAtom1 = mProduct.getBondAtom(0, pBond);
+ int pAtom2 = mProduct.getBondAtom(1, pBond);
+ if (isAssignedProductAtom[pAtom1])
+ hydrogenBondPenalty[pAtom1] -= pBondOrder;
+ if (isAssignedProductAtom[pAtom2])
+ hydrogenBondPenalty[pAtom2] -= pBondOrder;
+ }
}
}
@@ -135,7 +147,7 @@ public class MappingScorer {
boolean isHetero2 = mol.isElectronegative(atom2);
if (!isHetero1 && !isHetero2)
- return mol.isAromaticBond(bond) ? 3f : 1.9f + (float)mol.getBondOrder(bond) / 10f;
+ return mol.isAromaticBond(bond) ? 2.1f : 1.9f + (float)mol.getBondOrder(bond) / 10f;
if (isHetero1 && isHetero2) // e.g. m-CPBA
return 1.7f;
=====================================
src/main/java/com/actelion/research/chem/reaction/mapping/RootAtomPairSource.java
=====================================
@@ -139,10 +139,6 @@ public class RootAtomPairSource {
return true;
}
- public int getPairSequenceCount() {
- return mSequenceCount;
- }
-
/**
* RootAtomPairs are returned in similarity order. The first returned pair is that
* pair of atoms that is more similar than any other mutual combination of reactant
=====================================
src/main/java/com/actelion/research/chem/reaction/mapping/SimilarityGraphBasedReactionMapper.java
=====================================
@@ -75,7 +75,10 @@ public class SimilarityGraphBasedReactionMapper {
RootAtomPairSource rootAtomPairSource = new RootAtomPairSource(reactant, product, mReactantMapNo, mProductMapNo);
+ mAtomPairSequenceCount = 0;
+
while (rootAtomPairSource.hasNextPairSequence()) {
+ mAtomPairSequenceCount++;
mMapNo = rootAtomPairSource.getManualMapCount();
mMappableAtomCount = rootAtomPairSource.getMappableAtomCount();
@@ -117,8 +120,6 @@ if (DEBUG) {
productMapNo[i] = mProductMapNo[i];
}
}
-
- mAtomPairSequenceCount = rootAtomPairSource.getPairSequenceCount();
}
/**
@@ -299,16 +300,16 @@ if (DEBUG) {
&& mSimilarityComparator.compare(mReactantConnAtomEnv[reactantAtom][reactantConnIndex][radius],
mProductConnAtomEnv[productAtom][productConnIndex][radius]) == 0)
radius++;
- while (radius+NO_PI_PENALTY < MAX_ENVIRONMENT_RADIUS
- && mReactantNoPiAtomEnv[reactantAtom][reactantConnIndex][radius+NO_PI_PENALTY] != null
- && mSimilarityComparator.compare(mReactantNoPiAtomEnv[reactantAtom][reactantConnIndex][radius+NO_PI_PENALTY],
- mProductNoPiAtomEnv[productAtom][productConnIndex][radius+NO_PI_PENALTY]) == 0)
- radius++;
- while (radius+SKELETON_PENALTY < MAX_ENVIRONMENT_RADIUS
- && mReactantSkelAtomEnv[reactantAtom][reactantConnIndex][radius+SKELETON_PENALTY] != null
- && mSimilarityComparator.compare(mReactantSkelAtomEnv[reactantAtom][reactantConnIndex][radius+SKELETON_PENALTY],
- mProductSkelAtomEnv[productAtom][productConnIndex][radius+SKELETON_PENALTY]) == 0)
- radius++;
+// while (radius+NO_PI_PENALTY < MAX_ENVIRONMENT_RADIUS
+// && mReactantNoPiAtomEnv[reactantAtom][reactantConnIndex][radius+NO_PI_PENALTY] != null
+// && mSimilarityComparator.compare(mReactantNoPiAtomEnv[reactantAtom][reactantConnIndex][radius+NO_PI_PENALTY],
+// mProductNoPiAtomEnv[productAtom][productConnIndex][radius+NO_PI_PENALTY]) == 0)
+// radius++;
+// while (radius+SKELETON_PENALTY < MAX_ENVIRONMENT_RADIUS
+// && mReactantSkelAtomEnv[reactantAtom][reactantConnIndex][radius+SKELETON_PENALTY] != null
+// && mSimilarityComparator.compare(mReactantSkelAtomEnv[reactantAtom][reactantConnIndex][radius+SKELETON_PENALTY],
+// mProductSkelAtomEnv[productAtom][productConnIndex][radius+SKELETON_PENALTY]) == 0)
+// radius++;
return radius << SIMILARITY_SHIFT;
}
@@ -524,10 +525,10 @@ if (DEBUG) {
if (bondType == getBondType(mProduct, candidateBond)
|| skelSimilarity != 0) {
if (passesBasicRules(reactantRoot, reactantCandidate, productRoot, productCandidate)) {
- int envSimilarity = getCombinedAtomSimilarity(reactantRoot, reactantCandidate, productRoot, productCandidate);
+// int envSimilarity = getCombinedAtomSimilarity(reactantRoot, reactantCandidate, productRoot, productCandidate);
// introducing the non-pi similarity does not really seem to improve matters
-// int envSimilarity = getCombinedAtomSimilarity(reactantRoot, reactantCandidate, productRoot, productCandidate);
+ int envSimilarity = getAtomSimilarity(reactantRoot, reactantCandidate, productRoot, productCandidate);
//System.out.println("skel:"+skelSimilarity+" conn:"+envSimilarity+" comb:"+envSimilarityCandidate);
int similarity = Math.max(skelSimilarity, envSimilarity);
=====================================
src/main/java/com/actelion/research/gui/JDrawDialog.java
=====================================
@@ -19,15 +19,16 @@
package com.actelion.research.gui;
import com.actelion.research.chem.StereoMolecule;
-import com.actelion.research.chem.reaction.IReactionMapper;
-import com.actelion.research.chem.reaction.MCSReactionMapper;
import com.actelion.research.chem.reaction.Reaction;
import com.actelion.research.gui.clipboard.ClipboardHandler;
import com.actelion.research.gui.hidpi.HiDPIHelper;
import javax.swing.*;
import java.awt.*;
-import java.awt.event.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
import java.util.ArrayList;
public class JDrawDialog extends JDialog implements ActionListener,KeyListener {
@@ -60,6 +61,22 @@ public class JDrawDialog extends JDialog implements ActionListener,KeyListener {
initialize(owner, 0);
}
+ public JDrawDialog(Dialog owner, StereoMolecule[] mol, String title, ModalityType modalityType) {
+ super(owner, title, modalityType);
+ mMolecule = new StereoMolecule();
+ initialize(owner, JDrawArea.MODE_MULTIPLE_FRAGMENTS);
+ if (mol != null)
+ mArea.setFragments(mol);
+ }
+
+ public JDrawDialog(Dialog owner, Reaction rxn, String title, ModalityType modalityType) {
+ super(owner, title, modalityType);
+ mMolecule = new StereoMolecule();
+ initialize(owner, JDrawArea.MODE_REACTION);
+ if (rxn != null)
+ mArea.setReaction(rxn);
+ }
+
public JDrawDialog(Frame owner) {
this(owner, false, DEFAULT_TITLE);
}
@@ -108,7 +125,7 @@ public class JDrawDialog extends JDialog implements ActionListener,KeyListener {
public JDrawDialog(Frame owner, StereoMolecule[] mol, String title, ModalityType modalityType) {
super(owner, title, modalityType);
mMolecule = new StereoMolecule();
- initialize(owner, JDrawArea.MODE_REACTION);
+ initialize(owner, JDrawArea.MODE_MULTIPLE_FRAGMENTS);
if (mol != null)
mArea.setFragments(mol);
}
=====================================
src/main/java/com/actelion/research/gui/JEditableChemistryView.java
=====================================
@@ -149,7 +149,10 @@ public class JEditableChemistryView extends JChemistryView {
while (!(c instanceof Frame || c instanceof Dialog))
c = c.getParent();
- return new JDrawDialog((Frame)c, reaction, "Edit Reaction", Dialog.ModalityType.DOCUMENT_MODAL);
+ if (c instanceof Frame)
+ return new JDrawDialog((Frame)c, reaction, "Edit Reaction", Dialog.ModalityType.DOCUMENT_MODAL);
+ else
+ return new JDrawDialog((Dialog)c, reaction, "Edit Reaction", Dialog.ModalityType.DOCUMENT_MODAL);
}
protected JDrawDialog createDrawDialog(String title, StereoMolecule[] mol) {
@@ -157,6 +160,9 @@ public class JEditableChemistryView extends JChemistryView {
while (!(c instanceof Frame || c instanceof Dialog))
c = c.getParent();
- return new JDrawDialog((Frame)c, mol, "Edit Molecules", Dialog.ModalityType.DOCUMENT_MODAL);
- }
+ if (c instanceof Frame)
+ return new JDrawDialog((Frame)c, mol, "Edit Molecules", Dialog.ModalityType.DOCUMENT_MODAL);
+ else
+ return new JDrawDialog((Dialog)c, mol, "Edit Molecules", Dialog.ModalityType.DOCUMENT_MODAL);
+ }
}
=====================================
src/main/java/com/actelion/research/gui/clipboard/ClipboardHandler.java
=====================================
@@ -35,6 +35,7 @@ package com.actelion.research.gui.clipboard;
import com.actelion.research.chem.*;
import com.actelion.research.chem.coords.CoordinateInventor;
import com.actelion.research.chem.dnd.ChemistryFlavors;
+import com.actelion.research.chem.io.RXNFileCreator;
import com.actelion.research.chem.io.RXNFileParser;
import com.actelion.research.chem.name.StructureNameResolver;
import com.actelion.research.chem.reaction.Reaction;
@@ -497,10 +498,10 @@ public class ClipboardHandler implements IClipboardHandler
}
private boolean copyReactionToClipboard(String ctab, Reaction rxn) throws IOException {
-// if (ctab == null) {
-// RXNFileCreator mc = new RXNFileCreator(rxn);
-// ctab = mc.getRXNfile();
-// }
+ if (ctab == null) {
+ RXNFileCreator mc = new RXNFileCreator(rxn);
+ ctab = mc.getRXNfile();
+ }
ChemDrawCDX cdx = new com.actelion.research.gui.clipboard.external.ChemDrawCDX();
byte[] cdxBuffer = cdx.getChemDrawBuffer(rxn);
@@ -514,7 +515,7 @@ public class ClipboardHandler implements IClipboardHandler
out.close();
bos.close();
- return NativeClipboardAccessor.copyMoleculeToClipboard("", cdxBuffer, bos.toByteArray());
+ return NativeClipboardAccessor.copyReactionToClipboard(ctab.getBytes(), cdxBuffer, bos.toByteArray());
}
private boolean writeMol2Metafile(File temp, StereoMolecule m, byte[] sketch) {
=====================================
src/main/java/com/actelion/research/gui/dock/DividerChangeListener.java
=====================================
@@ -0,0 +1,5 @@
+package com.actelion.research.gui.dock;
+
+public interface DividerChangeListener {
+ public void dividerLocationChanged(TreeFork fork);
+}
=====================================
src/main/java/com/actelion/research/gui/dock/JDockingPanel.java
=====================================
@@ -28,6 +28,7 @@ public class JDockingPanel extends JPanel implements ActionListener {
private int mTargetPosition,mPreviousTargetPosition;
private GhostPreview mPreview;
private Dockable mMaximizedView;
+ private Vector<DividerChangeListener> mDividerChangeListeners;
/**
* Creates a docking panel to which any Dockables may be added by
@@ -85,6 +86,23 @@ public class JDockingPanel extends JPanel implements ActionListener {
}, true);
}
+ public void addDividerChangeLister(DividerChangeListener l) {
+ if (mDividerChangeListeners == null)
+ mDividerChangeListeners = new Vector<>();
+
+ mDividerChangeListeners.add(l);
+ if (mTreeRoot != null)
+ mTreeRoot.setDividerChangeListeners(mDividerChangeListeners);
+ }
+
+ public void removeDividerChangeLister(DividerChangeListener l) {
+ if (mDividerChangeListeners != null) {
+ mDividerChangeListeners.remove(l);
+ if (mTreeRoot != null)
+ mTreeRoot.setDividerChangeListeners(mDividerChangeListeners);
+ }
+ }
+
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().startsWith("close_")) {
String title = e.getActionCommand().substring(6);
@@ -309,7 +327,7 @@ public class JDockingPanel extends JPanel implements ActionListener {
else {
TreeLeaf newLeaf = new TreeLeaf(dockable, this, isDragging);
TreeContainer parent = treeLeaf.getParent();
- TreeFork treeFork = new TreeFork(treeLeaf, newLeaf, position, dividerPosition);
+ TreeFork treeFork = new TreeFork(treeLeaf, newLeaf, position, dividerPosition, mDividerChangeListeners);
parent.replaceChildElement(treeLeaf, treeFork);
mLeafMap.put(dockable.getTitle(), newLeaf);
}
@@ -430,6 +448,34 @@ public class JDockingPanel extends JPanel implements ActionListener {
}
}
+ /**
+ * Checks, whether a dockable with the given title exists, and whether it is visible (selected if in a JTabbedPane)
+ * and whether it is in the left or right branch (depending on parameter left) of a JSplitPane.
+ * @param title
+ * @param left if true, then
+ * @return true the respective dockable is visible and in the left part of a JSplitPane
+ */
+ public boolean isVisibleInSplitPane(String title, boolean left) {
+ Component view = mDockableMap.get(title);
+ if (view == null)
+ return false;
+
+ Component pane = view.getParent();
+ if (pane instanceof JTabbedPane) {
+ if (view != ((JTabbedPane)pane).getSelectedComponent())
+ return false;
+
+ view = pane;
+ pane = pane.getParent();
+ }
+
+ if (pane instanceof JSplitPane)
+ return (left && view == ((JSplitPane)pane).getLeftComponent())
+ || (!left && view == ((JSplitPane)pane).getRightComponent());
+
+ return false;
+ }
+
/**
* changes a title of a docked Dockable
* @param oldTitle existing title
@@ -596,7 +642,7 @@ public class JDockingPanel extends JPanel implements ActionListener {
Dockable dockable = dockables.get(size2);
bottomLeft = new TreeLeaf(dockable, this, false);
TreeContainer parent = topLeft.getParent();
- TreeFork treeFork = new TreeFork(topLeft, bottomLeft, DOCK_BOTTOM, .5);
+ TreeFork treeFork = new TreeFork(topLeft, bottomLeft, DOCK_BOTTOM, .5, mDividerChangeListeners);
parent.replaceChildElement(topLeft, treeFork);
mLeafMap.put(dockable.getTitle(), bottomLeft);
mDockableMap.put(dockable.getTitle(), dockable);
@@ -606,7 +652,7 @@ public class JDockingPanel extends JPanel implements ActionListener {
Dockable dockable = dockables.get(size1);
topRight = new TreeLeaf(dockable, this, false);
TreeContainer parent = topLeft.getParent();
- TreeFork treeFork = new TreeFork(topLeft, topRight, DOCK_RIGHT, .5);
+ TreeFork treeFork = new TreeFork(topLeft, topRight, DOCK_RIGHT, .5, mDividerChangeListeners);
parent.replaceChildElement(topLeft, treeFork);
mLeafMap.put(dockable.getTitle(), topRight);
mDockableMap.put(dockable.getTitle(), dockable);
@@ -616,7 +662,7 @@ public class JDockingPanel extends JPanel implements ActionListener {
Dockable dockable = dockables.get(size3);
bottomRight = new TreeLeaf(dockable, this, false);
TreeContainer parent = bottomLeft.getParent();
- TreeFork treeFork = new TreeFork(bottomLeft, bottomRight, DOCK_RIGHT, .5);
+ TreeFork treeFork = new TreeFork(bottomLeft, bottomRight, DOCK_RIGHT, .5, mDividerChangeListeners);
parent.replaceChildElement(bottomLeft, treeFork);
mLeafMap.put(dockable.getTitle(), bottomRight);
mDockableMap.put(dockable.getTitle(), dockable);
=====================================
src/main/java/com/actelion/research/gui/dock/TreeFork.java
=====================================
@@ -1,12 +1,18 @@
package com.actelion.research.gui.dock;
import javax.swing.*;
+import javax.swing.plaf.SplitPaneUI;
+import javax.swing.plaf.basic.BasicSplitPaneUI;
import java.awt.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
import java.util.ArrayList;
+import java.util.Vector;
public class TreeFork extends TreeContainer {
private TreeElement mLeftChildElement;
private TreeElement mRightChildElement;
+ private Vector<DividerChangeListener> mDividerChangeListeners;
/**
* Constructor to create a fork element that is inserted between the specified
@@ -14,42 +20,55 @@ public class TreeFork extends TreeContainer {
* @param oldLeaf
* @param newLeaf
* @param newLeafPosition
- * @param proportionalDividerLocation
+ * @param dividerLocation
*/
- public TreeFork(TreeLeaf oldLeaf, TreeLeaf newLeaf, int newLeafPosition, double proportionalDividerLocation) {
+ public TreeFork(TreeLeaf oldLeaf, TreeLeaf newLeaf, int newLeafPosition, double dividerLocation, Vector<DividerChangeListener> listeners) {
JSplitPane splitPane = null;
switch (newLeafPosition) {
case JDockingPanel.DOCK_TOP:
splitPane = new MySplitPane(JSplitPane.VERTICAL_SPLIT,
- newLeaf.getComponent(), oldLeaf.getComponent(), proportionalDividerLocation);
+ newLeaf.getComponent(), oldLeaf.getComponent(), dividerLocation);
mLeftChildElement = newLeaf;
mRightChildElement = oldLeaf;
break;
case JDockingPanel.DOCK_LEFT:
splitPane = new MySplitPane(JSplitPane.HORIZONTAL_SPLIT,
- newLeaf.getComponent(), oldLeaf.getComponent(), proportionalDividerLocation);
+ newLeaf.getComponent(), oldLeaf.getComponent(), dividerLocation);
mLeftChildElement = newLeaf;
mRightChildElement = oldLeaf;
break;
case JDockingPanel.DOCK_BOTTOM:
splitPane = new MySplitPane(JSplitPane.VERTICAL_SPLIT,
- oldLeaf.getComponent(), newLeaf.getComponent(), proportionalDividerLocation);
+ oldLeaf.getComponent(), newLeaf.getComponent(), dividerLocation);
mLeftChildElement = oldLeaf;
mRightChildElement = newLeaf;
break;
case JDockingPanel.DOCK_RIGHT:
splitPane = new MySplitPane(JSplitPane.HORIZONTAL_SPLIT,
- oldLeaf.getComponent(), newLeaf.getComponent(), proportionalDividerLocation);
+ oldLeaf.getComponent(), newLeaf.getComponent(), dividerLocation);
mLeftChildElement = oldLeaf;
mRightChildElement = newLeaf;
break;
}
-// splitPane.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, pce -> {} );
+ splitPane.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, e -> {
+ if (mDividerChangeListeners != null && ((MySplitPane)mComponent).isDragged())
+ for (DividerChangeListener l:mDividerChangeListeners)
+ l.dividerLocationChanged(this);
+ } );
+ mDividerChangeListeners = listeners;
mComponent = splitPane;
oldLeaf.setParent(this);
newLeaf.setParent(this);
}
+ public void updateDividerChangeListeners(Vector<DividerChangeListener> listeners) {
+ mDividerChangeListeners = listeners;
+ if (mLeftChildElement instanceof TreeFork)
+ ((TreeFork)mLeftChildElement).updateDividerChangeListeners(listeners);
+ if (mLeftChildElement instanceof TreeFork)
+ ((TreeFork)mRightChildElement).updateDividerChangeListeners(listeners);
+ }
+
public void removeWithLeaf(TreeLeaf leaf) {
assert(leaf == mLeftChildElement || leaf == mRightChildElement);
if (leaf == mLeftChildElement)
@@ -156,6 +175,7 @@ class MySplitPane extends JSplitPane {
private static final long serialVersionUID = 0x20070726;
private double mProportionalLocation;
+ private boolean mMouseDown;
public MySplitPane(int newOrientation, Component newLeftComponent, Component newRightComponent, double proportionalLocation) {
super(newOrientation, true, newLeftComponent, newRightComponent);
@@ -163,6 +183,22 @@ class MySplitPane extends JSplitPane {
setResizeWeight(proportionalLocation);
setBorder(null);
mProportionalLocation = proportionalLocation;
+
+ SplitPaneUI spui = getUI();
+ if (spui instanceof BasicSplitPaneUI) {
+ ((BasicSplitPaneUI) spui).getDivider().addMouseListener(new MouseAdapter() {
+ public void mousePressed(MouseEvent e) {
+ mMouseDown = true;
+ }
+ public void mouseReleased(MouseEvent e) {
+ mMouseDown = false;
+ }
+ } );
+ }
+ }
+
+ public boolean isDragged() {
+ return mMouseDown;
}
@Override
=====================================
src/main/java/com/actelion/research/gui/dock/TreeLeaf.java
=====================================
@@ -1,5 +1,7 @@
package com.actelion.research.gui.dock;
+import com.actelion.research.gui.hidpi.HiDPIHelper;
+
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
@@ -80,7 +82,13 @@ public class TreeLeaf extends TreeElement implements ChangeListener {
public void addContent(Dockable dockable, boolean isDragging) {
if (mComponent instanceof Dockable) {
Dockable existingDockable = (Dockable)mComponent;
- JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.BOTTOM);
+ JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.BOTTOM) {
+ @Override public Dimension getMinimumSize() {
+ // of not modified, the minimum size == preferred size.
+ // Then width is at least the width of the longest tab name.
+ return new Dimension(HiDPIHelper.scale(100),HiDPIHelper.scale(100));
+ }
+ };
tabbedPane.putClientProperty("Quaqua.TabbedPane.contentBorderPainted", Boolean.FALSE);
tabbedPane.add(existingDockable, existingDockable.getTitle());
tabbedPane.add(dockable, dockable.getTitle());
=====================================
src/main/java/com/actelion/research/gui/dock/TreeRoot.java
=====================================
@@ -1,17 +1,16 @@
package com.actelion.research.gui.dock;
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.util.ArrayList;
-
import javax.swing.*;
+import java.awt.*;
+import java.util.ArrayList;
+import java.util.Vector;
public class TreeRoot extends TreeContainer {
private TreeElement mChildElement;
/**
* Constructor to create a root element to which the first leaf should be connected.
- * @param parent
+ * @param rootComponent
*/
public TreeRoot(JComponent rootComponent, TreeElement child) {
mComponent = rootComponent;
@@ -20,6 +19,11 @@ public class TreeRoot extends TreeContainer {
mChildElement.setParent(this);
}
+ public void setDividerChangeListeners(Vector<DividerChangeListener> listeners) {
+ if (mChildElement instanceof TreeFork)
+ ((TreeFork)mChildElement).updateDividerChangeListeners(listeners);
+ }
+
public TreeElement getChild() {
return mChildElement;
}
=====================================
src/main/java/com/actelion/research/util/ConstantsDWAR.java
=====================================
@@ -115,6 +115,10 @@ public class ConstantsDWAR {
public static final String TAG_COOR2 = "idcoordinates2D";
+ public static final String IDCODE_EMPTY = "dH";
+
+
+
/**
* Can be one or multiple sets of 3D coordinates.
*/
View it on GitLab: https://salsa.debian.org/java-team/openchemlib/-/commit/f63e99bffb2f96ef45a8e4d1d087acd1dd99a4fb
--
View it on GitLab: https://salsa.debian.org/java-team/openchemlib/-/commit/f63e99bffb2f96ef45a8e4d1d087acd1dd99a4fb
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20211004/64aeeaf7/attachment.htm>
More information about the pkg-java-commits
mailing list