diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 2a33e3f..cad082d 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -6,8 +6,11 @@
-
+
+
+
+
@@ -82,7 +85,7 @@
"ShowUsagesActions.previewPropertyKey": "true",
"WebServerToolWindowFactoryState": "false",
"git-widget-placeholder": "main",
- "last_opened_file_path": "C:/Users/Lenovo/IdeaProjects/DataStreamReceiver",
+ "last_opened_file_path": "C:/Users/Lenovo/IdeaProjects/CodeGRITS/build/distributions/CodeGRITS-0.2.0.zip",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
@@ -91,7 +94,7 @@
"project.structure.last.edited": "Libraries",
"project.structure.proportion": "0.0",
"project.structure.side.proportion": "0.0",
- "settings.editor.selected.configurable": "preferences.lookFeel",
+ "settings.editor.selected.configurable": "preferences.pluginManager",
"vue.rearranger.settings.migration": "true"
}
}
@@ -190,6 +193,13 @@
+
+
+
+
+
+
+
diff --git a/docs/faq.md b/docs/faq.md
index 18b59e0..958454f 100644
--- a/docs/faq.md
+++ b/docs/faq.md
@@ -28,4 +28,21 @@ See [Accommodating New Eye Trackers](developer.md#accommodating-new-eye-trackers
See [Accommodating New IDEs](developer.md#accommodating-new-ides).
-[//]: # (Update the answer for the efficiency and storage space of CodeGRITS later.)
\ No newline at end of file
+#### Q5. How efficient is the processing of raw eye gaze data?
+
+In CodeGRITS, the efficiency of the processing of gaze data is negligible. For each gaze, we calculate the average time
+from the timestamp in the raw data to the timestamp after all processing is complete. This processing primarily involves
+location mapping and upward traversal of the AST. The average delay is 4.32 ms, equating to delays of approximately
+12.98% for 30Hz, 25.96% for 60Hz, and 51.92% for 120Hz eye gaze data. With such
+a high sampling frequency, meaningful changes in the content of the code editor's page are extremely rare within this
+short time frame, which ensures the accuracy of gaze processing. Moreover, compared
+to [iTrace](https://www.i-trace.org/), our method of receiving data from the
+eye-tracking device is more efficient, ensuring that all sampled gazes are mapped without any loss.
+
+#### Q6. How much storage space does CodeGRITS require?
+
+Generally speaking, a high sample frequency generates a large amount of gaze data. To conserve storage space, we
+only perform upward traversal of the AST of the first gaze and record the hierarchy structure, and mark the rest
+as `same`. This approach significantly reduces storage space. In a previous debugging study, we set the eye-tracking
+device's sample frequency to 60Hz, and during the 20-minute experiment, the eye-tracking data amounted to only about
+40MB.
diff --git a/src/main/java/actions/StartStopTrackingAction.java b/src/main/java/actions/StartStopTrackingAction.java
index e792e88..6e625de 100644
--- a/src/main/java/actions/StartStopTrackingAction.java
+++ b/src/main/java/actions/StartStopTrackingAction.java
@@ -52,7 +52,7 @@ public void actionPerformed(@NotNull AnActionEvent e) {
return;
}
if (config.getEyeTrackerDevice() != 0 && !AvailabilityChecker.checkEyeTracker(config.getPythonInterpreter())) {
- JOptionPane.showMessageDialog(null, "Eye tracker not found. Please use mouse tracker instead.");
+ JOptionPane.showMessageDialog(null, "Eye tracker not found. Please configure the mouse simulation first.");
return;
}
}
diff --git a/src/main/java/component/AlertDialog.java b/src/main/java/component/AlertDialog.java
index 304de2a..e0f0ae6 100644
--- a/src/main/java/component/AlertDialog.java
+++ b/src/main/java/component/AlertDialog.java
@@ -36,12 +36,10 @@ public AlertDialog(String label, Icon icon) {
JLabel icon = new JLabel();
label.setIcon(this.icon);
- System.out.println(UIManager.getIcon("OptionPane.warningIcon").getIconHeight());
icon.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 5));
label.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
label.setAlignmentX(Component.CENTER_ALIGNMENT);
icon.setAlignmentX(Component.CENTER_ALIGNMENT);
-// dialogPanel.add(icon);
dialogPanel.add(label);
return dialogPanel;
diff --git a/src/main/java/component/ConfigDialog.java b/src/main/java/component/ConfigDialog.java
index e4ad650..6bb10a7 100644
--- a/src/main/java/component/ConfigDialog.java
+++ b/src/main/java/component/ConfigDialog.java
@@ -52,11 +52,17 @@ public ConfigDialog(Project project) throws IOException, InterruptedException {
setSize(500, 500);
setAutoAdjustable(true);
setResizable(false);
- if (new File("config.json").exists()) {
- loadConfig();
+ Config config = new Config();
+ if (config.configExists()) {
+ config.loadFromJson();
+ List selected = config.getCheckBoxes();
+ for (int i = 0; i < selected.size(); i++) {
+ checkBoxes.get(i).setSelected(selected.get(i));
+ }
+ pythonInterpreterTextField.setText(config.getPythonInterpreter());
}
- addLabelArea(true);
if (getPythonInterpreter().equals(selectPythonInterpreterPlaceHolder) || getPythonInterpreter().equals("python") || getPythonInterpreter().equals("python3") || getPythonInterpreter().equals("") || getPythonInterpreter().endsWith("python") || getPythonInterpreter().endsWith("python3") || getPythonInterpreter().endsWith("python.exe") || getPythonInterpreter().endsWith("python3.exe")) {
+
pythonEnvironment = AvailabilityChecker.checkPythonEnvironment(getPythonInterpreter());
if (pythonEnvironment && checkBoxes.get(1).isSelected()) {
eyeTracker = AvailabilityChecker.checkEyeTracker(getPythonInterpreter());
@@ -64,9 +70,9 @@ public ConfigDialog(Project project) throws IOException, InterruptedException {
String trackerName = AvailabilityChecker.getEyeTrackerName(getPythonInterpreter());
if (trackerName != null && !trackerName.equals("Not Found")) {
deviceCombo.removeAllItems();
- deviceCombo.addItem(trackerName);
deviceCombo.addItem("Mouse");
- deviceCombo.setSelectedIndex(0);
+ deviceCombo.addItem(trackerName);
+ deviceCombo.setSelectedIndex(1);
}
List freqList = AvailabilityChecker.getFrequencies(getPythonInterpreter());
freqCombo.removeAllItems();
@@ -81,8 +87,7 @@ public ConfigDialog(Project project) throws IOException, InterruptedException {
freqCombo.addItem(60.0);
freqCombo.addItem(120.0);
}
- }
- if (!checkBoxes.get(1).isSelected() || !pythonEnvironment) {
+ } else {
freqCombo.setEnabled(false);
deviceCombo.setEnabled(false);
freqCombo.removeAllItems();
@@ -93,11 +98,8 @@ public ConfigDialog(Project project) throws IOException, InterruptedException {
freqCombo.addItem(120.0);
}
}
- Config config = new Config();
- if (config.configExists()) {
- config.loadFromJson();
- // load freq
- freqCombo.setSelectedItem(config.getSampleFreq());
+ if (new File("config.json").exists()) {
+ loadConfig();
}
}
@@ -114,16 +116,21 @@ private void loadConfig() {
for (int i = 0; i < selected.size(); i++) {
checkBoxes.get(i).setSelected(selected.get(i));
}
-
labelAreas = new ArrayList<>();
for (int i = 0; i < labels.size(); i++) {
addLabelArea(false);
labelAreas.get(i).setText(labels.get(i));
}
+ addLabelArea(true);
freqCombo.setSelectedItem(freq);
pythonInterpreterTextField.setText(config.getPythonInterpreter());
dataOutputTextField.setText(config.getDataOutputPath());
- deviceCombo.setSelectedIndex(config.getEyeTrackerDevice());
+
+ if (deviceCombo.getItemCount() > 1){
+ deviceCombo.setSelectedIndex(config.getEyeTrackerDevice());
+ } else {
+ deviceCombo.setSelectedIndex(0);
+ }
if (!checkBoxes.get(1).isSelected()) {
freqCombo.setEnabled(false);
deviceCombo.setEnabled(false);
@@ -202,14 +209,9 @@ protected JComponent createCenterPanel() {
checkBoxes.add(screenRecording);
checkBoxPanel.add(screenRecording);
- JCheckBox transmitData = new JCheckBox("Transmit Data");
-// checkBoxes.add(transmitData);
-// checkBoxPanel.add(transmitData);
-
iDETracking.setBorder(new EmptyBorder(contentMargin));
eyeTracking.setBorder(new EmptyBorder(contentMargin));
screenRecording.setBorder(new EmptyBorder(contentMargin));
- transmitData.setBorder(new EmptyBorder(contentMargin));
panel.add(checkBoxPanel);
@@ -223,7 +225,6 @@ protected JComponent createCenterPanel() {
pythonInterpreterLabel.setHorizontalTextPosition(JLabel.LEFT);
panel.add(pythonInterpreterLabel);
-// pythonInterpreterTextField = new TextFieldWithBrowseButton();
pythonInterpreterTextField.setEditable(false);
pythonInterpreterTextField.setMaximumSize(new Dimension(500, 40));
pythonInterpreterTextField.setBorder(new EmptyBorder(contentMargin));
@@ -265,7 +266,6 @@ protected void textChanged(@NotNull DocumentEvent e) {
panel.add(pythonInterpreterTextField);
-
JLabel dataOutputLabel = new JLabel("Data Output Path");
dataOutputLabel.setHorizontalTextPosition(JLabel.LEFT);
dataOutputLabel.setBorder(new EmptyBorder(JBUI.insetsLeft(20)));
@@ -277,15 +277,6 @@ protected void textChanged(@NotNull DocumentEvent e) {
dataOutputTextField.setText(selectDataOutputPlaceHolder);
dataOutputTextField.setAlignmentX(Component.LEFT_ALIGNMENT);
dataOutputTextField.addBrowseFolderListener(new TextBrowseFolderListener(new FileChooserDescriptor(false, true, false, false, false, false)));
-//
-// new ComponentValidator(getDisposable()).withValidator(() -> {
-// String text = dataOutputTextField.getText();
-// if (text.equals("Select Data Output Folder")) {
-// return new ValidationInfo("Please select a data output folder", dataOutputTextField.getTextField());
-// }
-// return null;
-// }).installOn(dataOutputTextField.getTextField());
-
panel.add(dataOutputTextField);
@@ -321,6 +312,7 @@ protected void textChanged(@NotNull DocumentEvent e) {
eyeTracking.addChangeListener(e -> {
freqCombo.setEnabled(eyeTracking.isSelected());
+ deviceCombo.setEnabled(eyeTracking.isSelected());
});
JPanel labelAreaPanel = new JPanel();
@@ -333,7 +325,6 @@ protected void textChanged(@NotNull DocumentEvent e) {
labelAreaPanel.add(labels);
panel.add(labelAreaPanel);
-
eyeTracking.addActionListener(actionEvent -> {
if (!pythonEnvironment) {
eyeTracking.setSelected(false);
@@ -355,18 +346,16 @@ protected void textChanged(@NotNull DocumentEvent e) {
String trackerName = AvailabilityChecker.getEyeTrackerName(getPythonInterpreter());
if (trackerName != null && !trackerName.equals("Not Found")) {
deviceCombo.removeAllItems();
- deviceCombo.addItem(trackerName);
deviceCombo.addItem("Mouse");
+ deviceCombo.addItem(trackerName);
+ deviceCombo.setSelectedIndex(1);
}
- deviceCombo.setSelectedIndex(0);
List freqList = AvailabilityChecker.getFrequencies(getPythonInterpreter());
freqCombo.removeAllItems();
for (String freq : freqList) {
freqCombo.addItem(Double.parseDouble(freq));
}
new AlertDialog("Eye tracker found.", AllIcons.General.InspectionsOK).show();
-
-
}
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e);
@@ -374,7 +363,6 @@ protected void textChanged(@NotNull DocumentEvent e) {
}
});
-
return panel;
}
diff --git a/src/main/java/trackers/ScreenRecorder.java b/src/main/java/trackers/ScreenRecorder.java
index 721c043..a18eea5 100644
--- a/src/main/java/trackers/ScreenRecorder.java
+++ b/src/main/java/trackers/ScreenRecorder.java
@@ -74,6 +74,7 @@ private void createEncoder() throws IOException {
public void startRecording() throws IOException {
state = 1;
clipNumber = 1;
+ timeList.clear();
isRecording = true;
File file = new File(dataOutputPath + "/screen_recording/frames.csv");
file.getParentFile().mkdirs();