boris-behav-obs 8.12__py3-none-any.whl → 9.7.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of boris-behav-obs might be problematic. Click here for more details.
- boris/__init__.py +1 -1
- boris/__main__.py +1 -1
- boris/about.py +28 -39
- boris/add_modifier.py +122 -109
- boris/add_modifier_ui.py +239 -135
- boris/advanced_event_filtering.py +81 -45
- boris/analysis_plugins/__init__.py +0 -0
- boris/analysis_plugins/_latency.py +59 -0
- boris/analysis_plugins/irr_cohen_kappa.py +109 -0
- boris/analysis_plugins/irr_cohen_kappa_with_modifiers.py +112 -0
- boris/analysis_plugins/irr_weighted_cohen_kappa.py +157 -0
- boris/analysis_plugins/irr_weighted_cohen_kappa_with_modifiers.py +162 -0
- boris/analysis_plugins/list_of_dataframe_columns.py +22 -0
- boris/analysis_plugins/number_of_occurences.py +22 -0
- boris/analysis_plugins/number_of_occurences_by_independent_variable.py +54 -0
- boris/analysis_plugins/time_budget.py +61 -0
- boris/behav_coding_map_creator.py +228 -229
- boris/behavior_binary_table.py +33 -50
- boris/behaviors_coding_map.py +17 -18
- boris/boris_cli.py +6 -25
- boris/cmd_arguments.py +12 -1
- boris/coding_pad.py +42 -49
- boris/config.py +141 -65
- boris/config_file.py +58 -67
- boris/connections.py +107 -61
- boris/converters.py +13 -37
- boris/converters_ui.py +187 -110
- boris/cooccurence.py +250 -0
- boris/core.py +2373 -1786
- boris/core_qrc.py +15895 -10743
- boris/core_ui.py +943 -798
- boris/db_functions.py +17 -42
- boris/dev.py +109 -8
- boris/dialog.py +482 -236
- boris/duration_widget.py +9 -14
- boris/edit_event.py +61 -31
- boris/edit_event_ui.py +208 -97
- boris/event_operations.py +408 -293
- boris/events_cursor.py +25 -17
- boris/events_snapshots.py +36 -82
- boris/exclusion_matrix.py +4 -9
- boris/export_events.py +184 -223
- boris/export_observation.py +74 -100
- boris/external_processes.py +123 -98
- boris/geometric_measurement.py +644 -290
- boris/gui_utilities.py +91 -14
- boris/image_overlay.py +4 -4
- boris/import_observations.py +190 -98
- boris/ipc_mpv.py +325 -0
- boris/irr.py +20 -57
- boris/latency.py +31 -24
- boris/measurement_widget.py +14 -18
- boris/media_file.py +17 -19
- boris/menu_options.py +17 -6
- boris/modifier_coding_map_creator.py +1013 -0
- boris/modifiers_coding_map.py +7 -9
- boris/mpv.py +1 -0
- boris/mpv2.py +732 -705
- boris/observation.py +533 -221
- boris/observation_operations.py +1025 -390
- boris/observation_ui.py +572 -362
- boris/observations_list.py +71 -53
- boris/otx_parser.py +74 -68
- boris/param_panel.py +31 -16
- boris/param_panel_ui.py +254 -138
- boris/player_dock_widget.py +90 -60
- boris/plot_data_module.py +25 -33
- boris/plot_events.py +127 -90
- boris/plot_events_rt.py +17 -31
- boris/plot_spectrogram_rt.py +95 -30
- boris/plot_waveform_rt.py +32 -21
- boris/plugins.py +431 -0
- boris/portion/__init__.py +18 -8
- boris/portion/const.py +35 -18
- boris/portion/dict.py +5 -5
- boris/portion/func.py +2 -2
- boris/portion/interval.py +21 -41
- boris/portion/io.py +41 -32
- boris/preferences.py +306 -83
- boris/preferences_ui.py +684 -227
- boris/project.py +448 -293
- boris/project_functions.py +671 -238
- boris/project_import_export.py +213 -222
- boris/project_ui.py +674 -438
- boris/qrc_boris.py +6 -3
- boris/qrc_boris5.py +6 -3
- boris/select_modifiers.py +74 -48
- boris/select_observations.py +20 -198
- boris/select_subj_behav.py +67 -39
- boris/state_events.py +52 -35
- boris/subjects_pad.py +6 -9
- boris/synthetic_time_budget.py +45 -28
- boris/time_budget_functions.py +171 -171
- boris/time_budget_widget.py +84 -114
- boris/transitions.py +41 -47
- boris/utilities.py +627 -236
- boris/version.py +3 -3
- boris/video_equalizer.py +16 -14
- boris/video_equalizer_ui.py +199 -130
- boris/video_operations.py +95 -29
- boris/view_df.py +104 -0
- boris/view_df_ui.py +75 -0
- boris/write_event.py +538 -0
- boris_behav_obs-9.7.6.dist-info/METADATA +139 -0
- boris_behav_obs-9.7.6.dist-info/RECORD +109 -0
- {boris_behav_obs-8.12.dist-info → boris_behav_obs-9.7.6.dist-info}/WHEEL +1 -1
- boris_behav_obs-9.7.6.dist-info/entry_points.txt +2 -0
- boris/README.TXT +0 -22
- boris/add_modifier.ui +0 -323
- boris/converters.ui +0 -289
- boris/core.qrc +0 -36
- boris/core.ui +0 -1556
- boris/edit_event.ui +0 -233
- boris/icons/logo_eye.ico +0 -0
- boris/map_creator.py +0 -850
- boris/observation.ui +0 -814
- boris/param_panel.ui +0 -379
- boris/preferences.ui +0 -537
- boris/project.ui +0 -1069
- boris/project_server.py +0 -236
- boris/vlc.py +0 -10343
- boris/vlc_local.py +0 -90
- boris_behav_obs-8.12.dist-info/LICENSE.TXT +0 -674
- boris_behav_obs-8.12.dist-info/METADATA +0 -128
- boris_behav_obs-8.12.dist-info/RECORD +0 -108
- boris_behav_obs-8.12.dist-info/entry_points.txt +0 -3
- {boris → boris_behav_obs-9.7.6.dist-info/licenses}/LICENSE.TXT +0 -0
- {boris_behav_obs-8.12.dist-info → boris_behav_obs-9.7.6.dist-info}/top_level.txt +0 -0
boris/connections.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
BORIS
|
|
3
3
|
Behavioral Observation Research Interactive Software
|
|
4
|
-
Copyright 2012-
|
|
4
|
+
Copyright 2012-2025 Olivier Friard
|
|
5
5
|
|
|
6
6
|
This program is free software; you can redistribute it and/or modify
|
|
7
7
|
it under the terms of the GNU General Public License as published by
|
|
@@ -19,8 +19,8 @@ Copyright 2012-2023 Olivier Friard
|
|
|
19
19
|
MA 02110-1301, USA.
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
from
|
|
23
|
-
from
|
|
22
|
+
from PySide6.QtCore import Qt, QTimer
|
|
23
|
+
from PySide6.QtGui import QAction
|
|
24
24
|
|
|
25
25
|
from . import config as cfg
|
|
26
26
|
from . import (
|
|
@@ -37,11 +37,11 @@ from . import (
|
|
|
37
37
|
import_observations,
|
|
38
38
|
irr,
|
|
39
39
|
latency,
|
|
40
|
+
cooccurence,
|
|
40
41
|
media_file,
|
|
41
42
|
observation_operations,
|
|
42
43
|
preferences,
|
|
43
44
|
project_import_export,
|
|
44
|
-
project_server,
|
|
45
45
|
synthetic_time_budget,
|
|
46
46
|
time_budget_widget,
|
|
47
47
|
transitions,
|
|
@@ -70,16 +70,12 @@ def connections(self):
|
|
|
70
70
|
self.actionExport_project.triggered.connect(lambda: project_import_export.export_project_as_pickle_object(self.pj))
|
|
71
71
|
self.actionClose_project.triggered.connect(self.close_project)
|
|
72
72
|
|
|
73
|
-
self.action_media_file_and_images_directories_relative_path.triggered.connect(
|
|
74
|
-
self.set_media_files_path_relative_to_project_dir
|
|
75
|
-
)
|
|
73
|
+
self.action_media_file_and_images_directories_relative_path.triggered.connect(self.set_media_files_path_relative_to_project_dir)
|
|
76
74
|
self.action_data_files_relative_path.triggered.connect(self.set_data_files_path_relative_to_project_dir)
|
|
77
75
|
|
|
78
76
|
self.action_remove_media_files_and_images_directories_path.triggered.connect(self.remove_media_files_path)
|
|
79
77
|
self.action_remove_data_files_path.triggered.connect(self.remove_data_files_path)
|
|
80
78
|
|
|
81
|
-
self.actionSend_project.triggered.connect(lambda: project_server.send_project_via_socket(self))
|
|
82
|
-
|
|
83
79
|
self.menuCreate_subtitles_2.triggered.connect(self.create_subtitles)
|
|
84
80
|
|
|
85
81
|
self.actionPreferences.triggered.connect(lambda: preferences.preferences(self))
|
|
@@ -87,19 +83,16 @@ def connections(self):
|
|
|
87
83
|
self.actionQuit.triggered.connect(self.actionQuit_activated)
|
|
88
84
|
|
|
89
85
|
# menu observations
|
|
90
|
-
self.actionNew_observation.triggered.connect(
|
|
91
|
-
lambda: observation_operations.new_observation(self, mode=cfg.NEW, obsId="")
|
|
92
|
-
)
|
|
86
|
+
self.actionNew_observation.triggered.connect(lambda: observation_operations.new_observation(self, mode=cfg.NEW, obsId=""))
|
|
93
87
|
|
|
94
|
-
self.actionOpen_observation.triggered.connect(
|
|
95
|
-
lambda: observation_operations.open_observation(self, mode=cfg.OBS_START)
|
|
96
|
-
)
|
|
88
|
+
self.actionOpen_observation.triggered.connect(lambda: observation_operations.open_observation(self, mode=cfg.OBS_START))
|
|
97
89
|
self.actionView_observation.triggered.connect(lambda: observation_operations.open_observation(self, mode=cfg.VIEW))
|
|
98
90
|
self.actionEdit_observation_2.triggered.connect(lambda: observation_operations.edit_observation(self))
|
|
99
91
|
self.actionObservationsList.triggered.connect(lambda: observation_operations.observations_list(self))
|
|
100
92
|
|
|
101
93
|
self.actionClose_observation.triggered.connect(lambda: observation_operations.close_observation(self))
|
|
102
94
|
|
|
95
|
+
self.action_create_observations.triggered.connect(lambda: observation_operations.create_observations(self))
|
|
103
96
|
self.actionRemove_observations.triggered.connect(lambda: observation_operations.remove_observations(self))
|
|
104
97
|
|
|
105
98
|
self.actionAdd_event.triggered.connect(lambda: event_operations.add_event(self))
|
|
@@ -110,22 +103,24 @@ def connections(self):
|
|
|
110
103
|
self.actionShow_all_events.triggered.connect(lambda: event_operations.show_all_events(self))
|
|
111
104
|
|
|
112
105
|
# twevent header
|
|
113
|
-
self.actionConfigure_twEvents_columns.triggered.connect(self.configure_twevents_columns)
|
|
106
|
+
# self.actionConfigure_twEvents_columns.triggered.connect(self.configure_twevents_columns)
|
|
114
107
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
108
|
+
# tv_events header
|
|
109
|
+
self.actionConfigure_tvevents_columns.triggered.connect(self.configure_tvevents_columns)
|
|
110
|
+
|
|
111
|
+
self.actionExport_observations_list.triggered.connect(lambda: observation_operations.export_observations_list_clicked(self))
|
|
118
112
|
|
|
119
113
|
self.actionCheckStateEvents.triggered.connect(lambda: state_events.check_state_events(self, mode="all"))
|
|
120
|
-
self.actionCheckStateEventsSingleObs.triggered.connect(
|
|
121
|
-
lambda: state_events.check_state_events(self, mode="current")
|
|
122
|
-
)
|
|
114
|
+
self.actionCheckStateEventsSingleObs.triggered.connect(lambda: state_events.check_state_events(self, mode="current"))
|
|
123
115
|
self.actionClose_unpaired_events.triggered.connect(lambda: state_events.fix_unpaired_events(self))
|
|
116
|
+
self.actionAdd_frame_indexes.triggered.connect(lambda: event_operations.add_frame_indexes(self))
|
|
117
|
+
|
|
124
118
|
self.actionRunEventOutside.triggered.connect(self.run_event_outside)
|
|
125
119
|
|
|
126
120
|
self.actionSelect_observations.triggered.connect(lambda: event_operations.select_events_between_activated(self))
|
|
127
121
|
|
|
128
122
|
self.actionEdit_selected_events.triggered.connect(lambda: event_operations.edit_selected_events(self))
|
|
123
|
+
self.action_add_comment.triggered.connect(lambda: event_operations.add_comment(self))
|
|
129
124
|
self.actionEdit_event_time.triggered.connect(lambda: event_operations.edit_time_selected_events(self))
|
|
130
125
|
|
|
131
126
|
self.actionCopy_events.triggered.connect(lambda: event_operations.copy_selected_events(self))
|
|
@@ -133,7 +128,7 @@ def connections(self):
|
|
|
133
128
|
|
|
134
129
|
self.actionExplore_project.triggered.connect(lambda: project_functions.explore_project(self))
|
|
135
130
|
self.actionFind_events.triggered.connect(lambda: event_operations.find_events(self))
|
|
136
|
-
self.actionFind_replace_events.triggered.connect(
|
|
131
|
+
self.actionFind_replace_events.triggered.connect(lambda: event_operations.find_replace_events(self))
|
|
137
132
|
self.actionDelete_all_events.triggered.connect(lambda: event_operations.delete_all_events(self))
|
|
138
133
|
self.actionDelete_selected_events.triggered.connect(lambda: event_operations.delete_selected_events(self))
|
|
139
134
|
|
|
@@ -166,13 +161,16 @@ def connections(self):
|
|
|
166
161
|
self.actionNumber_of_transitions.triggered.connect(lambda: transitions.transitions_matrix(self, "number"))
|
|
167
162
|
|
|
168
163
|
self.actionFrequencies_of_transitions_after_behaviors.triggered.connect(
|
|
169
|
-
lambda:
|
|
164
|
+
lambda: transitions.transitions_matrix(self, "frequencies_after_behaviors")
|
|
170
165
|
)
|
|
171
166
|
|
|
172
167
|
# menu playback
|
|
173
168
|
self.actionJumpTo.triggered.connect(self.jump_to)
|
|
169
|
+
self.action_deinterlace.triggered.connect(lambda: video_operations.deinterlace(self))
|
|
170
|
+
self.action_change_time_offset_of_players.triggered.connect(lambda: video_operations.change_player_offset(self))
|
|
174
171
|
self.actionZoom_level.triggered.connect(lambda: video_operations.zoom_level(self))
|
|
175
172
|
self.actionRotate_current_video.triggered.connect(lambda: video_operations.rotate_displayed_video(self))
|
|
173
|
+
|
|
176
174
|
self.actionDisplay_subtitles.triggered.connect(lambda: video_operations.display_subtitles(self))
|
|
177
175
|
self.actionVideo_equalizer.triggered.connect(lambda: video_equalizer.video_equalizer_show(self))
|
|
178
176
|
|
|
@@ -180,9 +178,7 @@ def connections(self):
|
|
|
180
178
|
self.action_block_dockwidgets.triggered.connect(self.block_dockwidgets)
|
|
181
179
|
|
|
182
180
|
self.action_create_modifiers_coding_map.triggered.connect(self.modifiers_coding_map_creator)
|
|
183
|
-
self.action_create_behaviors_coding_map.triggered.connect(
|
|
184
|
-
lambda: behav_coding_map_creator.behaviors_coding_map_creator(self)
|
|
185
|
-
)
|
|
181
|
+
self.action_create_behaviors_coding_map.triggered.connect(lambda: behav_coding_map_creator.behaviors_coding_map_creator(self))
|
|
186
182
|
|
|
187
183
|
self.actionShow_spectrogram.triggered.connect(lambda: self.show_plot_widget("spectrogram", warning=True))
|
|
188
184
|
self.actionShow_the_sound_waveform.triggered.connect(lambda: self.show_plot_widget("waveform", warning=True))
|
|
@@ -190,6 +186,7 @@ def connections(self):
|
|
|
190
186
|
|
|
191
187
|
self.actionShow_data_files.triggered.connect(self.show_data_files)
|
|
192
188
|
self.action_geometric_measurements.triggered.connect(lambda: geometric_measurement.show_widget(self))
|
|
189
|
+
|
|
193
190
|
self.actionBehaviors_coding_map.triggered.connect(lambda: behaviors_coding_map.show_behaviors_coding_map(self))
|
|
194
191
|
|
|
195
192
|
self.actionCoding_pad.triggered.connect(lambda: coding_pad.show_coding_pad(self))
|
|
@@ -199,24 +196,22 @@ def connections(self):
|
|
|
199
196
|
self.actionAdd_image_overlay_on_video.triggered.connect(lambda: image_overlay.add_image_overlay(self))
|
|
200
197
|
self.actionRemove_image_overlay.triggered.connect(lambda: image_overlay.remove_image_overlay(self))
|
|
201
198
|
|
|
199
|
+
self.actionMedia_file_information_2.triggered.connect(lambda: media_file.get_info(self))
|
|
202
200
|
self.actionRecode_resize_video.triggered.connect(lambda: external_processes.ffmpeg_process(self, "reencode_resize"))
|
|
203
201
|
self.actionRotate_video.triggered.connect(lambda: external_processes.ffmpeg_process(self, "rotate"))
|
|
204
202
|
self.actionMerge_media_files.triggered.connect(lambda: external_processes.ffmpeg_process(self, "merge"))
|
|
205
|
-
self.
|
|
203
|
+
self.actionCreate_video_spectrogram.triggered.connect(lambda: external_processes.ffmpeg_process(self, "video_spectrogram"))
|
|
206
204
|
|
|
207
205
|
self.actionCreate_transitions_flow_diagram.triggered.connect(transitions.transitions_dot_script)
|
|
208
206
|
self.actionCreate_transitions_flow_diagram_2.triggered.connect(transitions.transitions_flow_diagram)
|
|
209
207
|
|
|
210
208
|
# menu Analysis
|
|
209
|
+
|
|
211
210
|
self.actionTime_budget.triggered.connect(lambda: time_budget_widget.time_budget(self, mode="by_behavior"))
|
|
212
|
-
self.actionTime_budget_by_behaviors_category.triggered.connect(
|
|
213
|
-
lambda: time_budget_widget.time_budget(self, mode="by_category")
|
|
214
|
-
)
|
|
211
|
+
self.actionTime_budget_by_behaviors_category.triggered.connect(lambda: time_budget_widget.time_budget(self, mode="by_category"))
|
|
215
212
|
|
|
216
213
|
self.actionTime_budget_report.triggered.connect(lambda: synthetic_time_budget.synthetic_time_budget(self))
|
|
217
|
-
self.actionSynthetic_binned_time_budget.triggered.connect(
|
|
218
|
-
lambda: synthetic_time_budget.synthetic_binned_time_budget(self)
|
|
219
|
-
)
|
|
214
|
+
self.actionSynthetic_binned_time_budget.triggered.connect(lambda: synthetic_time_budget.synthetic_binned_time_budget(self))
|
|
220
215
|
|
|
221
216
|
self.actionBehavior_bar_plot.triggered.connect(lambda: self.behaviors_bar_plot(mode="list"))
|
|
222
217
|
self.actionBehavior_bar_plot.setVisible(True)
|
|
@@ -230,6 +225,8 @@ def connections(self):
|
|
|
230
225
|
|
|
231
226
|
self.action_latency.triggered.connect(lambda: latency.get_latency(self))
|
|
232
227
|
|
|
228
|
+
self.action_cooccurence.triggered.connect(lambda: cooccurence.get_cooccurence(self))
|
|
229
|
+
|
|
233
230
|
# menu Help
|
|
234
231
|
self.actionUser_guide.triggered.connect(self.actionUser_guide_triggered)
|
|
235
232
|
self.actionAbout.triggered.connect(lambda: about.actionAbout_activated(self))
|
|
@@ -255,9 +252,7 @@ def connections(self):
|
|
|
255
252
|
self.actionFrame_forward.triggered.connect(self.next_frame)
|
|
256
253
|
|
|
257
254
|
self.actionCloseObs.triggered.connect(lambda: observation_operations.close_observation(self))
|
|
258
|
-
self.actionCurrent_Time_Budget.triggered.connect(
|
|
259
|
-
lambda: time_budget_widget.time_budget(self, mode="by_behavior", mode2="current")
|
|
260
|
-
)
|
|
255
|
+
self.actionCurrent_Time_Budget.triggered.connect(lambda: time_budget_widget.time_budget(self, mode="by_behavior", mode2="current"))
|
|
261
256
|
self.actionPlot_current_observation.triggered.connect(lambda: self.plot_events_triggered(mode="current"))
|
|
262
257
|
|
|
263
258
|
self.actionPlot_current_time_budget.triggered.connect(lambda: self.behaviors_bar_plot(mode="current"))
|
|
@@ -265,10 +260,13 @@ def connections(self):
|
|
|
265
260
|
self.actionFind_in_current_obs.triggered.connect(lambda: event_operations.find_events(self))
|
|
266
261
|
|
|
267
262
|
# table Widget double click
|
|
268
|
-
self.twEvents.itemDoubleClicked.connect(self.twEvents_doubleClicked)
|
|
263
|
+
# self.twEvents.itemDoubleClicked.connect(self.twEvents_doubleClicked)
|
|
269
264
|
self.twEthogram.itemDoubleClicked.connect(self.twEthogram_doubleClicked)
|
|
270
265
|
self.twSubjects.itemDoubleClicked.connect(self.twSubjects_doubleClicked)
|
|
271
266
|
|
|
267
|
+
# events tableview
|
|
268
|
+
self.tv_events.doubleClicked.connect(self.tv_events_doubleClicked)
|
|
269
|
+
|
|
272
270
|
# Actions for twEthogram context menu
|
|
273
271
|
self.twEthogram.setContextMenuPolicy(Qt.ActionsContextMenu)
|
|
274
272
|
self.twEthogram.horizontalHeader().sortIndicatorChanged.connect(self.twEthogram_sorted)
|
|
@@ -276,7 +274,9 @@ def connections(self):
|
|
|
276
274
|
self.actionViewBehavior.triggered.connect(self.view_behavior)
|
|
277
275
|
self.twEthogram.addAction(self.actionViewBehavior)
|
|
278
276
|
|
|
279
|
-
self.actionFilterBehaviors.triggered.connect(
|
|
277
|
+
self.actionFilterBehaviors.triggered.connect(
|
|
278
|
+
lambda: self.filter_behaviors(table=cfg.ETHOGRAM, behavior_type=cfg.STATE_EVENT_TYPES + cfg.POINT_EVENT_TYPES)
|
|
279
|
+
)
|
|
280
280
|
self.twEthogram.addAction(self.actionFilterBehaviors)
|
|
281
281
|
|
|
282
282
|
self.actionShowAllBehaviors.triggered.connect(self.show_all_behaviors)
|
|
@@ -292,49 +292,95 @@ def connections(self):
|
|
|
292
292
|
self.twSubjects.addAction(self.actionShowAllSubjects)
|
|
293
293
|
|
|
294
294
|
# actions for twEvents horizontal header menu
|
|
295
|
-
tw_headers = self.twEvents.horizontalHeader()
|
|
296
|
-
tw_headers.setContextMenuPolicy(Qt.ActionsContextMenu)
|
|
297
|
-
tw_headers.addAction(self.actionConfigure_twEvents_columns)
|
|
295
|
+
# tw_headers = self.twEvents.horizontalHeader()
|
|
296
|
+
# tw_headers.setContextMenuPolicy(Qt.ActionsContextMenu)
|
|
297
|
+
# tw_headers.addAction(self.actionConfigure_twEvents_columns)
|
|
298
|
+
|
|
299
|
+
tv_headers = self.tv_events.horizontalHeader()
|
|
300
|
+
tv_headers.setContextMenuPolicy(Qt.ActionsContextMenu)
|
|
301
|
+
tv_headers.addAction(self.actionConfigure_tvevents_columns)
|
|
298
302
|
|
|
299
303
|
# Actions for twEvents menu
|
|
300
|
-
self.twEvents.setContextMenuPolicy(Qt.ActionsContextMenu)
|
|
304
|
+
# self.twEvents.setContextMenuPolicy(Qt.ActionsContextMenu)
|
|
305
|
+
|
|
306
|
+
# self.twEvents.addAction(self.actionAdd_event)
|
|
307
|
+
# self.twEvents.addAction(self.actionEdit_selected_events)
|
|
308
|
+
# self.twEvents.addAction(self.actionEdit_event_time)
|
|
309
|
+
|
|
310
|
+
# self.twEvents.addAction(self.actionCopy_events)
|
|
311
|
+
# self.twEvents.addAction(self.actionPaste_events)
|
|
312
|
+
|
|
313
|
+
# separator2 = QAction(self)
|
|
314
|
+
# separator2.setSeparator(True)
|
|
315
|
+
# self.twEvents.addAction(separator2)
|
|
316
|
+
|
|
317
|
+
# self.twEvents.addAction(self.actionFind_events)
|
|
318
|
+
# self.twEvents.addAction(self.actionFind_replace_events)
|
|
319
|
+
|
|
320
|
+
# separator2 = QAction(self)
|
|
321
|
+
# separator2.setSeparator(True)
|
|
322
|
+
# self.twEvents.addAction(separator2)
|
|
323
|
+
|
|
324
|
+
# self.twEvents.addAction(self.actionFilter_events)
|
|
325
|
+
# self.twEvents.addAction(self.actionShow_all_events)
|
|
301
326
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
self.twEvents.addAction(
|
|
327
|
+
# separator2 = QAction(self)
|
|
328
|
+
# separator2.setSeparator(True)
|
|
329
|
+
# self.twEvents.addAction(separator2)
|
|
305
330
|
|
|
306
|
-
self.twEvents.addAction(self.
|
|
307
|
-
self.twEvents.addAction(self.
|
|
331
|
+
# self.twEvents.addAction(self.actionCheckStateEventsSingleObs)
|
|
332
|
+
# self.twEvents.addAction(self.actionClose_unpaired_events)
|
|
333
|
+
|
|
334
|
+
# self.twEvents.addAction(self.actionRunEventOutside)
|
|
335
|
+
|
|
336
|
+
# separator2 = QAction(self)
|
|
337
|
+
# separator2.setSeparator(True)
|
|
338
|
+
# self.twEvents.addAction(separator2)
|
|
339
|
+
|
|
340
|
+
# self.twEvents.addAction(self.actionDelete_selected_events)
|
|
341
|
+
|
|
342
|
+
# Actions for tv_events menu
|
|
343
|
+
self.tv_events.setContextMenuPolicy(Qt.ActionsContextMenu)
|
|
344
|
+
|
|
345
|
+
self.tv_events.addAction(self.actionAdd_event)
|
|
346
|
+
self.tv_events.addAction(self.actionEdit_selected_events)
|
|
347
|
+
self.tv_events.addAction(self.action_add_comment)
|
|
348
|
+
|
|
349
|
+
self.tv_events.addAction(self.actionEdit_event_time)
|
|
350
|
+
|
|
351
|
+
self.tv_events.addAction(self.actionCopy_events)
|
|
352
|
+
self.tv_events.addAction(self.actionPaste_events)
|
|
308
353
|
|
|
309
354
|
separator2 = QAction(self)
|
|
310
355
|
separator2.setSeparator(True)
|
|
311
|
-
self.
|
|
356
|
+
self.tv_events.addAction(separator2)
|
|
312
357
|
|
|
313
|
-
self.
|
|
314
|
-
self.
|
|
358
|
+
self.tv_events.addAction(self.actionFind_events)
|
|
359
|
+
self.tv_events.addAction(self.actionFind_replace_events)
|
|
315
360
|
|
|
316
361
|
separator2 = QAction(self)
|
|
317
362
|
separator2.setSeparator(True)
|
|
318
|
-
self.
|
|
363
|
+
self.tv_events.addAction(separator2)
|
|
319
364
|
|
|
320
|
-
self.
|
|
321
|
-
self.
|
|
365
|
+
self.tv_events.addAction(self.actionFilter_events)
|
|
366
|
+
self.tv_events.addAction(self.actionShow_all_events)
|
|
322
367
|
|
|
323
368
|
separator2 = QAction(self)
|
|
324
369
|
separator2.setSeparator(True)
|
|
325
|
-
self.
|
|
370
|
+
self.tv_events.addAction(separator2)
|
|
371
|
+
|
|
372
|
+
self.tv_events.addAction(self.actionCheckStateEventsSingleObs)
|
|
373
|
+
self.tv_events.addAction(self.actionClose_unpaired_events)
|
|
326
374
|
|
|
327
|
-
self.
|
|
328
|
-
self.twEvents.addAction(self.actionClose_unpaired_events)
|
|
375
|
+
self.tv_events.addAction(self.actionAdd_frame_indexes)
|
|
329
376
|
|
|
330
|
-
self.
|
|
377
|
+
self.tv_events.addAction(self.actionRunEventOutside)
|
|
331
378
|
|
|
332
379
|
separator2 = QAction(self)
|
|
333
380
|
separator2.setSeparator(True)
|
|
334
|
-
self.
|
|
381
|
+
self.tv_events.addAction(separator2)
|
|
335
382
|
|
|
336
|
-
self.
|
|
337
|
-
# self.twEvents.addAction(self.actionDelete_all_events)
|
|
383
|
+
self.tv_events.addAction(self.actionDelete_selected_events)
|
|
338
384
|
|
|
339
385
|
# Actions for twSubjects context menu
|
|
340
386
|
self.actionDeselectCurrentSubject.triggered.connect(lambda: self.update_subject(""))
|
boris/converters.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
BORIS
|
|
3
3
|
Behavioral Observation Research Interactive Software
|
|
4
|
-
Copyright 2012-
|
|
4
|
+
Copyright 2012-2025 Olivier Friard
|
|
5
5
|
|
|
6
6
|
This file is part of BORIS.
|
|
7
7
|
|
|
@@ -22,14 +22,10 @@ This file is part of BORIS.
|
|
|
22
22
|
|
|
23
23
|
import sys
|
|
24
24
|
import json
|
|
25
|
-
import urllib.error
|
|
26
|
-
import urllib.parse
|
|
27
25
|
import urllib.request
|
|
28
26
|
|
|
29
27
|
|
|
30
|
-
from
|
|
31
|
-
from PyQt5.QtGui import *
|
|
32
|
-
from PyQt5.QtWidgets import *
|
|
28
|
+
from PySide6.QtWidgets import QMessageBox, QTableWidgetItem, QFileDialog, QInputDialog, QLineEdit
|
|
33
29
|
|
|
34
30
|
from . import dialog
|
|
35
31
|
from . import config as cfg
|
|
@@ -113,12 +109,8 @@ def modify_converter(self):
|
|
|
113
109
|
w.setEnabled(False)
|
|
114
110
|
|
|
115
111
|
self.le_converter_name.setText(self.tw_converters.item(self.tw_converters.selectedIndexes()[0].row(), 0).text())
|
|
116
|
-
self.le_converter_description.setText(
|
|
117
|
-
|
|
118
|
-
)
|
|
119
|
-
self.pteCode.setPlainText(
|
|
120
|
-
self.tw_converters.item(self.tw_converters.selectedIndexes()[0].row(), 2).text().replace("@", "\n")
|
|
121
|
-
)
|
|
112
|
+
self.le_converter_description.setText(self.tw_converters.item(self.tw_converters.selectedIndexes()[0].row(), 1).text())
|
|
113
|
+
self.pteCode.setPlainText(self.tw_converters.item(self.tw_converters.selectedIndexes()[0].row(), 2).text().replace("@", "\n"))
|
|
122
114
|
|
|
123
115
|
self.row_in_modification = self.tw_converters.selectedIndexes()[0].row()
|
|
124
116
|
|
|
@@ -153,9 +145,7 @@ def save_converter(self):
|
|
|
153
145
|
return
|
|
154
146
|
|
|
155
147
|
if not self.le_converter_name.text().replace("_", "a").isalnum():
|
|
156
|
-
QMessageBox.critical(
|
|
157
|
-
self, "BORIS", "Forbidden characters are used in converter name.<br>Use a..z, A..Z, 0..9 _"
|
|
158
|
-
)
|
|
148
|
+
QMessageBox.critical(self, "BORIS", "Forbidden characters are used in converter name.<br>Use a..z, A..Z, 0..9 _")
|
|
159
149
|
return
|
|
160
150
|
|
|
161
151
|
# test code with exec
|
|
@@ -164,7 +154,7 @@ def save_converter(self):
|
|
|
164
154
|
QMessageBox.critical(self, "BORIS", "The converter must have Python code")
|
|
165
155
|
return
|
|
166
156
|
|
|
167
|
-
function = code_2_func(self, self.le_converter_name.text(), code)
|
|
157
|
+
function = code_2_func(self, name=self.le_converter_name.text(), code=code)
|
|
168
158
|
|
|
169
159
|
try:
|
|
170
160
|
exec(function)
|
|
@@ -247,8 +237,7 @@ def load_converters_from_file_repo(self, mode: str):
|
|
|
247
237
|
|
|
248
238
|
converters_from_file = {}
|
|
249
239
|
if mode == "file":
|
|
250
|
-
|
|
251
|
-
file_name = fn[0] if type(fn) is tuple else fn
|
|
240
|
+
file_name, _ = QFileDialog.getOpenFileName(self, "Load converters from file", "", "All files (*)")
|
|
252
241
|
|
|
253
242
|
if file_name:
|
|
254
243
|
with open(file_name, "r") as f_in:
|
|
@@ -259,35 +248,25 @@ def load_converters_from_file_repo(self, mode: str):
|
|
|
259
248
|
return
|
|
260
249
|
|
|
261
250
|
if mode == "repo":
|
|
262
|
-
|
|
263
|
-
converters_repo_URL = "http://www.boris.unito.it/archive/converters.json"
|
|
251
|
+
converters_repo_URL = "https://www.boris.unito.it/static/converters.json"
|
|
264
252
|
try:
|
|
265
253
|
converters_from_repo = urllib.request.urlopen(converters_repo_URL).read().strip().decode("utf-8")
|
|
266
254
|
except Exception:
|
|
267
|
-
QMessageBox.critical(
|
|
268
|
-
self, cfg.programName, "An error occured during retrieving converters from BORIS remote repository"
|
|
269
|
-
)
|
|
255
|
+
QMessageBox.critical(self, cfg.programName, "An error occured during retrieving converters from BORIS remote repository")
|
|
270
256
|
return
|
|
271
257
|
|
|
272
258
|
try:
|
|
273
259
|
converters_from_file = eval(converters_from_repo)["BORIS converters"]
|
|
274
260
|
except Exception:
|
|
275
|
-
QMessageBox.critical(
|
|
276
|
-
self, cfg.programName, "An error occured during retrieving converters from BORIS remote repository"
|
|
277
|
-
)
|
|
261
|
+
QMessageBox.critical(self, cfg.programName, "An error occured during retrieving converters from BORIS remote repository")
|
|
278
262
|
return
|
|
279
263
|
|
|
280
264
|
if converters_from_file:
|
|
281
|
-
|
|
282
|
-
diag_choose_conv = dialog.ChooseObservationsToImport(
|
|
283
|
-
"Choose the converters to load:", sorted(list(converters_from_file.keys()))
|
|
284
|
-
)
|
|
265
|
+
diag_choose_conv = dialog.ChooseObservationsToImport("Choose the converters to load:", sorted(list(converters_from_file.keys())))
|
|
285
266
|
|
|
286
267
|
if diag_choose_conv.exec_():
|
|
287
|
-
|
|
288
268
|
selected_converters = diag_choose_conv.get_selected_observations()
|
|
289
269
|
if selected_converters:
|
|
290
|
-
|
|
291
270
|
# extract converter names from table
|
|
292
271
|
converter_names = []
|
|
293
272
|
for row in range(self.tw_converters.rowCount()):
|
|
@@ -325,7 +304,7 @@ def load_converters_from_file_repo(self, mode: str):
|
|
|
325
304
|
else:
|
|
326
305
|
continue
|
|
327
306
|
# test if code does not produce error
|
|
328
|
-
function =
|
|
307
|
+
function = code_2_func(self, name=converter_name, code=converters_from_file[converter]["code"])
|
|
329
308
|
|
|
330
309
|
try:
|
|
331
310
|
exec(function)
|
|
@@ -333,10 +312,7 @@ def load_converters_from_file_repo(self, mode: str):
|
|
|
333
312
|
QMessageBox.critical(
|
|
334
313
|
self,
|
|
335
314
|
"BORIS",
|
|
336
|
-
(
|
|
337
|
-
f"The code of {converter_name} converter produces an error: "
|
|
338
|
-
f"<br><b>{sys.exc_info()[1]}</b>"
|
|
339
|
-
),
|
|
315
|
+
(f"The code of {converter_name} converter produces an error: <br><b>{sys.exc_info()[1]}</b>"),
|
|
340
316
|
)
|
|
341
317
|
|
|
342
318
|
self.tw_converters.setRowCount(self.tw_converters.rowCount() + 1)
|