package org.mindswap.swoop.popup;
import java.awt.BorderLayout;
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.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.InputVerifier;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextField;
import javax.swing.ListModel;
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.CellRenderer;
import org.mindswap.swoop.renderer.SwoopCellRenderer;
import org.mindswap.swoop.utils.change.EnumElementChange;
import org.mindswap.swoop.utils.ui.EntityComparator;
import org.mindswap.swoop.utils.ui.OntologyComparator;
import org.semanticweb.owl.model.OWLClass;
import org.semanticweb.owl.model.OWLDataProperty;
import org.semanticweb.owl.model.OWLDescription;
import org.semanticweb.owl.model.OWLDifferentIndividualsAxiom;
import org.semanticweb.owl.model.OWLEntity;
import org.semanticweb.owl.model.OWLEquivalentPropertiesAxiom;
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.OWLSameIndividualsAxiom;
import org.semanticweb.owl.model.change.AddDomain;
import org.semanticweb.owl.model.change.AddEntity;
import org.semanticweb.owl.model.change.AddForeignEntity;
import org.semanticweb.owl.model.change.AddIndividualAxiom;
import org.semanticweb.owl.model.change.AddIndividualClass;
import org.semanticweb.owl.model.change.AddInverse;
import org.semanticweb.owl.model.change.AddObjectPropertyRange;
import org.semanticweb.owl.model.change.AddPropertyAxiom;
import org.semanticweb.owl.model.change.AddSuperProperty;
import org.semanticweb.owl.model.change.ChangeVisitor;
import org.semanticweb.owl.model.change.OntologyChange;
import org.semanticweb.owl.model.change.RemoveEntity;
/**
* @author Aditya Kalyanpur
* This class pops up whenever the user needs to specify an OWL Individual
* in an Ontology Change (For example: adding a sameAs or differentFrom axiom)
*/
public class PopupAddIndividual extends JFrame implements ActionListener, ListSelectionListener, KeyListener {
SwoopReasoner reasoner;
SwoopModel swoopModel;
public List changes;
String type;
int typeIntCode;
Font tahoma = new Font("Tahoma", Font.PLAIN, 11);
Font tahomaB = new Font("Tahoma", Font.BOLD, 10);
JButton applyBtn, addIndBtn, cancelBtn;
JList ontList, indList;
JTextField newIndFld;
public PopupAddIndividual(SwoopReasoner reas, String type, SwoopModel swoopModel) {
// setModal(true);
this.reasoner = reas;
this.type = getFullType(type);
this.swoopModel = swoopModel;
changes = new ArrayList();
setupUI();
}
/**
* Get the full type of the property-related-change
* given its abbreviated type code
* @param type - code for the change type
* @return
*/
private String getFullType(String type) {
// get full string type from type code
if (type.equals("SAM")) { typeIntCode = 0; return "SAME-AS INDIVIDUAL"; }
if (type.equals("DIF")) { typeIntCode = 1; return "DIFFERENT-FROM INDIVIDUAL"; }
if (type.equals("ONE")) { typeIntCode = 2; return "ONE-OF"; }
if (type.equals("INS")) { typeIntCode = 3; return "NEW INDIVIDUAL"; }
return "";
}
private void setupUI() {
JPanel tab1 = new JPanel();
tab1.setLayout(new BorderLayout());
ontList = new JList();
ontList.setFont(tahoma);
ontList.setCellRenderer(new CellRenderer());
indList = new JList();
indList.setFont(tahoma);
indList.setCellRenderer(new SwoopCellRenderer(swoopModel));
indList.addKeyListener(this);
applyBtn = new JButton("Add");
applyBtn.setFont(tahoma);
applyBtn.addActionListener(this);
addIndBtn = new JButton("Add & Close");
addIndBtn.setFont(tahoma);
addIndBtn.addActionListener(this);
JLabel ontLbl = new JLabel("Select Ontology:");
ontLbl.setFont(tahoma);
JLabel propLbl = new JLabel("Select Individual:");
propLbl.setFont(tahoma);
JPanel tab1W = new JPanel();
tab1W.setLayout(new BorderLayout());
tab1W.add(ontLbl, "North");
tab1W.add(new JScrollPane(ontList), "Center");
JPanel tab1E = new JPanel();
tab1E.setLayout(new BorderLayout());
tab1E.add(propLbl, "North");
tab1E.add(new JScrollPane(indList), "Center");
JSplitPane tab1Split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
tab1Split.setOneTouchExpandable(true);
tab1Split.setLeftComponent(tab1W);
tab1Split.setRightComponent(tab1E);
JPanel btnPanel = new JPanel();
btnPanel.setLayout(new GridLayout(1,3));
btnPanel.add(applyBtn);
btnPanel.add(addIndBtn);
cancelBtn = new JButton("Cancel");
cancelBtn.setFont(tahoma);
cancelBtn.addActionListener(this);
btnPanel.add(cancelBtn);
newIndFld = new JTextField();
newIndFld.setFont(tahoma);
newIndFld.addKeyListener(this);
JPanel newPanel = new JPanel();
newPanel.setLayout(new BorderLayout());
JLabel newLbl = new JLabel("OR Specify New Term/URI: ");
newLbl.setFont(tahoma);
JPanel newLblPanel = new JPanel();
newLblPanel.setLayout(new BorderLayout());
newLblPanel.add(newLbl, "West");
newPanel.add(newLblPanel, "West");
newPanel.add(newIndFld, "Center");
JPanel tab1P = new JPanel();
tab1P.setLayout(new BorderLayout());
tab1P.add(tab1Split, "Center");
tab1P.add(newPanel, "South");
tab1.add(tab1P, "Center");
tab1.add(btnPanel, "South");
fillValues();
// add tabbed pane to frame container
Container content = getContentPane();
content.setLayout(new BorderLayout());
JLabel typeLbl = new JLabel("[ ADDING "+type+".. ]");
typeLbl.setFont(tahoma);
content.add(typeLbl, "North");
content.add(tab1, "Center");
setSize(450,300);
setTitle("Specify Individual");
setResizable(true);
}
/**
* Fill the ontology combo-box with all the ontologies present in the SwoopModel
* Choosing a different ontology here causes a change in the property list
* i.e. fillPropBox()
*/
private void fillValues() {
Set sortedOntSet = new TreeSet(OntologyComparator.INSTANCE);
sortedOntSet.addAll(swoopModel.getOntologyURIs());
ontList.setFont(new Font(swoopModel.getFontFace(), Font.PLAIN, 11));
ontList.setListData(sortedOntSet.toArray());
// turn on listeners
ontList.addListSelectionListener(this);
// select current displayed ontology
try {
URI currOntURI = swoopModel.getSelectedOntology().getURI();
ontList.setSelectedValue(currOntURI, true);
}
catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* Method called when the user presses the add/apply individual change btn
* It gets the individual selected and passes it to makeChange(..)
*/
private boolean addIndividualChange() {
try {
OWLIndividual ind = null;
if ((newIndFld.getText()!=null) && (!newIndFld.getText().trim().equals(""))) {
// user-specified property name/uri
String indStr = newIndFld.getText();
indStr = indStr.replaceAll(" ","_");
URI ontURI = swoopModel.getSelectedOntology().getLogicalURI();
URI indURI = null;
if (isFragmentable(indStr)) {
String scheme = ontURI.getScheme();
String ssp = ontURI.getSchemeSpecificPart();
indURI = new URI(scheme, ssp, indStr);
} else {
indURI = ontURI.resolve(new URI(indStr));
}
// **create new individual
ind = swoopModel.getSelectedOntology().getOWLDataFactory().getOWLIndividual(indURI);
makeChange(ind);
}
else {
// get existing individual
Object[] inds = (Object[]) indList.getSelectedValues();
for (int i=0; i<inds.length; i++) {
ind = (OWLIndividual) inds[i];
makeChange(ind);
}
}
swoopModel.addUncommittedChanges(changes);
changes = new ArrayList(); // reset it after changes have been added
}
catch (URISyntaxException ex) {
JOptionPane.showMessageDialog(this, "Invalid URI!:\n"+ex, "Warning",
JOptionPane.ERROR_MESSAGE);
ex.printStackTrace();
return false;
}
catch (OWLException ex) {
JOptionPane.showMessageDialog(this, "Could not create OWL Individual:\n"+ex, "Warning",
JOptionPane.ERROR_MESSAGE);
ex.printStackTrace();
return false;
}
return true;
}
/**
* Creates the Individual related Ontology Change based on the
* currently selected ontology, entity and the OWL Individual passed to it
* @param ind - object (OWL Property) of the ontology change
*/
private void makeChange(OWLIndividual ind) {
OntologyChange change = null;
OWLOntology dispOnt = swoopModel.getSelectedOntology();
switch (typeIntCode) {
case 0: // add sameAs
Set sameSet = new HashSet();
sameSet.add((OWLIndividual) swoopModel.getSelectedEntity());
sameSet.add(ind);
try {
OWLSameIndividualsAxiom indAxiom = dispOnt.getOWLDataFactory().getOWLSameIndividualsAxiom(sameSet);
change = new AddIndividualAxiom(dispOnt, indAxiom, null);
changes.add(change);
}
catch (OWLException e) {
e.printStackTrace();
}
break;
case 1: // add differentFrom
Set diffSet = new HashSet();
diffSet.add((OWLIndividual) swoopModel.getSelectedEntity());
diffSet.add(ind);
try {
OWLDifferentIndividualsAxiom indAxiom = dispOnt.getOWLDataFactory().getOWLDifferentIndividualsAxiom(diffSet);
change = new AddIndividualAxiom(dispOnt, indAxiom, null);
changes.add(change);
}
catch (OWLException e) {
e.printStackTrace();
}
break;
case 2: // add owl:oneOf
change = new EnumElementChange("Add", dispOnt, (OWLClass) swoopModel.getSelectedEntity(), ind, null);
changes.add(change);
break;
case 3: // add new individual
change = new AddIndividualClass(dispOnt, ind, (OWLClass) swoopModel.getSelectedEntity(), null);
changes.add(change);
break;
}
}
/**
* Returns true if the string can be used as the fragment of a URI (post #).
* @param str
* @return
*/
private boolean isFragmentable(String str) {
if ((str.indexOf('#') >= 0) || (str.indexOf('/') >= 0)) {
// String contains path characters
return false;
}
try {
new URL(str);
// Valid URL
return false;
} catch (MalformedURLException ex) {}
return true;
}
public void actionPerformed(ActionEvent e) {
if (e.getSource()==addIndBtn) {
if (addIndividualChange()) {
dispose();
}
}
if (e.getSource()==applyBtn) {
addIndividualChange();
}
if (e.getSource()==cancelBtn) {
dispose();
}
}
/**
* Fill the individual box with all the OWL Individuals
* defined in the ontology selected by the user in the corresponding ont-combo box
*/
private void fillIndBox() {
try {
// fill individuals in IndBox based on selected ontology
URI ontURI = (URI) ontList.getSelectedValue();
OWLOntology currOnt = swoopModel.getOntology(ontURI);
Set indSet = new TreeSet(EntityComparator.INSTANCE);
indSet.addAll(currOnt.getIndividuals());
indList.setFont(new Font(swoopModel.getFontFace(), Font.PLAIN, 11));
indList.setListData(indSet.toArray());
}
catch (Exception ex) {
ex.printStackTrace();
}
}
public void valueChanged(ListSelectionEvent e) {
if (e.getSource()==ontList) {
fillIndBox();
}
}
public void keyTyped(KeyEvent arg0) {
}
public void keyPressed(KeyEvent e) {
if (e.getSource()==indList) {
String alpha = Character.toString(e.getKeyChar()).toLowerCase();
PopupCommon.listSelector(swoopModel, (JList) e.getSource(), alpha);
}
if (e.getSource()==newIndFld) {
if (e.getKeyCode()==10) {
applyBtn.doClick();
}
}
}
public void keyReleased(KeyEvent arg0) {
}
}