4 package eu
.etaxonomy
.taxeditor
.parser
;
6 import java
.lang
.reflect
.Method
;
7 import java
.util
.ArrayList
;
10 import org
.eclipse
.swt
.widgets
.Control
;
12 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
13 import eu
.etaxonomy
.cdm
.model
.agent
.TeamOrPersonBase
;
14 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
15 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameBase
;
16 import eu
.etaxonomy
.cdm
.model
.reference
.INomenclaturalReference
;
17 import eu
.etaxonomy
.cdm
.model
.reference
.ReferenceBase
;
18 import eu
.etaxonomy
.cdm
.strategy
.match
.MatchException
;
19 import eu
.etaxonomy
.cdm
.strategy
.parser
.NonViralNameParserImpl
;
20 import eu
.etaxonomy
.taxeditor
.preference
.PreferencesUtil
;
21 import eu
.etaxonomy
.taxeditor
.store
.CdmStore
;
22 import eu
.etaxonomy
.taxeditor
.store
.StoreUtil
;
25 * <p>ParseHandler class.</p>
30 public class ParseHandler
{
32 private TaxonNameBase taxonNameBase
;
34 private List
<INomenclaturalReference
> duplicateReferences
;
35 private List
<INomenclaturalReference
> duplicateInReferences
;
37 private List
<TaxonNameBase
> duplicateNames
;
39 private List
<TeamOrPersonBase
> duplicateCombinationAuthorTeams
;
40 private List
<TeamOrPersonBase
> duplicateExCombinationAuthorTeams
;
41 private List
<TeamOrPersonBase
> duplicateBasionymAuthorTeams
;
42 private List
<TeamOrPersonBase
> duplicateExBasionymAuthorTeams
;
44 private static NonViralNameParserImpl nonViralNameParser
= NonViralNameParserImpl
.NewInstance();
47 * The name that should get parsed
49 private NonViralName name
;
52 * The widget, the name got entered in
54 private Control textWidget
;
56 private boolean doResolveInReferences
;
59 * Creates a new instance
64 private ParseHandler(Control textWidget
, TaxonNameBase name
){
65 if(textWidget
!= null){
66 this.textWidget
= textWidget
;
67 checkControlHasText();
69 throw new IllegalArgumentException("text widget must not be null");
73 this.name
= nonViralNameParser
.getNonViralNameInstance("", PreferencesUtil
.getPreferredNomenclaturalCode());
75 this.name
= (NonViralName
) HibernateProxyHelper
.deproxy(name
);
80 * Factory method to create a new instance of the this class
82 * @param textWidget The text widget where the NonViralName may be entered into
83 * @param name An initial NonViralName or null when creating a new name
84 * @return An instance of this class
86 public static ParseHandler
NewInstance(Control textWidget
, TaxonNameBase name
){
87 return new ParseHandler(textWidget
, name
);
92 * Parses a given string and returns a <code>TaxonNameBase</code> instance with the
93 * reuslts of the parsing.
95 * This method should be used to quickly create a new name from a string.
96 * Wherever the string will be parsed again in subsequent editing, an instance
97 * of <code>ParseHandler</code> should be attached to the text widget.
99 * @param unparsedNameString a {@link java.lang.String} object.
100 * @return a {@link eu.etaxonomy.cdm.model.name.TaxonNameBase} object.
102 public static TaxonNameBase
quickParse(String unparsedNameString
){
103 TaxonNameBase name
= nonViralNameParser
.parseReferencedName(unparsedNameString
,
104 PreferencesUtil
.getPreferredNomenclaturalCode(), null);
106 // if (name.hasProblem()) {
107 // name.setFullTitleCache(unparsedNameString);
114 * Creates an empty <code>TaxonNameBase</code> instance with the nomenclatural code
115 * currently set in preferences.
117 * @return a {@link eu.etaxonomy.cdm.model.name.TaxonNameBase} object.
119 public static TaxonNameBase
createEmptyName(){
120 return nonViralNameParser
.getNonViralNameInstance("", PreferencesUtil
.getPreferredNomenclaturalCode());
124 * Check if the given control has a getText() method
126 private void checkControlHasText(){
127 Class clazz
= textWidget
.getClass();
130 clazz
.getDeclaredMethod("getText", null);
131 } catch (SecurityException e
) {
132 } catch (NoSuchMethodException e
) {
133 throw new IllegalArgumentException("Given composite does not have a getText method");
138 * Parses the string that was entered into the text widget and returns a
139 * NonViralName object that resulted from the parsing process.
141 * @return The parsed NonViralName object
143 public NonViralName
parse(){
146 String unparsedNameString
= "";
149 getText
= textWidget
.getClass().getDeclaredMethod("getText", null);
150 unparsedNameString
= (String
) getText
.invoke(textWidget
, null);
151 } catch (Exception e
) {
152 // we should never get here
153 StoreUtil
.error(this.getClass(), "Error trying to invoke getText method", e
);
157 nonViralNameParser
.parseReferencedName(name
, unparsedNameString
,
158 name
.getRank(), true);
160 // if (name.hasProblem()) {
161 // name.setFullTitleCache(unparsedNameString);
168 * Parses the string that was entered into the text widget and returns a
169 * NonViralName object that resulted from the parsing process.
171 * The atomized fields (scientific name, author and reference) will be matched
172 * against the database to find possible duplicates. If duplicates were found
173 * the respective parts of the NonViralName will be replaced with the found
176 * @return The parsed NonViralName object
178 public NonViralName
parseAndResolveDuplicates(){
184 resolveDuplicates(name
);
193 * @param name The name to resolve duplicates for.
195 private void resolveDuplicates(NonViralName name
) {
196 resolveDuplicateNames(name
);
198 resolveAllDuplicateAuthors(name
);
200 resolveDuplicateReferences(name
);
202 if(duplicateInReferences
!= null)
203 resolveDuplicateInReferences(name
);
208 * @param name The name to resolve duplicates for.
210 private void resolveDuplicateNames(NonViralName name
) {
212 if (duplicateNames
.size() == 1){
213 name
= (NonViralName
) duplicateNames
.iterator().next();
214 }else if(duplicateNames
.size() > 1){
215 // FIXME TODO resolve multiple duplications. Use first match for a start
216 name
= (NonViralName
) duplicateNames
.iterator().next();
221 * @param name The name to resolve duplicates for.
223 private void resolveDuplicateReferences(NonViralName name
) {
224 if(duplicateReferences
.size() == 1){
225 // exactly one match. We assume that the user wants this reference
226 INomenclaturalReference duplicate
= duplicateReferences
.iterator().next();
227 name
.setNomenclaturalReference(duplicate
);
228 }else if(duplicateReferences
.size() > 1){
229 // FIXME TODO resolve multiple duplications. Use first match for a start
230 INomenclaturalReference duplicate
= duplicateReferences
.iterator().next();
231 name
.setNomenclaturalReference(duplicate
);
236 * @param name The name to resolve duplicates for.
238 private void resolveDuplicateInReferences(NonViralName name
) {
239 ReferenceBase reference
= (ReferenceBase
) HibernateProxyHelper
.deproxy(name
.getNomenclaturalReference());
241 if(duplicateInReferences
.size() > 0){
242 ReferenceBase inReference
= (ReferenceBase
) duplicateInReferences
.iterator().next();
243 reference
.setInReference(inReference
);
244 StoreUtil
.warn(this.getClass(), reference
.generateTitle());
245 // FIXME TODO resolve multiple duplications. We use first match for a start
246 StoreUtil
.warn(this.getClass(), reference
.getTitleCache());
252 * @param name The name to resolve duplicates for.
254 private void resolveAllDuplicateAuthors(NonViralName name
) {
256 if(duplicateCombinationAuthorTeams
.size() > 0){
257 name
.setCombinationAuthorTeam(duplicateCombinationAuthorTeams
.iterator().next());
258 ReferenceBase reference
= (ReferenceBase
) name
.getNomenclaturalReference();
259 if(reference
!= null){
260 reference
.setAuthorTeam(duplicateCombinationAuthorTeams
.iterator().next());
262 // FIXME TODO resolve multiple duplications. We use first match for a start.
265 if(duplicateExCombinationAuthorTeams
.size() > 0){
266 name
.setExCombinationAuthorTeam(duplicateExCombinationAuthorTeams
.iterator().next());
267 // FIXME TODO resolve multiple duplications. We use first match for a start.
270 if(duplicateBasionymAuthorTeams
.size() > 0){
271 name
.setBasionymAuthorTeam(duplicateBasionymAuthorTeams
.iterator().next());
272 // FIXME TODO resolve multiple duplications. We use first match for a start.
275 if(duplicateExBasionymAuthorTeams
.size() > 0){
276 name
.setExBasionymAuthorTeam(duplicateExBasionymAuthorTeams
.iterator().next());
277 // FIXME TODO resolve multiple duplications. We use first match for a start.
282 * Splits a NonViralName into its parts and calls methods to find matches for these
283 * parts in the database.
285 * @param name The NonViralName to find matches for.
287 private void findMatches(NonViralName name
){
289 duplicateNames
= findMatchingLatinNames(name
);
291 duplicateCombinationAuthorTeams
= findMatchingAuthors((TeamOrPersonBase
) name
.getCombinationAuthorTeam());
292 duplicateExCombinationAuthorTeams
= findMatchingAuthors((TeamOrPersonBase
) name
.getExCombinationAuthorTeam());
293 duplicateBasionymAuthorTeams
= findMatchingAuthors((TeamOrPersonBase
) name
.getBasionymAuthorTeam());
294 duplicateExBasionymAuthorTeams
= findMatchingAuthors((TeamOrPersonBase
) name
.getExBasionymAuthorTeam());
296 INomenclaturalReference nomenclaturalReference
= name
.getNomenclaturalReference();
298 // check if the reference has an inreference and also check if the inReference already exists
299 if(nomenclaturalReference
!= null){
300 ReferenceBase inReference
= ((ReferenceBase
)nomenclaturalReference
).getInReference();
301 if(inReference
!= null){
302 doResolveInReferences
= true;
303 duplicateInReferences
= findMatchingNomenclaturalReference(inReference
);
307 duplicateReferences
= findMatchingNomenclaturalReference(nomenclaturalReference
);
311 * @param nomenclaturalReference The NomenclaturalReference to find matches for.
312 * @return A <code>List</code> of possibly matching NomenclaturalReference's.
314 private List
<INomenclaturalReference
> findMatchingNomenclaturalReference(INomenclaturalReference nomenclaturalReference
) {
315 if(nomenclaturalReference
== null) return new ArrayList
<INomenclaturalReference
>();
317 return CdmStore
.getCommonService().findMatching(nomenclaturalReference
, MatchStrategyConfigurator
.ReferenceMatchStrategy());
318 }catch (MatchException e
) {
319 StoreUtil
.error(this.getClass(), "Error finding matching references", e
);
325 * @param authorTeam The TeamOrPersonBase to find matches for.
326 * @return A <code>List</code> of possibly matching TeamOrPersonBase's.
328 private List
<TeamOrPersonBase
> findMatchingAuthors(TeamOrPersonBase authorTeam
) {
330 if(authorTeam
== null){
331 return new ArrayList
<TeamOrPersonBase
>();
335 return CdmStore
.getCommonService().findMatching(authorTeam
, MatchStrategyConfigurator
.TeamOrPersonMatchStrategy());
336 }catch (MatchException e
) {
337 StoreUtil
.error(this.getClass(), "Error finding matching authors", e
);
343 * @param taxonNameBase The TaxonNameBase to find matches for.
344 * @return A <code>List</code> of possibly matching TaxonNameBase's.
346 private List
<TaxonNameBase
> findMatchingLatinNames(TaxonNameBase taxonNameBase
) {
349 return CdmStore
.getCommonService().findMatching(taxonNameBase
, MatchStrategyConfigurator
.NonViralNameMatchStrategy());
351 } catch (MatchException e
) {
352 StoreUtil
.error(this.getClass(), "Error finding matching names", e
);
358 * <p>Getter for the field <code>textWidget</code>.</p>
360 * @return The Control this ParseHandler is attached to.
362 public Control
getTextWidget() {
367 * <p>Setter for the field <code>textWidget</code>.</p>
369 * @param textWidget The textWidget to set
371 public void setTextWidget(Control textWidget
) {
372 this.textWidget
= textWidget
;
373 checkControlHasText();