package org.mindswap.swoop.popup; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import java.io.File; import java.io.FileWriter; import java.io.StringReader; import java.io.StringWriter; import java.net.URI; import java.util.List; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JCheckBox; import javax.swing.JDialog; import javax.swing.JEditorPane; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.KeyStroke; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.UndoableEditEvent; import javax.swing.event.UndoableEditListener; import javax.swing.filechooser.FileFilter; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultHighlighter; import javax.swing.text.Document; import javax.swing.undo.CannotRedoException; import javax.swing.undo.CannotUndoException; import javax.swing.undo.UndoManager; import org.mindswap.swoop.SwoopFrame; import org.mindswap.swoop.SwoopModel; import org.mindswap.swoop.utils.owlapi.CorrectedRDFRenderer; import org.mindswap.swoop.utils.owlapi.diff.OWLDiff; import org.mindswap.swoop.utils.ui.ExceptionDialog; import org.mindswap.swoop.utils.ui.SwoopFileFilter; import org.semanticweb.owl.io.RendererException; import org.semanticweb.owl.model.OWLException; import org.semanticweb.owl.model.OWLOntology; import org.xngr.browser.editor.XmlEditorPane; import org.xngr.browser.properties.EditorProperties; /** * @author Aditya Kalyanpur * */ public class PopupOntologySource extends JFrame implements KeyListener, ActionListener, WindowListener, DocumentListener, MouseListener { EditorProperties props; SwoopFrame swoopHandler; SwoopModel swoopModel; public JEditorPane codePane; JMenuItem saveOnt, saveAsOnt, refreshOnt, findMenu, findNextMenu, findPreviousMenu; // JCheckBoxMenuItem autoRefreshClose; File ontFile = null; JFileChooser wrapChooser = new JFileChooser(); public String originalSrc; private OWLOntology originalOntology; boolean srcChanged = false; public String findMatch = ""; int currentMatch = 0, lastMatch = 0; protected UndoAction undoAction; protected RedoAction redoAction; UndoManager undo = new UndoManager(); public boolean matchCase = false; public boolean matchWord = true; public DefaultHighlighter dh; public DefaultHighlighter.DefaultHighlightPainter dhp = new DefaultHighlighter.DefaultHighlightPainter(Color.YELLOW); public int format; // use the same values as in the file filters: 0- RDF/XML, 1- AS , 2- Turtle int RDF_FORMAT = 0; int AS_FORMAT = 1; int TURTLE_FORMAT = 2; public String[] fileExt = { ".owl", ".txt",""}; JCheckBox caseChk; JCheckBox wordChk; public PopupOntologySource(SwoopFrame handler, SwoopModel model, int format) { this.swoopHandler = handler; this.swoopModel = model; this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); this.format = format; caseChk = new JCheckBox("Match Case"); wordChk = new JCheckBox("Match Whole Word"); caseChk.setSelected(false); wordChk.setSelected(false); setupUI(); setupMenu(); } public void displaySrcCode(OWLOntology ontology) { originalOntology = ontology; try { setTitle("View Source - "+ontology.getURI().toString()); } catch (OWLException e) { e.printStackTrace(); } StringWriter st = new StringWriter(); CorrectedRDFRenderer rdfRenderer = new CorrectedRDFRenderer(); org.semanticweb.owl.io.abstract_syntax.Renderer ASRenderer = new org.semanticweb.owl.io.abstract_syntax.Renderer(); String code = ""; try { switch (this.format) { case 0 : // source code in RDF rdfRenderer.renderOntology(ontology, st); code = st.toString(); break; case 1 : ASRenderer.renderOntology(ontology, st); code = st.toString(); break; case 2 : //TODO Turtle renderer break; } } catch (RendererException e) { e.printStackTrace(); } // codePane.setSelectionColor(Color.YELLOW); codePane.setText(code); codePane.setCaretPosition(0); originalSrc = codePane.getText(); codePane.getDocument().addUndoableEditListener(new MyUndoableEditListener()); codePane.getDocument().addDocumentListener(this); } private void setupUI() { codePane = new XmlEditorPane(); if (format!=RDF_FORMAT) { codePane = new JEditorPane(); codePane.setFont(new Font("Courier", Font.PLAIN, 13)); } codePane.setAutoscrolls(true); java.awt.Container content = getContentPane(); // create defaulthighlighter and associate with webPane dh = new DefaultHighlighter(); codePane.setHighlighter(dh); codePane.addMouseListener(this); content.setLayout(new BorderLayout()); content.add(new JScrollPane(codePane), "Center"); setLocation(10,10); setSize(800,600); this.addWindowListener(this); } private void setupMenu() { JMenuBar menuBar = new JMenuBar(); JMenu fileMenu = new JMenu("File"); menuBar.add(fileMenu); saveOnt = new JMenuItem("Save"); saveOnt.addActionListener(this); saveAsOnt = new JMenuItem("Save As.."); saveAsOnt.addActionListener(this); fileMenu.add(saveOnt); fileMenu.add(saveAsOnt); JMenuItem menuExit = new JMenuItem("Exit"); fileMenu.add(menuExit); menuExit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { dispose(); } }); JMenu editMenu = new JMenu("Edit"); menuBar.add(editMenu); findMenu = new JMenuItem("Find "); findMenu.addActionListener(this); findMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, ActionEvent.CTRL_MASK)); editMenu.add(findMenu); findPreviousMenu = new JMenuItem("Find Previous.."); findPreviousMenu.addActionListener(this); findPreviousMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_G, ActionEvent.CTRL_MASK)); editMenu.add(findPreviousMenu); findNextMenu = new JMenuItem("Find Next.."); findNextMenu.addActionListener(this); findNextMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_K, ActionEvent.CTRL_MASK)); editMenu.add(findNextMenu); editMenu.addSeparator(); undoAction = new UndoAction(); editMenu.add(undoAction); redoAction = new RedoAction(); editMenu.add(redoAction); JMenu refreshMenu = new JMenu("Update Model"); menuBar.add(refreshMenu); refreshOnt = new JMenuItem("Save State & Update Ontology in SWOOP"); refreshOnt.addActionListener(this); refreshOnt.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK)); // autoRefreshClose = new JCheckBoxMenuItem("Auto-Update Ontology upon Closing this Window"); // autoRefreshClose.setState(true); refreshMenu.add(refreshOnt); // refreshMenu.add(autoRefreshClose); setJMenuBar(menuBar); } private boolean updateOntology() { if (!srcChanged) { return true; } else { srcChanged = false; } try { URI baseURI = originalOntology.getURI(); StringReader originalReader = new StringReader(originalSrc); OWLOntology ontology = null; // = swoopModel.getSelectedOntology(); // add updated ontology StringReader updateReader = new StringReader(codePane.getText()); OWLOntology updatedOntology = null; System.out.println("originalReader: "+originalReader); System.out.println("baseURI: "+baseURI); switch (format) { case 0: ontology = swoopModel.loadOntologyInRDF(originalReader, baseURI); updatedOntology = swoopModel.loadOntologyInRDF(updateReader, baseURI); break; case 1: ontology = swoopModel.loadOntologyInAbstractSyntax(originalReader, baseURI); updatedOntology = swoopModel.loadOntologyInAbstractSyntax(updateReader, ontology.getURI()); break; } // restore old ontology, if exception loading new one if (updatedOntology==null) { JOptionPane.showMessageDialog(this, "Error parsing source code of Ontology.", "Parse Error", JOptionPane.ERROR_MESSAGE); // srcChanged = false; return false; } else { List changes = OWLDiff.getChanges(ontology, updatedOntology, originalOntology); swoopModel.addUncommittedChanges(changes); int result = JOptionPane.showConfirmDialog(this, "Ontology model updated successfully.\nApply changes now?", "Ontology Updated", JOptionPane.YES_NO_OPTION); if (result == JOptionPane.YES_OPTION) { swoopModel.applyOntologyChanges(); } } return true; } catch (Exception ex) { JDialog dialog = ExceptionDialog.createDialog(this, "Cannot parse ontology", ex); dialog.show(); ex.printStackTrace(); return false; } } public int findClosingParent(int start) { // TODO int balance = 0, i = 0; boolean seenFirst = false; String tmp=""; Document doc = codePane.getDocument(); try { tmp = doc.getText(start, doc.getLength()-start); } catch (BadLocationException e) { } while (true) { if (tmp.charAt(i)=='(') { balance++;seenFirst=true;} else if (tmp.charAt(i)==')') { balance--;seenFirst = true; } i++; if (balance==0 && seenFirst) break; if (i+start > doc.getLength()) { i = -1; break; } } if (i != -1) { codePane.select(start, start+i+1); } return start+i+1; } public String getEntityText(int startMatch, int endMatch) { Document doc = (Document) codePane.getDocument(); try { return doc.getText(startMatch, endMatch-startMatch); } catch (BadLocationException e) { return null; } } public int matchString(boolean forward, boolean showError) { // match the next occurence of originalSrc in codePane Document doc = (Document) codePane.getDocument(); if (forward) currentMatch++; else currentMatch--; try { boolean matchFound = false; while (currentMatch>=0 && currentMatch<(doc.getLength()-findMatch.length())) { String check = doc.getText(currentMatch, findMatch.length()); String prevChar = "_"; if (currentMatch>=1) prevChar = doc.getText(currentMatch-1, 1); String nextChar = "_"; if (currentMatch+findMatch.length()<doc.getLength()) nextChar = doc.getText(currentMatch+findMatch.length(), 1); int pcharValue = (int) prevChar.charAt(0); int ncharValue = (int) nextChar.charAt(0); boolean charsNotAlphabet = true; if (((ncharValue>=65 && ncharValue<=90) || (ncharValue>=97 && ncharValue<=122)) || ((pcharValue>=65 && pcharValue<=90) || (pcharValue>=97 && pcharValue<=122))) charsNotAlphabet = false; if (!matchCase) { check = check.toLowerCase(); findMatch = findMatch.toLowerCase(); } if ((matchWord && check.equals(findMatch) && charsNotAlphabet) || (!matchWord && check.indexOf(findMatch)>=0)) { matchFound = true; lastMatch = currentMatch; break; } if (forward) currentMatch++; else currentMatch--; } if (matchFound) { codePane.select(currentMatch, currentMatch+findMatch.length()); return currentMatch; } else { if (showError) JOptionPane.showMessageDialog(this, "No more matches found!", "Find Error", JOptionPane.ERROR_MESSAGE); currentMatch = lastMatch; } } catch (BadLocationException e) { e.printStackTrace(); } return -1; } public void actionPerformed(ActionEvent e) { if (e.getSource()==findMenu) { String findNewMatch = JOptionPane.showInputDialog( null, new Object[] { "Specify Search String:", caseChk, wordChk }, "Find", JOptionPane.PLAIN_MESSAGE ); if (findNewMatch!=null) { findMatch = findNewMatch; matchCase = caseChk.isSelected(); matchWord = wordChk.isSelected(); currentMatch = -1; matchString(true, true); } } if (e.getSource()==findPreviousMenu) { matchString(false, true); } if (e.getSource()==findNextMenu) { matchString(true, true); } if (e.getSource()==refreshOnt) { updateOntology(); } if (e.getSource()==saveOnt) { saveLocalOntology(); } if (e.getSource()==saveAsOnt) { ontFile = null; saveLocalOntology(); } } public void saveLocalOntology() { try { int returnVal; FileFilter[] filters = SwoopFileFilter.getOntologyFilters(); /* (*.swp, *.swo, *.owl, *.rdf, *.xml, ".txt) */ int mapFormatToFilterIndex[] = {1,4}; wrapChooser.setFileFilter(filters[mapFormatToFilterIndex[format]]); if(ontFile == null) { returnVal = wrapChooser.showSaveDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { ontFile = wrapChooser.getSelectedFile(); } else { // load cancelled return; } } if (ontFile != null) { wrapChooser.setSelectedFile(ontFile); FileWriter writer = new FileWriter(ontFile); writer.write(codePane.getText()); writer.close(); } System.out.println("Ontology saved successfully at "+ontFile.getPath().toString()); } catch (Exception ex) { ex.printStackTrace(); } } public void windowClosing(WindowEvent e) { boolean closeWindow = true; if (srcChanged) { int result = JOptionPane.showConfirmDialog(this, "Do you want to update the ontology in SWOOP?", "Update Model", JOptionPane.YES_NO_CANCEL_OPTION); if(result==JOptionPane.YES_OPTION) { closeWindow = updateOntology(); } else if (result==JOptionPane.CANCEL_OPTION) { closeWindow = false; } else { closeWindow = true; } } if (closeWindow) { dispose(); } } public void windowOpened(WindowEvent arg0) { } public void windowClosed(WindowEvent arg0) { } public void windowIconified(WindowEvent arg0) { } public void windowDeiconified(WindowEvent arg0) { } public void windowActivated(WindowEvent arg0) { } public void windowDeactivated(WindowEvent arg0) { } public void keyPressed(KeyEvent arg0) { } public void keyTyped(KeyEvent arg0) { } public void keyReleased(KeyEvent arg0) { } // This one listens for edits that can be undone. protected class MyUndoableEditListener implements UndoableEditListener { public void undoableEditHappened(UndoableEditEvent e) { //Remember the edit and update the menus. undo.addEdit(e.getEdit()); undoAction.updateUndoState(); redoAction.updateRedoState(); } } class UndoAction extends AbstractAction { public UndoAction() { super("Undo"); setEnabled(false); putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Z, ActionEvent.CTRL_MASK)); } public void actionPerformed(ActionEvent e) { try { undo.undo(); } catch (CannotUndoException ex) { System.out.println("Unable to undo: " + ex); ex.printStackTrace(); } updateUndoState(); redoAction.updateRedoState(); } protected void updateUndoState() { if (undo.canUndo()) { setEnabled(true); putValue(Action.NAME, undo.getUndoPresentationName()); putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Z, ActionEvent.CTRL_MASK)); } else { setEnabled(false); putValue(Action.NAME, "Undo"); putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Z, ActionEvent.CTRL_MASK)); } } } class RedoAction extends AbstractAction { public RedoAction() { super("Redo"); setEnabled(false); putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Y, ActionEvent.CTRL_MASK)); } public void actionPerformed(ActionEvent e) { try { undo.redo(); } catch (CannotRedoException ex) { System.out.println("Unable to redo: " + ex); ex.printStackTrace(); } updateRedoState(); undoAction.updateUndoState(); } protected void updateRedoState() { if (undo.canRedo()) { setEnabled(true); putValue(Action.NAME, undo.getRedoPresentationName()); putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Y, ActionEvent.CTRL_MASK)); } else { setEnabled(false); putValue(Action.NAME, "Redo"); putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Y, ActionEvent.CTRL_MASK)); } } } private void srcModified() { srcChanged = true; dh.removeAllHighlights(); } public void insertUpdate(DocumentEvent arg0) { srcModified(); } public void removeUpdate(DocumentEvent arg0) { srcModified(); } public void changedUpdate(DocumentEvent arg0) { srcModified(); } public void mouseClicked(MouseEvent e) { } public void mousePressed(MouseEvent e) { if (e.getSource()==codePane) dh.removeAllHighlights(); } public void mouseReleased(MouseEvent arg0) { } public void mouseEntered(MouseEvent arg0) { } public void mouseExited(MouseEvent arg0) { } }