001 /*
002 * The contents of this file are subject to the Mozilla Public
003 * License Version 1.1 (the "License"); you may not use this file
004 * except in compliance with the License. You may obtain a copy of
005 * the License at http://www.mozilla.org/MPL/
006 *
007 * Software distributed under the License is distributed on an "AS
008 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
009 * implied. See the License for the specific language governing
010 * rights and limitations under the License.
011 *
012 * The Original Code is Knowtator.
013 *
014 * The Initial Developer of the Original Code is University of Colorado.
015 * Copyright (C) 2005 - 2008. All Rights Reserved.
016 *
017 * Knowtator was developed by the Center for Computational Pharmacology
018 * (http://compbio.uchcs.edu) at the University of Colorado Health
019 * Sciences Center School of Medicine with support from the National
020 * Library of Medicine.
021 *
022 * Current information about Knowtator can be obtained at
023 * http://knowtator.sourceforge.net/
024 *
025 * Contributor(s):
026 * Philip V. Ogren <philip@ogren.info> (Original Author)
027 * Angus Roberts
028 */
029
030 /**
031 * Changes:
032 * 2/7/2007 ar updated handleAddAction to handle inverse slots
033 * 2/7/2007 ar added handleRemoveAction
034 * 9/7/2005 pvo added handleCreateAction which allows one to highlight a span of text and
035 * click the 'Create Instance' button for an annotations slot value and create
036 * an annotation for that slot at the selected span.
037 * 9/7/2005 pvo updated the SelectAnnotationsFromCollectionPanel such that mousing over an annotation
038 * in the panel causes the corresponding text in the text viewer to be highlighted.
039 * 8/10/2005 pvo list now uses ListCellRenderer obtained from the KB.getClientInformation()
040 * this was done in conjunction with creation of the BrowserTextUtil code
041 * 8/11/2005 pvo the handleAddAction calls pickAnnotationsFromCollection to ask for an annotation instead of the
042 * previously used DisplayUtilities.pickInstancesFromCollection.
043 * the method was copied from the DisplayUtilities and modified so that the
044 * displayed list uses the desired ListCellRenderer.
045 */
046
047 package edu.uchsc.ccp.knowtator;
048
049 import java.util.Collection;
050 import java.util.Collections;
051 import java.util.Comparator;
052 import java.util.HashSet;
053 import java.util.List;
054 import java.util.Set;
055
056 import javax.swing.JOptionPane;
057
058 import org.apache.log4j.Logger;
059
060 import edu.stanford.smi.protege.model.Cls;
061 import edu.stanford.smi.protege.model.Instance;
062 import edu.stanford.smi.protege.model.KnowledgeBase;
063 import edu.stanford.smi.protege.model.SimpleInstance;
064 import edu.stanford.smi.protege.model.Slot;
065 import edu.stanford.smi.protege.model.ValueType;
066 import edu.stanford.smi.protege.util.CollectionUtilities;
067 import edu.stanford.smi.protege.util.DoubleClickListener;
068 import edu.stanford.smi.protege.widget.InstanceListWidget;
069 import edu.uchsc.ccp.knowtator.ui.AnnotationPicker;
070 import edu.uchsc.ccp.knowtator.util.ProtegeUtil;
071
072 public class ComplexSlotMentionValueWidget extends InstanceListWidget implements DoubleClickListener {
073
074 static final long serialVersionUID = 0;
075
076 KnowtatorManager manager;
077
078 MentionUtil mentionUtil;
079
080 AnnotationUtil annotationUtil;
081
082 KnowtatorProjectUtil kpu;
083
084 TextSourceUtil textSourceUtil;
085
086 BrowserTextUtil browserTextUtil;
087
088 KnowledgeBase kb;
089
090 DisplayColors displayColors;
091
092 Logger logger = Logger.getLogger(ComplexSlotMentionValueWidget.class);
093
094 public void initialize() {
095 super.initialize();
096 manager = (KnowtatorManager) getKnowledgeBase().getClientInformation(Knowtator.KNOWTATOR_MANAGER);
097 mentionUtil = manager.getMentionUtil();
098 annotationUtil = manager.getAnnotationUtil();
099 kpu = manager.getKnowtatorProjectUtil();
100 textSourceUtil = manager.getTextSourceUtil();
101 browserTextUtil = manager.getBrowserTextUtil();
102 displayColors = manager.getDisplayColors();
103
104 kb = kpu.getKnowledgeBase();
105
106 setDoubleClickListener(this);
107 // we want the list to use our cell renderer
108 setRenderer(manager.getRenderer()); // this does nothing because it is
109 // reset in the super class
110 // AbstractSlotWidget.setInstance
111 // method.
112 }
113
114 public void setValues(Collection values) {
115 super.setValues(values);
116 try {
117 SimpleInstance slotMention = (SimpleInstance) getInstance();
118 Slot mentionSlot = mentionUtil.getSlotMentionSlot(slotMention);
119 if (mentionSlot == null)
120 return;
121 SimpleInstance mentionedByMention = mentionUtil.getMentionedBy(slotMention);
122 Cls mentionCls = mentionUtil.getMentionCls(mentionedByMention);
123 if (mentionCls == null)
124 return;
125
126 // this code doesn't work for some reason. It is supposed to paint
127 // the red border
128 // around this slot
129 // int minCardinality =
130 // mentionCls.getTemplateSlotMinimumCardinality(mentionSlot);
131 // int maxCardinality =
132 // mentionCls.getTemplateSlotMaximumCardinality(mentionSlot);
133 //
134 // if(values.size() < minCardinality || values.size() >
135 // maxCardinality)
136 // setInvalidValueBorder();
137 // else
138 // setNormalBorder();
139
140 getLabeledComponent().setHeaderLabel(ProtegeUtil.getSlotLabel(mentionCls, mentionSlot, getProject()));
141 } catch (NullPointerException npe) {
142 getLabeledComponent().setHeaderLabel("");
143 }
144 }
145
146 public void setInstance(Instance instance) {
147 super.setInstance(instance);
148 // the renderer is set in the super class AbstractSlotWidget - we must
149 // set it to our renderer to get it to show up.
150 setRenderer(manager.getRenderer());
151 }
152
153 @Override
154 protected void handleViewAction(Instance instance) {
155 logger.debug(browserTextUtil.getBrowserText((SimpleInstance) instance, 100));
156 SimpleInstance annotation = mentionUtil.getMentionAnnotation((SimpleInstance) instance);
157 manager.setSelectedAnnotation(annotation);
158 }
159
160 public void onDoubleClick(Object item) {
161 if (item instanceof SimpleInstance)
162 handleViewAction((SimpleInstance) item);
163 }
164
165 protected void handleCreateAction() {
166 // slotMention is the mention that corresponds to the instance handled
167 // by this widget
168 SimpleInstance slotMention = (SimpleInstance) getInstance();
169 // mentionSlot is the slot corresponding to the slotMention
170 Slot mentionSlot = mentionUtil.getSlotMentionSlot(slotMention);
171 if (mentionSlot == null) {
172 showSlotMissingMessage();
173 return;
174 }
175
176 // mention has slotMention as a value of one of its
177 // knowtator_slot_mention
178 SimpleInstance mention = mentionUtil.getMentionedBy(slotMention);
179 // mentionCls is the cls of the mention
180 Cls mentionCls = mentionUtil.getMentionCls(mention);
181 if (mentionCls == null) {
182 showTypeMissingMessage(mention);
183 return;
184 }
185
186 if (!checkValueTypeConstraint(mentionCls, mentionSlot))
187 return;
188
189 // Get the classes that are allowed by this class at this slot.
190 // This assumes the slot is constrained to be an instance of a cls and
191 // does not account for
192 // the possibility that the slot may be constrained to be a cls.
193 Set<Cls> allowedClses = new HashSet<Cls>((Collection<Cls>) mentionCls.getTemplateSlotAllowedClses(mentionSlot));
194
195 // this code needs to be expanded in two ways - if the slot of the cls
196 // is of type cls then
197 // we need to call mentionCls.getTemplateSlotAllowedParents(slot) and
198 // make sure that instances are not displayed for selection.
199 // if the slot of the cls is of type instance then we should display the
200 // annotations corresponding to instances for selection.
201 if (allowedClses == null || allowedClses.size() < 1) {
202 allowedClses = new HashSet<Cls>(manager.getRootClses());
203 }
204
205 Set<Cls> descendants = new HashSet<Cls>();
206 for (Cls allowedCls : allowedClses) {
207 descendants.addAll(allowedCls.getSubclasses());
208 }
209
210 descendants.addAll(allowedClses);
211
212 Cls newMentionCls;
213 if (descendants.size() > 1) {
214 newMentionCls = edu.stanford.smi.protege.ui.DisplayUtilities.pickCls(this, kb, allowedClses,
215 "Choose type for new annotation filling in the slot");
216 } else {
217 newMentionCls = (Cls) CollectionUtilities.getFirstItem(descendants);
218 }
219
220 if (newMentionCls == null)
221 return;
222
223 SimpleInstance newAnnotation = manager.createAnnotation(newMentionCls, false);
224
225 SimpleInstance newMention = annotationUtil.getMention(newAnnotation);
226
227 addItem(newMention);
228 mentionUtil.addInverse(mention, mentionSlot, newMention);
229 mentionUtil.adjustSlotMentionForCardinality(mentionCls, mentionSlot, mention);
230 manager.updateCurrentAnnotations();
231 }
232
233 private boolean checkValueTypeConstraint(Cls cls, Slot slot) {
234 ValueType type = cls.getTemplateSlotValueType(slot);
235 if (type == ValueType.INSTANCE || type == ValueType.CLS)
236 return true;
237 else {
238 JOptionPane.showMessageDialog(this, "It appears that the value type constraint\n"
239 + "has changed since the slot values for this\n" + "slot were entered.\n"
240 + "Please remove the slot values for this slot,\n"
241 + "select a different annotation, and re-select\n " + "the currently selected annotation.",
242 "value type constraint inconsistency", JOptionPane.WARNING_MESSAGE);
243 return false;
244 }
245 }
246
247 private void showTypeMissingMessage(SimpleInstance mention) {
248 if (mentionUtil.isClassMention(mention))
249 JOptionPane.showMessageDialog(this, "There is no class assigned to this annotation.\n"
250 + "You may not add a value to this slot until a \n" + "class is assigned.", "No class assigned",
251 JOptionPane.WARNING_MESSAGE);
252 else if (mentionUtil.isInstanceMention(mention))
253 JOptionPane.showMessageDialog(this, "There is no instance assigned to this annotation.\n"
254 + "You may not add a value to this slot until an \n" + "instance is assigned.",
255 "No instance assigned", JOptionPane.WARNING_MESSAGE);
256
257 }
258
259 private void showSlotMissingMessage() {
260 JOptionPane.showMessageDialog(this, "There is not a slot specified for this slot value.\n"
261 + "This is most likely a result of deleting a slot \n"
262 + "from the annotation schema after this annotation \n"
263 + "was created. Please remove this slot value, select\n"
264 + "another annotation, and re-select this annotation.", "Slot missing", JOptionPane.WARNING_MESSAGE);
265 }
266
267 /**
268 * At the moment the only value you can add is a mention from another
269 * annotation. First, loop through all of the available annotations, then
270 * choose only those that make sense for the slot.
271 *
272 * why isn't the allowedClses filled with getTemplateSlotAllowedParents too?
273 */
274 protected void handleAddAction() {
275 SimpleInstance slotMention = (SimpleInstance) getInstance();
276 Slot mentionSlot = mentionUtil.getSlotMentionSlot(slotMention);
277 if (mentionSlot == null) {
278 showSlotMissingMessage();
279 return;
280 }
281 SimpleInstance mention = mentionUtil.getMentionedBy(slotMention);
282 Cls mentionCls = mentionUtil.getMentionCls(mention);
283 if (mentionCls == null) {
284 showTypeMissingMessage(mention);
285 return;
286 }
287
288 if (!checkValueTypeConstraint(mentionCls, mentionSlot))
289 return;
290
291 List<SimpleInstance> partiallyFilteredAnnotations = manager.getCurrentPartiallyFilteredAnnotations();
292 List<SimpleInstance> annotations = mentionUtil.getSlotFillerCandidates(mention, mentionSlot,
293 partiallyFilteredAnnotations);
294
295 if (annotations.size() == 0) {
296 if (getList().getModel().getSize() == 0)
297 JOptionPane
298 .showMessageDialog(
299 this,
300 "There are no annotations available that satisfy the constraints for this slot on this annotation.",
301 "No appropriate annotations", JOptionPane.INFORMATION_MESSAGE);
302 else
303 JOptionPane
304 .showMessageDialog(
305 this,
306 "There are no other annotations available that satisfy the constraints for this slot on this annotation.",
307 "No appropriate annotations", JOptionPane.INFORMATION_MESSAGE);
308
309 return;
310 } else if (annotations.size() == 1) {
311 SimpleInstance annotationInstance = annotations.get(0);
312 SimpleInstance annotationMention = annotationUtil.getMention(annotationInstance);
313 addItem(annotationMention);
314 mentionUtil.addInverse(mention, mentionSlot, annotationMention);
315 } else {
316 Comparator comparator = manager.getAnnotationComparator();
317 Collections.sort(annotations, comparator);
318 List<SimpleInstance> pickedAnnotations = AnnotationPicker.pickAnnotationsFromCollection(this, manager,
319 annotations, "select annotation for '" + mentionSlot.getBrowserText() + "'");
320
321 for (SimpleInstance annotation : pickedAnnotations) {
322 SimpleInstance annotationMention = annotationUtil.getMention(annotation);
323 addItem(annotationMention);
324 mentionUtil.addInverse(mention, mentionSlot, annotationMention);
325 }
326 }
327
328 mentionUtil.adjustSlotMentionForCardinality(mentionCls, mentionSlot, mention);
329
330 // int maxCardinality =
331 // mentionCls.getTemplateSlotMaximumCardinality(mentionSlot);
332 // if(maxCardinality > 0)
333 // {
334 // ArrayList values = new ArrayList(getValues());
335 // removeAllItems();
336 // for(int i=values.size()-1, j=0; i >=0 && j<maxCardinality; i--)
337 // {
338 // addItem(values.get(i));
339 // j++;
340 // }
341 // }
342 manager.refreshAnnotationsDisplay(true);
343
344 }
345
346 protected void handleRemoveAction(Collection instances) {
347 super.handleRemoveAction(instances);
348
349 SimpleInstance slotMention = (SimpleInstance) getInstance();
350 Slot mentionSlot = mentionUtil.getSlotMentionSlot(slotMention);
351 if (mentionSlot != null) {
352 SimpleInstance mentionedByMention = mentionUtil.getMentionedBy(slotMention);
353
354 for (Object annotationMentionObj : instances)
355 mentionUtil.removeInverse(mentionedByMention, mentionSlot, (SimpleInstance) annotationMentionObj);
356 }
357 manager.refreshAnnotationsDisplay(true);
358 }
359 }