org.fcrepo.client.objecteditor.RDFTupleEditor Maven / Gradle / Ivy
/* The contents of this file are subject to the license and copyright terms
* detailed in the license directory at the root of the source tree (also
* available online at http://fedora-commons.org/license/).
*/
package org.fcrepo.client.objecteditor;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SpringLayout;
import javax.swing.SwingConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.table.AbstractTableModel;
import org.jrdf.graph.Literal;
import org.jrdf.graph.ObjectNode;
import org.jrdf.graph.Triple;
import org.trippi.RDFFormat;
import org.trippi.TripleIterator;
import org.trippi.io.TripleIteratorFactory;
import org.trippi.TrippiException;
import org.fcrepo.client.Administrator;
import org.fcrepo.common.Constants;
import org.fcrepo.common.PID;
import org.fcrepo.server.storage.types.RelationshipTuple;
import org.fcrepo.server.storage.types.TupleArrayTripleIterator;
import static org.fcrepo.common.Constants.MODEL;
/**
* An RDF editor/viewer.
*/
public class RDFTupleEditor
extends ContentEditor
implements DocumentListener, ActionListener, PropertyChangeListener, WindowListener {
/** This class handles the RDF MIME type. */
public static String[] s_types = new String[] {"application/rdf+xml"};
protected boolean m_dirty;
protected ActionListener m_dataChangeListener;
protected JTable m_editor;
protected JScrollPane m_scrollPane;
protected JPanel m_component;
protected RDFDataModel m_origContent;
protected RDFDataModel m_dataModel;
protected boolean m_isEditable;
protected JButton m_add;
protected JButton m_edit;
protected JButton m_delete;
protected String pid;
protected String dsid; // not used
protected HashMap m_map;
protected TripleIteratorFactory m_factory;
private static boolean s_registered = false;
public RDFTupleEditor() {
if (!s_registered) {
ContentHandlerFactory.register(this);
s_registered = true;
}
m_factory = new TripleIteratorFactory();
}
@Override
public String[] getTypes() {
return s_types;
}
@Override
public void setPIDAndDSID(String pid, String dsid) {
this.pid = pid;
this.dsid = dsid;
}
@Override
public void init(String type, InputStream data, boolean viewOnly)
throws IOException {
m_editor = new JTable() {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public void valueChanged(ListSelectionEvent e) {
super.valueChanged(e);
firePropertyChange("selection", e.getFirstIndex(), -1);
}
};
m_editor.setFont(new Font("monospaced", Font.PLAIN, 12));
setContent(data);
m_isEditable = !viewOnly;
m_scrollPane = new JScrollPane(m_editor);
m_component = new JPanel();
m_component.setLayout(new BorderLayout());
m_component.add(m_scrollPane, BorderLayout.CENTER);
m_editor.addPropertyChangeListener("selection", this);
m_map = new HashMap();
m_map.put(Constants.RELS_EXT.prefix, Constants.RELS_EXT.uri);
m_map.put(Constants.MODEL.prefix, Constants.MODEL.uri);
m_map.put(Constants.RDF.prefix, Constants.RDF.uri);
// Lay out the buttons from left to right.
if (!viewOnly) {
JPanel buttonPane = new JPanel();
buttonPane
.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
buttonPane
.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
buttonPane.add(Box.createHorizontalGlue());
buttonPane.add(m_add = MakeButton("Add...", this));
buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
buttonPane.add(m_edit = MakeButton("Edit...", this));
buttonPane.add(Box.createRigidArea(new Dimension(10, 0)));
buttonPane.add(m_delete = MakeButton("Delete", this));
buttonPane.add(Box.createHorizontalGlue());
m_edit.setEnabled(false);
m_delete.setEnabled(false);
m_component.add(buttonPane, BorderLayout.SOUTH);
}
}
static private JButton MakeButton(String label, ActionListener listener) {
JButton button = new JButton(label);
button.setActionCommand(label);
button.addActionListener(listener);
Administrator.constrainHeight(button);
return button;
}
@Override
public void setContent(InputStream data) throws IOException {
// get a string from the inputstream, assume it's UTF-8
m_dataModel = new RDFDataModel(data);
m_editor.setModel(m_dataModel);
if (m_origContent == null) {
m_origContent = m_dataModel.clone();
}
}
@Override
public JComponent getComponent() {
return m_component;
}
@Override
public void changesSaved() {
m_origContent = m_dataModel.clone();
dataChanged();
}
@Override
public void undoChanges() {
m_dataModel = m_origContent.clone();
m_editor.setModel(m_dataModel);
dataChanged();
}
@Override
public boolean isDirty() {
return !m_origContent.serializeAsString().equals(m_dataModel
.serializeAsString());
}
@Override
public void setContentChangeListener(ActionListener listener) {
m_dataChangeListener = listener;
}
@Override
public InputStream getContent() throws IOException {
return m_dataModel.serializeAsStream();
}
// Forward DocumentListener's events to the passed-in ActionListener
public void changedUpdate(DocumentEvent e) {
dataChanged();
}
public void insertUpdate(DocumentEvent e) {
dataChanged();
}
public void removeUpdate(DocumentEvent e) {
dataChanged();
}
private void dataChanged() {
if (m_dataChangeListener != null) {
m_dataChangeListener
.actionPerformed(new ActionEvent(this, 0, "dataChanged"));
}
m_editor.revalidate();
m_editor.repaint();
}
class RDFDataModel
extends AbstractTableModel {
/**
*
*/
private static final long serialVersionUID = 1L;
// Create columns names
String columnNames[] = {"Subject", "Predicate", "Object"};
ArrayList entries = null;
private RDFDataModel() {
} // only for use by clone
public RDFDataModel(InputStream data) {
TripleIterator iter;
try {
iter = m_factory.fromStream(data, RDFFormat.RDF_XML);
entries = new ArrayList();
for (int i = 0; iter.hasNext(); i++) {
Triple triple = iter.next();
String object = null;
boolean isLiteral = false;
URI typeURI = null;
ObjectNode oNode = triple.getObject();
if (oNode instanceof Literal) {
isLiteral = true;
typeURI = ((Literal) oNode).getDatatypeURI();
}
object = oNode.toString();
entries.add(new RelationshipTuple(triple.getSubject()
.toString(),
triple.getPredicate()
.toString(),
object,
isLiteral,
typeURI));
}
} catch (TrippiException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public RDFDataModel clone() {
RDFDataModel clone = new RDFDataModel();
clone.entries = (ArrayList) entries.clone();
return clone;
}
public void deleteRow(int i) {
entries.remove(i);
dataChanged();
}
public void addRow(String subject,
String predicate,
String object,
boolean isLiteral,
URI datatype) {
entries.add(new RelationshipTuple(subject,
predicate,
object,
isLiteral,
datatype));
dataChanged();
}
public void replaceRow(int selectedRow,
String subject,
String predicate,
String object,
boolean isLiteral,
URI datatype) {
entries.set(selectedRow, new RelationshipTuple(subject,
predicate,
object,
isLiteral,
datatype));
dataChanged();
}
public InputStream serializeAsStream() {
TupleArrayTripleIterator iter =
new TupleArrayTripleIterator(entries);
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
iter.toStream(os, RDFFormat.RDF_XML, false);
} catch (TrippiException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ByteArrayInputStream is =
new ByteArrayInputStream(os.toByteArray());
return is;
}
public String serializeAsString() {
TupleArrayTripleIterator iter =
new TupleArrayTripleIterator(entries);
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
iter.toStream(os, RDFFormat.RDF_XML, false);
} catch (TrippiException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String results = new String(os.toByteArray());
return results;
}
public Object getValueAt(int iRowIndex, int iColumnIndex) {
RelationshipTuple tuple = entries.get(iRowIndex);
switch (iColumnIndex) {
case 0:
return tuple.subject;
case 1:
return tuple.getRelationship();
case 2:
if (tuple.isLiteral) {
if (tuple.datatype == null) {
return String.format("\"%s\"", tuple.object);
} else {
String trimmedDataType = tuple.datatype.toString();
if (trimmedDataType.startsWith(Constants.XML_XSD.uri
+ "#")) {
trimmedDataType =
trimmedDataType
.substring(Constants.XML_XSD.uri
.length() + 1);
}
return String.format("\"%s\"^^<%s>",
tuple.object,
trimmedDataType);
}
} else {
return tuple.object;
}
}
return "";
}
@Override
public void setValueAt(Object aValue, int iRowIndex, int iColumnIndex) {
}
public int getColumnCount() {
return 3;
}
@Override
public String getColumnName(int i) {
return columnNames[i];
}
public int getRowCount() {
return entries.size();
}
}
public void propertyChange(PropertyChangeEvent arg0) {
boolean rowSelected = m_editor.getSelectedRow() >= 0;
m_edit.setEnabled(rowSelected);
m_delete.setEnabled(rowSelected);
}
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Add...")) {
TripleEditDialog dialog = new TripleEditDialog(null, m_map);
dialog.setVisible(true);
if (!dialog.isCancelled()) {
String subject = dialog.getSubject();
String predicate = dialog.getPredicate();
String objectURI = dialog.getObjectURI();
boolean literalValue = dialog.getIsLiteral();
URI literalType = dialog.getLiteralType();
m_dataModel.addRow(subject,
predicate,
objectURI,
literalValue,
literalType);
}
dialog = null;
} else if (e.getActionCommand().equals("Edit...")) {
if (m_editor.getSelectedRow() != -1) {
TripleEditDialog dialog =
new TripleEditDialog(m_dataModel.entries.get(m_editor
.getSelectedRow()), m_map);
dialog.setVisible(true);
if (!dialog.isCancelled()) {
String subject = dialog.getSubject();
String predicate = dialog.getPredicate();
String objectURI = dialog.getObjectURI();
boolean literalValue = dialog.getIsLiteral();
URI literalType = dialog.getLiteralType();
m_dataModel.replaceRow(m_editor.getSelectedRow(),
subject,
predicate,
objectURI,
literalValue,
literalType);
}
dialog = null;
}
} else if (e.getActionCommand().equals("Delete")) {
if (m_editor.getSelectedRow() != -1) {
m_dataModel.deleteRow(m_editor.getSelectedRow());
}
}
}
class TripleEditDialog
extends JDialog
implements ActionListener, DocumentListener {
/**
*
*/
private static final long serialVersionUID = 1L;
private JTextField m_subject;
private final JComboBox m_predicate;
private JTextField m_objectURI;
private JCheckBox m_isLiteral;
private JComboBox m_literalType;
private JLabel lab1, lab2, lab3, lab4, lab5;
private boolean cancelled = true;
public TripleEditDialog(RelationshipTuple tuple,
HashMap map) {
super(Administrator.getInstance(),
tuple == null ? "Enter Relationship" : "Edit Relationship",
true);
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new SpringLayout());
mainPanel.add(lab1 = new JLabel("Subject:", SwingConstants.RIGHT));
mainPanel.add(m_subject =
new JTextField(tuple != null ? tuple.subject : PID
.toURI(pid)));
m_subject.setBackground(Administrator.BACKGROUND_COLOR);
m_subject.setEditable(false);
mainPanel
.add(lab2 = new JLabel("Predicate:", SwingConstants.RIGHT));
String rels[] =
{"",
MODEL.HAS_MODEL.toString(),
MODEL.HAS_SERVICE.toString(),
MODEL.IS_CONTRACTOR_OF.toString(),
MODEL.IS_DEPLOYMENT_OF.toString(),
Constants.RELS_EXT.IS_MEMBER_OF.toString()};
m_predicate = new JComboBox(rels);
m_predicate.setEditable(true);
Administrator.constrainHeight(m_predicate);
mainPanel.add(m_predicate);
mainPanel.add(lab3 = new JLabel("Object:", SwingConstants.RIGHT));
mainPanel.add(m_objectURI = new JTextField(""));
m_objectURI.getDocument().addDocumentListener(this);
mainPanel
.add(lab4 = new JLabel("isLiteral:", SwingConstants.RIGHT));
mainPanel.add(m_isLiteral = new JCheckBox());
m_isLiteral.setSelected(false);
m_isLiteral.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
updateFields();
// setVisible(false);
}
});
mainPanel.add(lab5 =
new JLabel(" Type:", SwingConstants.RIGHT));
String types[] =
{"", "long", "int", "float", "double", "dateTime"};
mainPanel.add(m_literalType = new JComboBox(types));
m_literalType.setEditable(false);
Administrator.constrainHeight(m_literalType);
lab3.setLabelFor(m_objectURI);
lab4.setLabelFor(m_isLiteral);
lab5.setLabelFor(m_literalType);
// Lay out the panel.
SpringUtilities.makeCompactGrid(mainPanel, 5, 2, // rows, cols
6,
6, // initX, initY
6,
6); // xPad, yPad
getContentPane().setLayout(new BorderLayout());
getContentPane().add(mainPanel, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
JButton save;
buttonPanel.add(save = MakeButton("OK", this));
save.setDefaultCapable(true);
getRootPane().setDefaultButton(save);
buttonPanel.add(MakeButton("Cancel", this));
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
if (tuple != null) {
m_subject.setText(tuple.subject);
m_predicate.setSelectedItem(tuple.getRelationship());
m_objectURI.setText(tuple.object == null ? "" : tuple.object);
m_isLiteral.setSelected(tuple.isLiteral);
String trimmedDataType = tuple.datatype == null ? "" : tuple.datatype.toString();
if (trimmedDataType.startsWith(Constants.XML_XSD.uri
+ "#")) {
trimmedDataType =
trimmedDataType.substring(Constants.XML_XSD.uri
.length() + 1);
}
m_literalType.setSelectedItem(trimmedDataType);
if (m_isLiteral.isSelected()) {
m_literalType.setEnabled(true);
} else {
m_literalType.setEnabled(false);
}
}
validate();
pack();
setLocationRelativeTo(Administrator.getInstance());
}
public void actionPerformed(ActionEvent arg0) {
if (arg0.getActionCommand().equals("OK")) {
String msg = "predicate";
try {
URI uriSub = new URI(m_subject.getText());
RelationshipTuple
.makePredicateResourceFromRel(getPredicate(), m_map);
msg = "object";
RelationshipTuple
.makeObjectFromURIandLiteral(getObjectURI(),
getIsLiteral(),
getLiteralType(),
null);
} catch (URISyntaxException e) {
JOptionPane.showMessageDialog(this,
"Error: Invalid URI in "
+ msg);
return;
} catch (IllegalArgumentException e) {
JOptionPane.showMessageDialog(this,
"Error: Invalid URI in "
+ msg);
return;
}
cancelled = false;
setVisible(false);
}
if (arg0.getActionCommand().equals("Cancel")) {
cancelled = true;
setVisible(false);
}
}
public void insertUpdate(DocumentEvent arg0) {
updateFields();
}
public void removeUpdate(DocumentEvent arg0) {
updateFields();
}
public void changedUpdate(DocumentEvent arg0) {
updateFields();
}
public void updateFields() {
if (m_isLiteral.isSelected()) {
m_literalType.setEnabled(true);
} else {
m_literalType.setEnabled(false);
}
}
public boolean isCancelled() {
return cancelled;
}
public URI getLiteralType() {
if (!getIsLiteral()) {
return null;
}
if (m_literalType.getSelectedItem().toString().equals("")) {
return null;
}
URI result = null;
String litType = m_literalType.getSelectedItem().toString();
if (litType.length() == 0) return null;
try {
if (litType.startsWith(Constants.XML_XSD.uri)) {
result = new URI(litType);
} else {
result = new URI(Constants.XML_XSD.uri + "#" + litType);
}
} catch (URISyntaxException e) {} // won't happen
return result;
}
public boolean getIsLiteral() {
return m_isLiteral.isSelected();
}
public String getObjectURI() {
if (m_objectURI.getText().length() == 0) {
return null;
}
return m_objectURI.getText();
}
public String getPredicate() {
String predicate = m_predicate.getSelectedItem().toString();
if (predicate.startsWith(Constants.RELS_EXT.prefix)) {
predicate =
Constants.RELS_EXT.uri
+ predicate.substring(Constants.RELS_EXT.prefix
.length() + 1);
} else if (predicate.startsWith(Constants.MODEL.prefix)) {
predicate =
Constants.MODEL.uri
+ predicate.substring(Constants.MODEL.prefix
.length() + 1);
}
return predicate;
}
public String getSubject() {
return m_subject.getText();
}
}
@Override
public void windowActivated(WindowEvent e) {
}
@Override
public void windowClosed(WindowEvent e) {
}
@Override
public void windowClosing(WindowEvent e) {
m_factory.shutdown();
}
@Override
public void windowDeactivated(WindowEvent e) {
}
@Override
public void windowDeiconified(WindowEvent e) {
}
@Override
public void windowIconified(WindowEvent e) {
}
@Override
public void windowOpened(WindowEvent e) {
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy