package org.mindswap.swoop.popup;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextField;
import javax.swing.ListCellRenderer;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.mindswap.swoop.SwoopModel;
import org.mindswap.swoop.reasoner.SwoopReasoner;
import org.mindswap.swoop.renderer.SwoopCellRenderer;
import org.mindswap.swoop.utils.DataValueChecker;
import org.mindswap.swoop.utils.SetUtils;
import org.mindswap.swoop.utils.ui.AddCloseBar;
import org.mindswap.swoop.utils.ui.EntityComparator;
import org.semanticweb.owl.impl.model.OWLConcreteDataTypeImpl;
import org.semanticweb.owl.impl.model.OWLDataEnumerationImpl;
import org.semanticweb.owl.io.vocabulary.OWLVocabularyAdapter;
import org.semanticweb.owl.io.vocabulary.RDFVocabularyAdapter;
import org.semanticweb.owl.io.vocabulary.XMLSchemaSimpleDatatypeVocabulary;
import org.semanticweb.owl.model.OWLClass;
import org.semanticweb.owl.model.OWLDataProperty;
import org.semanticweb.owl.model.OWLDataRange;
import org.semanticweb.owl.model.OWLDataValue;
import org.semanticweb.owl.model.OWLDescription;
import org.semanticweb.owl.model.OWLEnumeration;
import org.semanticweb.owl.model.OWLException;
import org.semanticweb.owl.model.OWLIndividual;
import org.semanticweb.owl.model.OWLObjectProperty;
import org.semanticweb.owl.model.OWLOntology;
import org.semanticweb.owl.model.OWLProperty;
import org.semanticweb.owl.model.change.AddDataPropertyInstance;
import org.semanticweb.owl.model.change.AddIndividualClass;
import org.semanticweb.owl.model.change.AddObjectPropertyInstance;
import org.semanticweb.owl.model.change.RemoveEntity;
import org.semanticweb.owl.model.helper.OntologyHelper;
/**
* @author Aditya
* This class pops up whenever the user needs to specify an Property-Value pair
* in a Ontology Change on an OWL Individual
*
*/
public class PopupAddValue extends JFrame implements ActionListener, ListSelectionListener, KeyListener {
SwoopReasoner reasoner;
SwoopModel swoopModel;
OWLProperty prop;
public List changes;
Font tahoma = new Font("Tahoma", Font.PLAIN, 11);
JList rangeBox, valueBox;
JTextField newValueFld;
AddCloseBar actionBar;
boolean isRDFXMLLiteral = false;
public PopupAddValue(SwoopReasoner reasoner, SwoopModel swoopModel, OWLProperty prop) {
// setModal(true);
this.reasoner = reasoner;
this.swoopModel = swoopModel;
this.prop = prop;
this.changes = new ArrayList();
setupUI();
}
private void setupUI() {
JLabel propLbl = new JLabel("");
List rangeList = new ArrayList();
rangeBox = new JList();
rangeBox.setFont(tahoma);
rangeBox.setCellRenderer(new RangeRenderer(swoopModel));
rangeBox.addKeyListener(this);
Set valueList = new TreeSet(EntityComparator.INSTANCE);;
valueBox = new JList();
valueBox.setFont(tahoma);
valueBox.setCellRenderer(new SwoopCellRenderer(swoopModel));
valueBox.addKeyListener(this);
boolean shrink = false;
try {
String propName = swoopModel.shortForm(prop.getURI());
propLbl = new JLabel("Specify value for Property '"+propName+"'", JLabel.LEFT);
propLbl.setFont(tahoma);
// fill range box with property range's
OWLOntology ontology = swoopModel.getSelectedOntology();
Set ontologies;
if (swoopModel.getImportsSetting(ontology)) {
ontologies = OntologyHelper.importClosure(ontology);
} else {
ontologies = Collections.singleton(ontology);
}
Set rangeSet = prop.getRanges(ontologies);
if (rangeSet.size()>0) {
Iterator iter = rangeSet.iterator();
while (iter.hasNext()) {
if (prop instanceof OWLObjectProperty) {
// range of ObjectProperty is a class
Object obj = iter.next();
if (obj instanceof OWLClass) {
OWLClass desc = (OWLClass) obj;
rangeList.add(desc);
/* add owl:Thing regardless? */
OWLClass thing = swoopModel.getSelectedOntology().getOWLDataFactory().getOWLClass( URI.create( OWLVocabularyAdapter.INSTANCE.getThing()));
rangeList.add(thing);
addRangeSubClasses(desc, rangeList);
}
else if (obj instanceof OWLDescription) {
// one-of range of values
if (obj instanceof OWLEnumeration) {
OWLEnumeration enumElem = (OWLEnumeration) obj;
Iterator indIter = enumElem.getIndividuals().iterator();
Set indList = new TreeSet(EntityComparator.INSTANCE);
while (indIter.hasNext()) {
OWLIndividual ind = (OWLIndividual) indIter.next();
indList.add(ind);
}
valueList.addAll(indList);
}
}
}
else {
// range of DatatypeProperty is a
OWLDataRange desc = (OWLDataRange) iter.next();
if (desc instanceof OWLConcreteDataTypeImpl) {
OWLConcreteDataTypeImpl dt = (OWLConcreteDataTypeImpl) desc;
rangeList.add(dt);
shrink = true;
}
else if (desc instanceof OWLDataEnumerationImpl) {
OWLDataEnumerationImpl dt = (OWLDataEnumerationImpl) desc;
rangeList.add("OWL Data Range");
Iterator deIter = dt.getValues().iterator();
while (deIter.hasNext()) {
String val = deIter.next().toString();
String dType = val.substring(val.lastIndexOf("^")+1, val.length());
// dType = "("+dType.substring(dType.indexOf("#")+1, dType.length())+")";// ["+dType+"]";
val = val.substring(0, val.indexOf("^"));
valueList.add(val+" "+"("+dType+")");
}
}
}
}
}
else {
// ** no range specified **
// default - String? for Datatype Properties
// default - OWLThing for Object Properties
if (prop instanceof OWLDataProperty) {
URI xsdString = new URI("http://www.w3.org/2001/XMLSchema#string");
OWLConcreteDataTypeImpl dt = (OWLConcreteDataTypeImpl) swoopModel.getSelectedOntology().getOWLDataFactory().getOWLConcreteDataType(xsdString);
rangeList.add(dt);
shrink = true;
}
else {
OWLClass thing = swoopModel.getSelectedOntology().getOWLDataFactory().getOWLClass( URI.create( OWLVocabularyAdapter.INSTANCE.getThing()));
rangeList.add(thing);
addRangeSubClasses(thing, rangeList);
}
}
rangeBox.setListData(rangeList.toArray());
valueBox.setListData(valueList.toArray());
}
catch (Exception e) {
e.printStackTrace();
}
rangeBox.addListSelectionListener(this);
rangeBox.setSelectedIndex(-1);
if (rangeBox.getModel().getSize()>0) rangeBox.setSelectedIndex(0);
/*
applyBtn = new JButton("Add");
applyBtn.setFont(tahoma);
applyBtn.addActionListener(this);
addBtn = new JButton("Add & Close");
addBtn.setFont(tahoma);
addBtn.addActionListener(this);
cancelBtn = new JButton("Cancel");
cancelBtn.setFont(tahoma);
cancelBtn.addActionListener(this);
JPanel box = new JPanel();
box.setLayout(new GridLayout(1,3));
box.add(applyBtn);
box.add(addBtn);
box.add(cancelBtn);
*/
actionBar = new AddCloseBar();
actionBar.addActionListener(this);
Container content = getContentPane();
content.setLayout(new BorderLayout());
JPanel tab1W = new JPanel();
tab1W.setLayout(new BorderLayout());
JLabel propRangeLbl = new JLabel("Property Range");
propRangeLbl.setFont(tahoma);
tab1W.add(propRangeLbl, "North");
tab1W.add(new JScrollPane(rangeBox), "Center");
JPanel tab1E = new JPanel();
tab1E.setLayout(new BorderLayout());
String valText = " Datatype Value:";
if (prop instanceof OWLObjectProperty) valText = " Existing Instance(s):";
JLabel valueLbl = new JLabel(valText);
tab1E.add(valueLbl, "North");
tab1E.add(new JScrollPane(valueBox), "Center");
JSplitPane tab1Split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
tab1Split.setOneTouchExpandable(true);
tab1Split.setLeftComponent(tab1W);
if (prop instanceof OWLObjectProperty) tab1Split.setRightComponent(tab1E);
tab1Split.setDividerLocation(150);
newValueFld = new JTextField();
newValueFld.addKeyListener(this);
JPanel newValuePanel = null;
if (prop instanceof OWLObjectProperty) {
newValuePanel = createWidget("OR Specify New Value/URI: ", newValueFld, null);
tab1E.add(newValuePanel, "South");
}
else {
if (rangeList.get(0).toString().indexOf("OWL Data Range")==-1) {
newValuePanel = createWidget("Specify Data Value: ", newValueFld, null);
}
else {
newValuePanel = createWidget("Specify Data Value: ", new JScrollPane(valueBox), null);
}
tab1W.add(newValuePanel, "South");
}
JPanel tab1I = new JPanel();
tab1I.setLayout(new BorderLayout());
tab1I.add(tab1Split, "Center");
content.add(tab1I, "Center");
content.add(actionBar, "South");
setTitle("Adding Property Value");
if (shrink) setSize(445,130);
else setSize(445, 300);
}
private void addRangeSubClasses(OWLClass range, List rangeList) {
// add all subclasses of desc to range as well
//***********************************************
//Changed for Econnections
// in order not to get an exception with link prop.
//***********************************************
try {
if(!((OWLObjectProperty)prop).isLink()){
Set allSubCla = SetUtils.union(reasoner.descendantClassesOf(range));
Iterator allSubIter = allSubCla.iterator();
OWLClass nothing = swoopModel.getSelectedOntology().getOWLDataFactory().getOWLClass( URI.create( OWLVocabularyAdapter.INSTANCE.getNothing()));
while (allSubIter.hasNext()) {
Object subDesObj = allSubIter.next();
if (!(subDesObj instanceof OWLClass)) continue;
OWLClass subCla = (OWLClass) subDesObj;
if (!subCla.equals(nothing) && !rangeList.contains(subCla)) rangeList.add(subCla);
}
}
}
catch (OWLException ex) {
ex.printStackTrace();
}
}
private JPanel createWidget(Object title, JComponent comp, JComponent comp2) {
JPanel widget = new JPanel();
widget.setLayout(new BorderLayout());
if (title!=null) {
if (title instanceof String) {
String titleStr = title.toString();
JLabel lbl = new JLabel(titleStr);
lbl.setFont(tahoma);
widget.add(lbl, "West");
}
else widget.add((Component) title, "West");
}
widget.add(comp, "Center");
if (comp2!=null) widget.add(comp2, "East");
return widget;
}
/**
* Check for the validity of the property-value pair based on the range of the
* property and the data value specified by the user
* @param dt - XSD DataType (or rdfs:Literal)
* @param value - string value specified by user
* @return
*/
private boolean checkValidValue(OWLConcreteDataTypeImpl dt, String value) {
boolean valid = false;
String xsd = XMLSchemaSimpleDatatypeVocabulary.XS;
String errorMsg = "Invalid Value for Specified Datatype - require ";
if (dt.getURI().toString().equals(RDFVocabularyAdapter.RDF+"XMLLiteral"))
this.isRDFXMLLiteral = true;
return DataValueChecker.isValidValue( this, dt, value);
}
private boolean addValueChange() {
try {
isRDFXMLLiteral = false;
if (prop instanceof OWLDataProperty) {
// create datevalue from user-typed text
String val = newValueFld.getText();
OWLDataValue dVal = null;
if (!rangeBox.getModel().getElementAt(0).toString().equals("OWL Data Range")) {
// range is not data value range
OWLConcreteDataTypeImpl dt = (OWLConcreteDataTypeImpl) rangeBox.getSelectedValue();
URI datatypeURI = dt.getURI();
boolean valid = checkValidValue(dt, val);
if (valid) {
if (this.isRDFXMLLiteral) {
// //TODO AK: need to add parseType="Literal"
// currently escapeChars implemented below
}
// Evren: Do not use a language identifier becuase language identifiers can
// only be used with plain literals (but here we might have a different
// datatype) and also there is no need to assume that English is the default
// language.
dVal = swoopModel.getSelectedOntology().getOWLDataFactory().getOWLConcreteData(datatypeURI, null, val);
}
else {
return false;
}
}
else {
val = valueBox.getSelectedValue().toString();
String dType = val.substring(val.lastIndexOf("(")+1, val.length()-1);
//val = val.substring(0, val.lastIndexOf("(")).trim();
URI datatypeURI = new URI(dType);
// Evren: Do not use a language identifier becuase language identifiers can
// only be used with plain literals (but here we might have a different
// datatype) and also there is no need to assume that English is the default
// language.
dVal = swoopModel.getSelectedOntology().getOWLDataFactory().getOWLConcreteData(datatypeURI, null, val);
}
// create data property change
OWLIndividual dispInst = (OWLIndividual) swoopModel.getSelectedEntity();
AddDataPropertyInstance change = new AddDataPropertyInstance(swoopModel.getSelectedOntology(), dispInst, (OWLDataProperty) prop, dVal, null);
changes.add(change);
}
else {
// prop is an object property
Object[] individuals = null;
if ((newValueFld.getText()!=null) && (!newValueFld.getText().trim().equals(""))) {
// create new instance
String indID = newValueFld.getText();
// check for invalid chars in indID
indID = indID.replaceAll(" ","_");
if (indID.indexOf("#") < 0) {
indID = "#"+indID;
}
URI indURI = null;
if (!isURL(indID)) indURI =swoopModel.getSelectedOntology().getLogicalURI().resolve(indID);
else indURI = new URI(indID);
OWLIndividual ind = swoopModel.getSelectedOntology().getOWLDataFactory().getOWLIndividual(indURI);
individuals = new Object[] {ind};
OWLClass cla = (OWLClass) rangeBox.getSelectedValue();
AddIndividualClass change = new AddIndividualClass(swoopModel.getSelectedOntology(), ind, cla, null);
changes.add(change);
} else {
// get existing instance
individuals = valueBox.getSelectedValues();
}
// create object property instance
OWLIndividual dispInst = (OWLIndividual) swoopModel.getSelectedEntity();
for (int i = 0; i < individuals.length; i++) {
OWLIndividual ind = (OWLIndividual) individuals[i];
AddObjectPropertyInstance change = new AddObjectPropertyInstance(swoopModel.getSelectedOntology(), dispInst, (OWLObjectProperty) prop, ind, null);
changes.add(change);
// **************************************************
// Added for Econnections
// ***************************************************
if (prop instanceof OWLObjectProperty) {
if (((OWLObjectProperty) prop).isLink()) {
RemoveEntity oc2 = new RemoveEntity(swoopModel
.getSelectedOntology(), ind, null);
changes.add(oc2);
}
}
// *********************************
}
}
swoopModel.addUncommittedChanges(changes);
changes = new ArrayList(); // reset it after changes have been added
}
catch (Exception e) {
e.printStackTrace();
}
return true;
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == actionBar) {
if (AddCloseBar.ADD.equals(e.getActionCommand())) {
addValueChange();
}
if (AddCloseBar.ADDCLOSE.equals(e.getActionCommand())) {
if (addValueChange()) {
dispose();
}
}
if (AddCloseBar.CLOSE.equals(e.getActionCommand())) {
dispose();
}
}
if (e.getSource()==rangeBox) {
fillValueBox();
}
}
private void fillValueBox() {
Object selItem = rangeBox.getSelectedValue();
Set valueList = new TreeSet(EntityComparator.INSTANCE);
if (selItem instanceof OWLClass) {
OWLClass cla = (OWLClass) selItem;
// fill valueBox with existing instances of cla
try {
Set instSet = new HashSet();
if (!cla.getURI().toString().equals(OWLVocabularyAdapter.INSTANCE.getThing())) {
instSet = reasoner.instancesOf(cla);
// also get any enumerations of the class
Set enums = cla.getEnumerations(swoopModel.getSelectedOntology());
for (Iterator it = enums.iterator(); it.hasNext();) {
OWLEnumeration en = (OWLEnumeration) it.next();
instSet.addAll(en.getIndividuals());
}
}
else {
// add all individuals in the ontology for owl:Thing
instSet.addAll(swoopModel.getEntitySet(swoopModel.getSelectedOntology(), swoopModel.TRANSCLOSE_ONT, swoopModel.INDIVIDUALS));
}
Iterator iter = instSet.iterator();
while (iter.hasNext()) {
OWLIndividual ind = (OWLIndividual) iter.next();
valueList.add(ind);
}
valueBox.setFont(new Font(swoopModel.getFontFace(), Font.PLAIN, 11));
valueBox.setListData(valueList.toArray());
}
catch (OWLException ex) {
ex.printStackTrace();
}
}
}
private boolean isURL(String str) {
try {
URL url = new URL(str);
return true;
}
catch (Exception ex) {
ex.printStackTrace();
}
return false;
}
class RangeRenderer extends JLabel implements ListCellRenderer {
private SwoopModel swoopModel;
RangeRenderer(SwoopModel swoopModel) {
this.swoopModel = swoopModel;
}
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
try {
URI dispURI = null;
if (value instanceof OWLClass) {
OWLClass cla = (OWLClass) value;
dispURI = cla.getURI();
}
else if (value instanceof OWLConcreteDataTypeImpl) {
OWLConcreteDataTypeImpl dt = (OWLConcreteDataTypeImpl) value;
dispURI = dt.getURI();
}
else if (value instanceof OWLIndividual) {
OWLIndividual ind = (OWLIndividual) value;
dispURI = ind.getURI();
}
if (dispURI!=null) setText(swoopModel.shortForm(dispURI));
else setText(value.toString());
} catch (OWLException e) {
setText("Anonymous");
}
if (isSelected) {
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
} else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
setEnabled(list.isEnabled());
setFont(list.getFont());
setOpaque(true);
return this;
}
}
public void valueChanged(ListSelectionEvent e) {
if (e.getSource()==rangeBox) {
fillValueBox();
}
}
public void keyTyped(KeyEvent arg0) {
}
public void keyPressed(KeyEvent e) {
if (e.getSource()==rangeBox || e.getSource()==valueBox) {
String alpha = Character.toString(e.getKeyChar()).toLowerCase();
PopupCommon.listSelector(swoopModel, (JList) e.getSource(), alpha);
}
if (e.getSource()==newValueFld) {
if (e.getKeyCode()==10) {
addValueChange();
}
}
}
public void keyReleased(KeyEvent arg0) {
}
}