boris-behav-obs 9.7.12__py3-none-any.whl → 9.7.15__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/analysis_plugins/export_to_feral.py +336 -0
- boris/config.py +5 -2
- boris/converters_ui.py +2 -3
- boris/core.py +127 -124
- boris/plot_spectrogram_rt.py +41 -72
- boris/preferences.py +34 -3
- boris/preferences_ui.py +48 -18
- boris/project_functions.py +7 -10
- boris/version.py +2 -2
- {boris_behav_obs-9.7.12.dist-info → boris_behav_obs-9.7.15.dist-info}/METADATA +2 -2
- {boris_behav_obs-9.7.12.dist-info → boris_behav_obs-9.7.15.dist-info}/RECORD +15 -15
- boris/analysis_plugins/_export_to_feral.py +0 -225
- {boris_behav_obs-9.7.12.dist-info → boris_behav_obs-9.7.15.dist-info}/WHEEL +0 -0
- {boris_behav_obs-9.7.12.dist-info → boris_behav_obs-9.7.15.dist-info}/entry_points.txt +0 -0
- {boris_behav_obs-9.7.12.dist-info → boris_behav_obs-9.7.15.dist-info}/licenses/LICENSE.TXT +0 -0
- {boris_behav_obs-9.7.12.dist-info → boris_behav_obs-9.7.15.dist-info}/top_level.txt +0 -0
boris/core.py
CHANGED
|
@@ -31,31 +31,32 @@ os.environ["PATH"] = str(Path(__file__).parent / "misc") + os.pathsep + os.envir
|
|
|
31
31
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".")))
|
|
32
32
|
|
|
33
33
|
import datetime
|
|
34
|
+
import gzip
|
|
34
35
|
import json
|
|
36
|
+
import locale
|
|
35
37
|
import logging
|
|
38
|
+
import math
|
|
36
39
|
import platform
|
|
37
40
|
import re
|
|
38
|
-
import
|
|
39
|
-
import PIL.ImageEnhance
|
|
40
|
-
from PIL.ImageQt import Image
|
|
41
|
+
import shutil
|
|
41
42
|
import subprocess
|
|
42
|
-
import locale
|
|
43
43
|
import tempfile
|
|
44
|
-
import math
|
|
45
44
|
import time
|
|
46
45
|
import urllib.request
|
|
47
|
-
|
|
48
|
-
from decimal import ROUND_DOWN
|
|
49
|
-
import gzip
|
|
46
|
+
import zipfile
|
|
50
47
|
from collections import deque
|
|
48
|
+
from decimal import ROUND_DOWN
|
|
49
|
+
from decimal import Decimal as dec
|
|
50
|
+
|
|
51
51
|
import matplotlib
|
|
52
|
-
import
|
|
53
|
-
import
|
|
52
|
+
import PIL.Image
|
|
53
|
+
import PIL.ImageEnhance
|
|
54
|
+
from PIL.ImageQt import Image
|
|
54
55
|
|
|
55
56
|
matplotlib.use("QtAgg")
|
|
56
57
|
|
|
57
|
-
from PySide6.QtCore import
|
|
58
|
-
from PySide6.QtGui import
|
|
58
|
+
from PySide6.QtCore import QAbstractTableModel, QDateTime, QElapsedTimer, QEvent, QPoint, QSettings, Qt, QUrl, Signal
|
|
59
|
+
from PySide6.QtGui import QAction, QColor, QDesktopServices, QFont, QIcon, QKeyEvent, QPainter, QPixmap, QPolygon
|
|
59
60
|
from PySide6.QtMultimedia import QSoundEffect
|
|
60
61
|
from PySide6.QtWidgets import (
|
|
61
62
|
QAbstractItemView,
|
|
@@ -74,7 +75,6 @@ from PySide6.QtWidgets import (
|
|
|
74
75
|
QTableWidgetItem,
|
|
75
76
|
)
|
|
76
77
|
|
|
77
|
-
|
|
78
78
|
from . import cmd_arguments
|
|
79
79
|
|
|
80
80
|
# parse command line arguments
|
|
@@ -94,39 +94,39 @@ else:
|
|
|
94
94
|
level=logging.INFO,
|
|
95
95
|
)
|
|
96
96
|
|
|
97
|
-
from . import
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
97
|
+
from . import (
|
|
98
|
+
advanced_event_filtering,
|
|
99
|
+
config_file,
|
|
100
|
+
core_qrc,
|
|
101
|
+
dialog,
|
|
102
|
+
event_operations,
|
|
103
|
+
events_cursor,
|
|
104
|
+
geometric_measurement,
|
|
105
|
+
gui_utilities,
|
|
106
|
+
modifier_coding_map_creator,
|
|
107
|
+
modifiers_coding_map,
|
|
108
|
+
observation_operations,
|
|
109
|
+
otx_parser,
|
|
110
|
+
param_panel,
|
|
111
|
+
plot_events,
|
|
112
|
+
plot_events_rt,
|
|
113
|
+
plot_spectrogram_rt,
|
|
114
|
+
plot_waveform_rt,
|
|
115
|
+
plugins,
|
|
116
|
+
project,
|
|
117
|
+
project_functions,
|
|
118
|
+
select_observations,
|
|
119
|
+
select_subj_behav,
|
|
120
|
+
subjects_pad,
|
|
121
|
+
version,
|
|
122
|
+
video_operations,
|
|
123
|
+
write_event,
|
|
124
|
+
)
|
|
120
125
|
from . import config as cfg
|
|
121
|
-
from . import video_operations
|
|
122
|
-
from . import project
|
|
123
|
-
from . import menu_options as menu_options
|
|
124
126
|
from . import connections as connections
|
|
125
|
-
from . import
|
|
126
|
-
from . import
|
|
127
|
-
from . import
|
|
128
|
-
from . import write_event
|
|
129
|
-
|
|
127
|
+
from . import menu_options as menu_options
|
|
128
|
+
from . import utilities as util
|
|
129
|
+
from .core_ui import Ui_MainWindow
|
|
130
130
|
|
|
131
131
|
logging.debug("test")
|
|
132
132
|
|
|
@@ -177,8 +177,8 @@ class TableModel(QAbstractTableModel):
|
|
|
177
177
|
self.observation_type = observation_type
|
|
178
178
|
|
|
179
179
|
def headerData(self, section: int, orientation: Qt.Orientation, role: int):
|
|
180
|
-
if role == Qt.DisplayRole:
|
|
181
|
-
if orientation == Qt.Horizontal:
|
|
180
|
+
if role == Qt.ItemDataRole.DisplayRole:
|
|
181
|
+
if orientation == Qt.Orientation.Horizontal:
|
|
182
182
|
return self.header[section]
|
|
183
183
|
else:
|
|
184
184
|
return str(section + 1)
|
|
@@ -189,8 +189,8 @@ class TableModel(QAbstractTableModel):
|
|
|
189
189
|
def columnCount(self, parent=None):
|
|
190
190
|
return len(self._data[0]) if self.rowCount() else 0
|
|
191
191
|
|
|
192
|
-
def data(self, index, role=Qt.DisplayRole):
|
|
193
|
-
if role == Qt.DisplayRole:
|
|
192
|
+
def data(self, index, role=Qt.ItemDataRole.DisplayRole):
|
|
193
|
+
if role == Qt.ItemDataRole.DisplayRole:
|
|
194
194
|
row = index.row()
|
|
195
195
|
if 0 <= row < self.rowCount():
|
|
196
196
|
column = index.column()
|
|
@@ -348,7 +348,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
348
348
|
super(MainWindow, self).__init__(parent)
|
|
349
349
|
self.setupUi(self)
|
|
350
350
|
|
|
351
|
-
self.pb_live_obs.setFocusPolicy(Qt.NoFocus)
|
|
351
|
+
self.pb_live_obs.setFocusPolicy(Qt.FocusPolicy.NoFocus)
|
|
352
352
|
|
|
353
353
|
self.ffmpeg_bin = ffmpeg_bin
|
|
354
354
|
# set icons
|
|
@@ -379,7 +379,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
379
379
|
|
|
380
380
|
self.lbLogoBoris.setPixmap(QPixmap(":/logo"))
|
|
381
381
|
self.lbLogoBoris.setScaledContents(False)
|
|
382
|
-
self.lbLogoBoris.setAlignment(Qt.AlignCenter)
|
|
382
|
+
self.lbLogoBoris.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
383
383
|
|
|
384
384
|
self.toolBar.setEnabled(True)
|
|
385
385
|
|
|
@@ -413,13 +413,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
413
413
|
|
|
414
414
|
# observation time interval
|
|
415
415
|
self.lb_obs_time_interval = QLabel()
|
|
416
|
-
self.lb_obs_time_interval.setFrameStyle(QFrame.StyledPanel)
|
|
416
|
+
self.lb_obs_time_interval.setFrameStyle(QFrame.Shape.StyledPanel)
|
|
417
417
|
self.lb_obs_time_interval.setMinimumWidth(160)
|
|
418
418
|
self.statusbar.addPermanentWidget(self.lb_obs_time_interval)
|
|
419
419
|
|
|
420
420
|
# time offset
|
|
421
421
|
self.lbTimeOffset = QLabel()
|
|
422
|
-
self.lbTimeOffset.setFrameStyle(QFrame.StyledPanel)
|
|
422
|
+
self.lbTimeOffset.setFrameStyle(QFrame.Shape.StyledPanel)
|
|
423
423
|
self.lbTimeOffset.setMinimumWidth(160)
|
|
424
424
|
self.statusbar.addPermanentWidget(self.lbTimeOffset)
|
|
425
425
|
|
|
@@ -450,9 +450,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
450
450
|
for w in (self.dwEvents, self.dwEthogram, self.dwSubjects):
|
|
451
451
|
if self.action_block_dockwidgets.isChecked():
|
|
452
452
|
w.setFloating(False)
|
|
453
|
-
w.setFeatures(QDockWidget.NoDockWidgetFeatures)
|
|
453
|
+
w.setFeatures(QDockWidget.DockWidgetFeature.NoDockWidgetFeatures)
|
|
454
454
|
else:
|
|
455
|
-
w.setFeatures(QDockWidget.DockWidgetMovable | QDockWidget.DockWidgetFloatable)
|
|
455
|
+
w.setFeatures(QDockWidget.DockWidgetFeature.DockWidgetMovable | QDockWidget.DockWidgetFeature.DockWidgetFloatable)
|
|
456
456
|
|
|
457
457
|
def advanced_event_filtering(self):
|
|
458
458
|
"""
|
|
@@ -524,7 +524,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
524
524
|
"Removing the path of media files and image directories from the project file is irreversible.<br>"
|
|
525
525
|
"Are you sure to continue?"
|
|
526
526
|
),
|
|
527
|
-
|
|
527
|
+
(cfg.YES, cfg.NO),
|
|
528
528
|
)
|
|
529
529
|
== cfg.NO
|
|
530
530
|
):
|
|
@@ -542,13 +542,13 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
542
542
|
dialog.MessageDialog(
|
|
543
543
|
cfg.programName,
|
|
544
544
|
("Removing the path of external data files is irreversible.<br>Are you sure to continue?"),
|
|
545
|
-
|
|
545
|
+
(cfg.YES, cfg.NO),
|
|
546
546
|
)
|
|
547
547
|
== cfg.NO
|
|
548
548
|
):
|
|
549
549
|
return
|
|
550
550
|
|
|
551
|
-
if project_functions.remove_data_files_path(self.pj
|
|
551
|
+
if project_functions.remove_data_files_path(self.pj):
|
|
552
552
|
self.project_changed()
|
|
553
553
|
|
|
554
554
|
def set_media_files_path_relative_to_project_dir(self):
|
|
@@ -560,7 +560,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
560
560
|
dialog.MessageDialog(
|
|
561
561
|
cfg.programName,
|
|
562
562
|
("Are you sure to continue?"),
|
|
563
|
-
|
|
563
|
+
(cfg.YES, cfg.NO),
|
|
564
564
|
)
|
|
565
565
|
== cfg.NO
|
|
566
566
|
):
|
|
@@ -577,7 +577,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
577
577
|
dialog.MessageDialog(
|
|
578
578
|
cfg.programName,
|
|
579
579
|
("Are you sure to continue?"),
|
|
580
|
-
|
|
580
|
+
(cfg.YES, cfg.NO),
|
|
581
581
|
)
|
|
582
582
|
== cfg.NO
|
|
583
583
|
):
|
|
@@ -697,7 +697,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
697
697
|
QMessageBox.warning(self, cfg.programName, "No subjects to show")
|
|
698
698
|
return
|
|
699
699
|
self.subjects_pad = subjects_pad.SubjectsPad(self.pj, filtered_subjects)
|
|
700
|
-
self.subjects_pad.setWindowFlags(Qt.WindowStaysOnTopHint)
|
|
700
|
+
self.subjects_pad.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
|
|
701
701
|
self.subjects_pad.sendEventSignal.connect(self.signal_from_subjects_pad)
|
|
702
702
|
self.subjects_pad.click_signal.connect(self.click_signal_from_subjects_pad)
|
|
703
703
|
self.subjects_pad.close_signal.connect(self.close_signal_from_subjects_pad)
|
|
@@ -918,7 +918,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
918
918
|
w = dialog.Info_widget()
|
|
919
919
|
w.lwi.setVisible(False)
|
|
920
920
|
w.resize(350, 100)
|
|
921
|
-
w.setWindowFlags(Qt.WindowStaysOnTopHint)
|
|
921
|
+
w.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
|
|
922
922
|
w.setWindowTitle(cfg.programName)
|
|
923
923
|
w.label.setText("Extracting WAV from media files...")
|
|
924
924
|
|
|
@@ -1000,7 +1000,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1000
1000
|
f"You choose to visualize the {plot_type} during this observation.<br>"
|
|
1001
1001
|
f"{plot_type} generation can take some time for long media, be patient"
|
|
1002
1002
|
),
|
|
1003
|
-
|
|
1003
|
+
(cfg.YES, cfg.NO),
|
|
1004
1004
|
)
|
|
1005
1005
|
== cfg.NO
|
|
1006
1006
|
):
|
|
@@ -1018,8 +1018,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1018
1018
|
|
|
1019
1019
|
self.spectro = plot_spectrogram_rt.Plot_spectrogram_RT()
|
|
1020
1020
|
|
|
1021
|
-
self.spectro.setWindowFlags(Qt.WindowStaysOnTopHint)
|
|
1022
|
-
self.spectro.setWindowFlags(self.spectro.windowFlags() & ~Qt.WindowMinimizeButtonHint)
|
|
1021
|
+
self.spectro.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
|
|
1022
|
+
self.spectro.setWindowFlags(self.spectro.windowFlags() & ~Qt.WindowType.WindowMinimizeButtonHint)
|
|
1023
1023
|
|
|
1024
1024
|
self.spectro.interval = self.spectrogram_time_interval
|
|
1025
1025
|
self.spectro.cursor_color = cfg.REALTIME_PLOT_CURSOR_COLOR
|
|
@@ -1039,8 +1039,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1039
1039
|
self,
|
|
1040
1040
|
cfg.programName,
|
|
1041
1041
|
f"Error in spectrogram generation: {r['error']}",
|
|
1042
|
-
QMessageBox.Ok
|
|
1043
|
-
QMessageBox.NoButton,
|
|
1042
|
+
QMessageBox.StandardButton.Ok,
|
|
1043
|
+
QMessageBox.StandardButton.NoButton,
|
|
1044
1044
|
)
|
|
1045
1045
|
del self.spectro
|
|
1046
1046
|
return
|
|
@@ -1091,7 +1091,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1091
1091
|
"You choose to visualize the waveform during this observation.<br>"
|
|
1092
1092
|
"The waveform generation can take some time for long media, be patient"
|
|
1093
1093
|
),
|
|
1094
|
-
|
|
1094
|
+
(cfg.YES, cfg.NO),
|
|
1095
1095
|
)
|
|
1096
1096
|
== cfg.NO
|
|
1097
1097
|
):
|
|
@@ -1109,7 +1109,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1109
1109
|
|
|
1110
1110
|
self.waveform = plot_waveform_rt.Plot_waveform_RT()
|
|
1111
1111
|
|
|
1112
|
-
self.waveform.setWindowFlags(Qt.WindowStaysOnTopHint)
|
|
1112
|
+
self.waveform.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
|
|
1113
1113
|
self.waveform.setWindowFlags(self.waveform.windowFlags() & ~Qt.WindowMinimizeButtonHint)
|
|
1114
1114
|
|
|
1115
1115
|
self.waveform.interval = self.spectrogram_time_interval
|
|
@@ -1122,8 +1122,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1122
1122
|
self,
|
|
1123
1123
|
cfg.programName,
|
|
1124
1124
|
f"Error in waveform generation: {r['error']}",
|
|
1125
|
-
QMessageBox.Ok
|
|
1126
|
-
QMessageBox.NoButton,
|
|
1125
|
+
QMessageBox.StandardButton.Ok,
|
|
1126
|
+
QMessageBox.StandardButton.NoButton,
|
|
1127
1127
|
)
|
|
1128
1128
|
del self.waveform
|
|
1129
1129
|
return
|
|
@@ -1146,7 +1146,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1146
1146
|
|
|
1147
1147
|
self.plot_events = plot_events_rt.Plot_events_RT()
|
|
1148
1148
|
|
|
1149
|
-
self.plot_events.setWindowFlags(Qt.WindowStaysOnTopHint)
|
|
1149
|
+
self.plot_events.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
|
|
1150
1150
|
self.plot_events.setWindowFlags(self.plot_events.windowFlags() & ~Qt.WindowMinimizeButtonHint)
|
|
1151
1151
|
|
|
1152
1152
|
self.plot_events.groupby = "behaviors"
|
|
@@ -1285,8 +1285,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1285
1285
|
self,
|
|
1286
1286
|
cfg.programName,
|
|
1287
1287
|
"No project found",
|
|
1288
|
-
QMessageBox.Ok
|
|
1289
|
-
QMessageBox.NoButton,
|
|
1288
|
+
QMessageBox.StandardButton.Ok,
|
|
1289
|
+
QMessageBox.StandardButton.NoButton,
|
|
1290
1290
|
)
|
|
1291
1291
|
return
|
|
1292
1292
|
|
|
@@ -1301,7 +1301,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1301
1301
|
f"with the same name (<b>{behav_coding_map['name']}</b>).<br>"
|
|
1302
1302
|
"What do you want to do?"
|
|
1303
1303
|
),
|
|
1304
|
-
|
|
1304
|
+
("Replace the coding map", cfg.CANCEL),
|
|
1305
1305
|
)
|
|
1306
1306
|
if response == cfg.CANCEL:
|
|
1307
1307
|
return
|
|
@@ -1658,7 +1658,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1658
1658
|
time.sleep(0.3) # required for correct frame number
|
|
1659
1659
|
|
|
1660
1660
|
dw.frame_viewer.setPixmap(
|
|
1661
|
-
util.pil2pixmap(dw.player.screenshot_raw()).scaled(
|
|
1661
|
+
util.pil2pixmap(dw.player.screenshot_raw()).scaled(
|
|
1662
|
+
dw.frame_viewer.size(), Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation
|
|
1663
|
+
)
|
|
1662
1664
|
)
|
|
1663
1665
|
|
|
1664
1666
|
if self.playerType == cfg.IMAGES:
|
|
@@ -1667,8 +1669,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1667
1669
|
None,
|
|
1668
1670
|
cfg.programName,
|
|
1669
1671
|
("The picture directory has changed since the creation of observation."),
|
|
1670
|
-
QMessageBox.Ok
|
|
1671
|
-
QMessageBox.NoButton,
|
|
1672
|
+
QMessageBox.StandardButton.Ok,
|
|
1673
|
+
QMessageBox.StandardButton.NoButton,
|
|
1672
1674
|
)
|
|
1673
1675
|
return
|
|
1674
1676
|
|
|
@@ -1806,7 +1808,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
1806
1808
|
self,
|
|
1807
1809
|
"Select a directory to save the frames",
|
|
1808
1810
|
os.path.expanduser("~"),
|
|
1809
|
-
options=QFileDialog.ShowDirsOnly,
|
|
1811
|
+
options=QFileDialog.Option.ShowDirsOnly,
|
|
1810
1812
|
)
|
|
1811
1813
|
if not output_dir:
|
|
1812
1814
|
return
|
|
@@ -2188,8 +2190,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2188
2190
|
None,
|
|
2189
2191
|
cfg.programName,
|
|
2190
2192
|
("This function is not yet implemented"),
|
|
2191
|
-
QMessageBox.Ok
|
|
2192
|
-
QMessageBox.NoButton,
|
|
2193
|
+
QMessageBox.StandardButton.Ok,
|
|
2194
|
+
QMessageBox.StandardButton.NoButton,
|
|
2193
2195
|
)
|
|
2194
2196
|
|
|
2195
2197
|
return
|
|
@@ -2280,7 +2282,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2280
2282
|
self.tv_events.setModel(model)
|
|
2281
2283
|
|
|
2282
2284
|
# column width
|
|
2283
|
-
self.tv_events.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)
|
|
2285
|
+
self.tv_events.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Interactive)
|
|
2284
2286
|
|
|
2285
2287
|
def load_tw_events(self, obs_id) -> None:
|
|
2286
2288
|
"""
|
|
@@ -2544,8 +2546,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2544
2546
|
None,
|
|
2545
2547
|
cfg.programName,
|
|
2546
2548
|
("This function is not available for observations with events that do not have timestamp"),
|
|
2547
|
-
QMessageBox.Ok
|
|
2548
|
-
QMessageBox.NoButton,
|
|
2549
|
+
QMessageBox.StandardButton.Ok,
|
|
2550
|
+
QMessageBox.StandardButton.NoButton,
|
|
2549
2551
|
)
|
|
2550
2552
|
return
|
|
2551
2553
|
|
|
@@ -2557,7 +2559,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2557
2559
|
self,
|
|
2558
2560
|
"Choose a directory to save the plots",
|
|
2559
2561
|
os.path.expanduser("~"),
|
|
2560
|
-
options=QFileDialog.ShowDirsOnly,
|
|
2562
|
+
options=QFileDialog.Option.ShowDirsOnly,
|
|
2561
2563
|
)
|
|
2562
2564
|
|
|
2563
2565
|
if not plot_directory:
|
|
@@ -2660,8 +2662,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2660
2662
|
None,
|
|
2661
2663
|
cfg.programName,
|
|
2662
2664
|
("The duration of one or more observation is not available"),
|
|
2663
|
-
QMessageBox.Ok
|
|
2664
|
-
QMessageBox.NoButton,
|
|
2665
|
+
QMessageBox.StandardButton.Ok,
|
|
2666
|
+
QMessageBox.StandardButton.NoButton,
|
|
2665
2667
|
)
|
|
2666
2668
|
return
|
|
2667
2669
|
|
|
@@ -2673,8 +2675,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2673
2675
|
None,
|
|
2674
2676
|
cfg.programName,
|
|
2675
2677
|
("This function is not available for observations with events that do not have timestamp"),
|
|
2676
|
-
QMessageBox.Ok
|
|
2677
|
-
QMessageBox.NoButton,
|
|
2678
|
+
QMessageBox.StandardButton.Ok,
|
|
2679
|
+
QMessageBox.StandardButton.NoButton,
|
|
2678
2680
|
)
|
|
2679
2681
|
return
|
|
2680
2682
|
|
|
@@ -2709,7 +2711,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2709
2711
|
self,
|
|
2710
2712
|
"Choose a directory to save the plots",
|
|
2711
2713
|
os.path.expanduser("~"),
|
|
2712
|
-
options=QFileDialog.ShowDirsOnly,
|
|
2714
|
+
options=QFileDialog.Option.ShowDirsOnly,
|
|
2713
2715
|
)
|
|
2714
2716
|
if not plot_directory:
|
|
2715
2717
|
return
|
|
@@ -2777,7 +2779,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2777
2779
|
dialog.MessageDialog(
|
|
2778
2780
|
cfg.programName,
|
|
2779
2781
|
"There is a current observation. What do you want to do?",
|
|
2780
|
-
|
|
2782
|
+
("Close observation", "Continue observation"),
|
|
2781
2783
|
)
|
|
2782
2784
|
== "Close observation"
|
|
2783
2785
|
):
|
|
@@ -2789,7 +2791,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2789
2791
|
response = dialog.MessageDialog(
|
|
2790
2792
|
cfg.programName,
|
|
2791
2793
|
"What to do about the current unsaved project?",
|
|
2792
|
-
|
|
2794
|
+
(cfg.SAVE, cfg.DISCARD, cfg.CANCEL),
|
|
2793
2795
|
)
|
|
2794
2796
|
|
|
2795
2797
|
if response == cfg.SAVE:
|
|
@@ -2849,7 +2851,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2849
2851
|
"In this project all the behavior and subject keys are upper case.<br>"
|
|
2850
2852
|
"Do you want to convert them in lower case?"
|
|
2851
2853
|
),
|
|
2852
|
-
|
|
2854
|
+
(cfg.YES, cfg.NO),
|
|
2853
2855
|
)
|
|
2854
2856
|
== cfg.YES
|
|
2855
2857
|
):
|
|
@@ -2901,7 +2903,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2901
2903
|
dialog.MessageDialog(
|
|
2902
2904
|
cfg.programName,
|
|
2903
2905
|
"There is a current observation. What do you want to do?",
|
|
2904
|
-
|
|
2906
|
+
("Close observation", "Continue observation"),
|
|
2905
2907
|
)
|
|
2906
2908
|
== "Close observation"
|
|
2907
2909
|
):
|
|
@@ -2913,7 +2915,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2913
2915
|
response = dialog.MessageDialog(
|
|
2914
2916
|
cfg.programName,
|
|
2915
2917
|
"What to do about the current unsaved project?",
|
|
2916
|
-
|
|
2918
|
+
(cfg.SAVE, cfg.DISCARD, cfg.CANCEL),
|
|
2917
2919
|
)
|
|
2918
2920
|
|
|
2919
2921
|
if response == cfg.SAVE:
|
|
@@ -2964,7 +2966,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2964
2966
|
response = dialog.MessageDialog(
|
|
2965
2967
|
cfg.programName,
|
|
2966
2968
|
"There is a current observation. What do you want to do?",
|
|
2967
|
-
|
|
2969
|
+
("Close observation", "Continue observation"),
|
|
2968
2970
|
)
|
|
2969
2971
|
if response == "Close observation":
|
|
2970
2972
|
observation_operations.close_observation(self)
|
|
@@ -2975,7 +2977,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
2975
2977
|
response = dialog.MessageDialog(
|
|
2976
2978
|
cfg.programName,
|
|
2977
2979
|
"What to do about the current unsaved project?",
|
|
2978
|
-
|
|
2980
|
+
(cfg.SAVE, cfg.DISCARD, cfg.CANCEL),
|
|
2979
2981
|
)
|
|
2980
2982
|
if response == cfg.SAVE:
|
|
2981
2983
|
if self.save_project_activated() == "not saved":
|
|
@@ -3019,7 +3021,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3019
3021
|
response = dialog.MessageDialog(
|
|
3020
3022
|
cfg.programName,
|
|
3021
3023
|
"The current observation will be closed. Do you want to continue?",
|
|
3022
|
-
|
|
3024
|
+
(cfg.YES, cfg.NO),
|
|
3023
3025
|
)
|
|
3024
3026
|
if response == cfg.NO:
|
|
3025
3027
|
self.show_data_files()
|
|
@@ -3032,7 +3034,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3032
3034
|
response = dialog.MessageDialog(
|
|
3033
3035
|
cfg.programName,
|
|
3034
3036
|
"What to do with the current unsaved project?",
|
|
3035
|
-
|
|
3037
|
+
(cfg.SAVE, cfg.DISCARD, cfg.CANCEL),
|
|
3036
3038
|
)
|
|
3037
3039
|
|
|
3038
3040
|
if response == cfg.SAVE:
|
|
@@ -3233,7 +3235,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3233
3235
|
|
|
3234
3236
|
del newProjectWindow
|
|
3235
3237
|
|
|
3236
|
-
def save_project_json(self, project_file_name: str) -> int:
|
|
3238
|
+
def save_project_json(self, project_file_name: str) -> int | None:
|
|
3237
3239
|
"""
|
|
3238
3240
|
save project to JSON file
|
|
3239
3241
|
convert Decimal type in float
|
|
@@ -3299,21 +3301,21 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3299
3301
|
None,
|
|
3300
3302
|
cfg.programName,
|
|
3301
3303
|
"Permission denied to save the project file. Try another directory",
|
|
3302
|
-
QMessageBox.Ok
|
|
3303
|
-
QMessageBox.NoButton,
|
|
3304
|
+
QMessageBox.StandardButton.Ok,
|
|
3305
|
+
QMessageBox.StandardButton.NoButton,
|
|
3304
3306
|
)
|
|
3305
3307
|
self.save_project_json_started = False
|
|
3306
3308
|
return 1
|
|
3307
3309
|
|
|
3308
3310
|
except OSError:
|
|
3309
3311
|
_, value, _ = sys.exc_info()
|
|
3310
|
-
QMessageBox.critical(None, cfg.programName, f"Error saving the project file: {value}", QMessageBox.Ok)
|
|
3312
|
+
QMessageBox.critical(None, cfg.programName, f"Error saving the project file: {value}", QMessageBox.StandardButton.Ok)
|
|
3311
3313
|
self.save_project_json_started = False
|
|
3312
3314
|
return 4
|
|
3313
3315
|
|
|
3314
3316
|
except Exception:
|
|
3315
3317
|
_, value, _ = sys.exc_info()
|
|
3316
|
-
QMessageBox.critical(None, cfg.programName, f"Error saving the project file: {value}", QMessageBox.Ok)
|
|
3318
|
+
QMessageBox.critical(None, cfg.programName, f"Error saving the project file: {value}", QMessageBox.StandardButton.Ok)
|
|
3317
3319
|
self.save_project_json_started = False
|
|
3318
3320
|
return 2
|
|
3319
3321
|
|
|
@@ -3344,7 +3346,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3344
3346
|
dialog.MessageDialog(
|
|
3345
3347
|
cfg.programName,
|
|
3346
3348
|
f"The file {project_new_file_name} already exists.",
|
|
3347
|
-
|
|
3349
|
+
(cfg.CANCEL, cfg.OVERWRITE),
|
|
3348
3350
|
)
|
|
3349
3351
|
== cfg.CANCEL
|
|
3350
3352
|
):
|
|
@@ -3360,7 +3362,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3360
3362
|
dialog.MessageDialog(
|
|
3361
3363
|
cfg.programName,
|
|
3362
3364
|
f"The file {project_new_file_name} already exists.",
|
|
3363
|
-
|
|
3365
|
+
(cfg.CANCEL, cfg.OVERWRITE),
|
|
3364
3366
|
)
|
|
3365
3367
|
== cfg.CANCEL
|
|
3366
3368
|
):
|
|
@@ -3440,7 +3442,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3440
3442
|
dialog.MessageDialog(
|
|
3441
3443
|
cfg.programName,
|
|
3442
3444
|
f"The file {self.projectFileName} already exists.",
|
|
3443
|
-
|
|
3445
|
+
(cfg.CANCEL, cfg.OVERWRITE),
|
|
3444
3446
|
)
|
|
3445
3447
|
== cfg.CANCEL
|
|
3446
3448
|
):
|
|
@@ -3459,7 +3461,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3459
3461
|
dialog.MessageDialog(
|
|
3460
3462
|
cfg.programName,
|
|
3461
3463
|
f"The file {self.projectFileName} already exists.",
|
|
3462
|
-
|
|
3464
|
+
(cfg.CANCEL, cfg.OVERWRITE),
|
|
3463
3465
|
)
|
|
3464
3466
|
== cfg.CANCEL
|
|
3465
3467
|
):
|
|
@@ -3622,8 +3624,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3622
3624
|
None,
|
|
3623
3625
|
cfg.programName,
|
|
3624
3626
|
("This function is not available for observations with events that do not have timestamp"),
|
|
3625
|
-
QMessageBox.Ok
|
|
3626
|
-
QMessageBox.NoButton,
|
|
3627
|
+
QMessageBox.StandardButton.Ok,
|
|
3628
|
+
QMessageBox.StandardButton.NoButton,
|
|
3627
3629
|
)
|
|
3628
3630
|
return
|
|
3629
3631
|
|
|
@@ -3656,7 +3658,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3656
3658
|
self,
|
|
3657
3659
|
"Choose a directory to save subtitles",
|
|
3658
3660
|
os.path.expanduser("~"),
|
|
3659
|
-
options=QFileDialog.ShowDirsOnly,
|
|
3661
|
+
options=QFileDialog.Option.ShowDirsOnly,
|
|
3660
3662
|
)
|
|
3661
3663
|
if not export_dir:
|
|
3662
3664
|
return
|
|
@@ -3667,8 +3669,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3667
3669
|
None,
|
|
3668
3670
|
cfg.programName,
|
|
3669
3671
|
f"Error creating subtitles: {msg}",
|
|
3670
|
-
QMessageBox.Ok
|
|
3671
|
-
QMessageBox.NoButton,
|
|
3672
|
+
QMessageBox.StandardButton.Ok,
|
|
3673
|
+
QMessageBox.StandardButton.NoButton,
|
|
3672
3674
|
)
|
|
3673
3675
|
|
|
3674
3676
|
def next_frame(self) -> None:
|
|
@@ -3900,7 +3902,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
3900
3902
|
msg_box = QMessageBox(
|
|
3901
3903
|
QMessageBox.Critical, cfg.programName, f"The code <b>{code}</b> of behavior coding map does not exist in ethogram."
|
|
3902
3904
|
)
|
|
3903
|
-
msg_box.setWindowFlags(msg_box.windowFlags() | Qt.WindowStaysOnTopHint)
|
|
3905
|
+
msg_box.setWindowFlags(msg_box.windowFlags() | Qt.WindowType.WindowStaysOnTopHint)
|
|
3904
3906
|
msg_box.exec()
|
|
3905
3907
|
return
|
|
3906
3908
|
|
|
@@ -4062,17 +4064,18 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
4062
4064
|
|
|
4063
4065
|
Args:
|
|
4064
4066
|
n_player (int): player
|
|
4065
|
-
new_time (
|
|
4067
|
+
new_time (float): new time in ms
|
|
4066
4068
|
"""
|
|
4069
|
+
new_time_dec = dec(new_time)
|
|
4067
4070
|
|
|
4068
4071
|
if self.dw_player[n_player].player.playlist_count == 1:
|
|
4069
4072
|
if self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]:
|
|
4070
4073
|
if self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)] > 0:
|
|
4071
|
-
if
|
|
4074
|
+
if new_time_dec < self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]:
|
|
4072
4075
|
# hide video and mute audio if time < offset
|
|
4073
4076
|
self.media_player_enabled(n_player, enable=False)
|
|
4074
4077
|
else:
|
|
4075
|
-
if
|
|
4078
|
+
if new_time_dec - dec(
|
|
4076
4079
|
self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]
|
|
4077
4080
|
) > sum(self.dw_player[n_player].media_durations):
|
|
4078
4081
|
# hide video and mute audio if required time > video time + offset
|
|
@@ -4081,26 +4084,27 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
4081
4084
|
# show video and enable audio
|
|
4082
4085
|
self.media_player_enabled(n_player, enable=True)
|
|
4083
4086
|
self.seek_mediaplayer(
|
|
4084
|
-
|
|
4087
|
+
new_time_dec
|
|
4085
4088
|
- dec(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]),
|
|
4086
4089
|
player=n_player,
|
|
4087
4090
|
)
|
|
4088
4091
|
|
|
4089
4092
|
elif self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)] < 0:
|
|
4090
|
-
if
|
|
4091
|
-
self.
|
|
4092
|
-
):
|
|
4093
|
+
if new_time_dec - dec(
|
|
4094
|
+
self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]
|
|
4095
|
+
) > sum(self.dw_player[n_player].media_durations):
|
|
4093
4096
|
# hide video and mute audio if required time > video time + offset
|
|
4094
4097
|
self.media_player_enabled(n_player, enable=False)
|
|
4095
4098
|
else:
|
|
4096
4099
|
self.media_player_enabled(n_player, enable=True)
|
|
4097
4100
|
self.seek_mediaplayer(
|
|
4098
|
-
|
|
4101
|
+
new_time_dec
|
|
4102
|
+
- dec(self.pj[cfg.OBSERVATIONS][self.observationId][cfg.MEDIA_INFO][cfg.OFFSET][str(n_player + 1)]),
|
|
4099
4103
|
player=n_player,
|
|
4100
4104
|
)
|
|
4101
4105
|
|
|
4102
4106
|
else: # no offset
|
|
4103
|
-
self.seek_mediaplayer(
|
|
4107
|
+
self.seek_mediaplayer(new_time_dec, player=n_player)
|
|
4104
4108
|
|
|
4105
4109
|
elif self.dw_player[n_player].player.playlist_count > 1:
|
|
4106
4110
|
# check if new time is before the end of last video
|
|
@@ -4297,9 +4301,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
|
|
4297
4301
|
self.mem_media_name = current_media_name
|
|
4298
4302
|
self.mem_playlist_index = current_playlist_index
|
|
4299
4303
|
|
|
4300
|
-
playlist_length = len(self.dw_player[0].player.playlist)
|
|
4301
|
-
|
|
4302
4304
|
# update observation info
|
|
4305
|
+
playlist_length = len(playlist) if playlist else 0
|
|
4303
4306
|
msg = ""
|
|
4304
4307
|
if self.dw_player[0].player.time_pos is not None: # check if video
|
|
4305
4308
|
msg = f"Current media name: <b>{current_media_name}</b> (#{self.dw_player[0].player.playlist_pos + 1} / {playlist_length})<br>"
|