Skip to content

Commit 6048cbb

Browse files
committed
Log detailed info of editor activity changes only when modifying tmc-projets.
1 parent a7ca568 commit 6048cbb

File tree

3 files changed

+103
-61
lines changed

3 files changed

+103
-61
lines changed

tmc-plugin/nbproject/genfiles.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ build.xml.script.CRC32=84aa6cb9
33
build.xml.stylesheet.CRC32=a56c6a5b@1.45.1
44
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
55
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
6-
nbproject/build-impl.xml.data.CRC32=eb1e762e
6+
nbproject/build-impl.xml.data.CRC32=15a6abed
77
nbproject/build-impl.xml.script.CRC32=72a9c69e
88
nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.67.1

tmc-plugin/nbproject/project.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,15 @@
8585
<specification-version>1.63.1.5.19.31</specification-version>
8686
</run-dependency>
8787
</dependency>
88+
<dependency>
89+
<code-name-base>org.netbeans.modules.editor.lib</code-name-base>
90+
<build-prerequisite/>
91+
<compile-dependency/>
92+
<run-dependency>
93+
<release-version>3</release-version>
94+
<specification-version>3.49.2.22.43</specification-version>
95+
</run-dependency>
96+
</dependency>
8897
<dependency>
8998
<code-name-base>org.netbeans.modules.editor.lib2</code-name-base>
9099
<build-prerequisite/>
Lines changed: 93 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
11
package fi.helsinki.cs.tmc.spyware.eventsources;
22

3+
import com.google.common.base.CaseFormat;
4+
import fi.helsinki.cs.tmc.data.Exercise;
35
import fi.helsinki.cs.tmc.model.CourseDb;
46
import fi.helsinki.cs.tmc.model.ProjectMediator;
7+
import fi.helsinki.cs.tmc.model.TmcProjectInfo;
58
import fi.helsinki.cs.tmc.spyware.EventReceiver;
69
import fi.helsinki.cs.tmc.spyware.LoggableEvent;
710
import fi.helsinki.cs.tmc.utilities.JsonMaker;
11+
import fi.helsinki.cs.tmc.utilities.TmcFileUtils;
812

9-
import org.openide.windows.WindowManager;
13+
import org.netbeans.api.editor.EditorRegistry;
14+
import org.netbeans.editor.GuardedDocument;
15+
import org.netbeans.modules.editor.NbEditorDocument;
16+
import org.openide.filesystems.FileObject;
17+
import org.openide.loaders.DataObject;
1018
import org.openide.windows.Mode;
19+
import org.openide.windows.WindowManager;
1120

1221
import java.awt.event.WindowEvent;
1322
import java.awt.event.WindowListener;
@@ -20,8 +29,7 @@
2029
import javax.swing.JEditorPane;
2130
import javax.swing.text.Document;
2231
import javax.swing.text.JTextComponent;
23-
import org.netbeans.api.editor.EditorRegistry;
24-
import org.openide.filesystems.FileObject;
32+
import org.netbeans.api.annotations.common.NullAllowed;
2533

