11package fi .helsinki .cs .tmc .spyware .eventsources ;
22
3+ import com .google .common .base .CaseFormat ;
4+ import fi .helsinki .cs .tmc .data .Exercise ;
35import fi .helsinki .cs .tmc .model .CourseDb ;
46import fi .helsinki .cs .tmc .model .ProjectMediator ;
7+ import fi .helsinki .cs .tmc .model .TmcProjectInfo ;
58import fi .helsinki .cs .tmc .spyware .EventReceiver ;
69import fi .helsinki .cs .tmc .spyware .LoggableEvent ;
710import 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 ;
1018import org .openide .windows .Mode ;
19+ import org .openide .windows .WindowManager ;
1120
1221import java .awt .event .WindowEvent ;
1322import java .awt .event .WindowListener ;
2029import javax .swing .JEditorPane ;
2130import javax .swing .text .Document ;
2231import 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
2634public 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