package edu.ysu.itrace.solvers; import java.awt.Dimension; import java.awt.Toolkit; import java.io.File; import java.io.FileWriter; 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 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 com.google.gson.stream.JsonWriter; 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 JSON format. */ public class JSONGazeExportSolver implements IFileExportSolver, EventHandler { private JsonWriter responseWriter; private File outFile; private String filename = "gaze-responses-USERNAME" + "-yyMMddTHHmmss-SSSS-Z.json"; private Dimension screenRect; private String sessionID; private IEventBroker eventBroker; public JSONGazeExportSolver() { 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 = new JsonWriter(new FileWriter(outFile)); //responseWriter.setIndent(""); // to pretty print, use this one instead responseWriter.setIndent(" "); } catch (IOException e) { throw new RuntimeException("Log files could not be created: " + e.getMessage()); } System.out.println("Putting files at " + outFile.getAbsolutePath()); try { responseWriter.beginObject() .name("environment") .beginObject() .name("screen_size") .beginObject() .name("width") .value(screenRect.width) .name("height") .value(screenRect.height) .endObject() .endObject() .name("gazes") .beginArray(); } catch (IOException 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.beginObject() .name("name") .value(response.getName()) .name("type") .value(response.getGazeType()) .name("x") .value(screenX) .name("y") .value(screenY) .name("left_validation") .value(response.getGaze().getLeftValidity()) .name("right_validation") .value(response.getGaze().getRightValidity()) .name("left_pupil_diameter") .value(response.getGaze().getLeftPupilDiameter()) .name("right_pupil_diameter") .value(response.getGaze().getRightPupilDiameter()) .name("timestamp") .value(response.getGaze().getTimestamp()) .name("session_time") .value(response.getGaze().getSessionTime()) .name("tracker_time") .value(response.getGaze().getTrackerTime()) .name("system_time") .value(response.getGaze().getSystemTime()) .name("nano_time") .value(response.getGaze().getNanoTime()); if (response instanceof IStyledTextGazeResponse) { IStyledTextGazeResponse styledResponse = (IStyledTextGazeResponse) response; responseWriter.name("path") .value(styledResponse.getPath()) .name("line_height") .value(styledResponse.getLineHeight()) .name("font_height") .value(styledResponse.getFontHeight()) .name("line") .value(styledResponse.getLine()) .name("col") .value(styledResponse.getCol()) .name("line_base_x") .value(styledResponse.getLineBaseX()) .name("line_base_y") .value(styledResponse.getLineBaseY()) .name("sces") .beginArray(); for (SourceCodeEntity sce : styledResponse.getSCEs()) { responseWriter.beginObject() .name("name") .value(sce.getName()) .name("type") .value(sce.type.toString()) .name("how") .value(sce.how.toString()) .name("total_length") .value(sce.totalLength) .name("start_line") .value(sce.startLine) .name("end_line") .value(sce.endLine) .name("start_col") .value(sce.startCol) .name("end_col") .value(sce.endCol) .endObject(); } responseWriter.endArray(); } else if (response instanceof IStackOverflowGazeResponse) { IStackOverflowGazeResponse stackOverflowResponse = (IStackOverflowGazeResponse) response; StackOverflowEntity soe = stackOverflowResponse.getSOE(); responseWriter.name("url") .value(stackOverflowResponse.getURL()) .name("Id") .value(stackOverflowResponse.getID()) .name("soe") .beginObject() .name("part") .value(soe.part.toString()) .name("part_number") .value(soe.partNum) .name("type") .value(soe.type.toString()) .name("type_number") .value(soe.typeNum) .endObject(); } else if (response instanceof IBugReportGazeResponse) { IBugReportGazeResponse bugReportResponse = (IBugReportGazeResponse) response; BugReportEntity bre = bugReportResponse.getBRE(); responseWriter.name("url") .value(bugReportResponse.getURL()) .name("Id") .value(bugReportResponse.getID()) .name("bre") .beginObject() .name("part") .value(bre.part.toString()) .name("part_number") .value(bre.partNum) .name("type") .value(bre.type.toString()) .name("type_number") .value(bre.typeNum) .endObject(); } else { //ignore anything else } responseWriter.endObject(); } catch (IOException e) { // ignore write errors } } @Override public void dispose() { try { responseWriter.endArray() .endObject(); responseWriter.flush(); responseWriter.close(); System.out.println("Gaze responses saved."); } catch (IOException 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 + ".json"; this.sessionID = sessionID; } @Override public String getFilename() { String workspaceLocation = ResourcesPlugin.getWorkspace().getRoot().getLocation() .toString(); return workspaceLocation + "/" + sessionID + "/" + filename; } @Override public String friendlyName() { return "JSON 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); } }