boris-behav-obs 8.27.10__py2.py3-none-any.whl → 9.0.1__py2.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.
- boris/about.py +7 -5
- boris/add_modifier.py +35 -35
- boris/add_modifier_ui.py +229 -129
- boris/advanced_event_filtering.py +3 -3
- boris/analysis_plugins/__init__.py +0 -0
- boris/analysis_plugins/number_of_occurences.py +60 -0
- boris/analysis_plugins/number_of_occurences_by_independent_variable.py +72 -0
- boris/analysis_plugins/time_budget.py +95 -0
- boris/behav_coding_map_creator.py +103 -108
- boris/behavior_binary_table.py +1 -1
- boris/behaviors_coding_map.py +8 -8
- boris/coding_pad.py +6 -6
- boris/config.py +6 -0
- boris/config_file.py +1 -1
- boris/connections.py +4 -2
- boris/converters.py +2 -3
- boris/converters_ui.py +187 -110
- boris/cooccurence.py +2 -2
- boris/core.py +340 -94
- boris/core_qrc.py +16088 -13246
- boris/core_ui.py +922 -812
- boris/dialog.py +14 -13
- boris/duration_widget.py +5 -5
- boris/edit_event.py +1 -1
- boris/edit_event_ui.py +162 -88
- boris/event_operations.py +4 -25
- boris/events_cursor.py +17 -9
- boris/events_snapshots.py +5 -5
- boris/exclusion_matrix.py +1 -1
- boris/export_events.py +38 -28
- boris/export_observation.py +1 -1
- boris/external_processes.py +3 -5
- boris/geometric_measurement.py +49 -26
- boris/gui_utilities.py +31 -30
- boris/import_observations.py +2 -4
- boris/irr.py +1 -1
- boris/latency.py +1 -1
- boris/map_creator.py +77 -89
- boris/measurement_widget.py +4 -4
- boris/media_file.py +2 -4
- boris/menu_options.py +1 -3
- boris/modifiers_coding_map.py +4 -4
- boris/mpv2.py +0 -2
- boris/observation.py +124 -29
- boris/observation_operations.py +18 -40
- boris/observation_ui.py +566 -374
- boris/observations_list.py +6 -6
- boris/param_panel.py +2 -2
- boris/param_panel_ui.py +246 -141
- boris/player_dock_widget.py +16 -21
- boris/plot_data_module.py +6 -6
- boris/plot_events_rt.py +7 -8
- boris/plot_spectrogram_rt.py +7 -8
- boris/plot_waveform_rt.py +6 -7
- boris/plugins.py +79 -0
- boris/preferences.py +127 -17
- boris/preferences_ui.py +464 -240
- boris/project.py +69 -72
- boris/project_functions.py +233 -31
- boris/project_import_export.py +59 -67
- boris/project_ui.py +672 -440
- boris/qrc_boris.py +6 -3
- boris/qrc_boris5.py +6 -3
- boris/select_modifiers.py +2 -2
- boris/select_observations.py +2 -2
- boris/select_subj_behav.py +3 -3
- boris/state_events.py +1 -1
- boris/subjects_pad.py +5 -5
- boris/synthetic_time_budget.py +2 -2
- boris/time_budget_functions.py +15 -0
- boris/time_budget_widget.py +4 -4
- boris/transitions.py +34 -25
- boris/utilities.py +95 -2
- boris/version.py +2 -2
- boris/video_equalizer.py +4 -4
- boris/video_equalizer_ui.py +199 -130
- boris/video_operations.py +1 -1
- boris/view_df.py +106 -0
- boris/view_df_ui.py +75 -0
- boris/write_event.py +9 -1
- {boris_behav_obs-8.27.10.dist-info → boris_behav_obs-9.0.1.dist-info}/METADATA +5 -5
- boris_behav_obs-9.0.1.dist-info/RECORD +103 -0
- {boris_behav_obs-8.27.10.dist-info → boris_behav_obs-9.0.1.dist-info}/WHEEL +1 -1
- boris/qdarkstyle/__init__.py +0 -479
- boris/qdarkstyle/__main__.py +0 -66
- boris/qdarkstyle/colorsystem.py +0 -38
- boris/qdarkstyle/dark/__init__.py +0 -1
- boris/qdarkstyle/dark/darkstyle_rc.py +0 -11379
- boris/qdarkstyle/dark/palette.py +0 -38
- boris/qdarkstyle/example/__init__.py +0 -4
- boris/qdarkstyle/example/__main__.py +0 -386
- boris/qdarkstyle/example/ui/__init__.py +0 -4
- boris/qdarkstyle/light/__init__.py +0 -1
- boris/qdarkstyle/light/lightstyle_rc.py +0 -11305
- boris/qdarkstyle/light/palette.py +0 -37
- boris/qdarkstyle/palette.py +0 -102
- boris/qdarkstyle/utils/__init__.py +0 -73
- boris/qdarkstyle/utils/__main__.py +0 -96
- boris/qdarkstyle/utils/images.py +0 -449
- boris/qdarkstyle/utils/scss.py +0 -318
- boris/vlc_local.py +0 -83
- boris_behav_obs-8.27.10.dist-info/RECORD +0 -114
- {boris_behav_obs-8.27.10.dist-info → boris_behav_obs-9.0.1.dist-info}/LICENSE.TXT +0 -0
- {boris_behav_obs-8.27.10.dist-info → boris_behav_obs-9.0.1.dist-info}/entry_points.txt +0 -0
- {boris_behav_obs-8.27.10.dist-info → boris_behav_obs-9.0.1.dist-info}/top_level.txt +0 -0
boris/measurement_widget.py
CHANGED
|
@@ -22,10 +22,10 @@ This file is part of BORIS.
|
|
|
22
22
|
|
|
23
23
|
import logging
|
|
24
24
|
|
|
25
|
-
from
|
|
25
|
+
from PySide6.QtCore import Signal
|
|
26
26
|
|
|
27
|
-
# from
|
|
28
|
-
from
|
|
27
|
+
# from PySide6.QtGui import *
|
|
28
|
+
from PySide6.QtWidgets import (
|
|
29
29
|
QApplication,
|
|
30
30
|
QWidget,
|
|
31
31
|
QRadioButton,
|
|
@@ -46,7 +46,7 @@ from . import config as cfg
|
|
|
46
46
|
class wgMeasurement(QWidget):
|
|
47
47
|
""" """
|
|
48
48
|
|
|
49
|
-
closeSignal, clearSignal =
|
|
49
|
+
closeSignal, clearSignal = Signal(), Signal()
|
|
50
50
|
flagSaved = True
|
|
51
51
|
draw_mem = []
|
|
52
52
|
|
boris/media_file.py
CHANGED
|
@@ -20,12 +20,11 @@ This file is part of BORIS.
|
|
|
20
20
|
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
|
-
|
|
24
23
|
from . import config as cfg
|
|
25
24
|
from . import utilities as util
|
|
26
25
|
from . import dialog
|
|
27
26
|
from . import project_functions
|
|
28
|
-
from
|
|
27
|
+
from PySide6.QtWidgets import QFileDialog
|
|
29
28
|
|
|
30
29
|
|
|
31
30
|
def get_info(self) -> None:
|
|
@@ -100,8 +99,7 @@ def get_info(self) -> None:
|
|
|
100
99
|
tot_output += mpv_output + ffmpeg_output + "<br><hr>"
|
|
101
100
|
|
|
102
101
|
else: # no open observation
|
|
103
|
-
|
|
104
|
-
file_paths = fn[0] if type(fn) is tuple else fn
|
|
102
|
+
file_paths, _ = QFileDialog().getOpenFileNames(self, "Select a media file", "", "Media files (*)")
|
|
105
103
|
if not file_paths:
|
|
106
104
|
return
|
|
107
105
|
|
boris/menu_options.py
CHANGED
|
@@ -19,10 +19,9 @@ Copyright 2012-2024 Olivier Friard
|
|
|
19
19
|
MA 02110-1301, USA.
|
|
20
20
|
"""
|
|
21
21
|
|
|
22
|
-
|
|
23
22
|
import logging
|
|
24
23
|
from . import config as cfg
|
|
25
|
-
from
|
|
24
|
+
from PySide6.QtCore import QSize
|
|
26
25
|
|
|
27
26
|
|
|
28
27
|
def update_windows_title(self):
|
|
@@ -73,7 +72,6 @@ def update_menu(self):
|
|
|
73
72
|
self.actionExport_project,
|
|
74
73
|
self.actionCheck_project,
|
|
75
74
|
self.actionClose_project,
|
|
76
|
-
self.actionSend_project,
|
|
77
75
|
self.actionNew_observation,
|
|
78
76
|
self.actionRemove_path_from_media_files,
|
|
79
77
|
self.action_create_observations,
|
boris/modifiers_coding_map.py
CHANGED
|
@@ -22,9 +22,9 @@ This file is part of BORIS.
|
|
|
22
22
|
|
|
23
23
|
import binascii
|
|
24
24
|
|
|
25
|
-
from
|
|
26
|
-
from
|
|
27
|
-
from
|
|
25
|
+
from PySide6.QtCore import Signal, QPoint, Qt
|
|
26
|
+
from PySide6.QtGui import QPen, QPixmap, QBrush, QMouseEvent, QPolygonF, QColor
|
|
27
|
+
from PySide6.QtWidgets import (
|
|
28
28
|
QDialog,
|
|
29
29
|
QGraphicsView,
|
|
30
30
|
QGraphicsScene,
|
|
@@ -41,7 +41,7 @@ from PyQt5.QtWidgets import (
|
|
|
41
41
|
|
|
42
42
|
class ModifiersCodingMapWindowClass(QDialog):
|
|
43
43
|
class View(QGraphicsView):
|
|
44
|
-
mousePress =
|
|
44
|
+
mousePress = Signal(QMouseEvent)
|
|
45
45
|
|
|
46
46
|
def mousePressEvent(self, event):
|
|
47
47
|
self.mousePress.emit(event)
|
boris/mpv2.py
CHANGED
boris/observation.py
CHANGED
|
@@ -26,9 +26,9 @@ import pandas as pd
|
|
|
26
26
|
import pathlib as pl
|
|
27
27
|
import datetime as dt
|
|
28
28
|
|
|
29
|
-
from
|
|
30
|
-
from
|
|
31
|
-
from
|
|
29
|
+
from PySide6.QtCore import Qt
|
|
30
|
+
from PySide6.QtGui import QColor, QTextCursor, QAction
|
|
31
|
+
from PySide6.QtWidgets import (
|
|
32
32
|
QDialog,
|
|
33
33
|
QVBoxLayout,
|
|
34
34
|
QHBoxLayout,
|
|
@@ -134,7 +134,8 @@ class Observation(QDialog, Ui_Form):
|
|
|
134
134
|
self.rb_images.toggled.connect(self.obs_type_changed)
|
|
135
135
|
|
|
136
136
|
# button menu for media
|
|
137
|
-
|
|
137
|
+
|
|
138
|
+
add_media_menu_items = [
|
|
138
139
|
"media abs path|with absolute path",
|
|
139
140
|
"media rel path|with relative path",
|
|
140
141
|
{
|
|
@@ -144,10 +145,30 @@ class Observation(QDialog, Ui_Form):
|
|
|
144
145
|
]
|
|
145
146
|
},
|
|
146
147
|
]
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
|
|
149
|
+
self.media_menu = QMenu()
|
|
150
|
+
# Add actions to the menu
|
|
151
|
+
"""
|
|
152
|
+
self.action1 = QAction("with absolute path")
|
|
153
|
+
self.action2 = QAction("with relative path")
|
|
154
|
+
self.action3 = QAction("directory with absolute path")
|
|
155
|
+
self.action4 = QAction("directory with relative path")
|
|
156
|
+
|
|
157
|
+
self.menu.addAction(self.action1)
|
|
158
|
+
self.menu.addAction(self.action2)
|
|
159
|
+
self.menu.addAction(self.action3)
|
|
160
|
+
self.menu.addAction(self.action4)
|
|
161
|
+
|
|
162
|
+
# Connect actions to functions
|
|
163
|
+
self.action1.triggered.connect(lambda: self.add_media(mode="media abs path|with absolute path"))
|
|
164
|
+
self.action2.triggered.connect(lambda: self.add_media(mode="media rel path|with relative path"))
|
|
165
|
+
self.action3.triggered.connect(lambda: self.add_media(mode="dir abs path|with absolute path"))
|
|
166
|
+
self.action4.triggered.connect(lambda: self.add_media(mode="dir rel path|wih relative path"))
|
|
167
|
+
"""
|
|
168
|
+
|
|
169
|
+
self.media_menu.triggered.connect(lambda x: self.add_media(mode=x.statusTip()))
|
|
170
|
+
self.add_button_menu(add_media_menu_items, self.media_menu)
|
|
171
|
+
self.pbAddVideo.setMenu(self.media_menu)
|
|
151
172
|
|
|
152
173
|
self.pbRemoveVideo.clicked.connect(self.remove_media)
|
|
153
174
|
|
|
@@ -157,10 +178,23 @@ class Observation(QDialog, Ui_Form):
|
|
|
157
178
|
"data rel path|with relative path",
|
|
158
179
|
]
|
|
159
180
|
|
|
160
|
-
menu_data = QMenu()
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
181
|
+
self.menu_data = QMenu()
|
|
182
|
+
|
|
183
|
+
# Add actions to the menu
|
|
184
|
+
"""
|
|
185
|
+
self.data_action1 = QAction("with absolute path")
|
|
186
|
+
self.data_action2 = QAction("with relative path")
|
|
187
|
+
self.menu_data.addAction(self.data_action1)
|
|
188
|
+
self.menu_data.addAction(self.data_action2)
|
|
189
|
+
|
|
190
|
+
# Connect actions to functions
|
|
191
|
+
self.data_action1.triggered.connect(lambda: self.add_data_file(mode="data abs path|with absolute path"))
|
|
192
|
+
self.data_action2.triggered.connect(lambda: self.add_data_file(mode="data rel path|with relative path"))
|
|
193
|
+
"""
|
|
194
|
+
|
|
195
|
+
self.menu_data.triggered.connect(lambda x: self.add_data_file(mode=x.statusTip()))
|
|
196
|
+
self.add_button_menu(data_menu_items, self.menu_data)
|
|
197
|
+
self.pb_add_data_file.setMenu(self.menu_data)
|
|
164
198
|
|
|
165
199
|
# button menu for images
|
|
166
200
|
images_menu_items = [
|
|
@@ -168,10 +202,11 @@ class Observation(QDialog, Ui_Form):
|
|
|
168
202
|
"images rel path|with relative path",
|
|
169
203
|
]
|
|
170
204
|
|
|
171
|
-
menu_images = QMenu()
|
|
172
|
-
|
|
173
|
-
self.
|
|
174
|
-
self.
|
|
205
|
+
self.menu_images = QMenu()
|
|
206
|
+
|
|
207
|
+
self.menu_images.triggered.connect(lambda x: self.add_images_directory(mode=x.statusTip()))
|
|
208
|
+
self.add_button_menu(images_menu_items, self.menu_images)
|
|
209
|
+
self.pb_add_directory.setMenu(self.menu_images)
|
|
175
210
|
|
|
176
211
|
self.pb_remove_data_file.clicked.connect(self.remove_data_file)
|
|
177
212
|
self.pb_view_data_head.clicked.connect(self.view_data_file_head_tail)
|
|
@@ -183,8 +218,6 @@ class Observation(QDialog, Ui_Form):
|
|
|
183
218
|
self.cbVisualizeSpectrogram.clicked.connect(self.extract_wav)
|
|
184
219
|
self.cb_visualize_waveform.clicked.connect(self.extract_wav)
|
|
185
220
|
|
|
186
|
-
# self.cb_media_creation_date_as_offset.clicked.connect(self.check_creation_date)
|
|
187
|
-
|
|
188
221
|
self.cb_observation_time_interval.clicked.connect(self.limit_time_interval)
|
|
189
222
|
|
|
190
223
|
self.pbSave.clicked.connect(self.pbSave_clicked)
|
|
@@ -223,6 +256,48 @@ class Observation(QDialog, Ui_Form):
|
|
|
223
256
|
# """
|
|
224
257
|
# self.de_date_offset.setEnabled(self.cb_date_offset.isChecked())
|
|
225
258
|
|
|
259
|
+
def check_media_creation_date(self):
|
|
260
|
+
"""
|
|
261
|
+
check if all media files contain creation date time
|
|
262
|
+
search in metadata then in filename
|
|
263
|
+
"""
|
|
264
|
+
|
|
265
|
+
creation_date_not_found: list = []
|
|
266
|
+
flag_filename_used = False
|
|
267
|
+
|
|
268
|
+
self.media_creation_time = {}
|
|
269
|
+
|
|
270
|
+
if self.cb_media_creation_date_as_offset.isChecked():
|
|
271
|
+
for row in range(self.twVideo1.rowCount()):
|
|
272
|
+
if self.twVideo1.item(row, 2).text(): # media file path
|
|
273
|
+
date_time_original = util.extract_video_creation_date(
|
|
274
|
+
project_functions.full_path(self.twVideo1.item(row, 2).text(), self.project_path)
|
|
275
|
+
)
|
|
276
|
+
if date_time_original is None:
|
|
277
|
+
date_time_file_name = util.extract_date_time_from_file_name(self.twVideo1.item(row, 2).text())
|
|
278
|
+
if date_time_file_name is None:
|
|
279
|
+
creation_date_not_found.append(self.twVideo1.item(row, 2).text())
|
|
280
|
+
else:
|
|
281
|
+
self.media_creation_time[self.twVideo1.item(row, 2).text()] = date_time_file_name
|
|
282
|
+
flag_filename_used = True
|
|
283
|
+
else:
|
|
284
|
+
self.media_creation_time[self.twVideo1.item(row, 2).text()] = date_time_original
|
|
285
|
+
|
|
286
|
+
if creation_date_not_found:
|
|
287
|
+
QMessageBox.warning(
|
|
288
|
+
self, cfg.programName, "The creation date time was not found for all media file(s).\nThe option was disabled."
|
|
289
|
+
)
|
|
290
|
+
self.cb_media_creation_date_as_offset.setChecked(False)
|
|
291
|
+
self.media_creation_time = {}
|
|
292
|
+
return 1
|
|
293
|
+
|
|
294
|
+
elif flag_filename_used:
|
|
295
|
+
QMessageBox.information(
|
|
296
|
+
self, cfg.programName, "The creation date time was not found in metadata. The media file name(s) was/were used"
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
return 0
|
|
300
|
+
|
|
226
301
|
def cb_time_offset_changed(self):
|
|
227
302
|
"""
|
|
228
303
|
activate/desactivate date value
|
|
@@ -237,7 +312,7 @@ class Observation(QDialog, Ui_Form):
|
|
|
237
312
|
QMessageBox.critical(self, cfg.programName, "A media file must be loaded in player #1")
|
|
238
313
|
return
|
|
239
314
|
|
|
240
|
-
first_media_file = ""
|
|
315
|
+
first_media_file: str = ""
|
|
241
316
|
for row in range(self.twVideo1.rowCount()):
|
|
242
317
|
if int(self.twVideo1.cellWidget(row, 0).currentText()) == 1:
|
|
243
318
|
first_media_file = self.twVideo1.item(row, 2).text()
|
|
@@ -513,6 +588,13 @@ class Observation(QDialog, Ui_Form):
|
|
|
513
588
|
else:
|
|
514
589
|
QMessageBox.warning(self, cfg.programName, "Select a data file")
|
|
515
590
|
|
|
591
|
+
def not_editable_column_color(self):
|
|
592
|
+
"""
|
|
593
|
+
return a color for the not editable column
|
|
594
|
+
"""
|
|
595
|
+
window_color = QApplication.instance().palette().window().color()
|
|
596
|
+
return QColor(window_color.red() - 5, window_color.green() - 5, window_color.blue() - 5)
|
|
597
|
+
|
|
516
598
|
def add_data_file(self, mode: str):
|
|
517
599
|
"""
|
|
518
600
|
user select a data file to be plotted synchronously with media file
|
|
@@ -546,16 +628,14 @@ class Observation(QDialog, Ui_Form):
|
|
|
546
628
|
QMessageBox.warning(
|
|
547
629
|
self,
|
|
548
630
|
cfg.programName,
|
|
549
|
-
("It is not yet possible to plot more than 2 external data
|
|
631
|
+
("It is not yet possible to plot more than 2 external data sourcesThis limitation will be removed in future"),
|
|
550
632
|
)
|
|
551
633
|
return
|
|
552
634
|
|
|
553
635
|
fd = QFileDialog()
|
|
554
636
|
fd.setDirectory(os.path.expanduser("~") if (" abs " in mode) else str(pl.Path(self.project_path).parent))
|
|
555
637
|
|
|
556
|
-
|
|
557
|
-
file_name = fn[0] if type(fn) is tuple else fn
|
|
558
|
-
|
|
638
|
+
file_name, _ = fd.getOpenFileName(self, "Add data file", "", "All files (*)")
|
|
559
639
|
if not file_name:
|
|
560
640
|
return
|
|
561
641
|
|
|
@@ -662,7 +742,8 @@ class Observation(QDialog, Ui_Form):
|
|
|
662
742
|
item = QTableWidgetItem(value)
|
|
663
743
|
if col_idx == cfg.PLOT_DATA_CONVERTERS_IDX:
|
|
664
744
|
item.setFlags(Qt.ItemIsEnabled)
|
|
665
|
-
item.setBackground(QColor(230, 230, 230))
|
|
745
|
+
# item.setBackground(QColor(230, 230, 230))
|
|
746
|
+
item.setBackground(self.not_editable_column_color())
|
|
666
747
|
self.tw_data_files.setItem(self.tw_data_files.rowCount() - 1, col_idx, item)
|
|
667
748
|
|
|
668
749
|
# substract first value
|
|
@@ -841,6 +922,7 @@ class Observation(QDialog, Ui_Form):
|
|
|
841
922
|
ret = dlg.exec_()
|
|
842
923
|
"""
|
|
843
924
|
|
|
925
|
+
"""
|
|
844
926
|
not_tagged_media_list: list = []
|
|
845
927
|
for row in range(self.twVideo1.rowCount()):
|
|
846
928
|
if self.twVideo1.item(row, 2).text() not in media_not_found_list:
|
|
@@ -879,6 +961,8 @@ class Observation(QDialog, Ui_Form):
|
|
|
879
961
|
return 1
|
|
880
962
|
else:
|
|
881
963
|
return 0 # OK all media have a 'creation time' tag
|
|
964
|
+
"""
|
|
965
|
+
return 0
|
|
882
966
|
|
|
883
967
|
def closeEvent(self, event):
|
|
884
968
|
"""
|
|
@@ -1062,13 +1146,17 @@ class Observation(QDialog, Ui_Form):
|
|
|
1062
1146
|
return False
|
|
1063
1147
|
|
|
1064
1148
|
# check media creation time tag in metadata
|
|
1065
|
-
# Disable because the check will be made at the
|
|
1149
|
+
# Disable because the check will be made at the observation start
|
|
1066
1150
|
"""
|
|
1067
1151
|
if self.cb_media_creation_date_as_offset.isChecked():
|
|
1068
1152
|
if self.check_creation_date():
|
|
1069
1153
|
return False
|
|
1070
1154
|
"""
|
|
1071
1155
|
|
|
1156
|
+
# check media creation date time (if option enabled)
|
|
1157
|
+
if self.check_media_creation_date():
|
|
1158
|
+
return False
|
|
1159
|
+
|
|
1072
1160
|
if self.rb_images.isChecked(): # observation based on images directory
|
|
1073
1161
|
if not self.lw_images_directory.count():
|
|
1074
1162
|
QMessageBox.critical(self, cfg.programName, "You have to select at least one images directory")
|
|
@@ -1191,8 +1279,7 @@ class Observation(QDialog, Ui_Form):
|
|
|
1191
1279
|
# enable stop ongoing state events if n. media > 1
|
|
1192
1280
|
self.cbCloseCurrentBehaviorsBetweenVideo.setEnabled(self.twVideo1.rowCount() > 0)
|
|
1193
1281
|
|
|
1194
|
-
#
|
|
1195
|
-
self.cb_media_creation_date_as_offset.setEnabled(False)
|
|
1282
|
+
# self.creation_date_as_offset()
|
|
1196
1283
|
|
|
1197
1284
|
def add_media(self, mode: str):
|
|
1198
1285
|
"""
|
|
@@ -1231,8 +1318,7 @@ class Observation(QDialog, Ui_Form):
|
|
|
1231
1318
|
fd.setDirectory(os.path.expanduser("~") if (" abs " in mode) else str(pl.Path(self.project_path).parent))
|
|
1232
1319
|
|
|
1233
1320
|
if "media " in mode:
|
|
1234
|
-
|
|
1235
|
-
file_paths = fn[0] if type(fn) is tuple else fn
|
|
1321
|
+
file_paths, _ = fd.getOpenFileNames(self, "Add media file(s)", "", "All files (*)")
|
|
1236
1322
|
|
|
1237
1323
|
if file_paths:
|
|
1238
1324
|
# store directory for next usage
|
|
@@ -1274,6 +1360,15 @@ class Observation(QDialog, Ui_Form):
|
|
|
1274
1360
|
)
|
|
1275
1361
|
if response == cfg.CANCEL:
|
|
1276
1362
|
break
|
|
1363
|
+
# ask to use directory name / path as observation id
|
|
1364
|
+
if response != cfg.CANCEL:
|
|
1365
|
+
selected_obs_id = dialog.MessageDialog(
|
|
1366
|
+
cfg.programName,
|
|
1367
|
+
"Select the observation id",
|
|
1368
|
+
[dir_name, str(pl.Path(dir_name).name), cfg.CANCEL],
|
|
1369
|
+
)
|
|
1370
|
+
if selected_obs_id != cfg.CANCEL:
|
|
1371
|
+
self.leObservationId.setText(selected_obs_id)
|
|
1277
1372
|
|
|
1278
1373
|
self.update_media_options()
|
|
1279
1374
|
|
boris/observation_operations.py
CHANGED
|
@@ -32,7 +32,7 @@ import datetime as dt
|
|
|
32
32
|
from typing import List, Tuple, Optional
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
from
|
|
35
|
+
from PySide6.QtWidgets import (
|
|
36
36
|
QMessageBox,
|
|
37
37
|
QFileDialog,
|
|
38
38
|
QDateTimeEdit,
|
|
@@ -42,10 +42,10 @@ from PyQt5.QtWidgets import (
|
|
|
42
42
|
QMainWindow,
|
|
43
43
|
QDockWidget,
|
|
44
44
|
)
|
|
45
|
-
from
|
|
46
|
-
from
|
|
45
|
+
from PySide6.QtCore import Qt, QDateTime, QTimer
|
|
46
|
+
from PySide6.QtGui import QFont, QIcon, QTextCursor
|
|
47
47
|
|
|
48
|
-
from
|
|
48
|
+
from PySide6 import QtTest
|
|
49
49
|
|
|
50
50
|
from . import menu_options
|
|
51
51
|
from . import config as cfg
|
|
@@ -137,7 +137,7 @@ def observations_list(self):
|
|
|
137
137
|
QMessageBox.warning(
|
|
138
138
|
self,
|
|
139
139
|
cfg.programName,
|
|
140
|
-
(f"The observation <b>{self.observationId}</b> is running!<br>
|
|
140
|
+
(f"The observation <b>{self.observationId}</b> is running!<br>Close it before editing."),
|
|
141
141
|
)
|
|
142
142
|
|
|
143
143
|
logging.debug("end observations list")
|
|
@@ -490,7 +490,7 @@ def observation_length(pj: dict, selected_observations: list) -> tuple:
|
|
|
490
490
|
if (
|
|
491
491
|
dialog.MessageDialog(
|
|
492
492
|
cfg.programName,
|
|
493
|
-
(f"The observation length is not available (<b>{obs_id}</b>).<br>
|
|
493
|
+
(f"The observation length is not available (<b>{obs_id}</b>).<br>Use last event time as observation length?"),
|
|
494
494
|
(cfg.YES, cfg.NO),
|
|
495
495
|
)
|
|
496
496
|
== cfg.YES
|
|
@@ -655,11 +655,11 @@ def new_observation(self, mode: str = cfg.NEW, obsId: str = "") -> None:
|
|
|
655
655
|
observationWindow.teDescription.setPlainText(self.pj[cfg.OBSERVATIONS][obsId][cfg.DESCRIPTION])
|
|
656
656
|
|
|
657
657
|
try:
|
|
658
|
-
observationWindow.mediaDurations
|
|
659
|
-
observationWindow.mediaFPS
|
|
658
|
+
observationWindow.mediaDurations = self.pj[cfg.OBSERVATIONS][obsId][cfg.MEDIA_INFO][cfg.LENGTH]
|
|
659
|
+
observationWindow.mediaFPS = self.pj[cfg.OBSERVATIONS][obsId][cfg.MEDIA_INFO][cfg.FPS]
|
|
660
660
|
except Exception:
|
|
661
|
-
observationWindow.mediaDurations
|
|
662
|
-
observationWindow.mediaFPS
|
|
661
|
+
observationWindow.mediaDurations = {}
|
|
662
|
+
observationWindow.mediaFPS = {}
|
|
663
663
|
|
|
664
664
|
try:
|
|
665
665
|
if cfg.HAS_VIDEO in self.pj[cfg.OBSERVATIONS][obsId][cfg.MEDIA_INFO]:
|
|
@@ -743,7 +743,7 @@ def new_observation(self, mode: str = cfg.NEW, obsId: str = "") -> None:
|
|
|
743
743
|
observationWindow.cb_media_creation_date_as_offset.setEnabled(True)
|
|
744
744
|
|
|
745
745
|
# DEVELOPMENT (REMOVE BEFORE RELEASE)
|
|
746
|
-
observationWindow.cb_media_creation_date_as_offset.setEnabled(False)
|
|
746
|
+
# observationWindow.cb_media_creation_date_as_offset.setEnabled(False)
|
|
747
747
|
|
|
748
748
|
observationWindow.cb_media_creation_date_as_offset.setChecked(
|
|
749
749
|
self.pj[cfg.OBSERVATIONS][obsId].get(cfg.MEDIA_CREATION_DATE_AS_OFFSET, False)
|
|
@@ -1083,7 +1083,7 @@ def close_observation(self):
|
|
|
1083
1083
|
self.saved_state = self.saveState()
|
|
1084
1084
|
|
|
1085
1085
|
if self.playerType == cfg.MEDIA:
|
|
1086
|
-
self.media_scan_sampling_mem
|
|
1086
|
+
self.media_scan_sampling_mem = []
|
|
1087
1087
|
logging.info("Stop plot timer")
|
|
1088
1088
|
self.plot_timer.stop()
|
|
1089
1089
|
|
|
@@ -1180,31 +1180,6 @@ def check_creation_date(self) -> Tuple[int, dict]:
|
|
|
1180
1180
|
|
|
1181
1181
|
"""
|
|
1182
1182
|
|
|
1183
|
-
# check if media files exist
|
|
1184
|
-
|
|
1185
|
-
"""
|
|
1186
|
-
media_not_found_list: list = []
|
|
1187
|
-
for row in range(self.twVideo1.rowCount()):
|
|
1188
|
-
if not pl.Path(self.twVideo1.item(row, 2).text()).is_file():
|
|
1189
|
-
media_not_found_list.append(self.twVideo1.item(row, 2).text())
|
|
1190
|
-
|
|
1191
|
-
if media_list:
|
|
1192
|
-
dlg = dialog.Results_dialog()
|
|
1193
|
-
dlg.setWindowTitle("BORIS")
|
|
1194
|
-
dlg.pbOK.setText("OK")
|
|
1195
|
-
dlg.pbCancel.setVisible(False)
|
|
1196
|
-
dlg.ptText.clear()
|
|
1197
|
-
dlg.ptText.appendHtml(
|
|
1198
|
-
(
|
|
1199
|
-
"Some media file(s) were not found:<br>"
|
|
1200
|
-
f"{'<br>'.join(media_list)}<br><br>"
|
|
1201
|
-
"You cannot select the <b>Use the media creation date/time option</b>."
|
|
1202
|
-
)
|
|
1203
|
-
)
|
|
1204
|
-
dlg.ptText.moveCursor(QTextCursor.Start)
|
|
1205
|
-
ret = dlg.exec_()
|
|
1206
|
-
"""
|
|
1207
|
-
|
|
1208
1183
|
not_tagged_media_list: list = []
|
|
1209
1184
|
media_creation_time: dict = {}
|
|
1210
1185
|
|
|
@@ -1266,7 +1241,7 @@ def initialize_new_media_observation(self) -> bool:
|
|
|
1266
1241
|
|
|
1267
1242
|
logging.debug("function: initialize new observation for media file(s)")
|
|
1268
1243
|
|
|
1269
|
-
for dw in
|
|
1244
|
+
for dw in (self.dwEthogram, self.dwSubjects, self.dwEvents):
|
|
1270
1245
|
dw.setVisible(True)
|
|
1271
1246
|
|
|
1272
1247
|
ok, msg = project_functions.check_if_media_available(self.pj[cfg.OBSERVATIONS][self.observationId], self.projectFileName)
|
|
@@ -1313,12 +1288,15 @@ def initialize_new_media_observation(self) -> bool:
|
|
|
1313
1288
|
self.dw_player: list = []
|
|
1314
1289
|
|
|
1315
1290
|
# check if media creation time used as offset
|
|
1291
|
+
# TODO check if cfg.MEDIA_CREATION_TIME dict is present
|
|
1292
|
+
"""
|
|
1316
1293
|
if self.pj[cfg.OBSERVATIONS][self.observationId].get(cfg.MEDIA_CREATION_DATE_AS_OFFSET, False):
|
|
1317
1294
|
r, media_creation_time = check_creation_date(self)
|
|
1318
1295
|
|
|
1319
1296
|
if r:
|
|
1320
1297
|
return False
|
|
1321
1298
|
self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.MEDIA_CREATION_TIME] = dict(media_creation_time)
|
|
1299
|
+
"""
|
|
1322
1300
|
|
|
1323
1301
|
# create dock widgets for players
|
|
1324
1302
|
for i in range(cfg.N_PLAYER):
|
|
@@ -1888,7 +1866,7 @@ def initialize_new_media_observation(self) -> bool:
|
|
|
1888
1866
|
self.mpv_eof_reached_signal.connect(self.mpv_eof_reached)
|
|
1889
1867
|
self.video_click_signal.connect(self.player_clicked)
|
|
1890
1868
|
|
|
1891
|
-
self.actionPlay.setIcon(QIcon(":/
|
|
1869
|
+
self.actionPlay.setIcon(QIcon(f":/play_{self.theme_mode()}"))
|
|
1892
1870
|
|
|
1893
1871
|
self.display_statusbar_info(self.observationId)
|
|
1894
1872
|
|
|
@@ -2368,7 +2346,7 @@ def create_observations(self):
|
|
|
2368
2346
|
QMessageBox.critical(
|
|
2369
2347
|
self,
|
|
2370
2348
|
cfg.programName,
|
|
2371
|
-
(f"The observation <b>{media_file}</b> already exists
|
|
2349
|
+
(f"The observation <b>{media_file}</b> already exists.<br><br>Aborting the creation of observations"),
|
|
2372
2350
|
)
|
|
2373
2351
|
return
|
|
2374
2352
|
|