2634
public final class WindowStatechangesEventSource implements PropertyChangeListener, WindowListener {
2735

@@ -39,104 +47,129 @@ public WindowStatechangesEventSource(EventReceiver receiver) {
3947
}
4048

4149
void startListening() {
42-
log.log(Level.INFO, "Attaching to listen WindowEventProperties");
50+
log.log(Level.INFO, "Attaching window listeners.");
4351
WindowManager.getDefault().addPropertyChangeListener(this);
4452
EditorRegistry.addPropertyChangeListener(this);
4553
WindowManager.getDefault().getMainWindow().addWindowListener(this);
4654
}
4755

4856
/**
49-
* Receives window events. This includes at least events when active
50-
* subwindow has changed (projects tab or code)
57+
* Receives and logs sub window change events. Such as opening and closing a
58+
* new file and changing between open files.
5159
*/
5260
@Override
5361
public void propertyChange(PropertyChangeEvent evt) {
54-
JTextComponent jtc = EditorRegistry.lastFocusedComponent();
55-
Document d = null;
56-
FileObject fd = null;
57-
if (jtc != null) {
58-
d = jtc.getDocument();
59-
if (d instanceof FileObject) {
60-
fd = ((FileObject) d);
61-
}
62-
// use the document
62+
FileObject changedFile = getChangedFile();
63+
64+
Exercise exercise = getExercise(changedFile);
65+
String eventName = underscorify(evt.getPropertyName());
66+
67+
LoggableEvent event;
68+
if (exercise != null) {
69+
log.log(Level.FINER, "Exercise: {0}", exercise);
70+
String filePath = TmcFileUtils.tryGetPathRelativeToProject(changedFile);
71+
String data = JsonMaker.create()
72+
.add("new_value", toStringWithObjects(evt.getNewValue()))
73+
.add("old_value", toStringWithObjects(evt.getOldValue()))
74+
.add("file", toStringWithObjects(filePath))
75+
.toString();
76+
event = new LoggableEvent(exercise, eventName, data.getBytes(Charset.forName("UTF-8")));
77+
} else {
78+
String data = JsonMaker.create()
79+
.add("new_value", toStringWithObjects(evt.getNewValue()))
80+
.add("old_value", toStringWithObjects(evt.getOldValue()))
81+
.add("non_tmc_project", true)
82+
.toString();
83+
event = new LoggableEvent(eventName, data.getBytes(Charset.forName("UTF-8")));
6384
}
6485

65-
String data = JsonMaker.create()
66-
.add("name", evt.getPropertyName())
67-
.add("new_value", toStringWithObjects(evt.getNewValue()))
68-
.add("old_value", toStringWithObjects(evt.getOldValue()))
69-
.add("fd", toStringWithObjects(fd))
70-
.add("propagation_id", toStringWithObjects(evt.getPropagationId()))
71-
.add("document", toStringWithObjects(d))
72-
.add("jtc", toStringWithObjects(jtc))
73-
.toString();
74-
75-
LoggableEvent event = new LoggableEvent(courseDb.getCurrentCourse(), "window_event", data.getBytes(Charset.forName("UTF-8")));
76-
77-
receiver.receiveEvent (event);
78-
}
86+
receiver.receiveEvent(event);
87+
}
7988

80-
private String toStringWithObjects(Object object) {
81-
if (object == null) {
82-
return "null";
83-
}
84-
if (object instanceof FileObject){
85-
return ((FileObject) object).getName() + "--" + ((FileObject) object).getPath();
86-
}else if (object instanceof Mode) {
87-
return ((Mode) object).getName();
88-
} else if (object instanceof Accessible) {
89-
return ((Accessible) object).getAccessibleContext().getAccessibleName();
90-
} else if (object instanceof JEditorPane) {
91-
return ((JEditorPane) object).getAccessibleContext().getAccessibleName();
92-
}
93-
log.log(Level.WARNING, "[spyware] Add support for toStringing class: {0}",
94-
object.getClass().getName());
95-
return object.toString();
89+
/**
90+
* Logs window events.
91+
*/
92+
private void reactToEvent(String action, WindowEvent event) {
93+
String data = JsonMaker.create()
94+
.add("new_state", event.getNewState())
95+
.add("old_state", event.getOldState())
96+
.toString();
97+
receiver.receiveEvent(
98+
new LoggableEvent(courseDb.getCurrentCourse(), action, data.getBytes(Charset.forName("UTF-8"))));
9699
}
97100

98101
@Override
99-
public void windowOpened(WindowEvent e) {
102+
public void windowOpened(WindowEvent e) {
100103
reactToEvent("window_opened", e);
101104
}
102105

103106
@Override
104-
public void windowClosing(WindowEvent e) {
107+
public void windowClosing(WindowEvent e) {
105108
reactToEvent("window_closing", e);
106109
}
107110

108111
@Override
109-
public void windowClosed(WindowEvent e) {
112+
public void windowClosed(WindowEvent e) {
110113
reactToEvent("window_closed", e);
111114
}
112115

113116
@Override
114-
public void windowIconified(WindowEvent e) {
117+
public void windowIconified(WindowEvent e) {
115118
reactToEvent("window_iconified", e);
116119
}
117120

118121
@Override
119-
public void windowDeiconified(WindowEvent e) {
122+
public void windowDeiconified(WindowEvent e) {
120123
reactToEvent("window_deiconified", e);
121124
}
122125

123126
@Override
124-
public void windowActivated(WindowEvent e) {
127+
public void windowActivated(WindowEvent e) {
125128
reactToEvent("window_activated", e);
126129
}
127130

128131
@Override
129-
public void windowDeactivated(WindowEvent e) {
132+
public void windowDeactivated(WindowEvent e) {
130133
reactToEvent("window_deactivated", e);
131134
}
132135

133-
void reactToEvent(String action, WindowEvent event) {
134-
String data = JsonMaker.create()
135-
.add("action", action)
136-
.add("new_state", event.getNewState())
137-
.add("old_state", event.getOldState())
138-
.toString();
139-
receiver.receiveEvent(
140-
new LoggableEvent(courseDb.getCurrentCourse(), "window_event", data.getBytes(Charset.forName("UTF-8"))));
136+
private Exercise getExercise(@NullAllowed FileObject obj) {
137+
if (obj == null) {
138+
return null;
139+
}
140+
ProjectMediator pm = ProjectMediator.getInstance();
141+
TmcProjectInfo project = pm.tryGetProjectOwningFile(obj);
142+
return pm.tryGetExerciseForProject(project, courseDb);
143+
}
144+
145+
private String toStringWithObjects(Object object) {
146+
if (object == null) {
147+
return "null";
148+
} else if (object instanceof Mode) {
149+
return ((Mode) object).getName();
150+
} else if (object instanceof Accessible) {
151+
return ((Accessible) object).getAccessibleContext().getAccessibleName();
152+
}
153+
return object.toString();
154+
}
155+
156+
private String underscorify(String string) {
157+
return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, string);
158+
}
159+
160+
/**
161+
* Returns {@link FileObject} representing the last active file for each event.
162+
*/
163+
private FileObject getChangedFile() {
164+
JTextComponent jtc = EditorRegistry.lastFocusedComponent();
165+
if (jtc != null) {
166+
Document d = jtc.getDocument();
167+
Object fileObj = d.getProperty(NbEditorDocument.StreamDescriptionProperty);
168+
if (fileObj instanceof DataObject) {
169+
DataObject changedDataObject = (DataObject) fileObj;
170+
return changedDataObject.getPrimaryFile();
171+
}
172+
}
173+
return null;
141174
}
142175
}

0 commit comments

Comments
 (0)