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     */
028    
029    package edu.uchsc.ccp.knowtator;
030    
031    import java.util.ArrayList;
032    import java.util.Collection;
033    
034    import javax.swing.Action;
035    import javax.swing.JOptionPane;
036    
037    import org.apache.log4j.Logger;
038    
039    import edu.stanford.smi.protege.model.Cls;
040    import edu.stanford.smi.protege.model.Facet;
041    import edu.stanford.smi.protege.model.KnowledgeBase;
042    import edu.stanford.smi.protege.model.SimpleInstance;
043    import edu.stanford.smi.protege.model.Slot;
044    import edu.stanford.smi.protege.model.ValueType;
045    import edu.stanford.smi.protege.resource.ResourceKey;
046    import edu.stanford.smi.protege.util.AddAction;
047    import edu.stanford.smi.protege.util.AllowableAction;
048    import edu.stanford.smi.protege.util.CollectionUtilities;
049    import edu.stanford.smi.protege.util.RemoveAction;
050    import edu.stanford.smi.protege.widget.AbstractListWidget;
051    import edu.stanford.smi.protege.widget.ClsWidget;
052    import edu.stanford.smi.protege.widget.SlotWidget;
053    
054    public class SlotMentionValueWidget extends AbstractListWidget {
055            static final long serialVersionUID = 0;
056    
057            KnowtatorManager manager;
058    
059            MentionUtil mentionUtil;
060    
061            AnnotationUtil annotationUtil;
062    
063            KnowtatorProjectUtil kpu;
064    
065            private AllowableAction _addValueAction;
066    
067            private AllowableAction _removeValueAction;
068    
069            Logger logger = Logger.getLogger(SlotMentionValueWidget.class);
070    
071            public void initialize() {
072                    super.initialize();
073                    addButton(getAddValueAction());
074                    addButton(getRemoveValueAction());
075                    manager = (KnowtatorManager) getKnowledgeBase().getClientInformation(Knowtator.KNOWTATOR_MANAGER);
076                    mentionUtil = manager.getMentionUtil();
077                    annotationUtil = manager.getAnnotationUtil();
078                    kpu = manager.getKnowtatorProjectUtil();
079            }
080    
081            public void setValues(Collection values) {
082                    super.setValues(values);
083                    SimpleInstance slotMention = (SimpleInstance) getInstance();
084                    Slot mentionSlot = mentionUtil.getSlotMentionSlot(slotMention);
085    
086                    String slotLabel = null;
087                    try {
088                            SimpleInstance mentionedByMention = mentionUtil.getMentionedBy(slotMention);
089                            Cls mentionCls = mentionUtil.getMentionCls(mentionedByMention);
090                            ClsWidget clsWidget = getProject().getDesignTimeClsWidget(mentionCls);
091                            SlotWidget slotWidget = clsWidget.getSlotWidget(mentionSlot);
092                            slotLabel = slotWidget.getLabel();
093                    } catch (Exception e) {
094                            logger.debug("", e);
095                    }
096    
097                    if (slotLabel != null)
098                            getLabeledComponent().setHeaderLabel(slotLabel);
099                    else
100                            getLabeledComponent().setHeaderLabel(mentionSlot.getBrowserText());
101    
102            }
103    
104            protected Action getAddValueAction() {
105                    _addValueAction = new AddAction(ResourceKey.VALUE_ADD) {
106                            static final long serialVersionUID = 0;
107    
108                            public void onAdd() {
109                                    handleAddAction();
110                            }
111                    };
112                    return _addValueAction;
113            }
114    
115            String requestSymbolValue(Cls mentionCls, Slot mentionSlot) {
116                    Object defaultValue = getDefaultValue(mentionCls, mentionSlot);
117    
118                    java.util.List values = new ArrayList();
119                    values.addAll(mentionCls.getTemplateSlotAllowedValues(mentionSlot));
120                    if (values.size() > 0) {
121                            if (defaultValue == null)
122                                    defaultValue = values.get(0);
123    
124                            Object selection = JOptionPane.showInputDialog(this, "Select symbol", "Symbol selection",
125                                            JOptionPane.PLAIN_MESSAGE, null, values.toArray(), defaultValue);
126                            if (selection != null)
127                                    return selection.toString();
128                    }
129                    return null;
130            }
131    
132            Boolean requestBooleanValue(Cls mentionCls, Slot mentionSlot) {
133                    Object defaultValue = getDefaultValue(mentionCls, mentionSlot);
134                    if (defaultValue == null)
135                            defaultValue = Boolean.TRUE;
136    
137                    java.util.List values = new ArrayList();
138                    values.add(Boolean.TRUE);
139                    values.add(Boolean.FALSE);
140                    Object selection = JOptionPane.showInputDialog(this, "Select true or false", "Boolean selection",
141                                    JOptionPane.PLAIN_MESSAGE, null, values.toArray(), defaultValue);
142                    if (selection != null) {
143                            return (Boolean) selection;
144                    }
145                    return null;
146            }
147    
148            String requestStringValue(Cls mentionCls, Slot mentionSlot) {
149                    Object defaultValue = getDefaultValue(mentionCls, mentionSlot);
150                    if (defaultValue == null)
151                            defaultValue = "";
152    
153                    String stringValue = JOptionPane.showInputDialog(this, "Enter string value", defaultValue);
154                    if (stringValue != null && stringValue.trim().length() > 0) {
155                            return stringValue;
156                    }
157                    return null;
158            }
159    
160            Integer requestIntegerValue(Cls mentionCls, Slot mentionSlot) {
161                    Object defaultValue = getDefaultValue(mentionCls, mentionSlot);
162    
163                    String intValue = null;
164                    if (defaultValue == null)
165                            intValue = JOptionPane.showInputDialog(this, "Enter an integer value");
166                    else
167                            intValue = JOptionPane.showInputDialog(this, "Enter an integer value", defaultValue);
168    
169                    if (intValue == null || intValue.trim().equals(""))
170                            return null;
171    
172                    String invalidErrorMessage = getInvalidIntegerDescription(intValue, mentionCls, mentionSlot);
173                    if (invalidErrorMessage != null) {
174                            JOptionPane
175                                            .showMessageDialog(this, invalidErrorMessage, "Invalid integer value", JOptionPane.ERROR_MESSAGE);
176                            return null;
177                    } else
178                            return new Integer(intValue);
179            }
180    
181            Float requestFloatValue(Cls mentionCls, Slot mentionSlot) {
182                    Object defaultValue = getDefaultValue(mentionCls, mentionSlot);
183    
184                    String floatValue = null;
185                    if (defaultValue == null)
186                            floatValue = JOptionPane.showInputDialog(this, "Enter a number");
187                    else
188                            floatValue = JOptionPane.showInputDialog(this, "Enter a number", defaultValue);
189    
190                    if (floatValue == null || floatValue.trim().equals(""))
191                            return null;
192    
193                    String invalidErrorMessage = getInvalidFloatDescription(floatValue, mentionCls, mentionSlot);
194                    if (invalidErrorMessage != null) {
195                            JOptionPane.showMessageDialog(this, invalidErrorMessage, "Invalid number", JOptionPane.ERROR_MESSAGE);
196                            return null;
197                    } else
198                            return new Float(floatValue);
199            }
200    
201            Object getDefaultValue(Cls mentionCls, Slot mentionSlot) {
202                    Collection defaultValues = mentionCls.getTemplateSlotValues(mentionSlot);
203                    if (defaultValues == null || defaultValues.size() == 0) {
204                            defaultValues = mentionCls.getTemplateSlotDefaultValues(mentionSlot);
205                    }
206                    if (defaultValues != null && defaultValues.size() > 0)
207                            return CollectionUtilities.getFirstItem(defaultValues);
208                    return null;
209            }
210    
211            private void showSlotMissingMessage() {
212                    JOptionPane.showMessageDialog(this, "There is not a slot specified for this slot value.\n"
213                                    + "This is most likely a result of deleting a slot \n"
214                                    + "from the annotation schema after this annotation \n"
215                                    + "was created.  Please remove this slot value, select\n"
216                                    + "another annotation, and re-select this annotation.", "Slot missing", JOptionPane.WARNING_MESSAGE);
217            }
218    
219            private void showTypeMissingMessage(SimpleInstance mention) {
220                    if (mentionUtil.isClassMention(mention))
221                            JOptionPane.showMessageDialog(this, "There is no class assigned to this annotation.\n"
222                                            + "You may not add a value to this slot until a \n" + "class is assigned.", "No class assigned",
223                                            JOptionPane.WARNING_MESSAGE);
224                    else if (mentionUtil.isInstanceMention(mention))
225                            JOptionPane.showMessageDialog(this, "There is no instance assigned to this annotation.\n"
226                                            + "You may not add a value to this slot until an \n" + "instance is assigned.",
227                                            "No instance assigned", JOptionPane.WARNING_MESSAGE);
228    
229            }
230    
231            protected void handleAddAction() {
232                    SimpleInstance slotMention = (SimpleInstance) getInstance();
233                    Slot mentionSlot = mentionUtil.getSlotMentionSlot(slotMention);
234                    if (mentionSlot == null) {
235                            showSlotMissingMessage();
236                            return;
237                    }
238    
239                    SimpleInstance mentionedByMention = mentionUtil.getMentionedBy(slotMention);
240                    Cls mentionCls = mentionUtil.getMentionCls(mentionedByMention);
241                    if (mentionCls == null) {
242                            showTypeMissingMessage(mentionedByMention);
243                            return;
244                    }
245    
246                    Object value = null;
247                    ValueType type = mentionCls.getTemplateSlotValueType(mentionSlot);
248    
249                    if (type == ValueType.SYMBOL) {
250                            value = requestSymbolValue(mentionCls, mentionSlot);
251                    } else if (type == ValueType.BOOLEAN) {
252                            value = requestBooleanValue(mentionCls, mentionSlot);
253                    } else if (type == ValueType.STRING) {
254                            value = requestStringValue(mentionCls, mentionSlot);
255                    } else if (type == ValueType.INTEGER) {
256                            value = requestIntegerValue(mentionCls, mentionSlot);
257                    } else if (type == ValueType.FLOAT) {
258                            value = requestFloatValue(mentionCls, mentionSlot);
259                    } else if (type == ValueType.CLS || type == ValueType.INSTANCE) {
260                            JOptionPane.showMessageDialog(this, "It appears that the value type constraint\n"
261                                            + "has changed since the slot values for this\n" + "slot were entered.\n"
262                                            + "Please remove the slot values for this slot,\n"
263                                            + "select a different annotation, and re-select\n " + "the currently selected annotation.",
264                                            "value type constraint inconsistency", JOptionPane.WARNING_MESSAGE);
265                    } else {
266                            JOptionPane.showMessageDialog(this, "this type is not handled yet!");
267                    }
268                    if (value != null)
269                            addItem(value);
270    
271                    /**
272                     * "enforces" maximum cardinality constraint. Assumes that the values
273                     * will be ordered as they appear in the widget (oldest to newest
274                     * additions)
275                     */
276                    int maxCardinality = mentionCls.getTemplateSlotMaximumCardinality(mentionSlot);
277                    if (maxCardinality > 0) {
278                            ArrayList values = new ArrayList(getValues());
279                            removeAllItems();
280                            for (int i = values.size() - 1, j = 0; i >= 0 && j < maxCardinality; i--) {
281                                    addItem(values.get(i));
282                                    j++;
283                            }
284                    }
285    
286                    // now we need to check if the values are valid (and in setValues)
287                    // if the values are not valid we can call
288                    // AbstractSlotWidget.setInvalidValueBorder
289                    // if they are fine, then call AbstractSlotWidget.setNormalBorder
290            }
291    
292            /**
293             * The code for this method was copied from
294             * edu.stanford.smi.protege.widget.IntegerFieldWidget and modified slightly
295             */
296    
297            protected String getInvalidIntegerDescription(String text, Cls mentionCls, Slot mentionSlot) {
298                    String result = null;
299                    try {
300                            int i = new Integer(text).intValue();
301                            Number min = mentionCls.getTemplateSlotMinimumValue(mentionSlot);
302                            if (min != null && i < min.intValue()) {
303                                    result = "The minimum value is " + min;
304                            }
305                            Number max = mentionCls.getTemplateSlotMaximumValue(mentionSlot);
306                            if (max != null && i > max.intValue()) {
307                                    result = "The maximum value is " + max;
308                            }
309                    } catch (NumberFormatException e) {
310                            result = "The value must be an integer";
311                    }
312                    return result;
313            }
314    
315            /**
316             * The code for this method was copied from
317             * edu.stanford.smi.protege.widget.FloatFieldWidget and modified slightly
318             */
319    
320            protected String getInvalidFloatDescription(String text, Cls mentionCls, Slot mentionSlot) {
321                    String result = null;
322                    try {
323                            float f = Float.parseFloat(text);
324                            Number min = mentionCls.getTemplateSlotMinimumValue(mentionSlot);
325                            if (min != null && f < min.floatValue()) {
326                                    result = "The minimum value is " + min;
327                            }
328                            Number max = mentionCls.getTemplateSlotMaximumValue(mentionSlot);
329                            if (max != null && f > max.floatValue()) {
330                                    result = "The maximum value is " + max;
331                            }
332                    } catch (NumberFormatException e) {
333                            result = "The value must be a number";
334                    }
335                    return result;
336            }
337    
338            protected Action getRemoveValueAction() {
339                    _removeValueAction = new RemoveAction(ResourceKey.VALUE_REMOVE, this) {
340                            public void onRemove(Collection values) {
341                                    handleRemoveAction(values);
342                            }
343                    };
344                    return _removeValueAction;
345            }
346    
347            protected void handleRemoveAction(Collection values) {
348                    removeItems(values);
349            }
350    
351            public static boolean isSuitable(Cls cls, Slot slot, Facet facet) {
352                    KnowledgeBase kb = slot.getKnowledgeBase();
353                    Cls complexSlotMentionCls = kb.getCls(KnowtatorProjectUtil.COMPLEX_SLOT_MENTION_CLS_NAME);
354                    Slot mentionSlotValueSlot = kb.getSlot(KnowtatorProjectUtil.MENTION_SLOT_VALUE_SLOT_NAME);
355                    if (!cls.equals(complexSlotMentionCls) && mentionSlotValueSlot.equals(slot))
356                            return true;
357                    return false;
358            }
359    
360            public void setEditable(boolean b) {
361                    setAllowed(_addValueAction, b);
362            }
363    
364    }