package edu.ysu.itrace.solvers; import java.awt.Dimension; import java.awt.Toolkit; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import javax.swing.BoxLayout; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.UIManager; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.e4.core.services.events.IEventBroker; import org.eclipse.ui.PlatformUI; import org.osgi.service.event.Event; import org.osgi.service.event.EventHandler; import edu.ysu.itrace.AstManager.SourceCodeEntity; import edu.ysu.itrace.SOManager.StackOverflowEntity; import edu.ysu.itrace.BRManager.BugReportEntity; import edu.ysu.itrace.gaze.IGazeResponse; import edu.ysu.itrace.gaze.IStackOverflowGazeResponse; import edu.ysu.itrace.gaze.IBugReportGazeResponse; import edu.ysu.itrace.gaze.IStyledTextGazeResponse; /** * Solver that simply dumps gaze data to disk in XML format. */ public class XMLGazeExportSolver implements IFileExportSolver, EventHandler { private static final String EOL = System.getProperty("line.separator"); private XMLOutputFactory outFactory = XMLOutputFactory.newInstance(); private XMLStreamWriter responseWriter; private File outFile; private String filename = "gaze-responses-USERNAME" + "-yyMMddTHHmmss-SSSS-Z.xml"; private Dimension screenRect; private String sessionID; private IEventBroker eventBroker; public XMLGazeExportSolver() { UIManager.put("swing.boldMetal", new Boolean(false)); //make UI font plain eventBroker = PlatformUI.getWorkbench().getService(IEventBroker.class); //eventBroker.subscribe("iTrace/newdata", this); } @Override public void init() { screenRect = Toolkit.getDefaultToolkit().getScreenSize(); try { outFile = new File(getFilename()); // Check that file does not already exist. If it does, do not begin // tracking. if (outFile.exists()) { System.out.println(friendlyName()); System.out.println("You cannot overwrite this file. If you " + "wish to continue, delete the file " + "manually."); return; } responseWriter = outFactory.createXMLStreamWriter(new FileOutputStream(outFile), "UTF-8"); } catch (IOException e) { throw new RuntimeException("Log files could not be created: " + e.getMessage()); } catch (XMLStreamException e) { throw new RuntimeException("Log files could not be created: " + e.getMessage()); } System.out.println("Putting files at " + outFile.getAbsolutePath()); try { responseWriter.writeStartDocument("utf-8", "1.0"); responseWriter.writeCharacters(EOL); responseWriter.writeStartElement("itrace-records"); responseWriter.writeCharacters(EOL); responseWriter.writeStartElement("environment"); responseWriter.writeCharacters(EOL); responseWriter.writeEmptyElement("screen-size"); responseWriter.writeAttribute("width", String.valueOf(screenRect.width)); responseWriter.writeAttribute("height", String.valueOf(screenRect.height)); responseWriter.writeCharacters(EOL); responseWriter.writeEndElement(); responseWriter.writeCharacters(EOL); responseWriter.writeStartElement("gazes"); responseWriter.writeCharacters(EOL); } catch (Exception e) { throw new RuntimeException("Log file header could not be written: " + e.getMessage()); } } @Override public void process(IGazeResponse response) { try { int screenX = (int) (screenRect.width * response.getGaze().getX()); int screenY = (int) (screenRect.height * response.getGaze().getY()); responseWriter.writeStartElement("response"); responseWriter.writeAttribute("name", response.getName()); responseWriter.writeAttribute("type", response.getGazeType()); responseWriter.writeAttribute("x", String.valueOf(screenX)); responseWriter.writeAttribute("y", String.valueOf(screenY)); responseWriter.writeAttribute("left_validation", String.valueOf(response.getGaze().getLeftValidity())); responseWriter.writeAttribute("right_validation", String.valueOf(response.getGaze().getRightValidity())); responseWriter.writeAttribute("left_pupil_diameter", String.valueOf(response.getGaze() .getLeftPupilDiameter())); responseWriter.writeAttribute("right_pupil_diameter", String.valueOf(response.getGaze() .getRightPupilDiameter())); responseWriter.writeAttribute( "timestamp", String.valueOf(response.getGaze().getTimestamp())); responseWriter.writeAttribute( "session_time", String.valueOf(response.getGaze().getSessionTime())); responseWriter.writeAttribute( "tracker_time", String.valueOf(response.getGaze().getTrackerTime())); responseWriter.writeAttribute( "system_time", String.valueOf(response.getGaze().getSystemTime())); responseWriter.writeAttribute( "nano_time", String.valueOf(response.getGaze().getNanoTime())); if (response instanceof IStyledTextGazeResponse) { IStyledTextGazeResponse styledResponse = (IStyledTextGazeResponse) response; responseWriter.writeAttribute("path", styledResponse.getPath()); responseWriter.writeAttribute("line_height", String.valueOf(styledResponse.getLineHeight())); responseWriter.writeAttribute("font_height", String.valueOf(styledResponse.getFontHeight())); responseWriter.writeAttribute("line", String.valueOf(styledResponse.getLine())); responseWriter.writeAttribute("col", String.valueOf(styledResponse.getCol())); responseWriter.writeAttribute("line_base_x", String.valueOf(styledResponse.getLineBaseX())); responseWriter.writeAttribute("line_base_y", String.valueOf(styledResponse.getLineBaseY())); responseWriter.writeStartElement("sces"); for (SourceCodeEntity sce : styledResponse.getSCEs()) { responseWriter.writeStartElement("sce"); responseWriter.writeAttribute("name", sce.getName()); responseWriter.writeAttribute("type", sce.type.toString()); responseWriter.writeAttribute("how", sce.how.toString()); responseWriter.writeAttribute("total_length", String.valueOf(sce.totalLength)); responseWriter.writeAttribute("start_line", String.valueOf(sce.startLine)); responseWriter.writeAttribute("end_line", String.valueOf(sce.endLine)); responseWriter.writeAttribute("start_col", String.valueOf(sce.startCol)); responseWriter.writeAttribute("end_col", String.valueOf(sce.endCol)); responseWriter.writeEndElement(); } responseWriter.writeEndElement(); } else if (response instanceof IStackOverflowGazeResponse) { IStackOverflowGazeResponse stackOverflowResponse = (IStackOverflowGazeResponse) response; StackOverflowEntity soe = stackOverflowResponse.getSOE(); responseWriter.writeAttribute("url", stackOverflowResponse.getURL()); responseWriter.writeAttribute("Id", stackOverflowResponse.getID()); responseWriter.writeStartElement("soe"); responseWriter.writeAttribute("part", soe.part.toString()); responseWriter.writeAttribute("part_number", String.valueOf(soe.partNum)); responseWriter.writeAttribute("type", soe.type.toString()); responseWriter.writeAttribute("type_number", String.valueOf(soe.typeNum)); responseWriter.writeEndElement(); } else if (response instanceof IBugReportGazeResponse) { IBugReportGazeResponse bugReportResponse = (IBugReportGazeResponse) response; BugReportEntity bre = bugReportResponse.getBRE(); responseWriter.writeAttribute("url", bugReportResponse.getURL()); responseWriter.writeAttribute("Id", bugReportResponse.getID()); responseWriter.writeStartElement("bre"); responseWriter.writeAttribute("part", bre.part.toString()); responseWriter.writeAttribute("part_number", String.valueOf(bre.partNum)); responseWriter.writeAttribute("type", bre.type.toString()); responseWriter.writeAttribute("type_number", String.valueOf(bre.typeNum)); responseWriter.writeEndElement(); } else { //ignore anything else } responseWriter.writeEndElement(); responseWriter.writeCharacters(EOL); } catch (XMLStreamException e) { // ignore write errors } } @Override public void dispose() { try { responseWriter.writeEndElement(); responseWriter.writeCharacters(EOL); responseWriter.writeEndElement(); responseWriter.writeCharacters(EOL); responseWriter.writeEndDocument(); responseWriter.writeCharacters(EOL); responseWriter.flush(); responseWriter.close(); System.out.println("Gaze responses saved."); } catch (XMLStreamException e) { throw new RuntimeException("Log file footer could not be written: " + e.getMessage()); } outFile = null; } @Override public void config(String sessionID, String devUsername) { filename = "gaze-responses-" + devUsername + "-" + sessionID + ".xml"; this.sessionID = sessionID; } @Override public String getFilename() { String workspaceLocation = ResourcesPlugin.getWorkspace().getRoot().getLocation() .toString(); return workspaceLocation + "/" + sessionID + "/" + filename; } @Override public String friendlyName() { return "XML Gaze Export"; } @Override public void displayExportFile() { JTextField displayVal = new JTextField(filename); displayVal.setEditable(false); JPanel displayPanel = new JPanel(); displayPanel.setLayout(new BoxLayout(displayPanel, BoxLayout.Y_AXIS)); //vertically align displayPanel.add(new JLabel("Export Filename")); displayPanel.add(displayVal); displayPanel.setPreferredSize(new Dimension(400,40)); //resize appropriately final int displayDialog = JOptionPane.showConfirmDialog(null, displayPanel, friendlyName() + " Display", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); if (displayDialog == JOptionPane.OK_OPTION) { //do nothing } } @Override public void handleEvent(Event event) { if(outFile == null) this.init(); String[] propertyNames = event.getPropertyNames(); IGazeResponse response = (IGazeResponse)event.getProperty(propertyNames[0]); this.process(response); } }