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 }