1 /*
2  * Copyright (c) 2015 John May <jwmay@users.sf.net>
3  *
4  * Contact: cdk-devel@lists.sourceforge.net
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or (at
9  * your option) any later version. All we ask is that proper credit is given
10  * for our work, which includes - but is not limited to - adding the above
11  * copyright notice to the beginning of your source code files, and to any
12  * copyright notice that you may distribute with programs based on this work.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 U
22  */
23 
24 package org.openscience.cdk.renderer.elements;
25 
26 import org.openscience.cdk.interfaces.IAtom;
27 import org.openscience.cdk.interfaces.IAtomContainer;
28 import org.openscience.cdk.interfaces.IBond;
29 import org.openscience.cdk.interfaces.IChemObject;
30 
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.List;
34 
35 /**
36  * A marked element adds meta-data (id and tags) to a CDK rendering
37  * element (or group of elements). The id should be unique per depiction.
38  * The primary use case it to be able to set the 'id' and 'class'
39  * attributes in SVG.
40  *
41  * To set the mol, atom, or bond id set a String property to {@link #ID_KEY}.
42  * Similarly, the {@link #CLASS_KEY} can be used to set the classes.
43  *
44  * <pre>{@code
45  * IAtomContainer mol;
46  * atom.setProperty(MarkedElement.ID_KEY, "my_atm_id");
47  * atom.setProperty(MarkedElement.CLASS_KEY, "h_donor");
48  * atom.setProperty(MarkedElement.CLASS_KEY, "h_acceptor");
49  * }</pre>
50  */
51 public final class MarkedElement implements IRenderingElement {
52 
53     public static final String ID_KEY    = MarkedElement.class.getName() + "_ID";
54     public static final String CLASS_KEY = MarkedElement.class.getName() + "_CLS";
55 
56     final   IRenderingElement elem;
57     private String            id;
58     private final List<String> classes = new ArrayList<>(5);
59 
MarkedElement(IRenderingElement elem)60     private MarkedElement(IRenderingElement elem) {
61         this.elem = elem;
62     }
63 
64     /**
65      * Set the identifier of the tagged element.
66      *
67      * @param id the id
68      */
setId(String id)69     private void setId(String id) {
70         this.id = id;
71     }
72 
73     /**
74      * Add a cls to the element.
75      *
76      * @param cls a cls
77      */
aggClass(String cls)78     private void aggClass(String cls) {
79         if (cls != null)
80             this.classes.add(cls);
81     }
82 
83     /**
84      * Access the id of the element.
85      *
86      * @return id, null if none
87      */
getId()88     public String getId() {
89         return id;
90     }
91 
92     /**
93      * Access the classes of the element.
94      *
95      * @return id, empty if none
96      */
getClasses()97     public List<String> getClasses() {
98         return Collections.unmodifiableList(classes);
99     }
100 
101     /**
102      *{@inheritDoc}
103      */
104     @Override
accept(IRenderingVisitor visitor)105     public void accept(IRenderingVisitor visitor) {
106         visitor.visit(this);
107     }
108 
109     /**
110      * Access the element of which the id and classes apply.
111      *
112      * @return rendering element
113      */
element()114     public IRenderingElement element() {
115         return elem;
116     }
117 
118     /**
119      * Markup a rendering element with the specified classes.
120      *
121      * @param elem rendering element
122      * @param classes classes
123      * @return the marked element
124      */
markup(IRenderingElement elem, String... classes)125     public static MarkedElement markup(IRenderingElement elem, String... classes) {
126         assert elem != null;
127         MarkedElement tagElem = new MarkedElement(elem);
128         for (String cls : classes)
129             tagElem.aggClass(cls);
130         return tagElem;
131     }
132 
markupChemObj(IRenderingElement elem, IChemObject chemObj)133     private static MarkedElement markupChemObj(IRenderingElement elem, IChemObject chemObj) {
134         assert elem != null;
135         MarkedElement tagElem = new MarkedElement(elem);
136         if (chemObj != null) {
137             tagElem.setId(chemObj.getProperty(ID_KEY, String.class));
138             tagElem.aggClass(chemObj.getProperty(CLASS_KEY, String.class));
139         }
140         return tagElem;
141     }
142 
143     /**
144      * Markup a molecule with the class 'mol' and optionally the ids/classes
145      * from it's properties.
146      *
147      * @param elem rendering element
148      * @param mol molecule
149      * @return the marked element
150      */
markupMol(IRenderingElement elem, IAtomContainer mol)151     public static MarkedElement markupMol(IRenderingElement elem, IAtomContainer mol) {
152         assert elem != null;
153         MarkedElement tagElem = markupChemObj(elem, mol);
154         tagElem.aggClass("mol");
155         return tagElem;
156     }
157 
158     /**
159      * Markup a atom with the class 'atom' and optionally the ids/classes
160      * from it's properties.
161      *
162      * @param elem rendering element
163      * @param atom atom
164      * @return the marked element
165      */
markupAtom(IRenderingElement elem, IAtom atom)166     public static MarkedElement markupAtom(IRenderingElement elem, IAtom atom) {
167         if (elem == null)
168             return null;
169         MarkedElement tagElem = markupChemObj(elem, atom);
170         tagElem.aggClass("atom");
171         return tagElem;
172     }
173 
174     /**
175      * Markup a bond with the class 'bond' and optionally the ids/classes
176      * from it's properties.
177      *
178      * @param elem rendering element
179      * @param bond bond
180      * @return the marked element
181      */
markupBond(IRenderingElement elem, IBond bond)182     public static MarkedElement markupBond(IRenderingElement elem, IBond bond) {
183         assert elem != null;
184         MarkedElement tagElem = markupChemObj(elem, bond);
185         tagElem.aggClass("bond");
186         return tagElem;
187     }
188 }
189