cosmos 3.0.1 → 3.1.0

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.
Files changed (912) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +48 -48
  4. data/.travis.yml +7 -7
  5. data/CONTRIBUTING.txt +50 -50
  6. data/Gemfile +6 -6
  7. data/Guardfile +27 -27
  8. data/LICENSE.txt +879 -879
  9. data/Manifest.txt +1116 -1114
  10. data/README.md +109 -107
  11. data/Rakefile +214 -214
  12. data/autohotkey/config/data/diamond.STL +57 -57
  13. data/autohotkey/config/system/system.txt +34 -34
  14. data/autohotkey/config/targets/COSMOS/cmd_tlm/cosmos_server_cmds.txt +41 -41
  15. data/autohotkey/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +15 -15
  16. data/autohotkey/config/targets/COSMOS/cmd_tlm_server.txt +6 -6
  17. data/autohotkey/config/targets/COSMOS/target.txt +5 -5
  18. data/autohotkey/config/targets/INST/cmd_tlm/inst_cmds.txt +121 -121
  19. data/autohotkey/config/targets/INST/cmd_tlm/inst_tlm.txt +247 -247
  20. data/autohotkey/config/targets/INST/cmd_tlm_server.txt +5 -5
  21. data/autohotkey/config/targets/INST/lib/example_limits_response.rb +30 -30
  22. data/autohotkey/config/targets/INST/lib/sim_inst.rb +305 -294
  23. data/autohotkey/config/targets/INST/screens/adcs.txt +46 -46
  24. data/autohotkey/config/targets/INST/screens/array.txt +7 -7
  25. data/autohotkey/config/targets/INST/screens/block.txt +8 -8
  26. data/autohotkey/config/targets/INST/screens/commanding.txt +30 -30
  27. data/autohotkey/config/targets/INST/screens/graphs.txt +14 -14
  28. data/autohotkey/config/targets/INST/screens/ground.txt +25 -25
  29. data/autohotkey/config/targets/INST/screens/health_status.txt +33 -33
  30. data/autohotkey/config/targets/INST/screens/hs.txt +49 -49
  31. data/autohotkey/config/targets/INST/screens/image.txt +21 -21
  32. data/autohotkey/config/targets/INST/screens/latest.txt +23 -23
  33. data/autohotkey/config/targets/INST/screens/mech.txt +25 -25
  34. data/autohotkey/config/targets/INST/screens/other.txt +25 -25
  35. data/autohotkey/config/targets/INST/screens/params.txt +25 -25
  36. data/autohotkey/config/targets/INST/screens/tabs.txt +68 -68
  37. data/autohotkey/config/targets/INST/target.txt +26 -26
  38. data/autohotkey/config/targets/META/cmd_tlm/meta_cmd.txt +10 -10
  39. data/autohotkey/config/targets/META/cmd_tlm/meta_tlm.txt +9 -9
  40. data/autohotkey/config/targets/SYSTEM/cmd_tlm/limits_groups.txt +7 -7
  41. data/autohotkey/config/targets/SYSTEM/screens/error.txt +11 -11
  42. data/autohotkey/config/tools/cmd_tlm_server/cmd_tlm_server.txt +22 -22
  43. data/autohotkey/config/tools/data_viewer/data_viewer.txt +11 -11
  44. data/autohotkey/config/tools/handbook_creator/handbook_creator.txt +49 -49
  45. data/autohotkey/config/tools/handbook_creator/templates/command_packets.html.erb +86 -86
  46. data/autohotkey/config/tools/handbook_creator/templates/command_toc.html.erb +38 -38
  47. data/autohotkey/config/tools/handbook_creator/templates/footer.html.erb +9 -9
  48. data/autohotkey/config/tools/handbook_creator/templates/header.html.erb +25 -25
  49. data/autohotkey/config/tools/handbook_creator/templates/limits_groups.html.erb +13 -13
  50. data/autohotkey/config/tools/handbook_creator/templates/nav.html.erb +27 -27
  51. data/autohotkey/config/tools/handbook_creator/templates/overview.html.erb +1 -1
  52. data/autohotkey/config/tools/handbook_creator/templates/pdf_cover.html.erb +23 -23
  53. data/autohotkey/config/tools/handbook_creator/templates/pdf_footer.html.erb +33 -33
  54. data/autohotkey/config/tools/handbook_creator/templates/pdf_header.html.erb +41 -41
  55. data/autohotkey/config/tools/handbook_creator/templates/telemetry_packets.html.erb +80 -80
  56. data/autohotkey/config/tools/handbook_creator/templates/telemetry_toc.html.erb +38 -38
  57. data/autohotkey/config/tools/handbook_creator/templates/title.html.erb +1 -1
  58. data/autohotkey/config/tools/launcher/launcher.txt +38 -38
  59. data/autohotkey/config/tools/script_runner/script_runner.txt +3 -3
  60. data/autohotkey/config/tools/table_manager/ConfigTables_def.txt +8 -8
  61. data/autohotkey/config/tools/table_manager/OneDimensionalTable_def.txt +19 -19
  62. data/autohotkey/config/tools/table_manager/TwoDimensionalTable_def.txt +248 -248
  63. data/autohotkey/config/tools/test_runner/test_runner.txt +8 -8
  64. data/autohotkey/config/tools/test_runner/test_runner2.txt +11 -11
  65. data/autohotkey/config/tools/test_runner/test_runner3.txt +6 -6
  66. data/autohotkey/config/tools/test_runner/test_runner4.txt +1 -1
  67. data/autohotkey/config/tools/tlm_extractor/tlm_extractor.txt +13 -13
  68. data/autohotkey/config/tools/tlm_extractor/tlm_extractor2.txt +9 -9
  69. data/autohotkey/config/tools/tlm_grapher/bad.txt +50 -50
  70. data/autohotkey/config/tools/tlm_grapher/temp1-4.txt +51 -51
  71. data/autohotkey/config/tools/tlm_grapher/test2.txt +111 -111
  72. data/autohotkey/config/tools/tlm_viewer/tlm_viewer.txt +24 -24
  73. data/autohotkey/config/tools/tlm_viewer/tlm_viewer2.txt +4 -4
  74. data/autohotkey/config/tools/tlm_viewer/tlm_viewer3.txt +3 -3
  75. data/autohotkey/lib/example_background_task.rb +42 -42
  76. data/autohotkey/lib/user_version.rb +3 -3
  77. data/autohotkey/procedures/clear_util.rb +7 -7
  78. data/autohotkey/procedures/collect.rb +18 -18
  79. data/autohotkey/procedures/collect_util.rb +14 -14
  80. data/autohotkey/procedures/example_test.rb +67 -67
  81. data/autohotkey/procedures/example_test2.rb +74 -74
  82. data/autohotkey/procedures/script_test.rb +17 -17
  83. data/autohotkey/procedures/syntax_error.rb +18 -18
  84. data/autohotkey/tools/CmdExtractorAHK +16 -16
  85. data/autohotkey/tools/CmdSender +14 -14
  86. data/autohotkey/tools/CmdSenderAHK +18 -18
  87. data/autohotkey/tools/CmdTlmServer +14 -14
  88. data/autohotkey/tools/CmdTlmServerAHK +28 -28
  89. data/autohotkey/tools/CmdTlmServerAHK2 +17 -17
  90. data/autohotkey/tools/DataViewer +14 -14
  91. data/autohotkey/tools/DataViewerAHK +17 -17
  92. data/autohotkey/tools/HandbookCreatorAHK +20 -20
  93. data/autohotkey/tools/LauncherAHK +17 -17
  94. data/autohotkey/tools/LimitsMonitorAHK +20 -20
  95. data/autohotkey/tools/OpenGLBuilderAHK +20 -20
  96. data/autohotkey/tools/PacketViewer +14 -14
  97. data/autohotkey/tools/PacketViewerAHK +18 -18
  98. data/autohotkey/tools/PacketViewerAHK2 +17 -17
  99. data/autohotkey/tools/Replay +14 -14
  100. data/autohotkey/tools/Replay.bat +59 -59
  101. data/autohotkey/tools/ReplayAHK +17 -17
  102. data/autohotkey/tools/ScriptRunner +14 -14
  103. data/autohotkey/tools/ScriptRunnerAHK +20 -20
  104. data/autohotkey/tools/ScriptRunnerAHK2 +17 -17
  105. data/autohotkey/tools/TableManager +14 -14
  106. data/autohotkey/tools/TableManagerAHK +30 -30
  107. data/autohotkey/tools/TestRunner +15 -15
  108. data/autohotkey/tools/TestRunnerAHK +17 -17
  109. data/autohotkey/tools/TestRunnerAHK2 +17 -17
  110. data/autohotkey/tools/TestRunnerAHK3 +17 -17
  111. data/autohotkey/tools/TestRunnerAHK4 +17 -17
  112. data/autohotkey/tools/TlmExtractor +15 -15
  113. data/autohotkey/tools/TlmExtractorAHK +19 -19
  114. data/autohotkey/tools/TlmExtractorAHK2 +16 -16
  115. data/autohotkey/tools/TlmExtractorAHK3 +16 -16
  116. data/autohotkey/tools/TlmGrapher +14 -14
  117. data/autohotkey/tools/TlmGrapherAHK +19 -19
  118. data/autohotkey/tools/TlmGrapherAHK2 +23 -23
  119. data/autohotkey/tools/TlmGrapherAHK3 +17 -17
  120. data/autohotkey/tools/TlmGrapherAHK4 +17 -17
  121. data/autohotkey/tools/TlmViewer +14 -14
  122. data/autohotkey/tools/TlmViewerAHK +28 -28
  123. data/autohotkey/tools/TlmViewerAHK2 +18 -18
  124. data/autohotkey/tools/TlmViewerAHK3 +18 -18
  125. data/autohotkey/tools/TlmViewerAHK4 +18 -18
  126. data/autohotkey/tools/TlmViewerAHK5 +18 -18
  127. data/autohotkey/tools/autohotkey.rb +37 -37
  128. data/autohotkey/tools/cmd_extractor.ahk +27 -27
  129. data/autohotkey/tools/cmd_sender.ahk +182 -162
  130. data/autohotkey/tools/cmd_tlm_server.ahk +89 -89
  131. data/autohotkey/tools/cmd_tlm_server2.ahk +45 -45
  132. data/autohotkey/tools/data_viewer.ahk +135 -135
  133. data/autohotkey/tools/handbook_creator.ahk +23 -23
  134. data/autohotkey/tools/launcher.ahk +41 -41
  135. data/autohotkey/tools/limits_monitor.ahk +70 -70
  136. data/autohotkey/tools/open_gl_builder.ahk +134 -134
  137. data/autohotkey/tools/packet_viewer.ahk +143 -143
  138. data/autohotkey/tools/packet_viewer2.ahk +9 -9
  139. data/autohotkey/tools/replay.ahk +98 -98
  140. data/autohotkey/tools/script_runner.ahk +589 -589
  141. data/autohotkey/tools/script_runner2.ahk +34 -31
  142. data/autohotkey/tools/table_manager.ahk +220 -220
  143. data/autohotkey/tools/test_runner.ahk +262 -259
  144. data/autohotkey/tools/test_runner2.ahk +52 -52
  145. data/autohotkey/tools/test_runner3.ahk +13 -13
  146. data/autohotkey/tools/tlm_extractor.ahk +272 -272
  147. data/autohotkey/tools/tlm_grapher.ahk +642 -642
  148. data/autohotkey/tools/tlm_grapher2.ahk +115 -115
  149. data/autohotkey/tools/tlm_grapher3.ahk +24 -24
  150. data/autohotkey/tools/tlm_viewer.ahk +133 -133
  151. data/autohotkey/tools/tlm_viewer2.ahk +50 -49
  152. data/autohotkey/tools/tlm_viewer4.ahk +4 -4
  153. data/autohotkey/tools/tlm_viewer5.ahk +20 -20
  154. data/bin/cosmos +96 -96
  155. data/bin/cstol_converter +1166 -1166
  156. data/bin/rubysloc +85 -85
  157. data/cosmos.gemspec +98 -97
  158. data/data/about.txt +4 -4
  159. data/data/crc.txt +306 -305
  160. data/data/diamond.STL +57 -57
  161. data/data/legal.txt +9 -9
  162. data/demo/Gemfile +6 -6
  163. data/demo/Launcher +15 -15
  164. data/demo/Launcher.bat +59 -59
  165. data/demo/Rakefile +61 -61
  166. data/demo/config/data/crc.txt +222 -206
  167. data/demo/config/data/diamond.STL +57 -57
  168. data/demo/config/data/meta_init.txt +4 -4
  169. data/demo/config/system/system.txt +34 -34
  170. data/demo/config/system/system2.txt +33 -33
  171. data/demo/config/targets/COSMOS/cmd_tlm/cosmos_server_cmds.txt +41 -41
  172. data/demo/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +15 -15
  173. data/demo/config/targets/COSMOS/cmd_tlm_server.txt +6 -6
  174. data/demo/config/targets/COSMOS/screens/limits_change.txt +20 -20
  175. data/demo/config/targets/COSMOS/screens/version.txt +19 -19
  176. data/demo/config/targets/COSMOS/target.txt +11 -11
  177. data/demo/config/targets/EXAMPLE/cmd_tlm/example_cmds.txt +2 -2
  178. data/demo/config/targets/EXAMPLE/cmd_tlm/example_tlm.txt +3 -3
  179. data/demo/config/targets/EXAMPLE/cmd_tlm_server.txt +6 -6
  180. data/demo/config/targets/EXAMPLE/lib/example_interface.rb +22 -22
  181. data/demo/config/targets/EXAMPLE/target.txt +6 -6
  182. data/demo/config/targets/INST/cmd_tlm/inst_cmds.txt +121 -121
  183. data/demo/config/targets/INST/cmd_tlm/inst_tlm.txt +247 -247
  184. data/demo/config/targets/INST/cmd_tlm_server.txt +5 -5
  185. data/demo/config/targets/INST/lib/example_limits_response.rb +30 -30
  186. data/demo/config/targets/INST/lib/sim_inst.rb +305 -294
  187. data/demo/config/targets/INST/screens/adcs.txt +46 -46
  188. data/demo/config/targets/INST/screens/array.txt +15 -15
  189. data/demo/config/targets/INST/screens/block.txt +8 -8
  190. data/demo/config/targets/INST/screens/commanding.txt +30 -30
  191. data/demo/config/targets/INST/screens/graphs.txt +14 -14
  192. data/demo/config/targets/INST/screens/ground.txt +25 -25
  193. data/demo/config/targets/INST/screens/hs.txt +44 -44
  194. data/demo/config/targets/INST/screens/latest.txt +23 -23
  195. data/demo/config/targets/INST/screens/other.txt +29 -29
  196. data/demo/config/targets/INST/screens/tabs.txt +70 -70
  197. data/demo/config/targets/INST/target.txt +33 -33
  198. data/demo/config/targets/META/cmd_tlm/meta_cmd.txt +10 -10
  199. data/demo/config/targets/META/cmd_tlm/meta_tlm.txt +13 -13
  200. data/demo/config/targets/SYSTEM/cmd_tlm/limits_groups.txt +7 -7
  201. data/demo/config/targets/SYSTEM/cmd_tlm/override.txt +29 -29
  202. data/demo/config/targets/SYSTEM/screens/status.txt +12 -12
  203. data/demo/config/targets/TEMPLATED/cmd_tlm/templated_cmds.txt +13 -12
  204. data/demo/config/targets/TEMPLATED/cmd_tlm/templated_tlm.txt +3 -3
  205. data/demo/config/targets/TEMPLATED/cmd_tlm_server.txt +6 -6
  206. data/demo/config/targets/TEMPLATED/lib/templated_interface.rb +54 -48
  207. data/demo/config/targets/TEMPLATED/target.txt +6 -6
  208. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +33 -33
  209. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server2.txt +29 -29
  210. data/demo/config/tools/data_viewer/data_viewer.txt +11 -11
  211. data/demo/config/tools/handbook_creator/handbook_creator.txt +66 -66
  212. data/demo/config/tools/handbook_creator/templates/command_packets.html.erb +86 -86
  213. data/demo/config/tools/handbook_creator/templates/command_toc.html.erb +38 -38
  214. data/demo/config/tools/handbook_creator/templates/footer.html.erb +9 -9
  215. data/demo/config/tools/handbook_creator/templates/header.html.erb +25 -25
  216. data/demo/config/tools/handbook_creator/templates/limits_groups.html.erb +13 -13
  217. data/demo/config/tools/handbook_creator/templates/nav.html.erb +27 -27
  218. data/demo/config/tools/handbook_creator/templates/overview.html.erb +1 -1
  219. data/demo/config/tools/handbook_creator/templates/pdf_cover.html.erb +23 -23
  220. data/demo/config/tools/handbook_creator/templates/pdf_footer.html.erb +33 -33
  221. data/demo/config/tools/handbook_creator/templates/pdf_header.html.erb +41 -41
  222. data/demo/config/tools/handbook_creator/templates/telemetry_packets.html.erb +80 -80
  223. data/demo/config/tools/handbook_creator/templates/telemetry_toc.html.erb +38 -38
  224. data/demo/config/tools/handbook_creator/templates/title.html.erb +1 -1
  225. data/demo/config/tools/launcher/launcher.txt +45 -45
  226. data/demo/config/tools/launcher/launcher2.txt +45 -45
  227. data/demo/config/tools/script_runner/script_runner.txt +3 -3
  228. data/demo/config/tools/table_manager/ConfigTables_def.txt +8 -8
  229. data/demo/config/tools/table_manager/ExampleTableDefinition.txt +24 -24
  230. data/demo/config/tools/table_manager/MCConfigurationTable_fsw1_def.txt +25 -25
  231. data/demo/config/tools/table_manager/MCConfigurationTable_fsw2_def.txt +25 -25
  232. data/demo/config/tools/table_manager/PPSSelectionTable_def.txt +8 -8
  233. data/demo/config/tools/table_manager/TLMMonitoringTable_def.txt +248 -248
  234. data/demo/config/tools/test_runner/test_runner.txt +17 -17
  235. data/demo/config/tools/tlm_extractor/tlm_extractor.txt +13 -13
  236. data/demo/config/tools/tlm_extractor/tlm_extractor2.txt +2 -2
  237. data/demo/config/tools/tlm_extractor/tlm_extractor3.txt +2 -2
  238. data/demo/config/tools/tlm_extractor/tlm_extractor4.txt +2 -2
  239. data/demo/config/tools/tlm_viewer/tlm_viewer.txt +41 -41
  240. data/demo/lib/example_background_task.rb +57 -52
  241. data/demo/lib/example_target.rb +113 -108
  242. data/demo/lib/scpi_target.rb +74 -74
  243. data/demo/lib/user_version.rb +3 -3
  244. data/demo/procedures/checks.rb +11 -11
  245. data/demo/procedures/clear_util.rb +7 -7
  246. data/demo/procedures/collect.rb +18 -18
  247. data/demo/procedures/collect_util.rb +14 -14
  248. data/demo/procedures/cosmos_api_test.rb +293 -293
  249. data/demo/procedures/disconnect.rb +29 -29
  250. data/demo/procedures/example_test.rb +182 -182
  251. data/demo/procedures/plot_test.rb +8 -8
  252. data/demo/procedures/run_example_test.rb +3 -3
  253. data/demo/procedures/test.rb +51 -51
  254. data/demo/tools/CmdExtractor +15 -15
  255. data/demo/tools/CmdExtractor.bat +59 -59
  256. data/demo/tools/CmdSender +15 -15
  257. data/demo/tools/CmdSender.bat +59 -59
  258. data/demo/tools/CmdTlmServer +15 -15
  259. data/demo/tools/CmdTlmServer.bat +59 -59
  260. data/demo/tools/DataViewer +15 -15
  261. data/demo/tools/DataViewer.bat +59 -59
  262. data/demo/tools/ExampleTarget +15 -15
  263. data/demo/tools/ExampleTarget.bat +59 -59
  264. data/demo/tools/HandbookCreator +15 -15
  265. data/demo/tools/HandbookCreator.bat +61 -61
  266. data/demo/tools/Launcher +15 -15
  267. data/demo/tools/Launcher.bat +59 -59
  268. data/demo/tools/LimitsMonitor +15 -15
  269. data/demo/tools/LimitsMonitor.bat +59 -59
  270. data/demo/tools/OpenGLBuilder +15 -15
  271. data/demo/tools/OpenGLBuilder.bat +59 -59
  272. data/demo/tools/PacketViewer +15 -15
  273. data/demo/tools/PacketViewer.bat +59 -59
  274. data/demo/tools/Replay +15 -15
  275. data/demo/tools/Replay.bat +59 -59
  276. data/demo/tools/ScpiTarget +15 -15
  277. data/demo/tools/ScpiTarget.bat +59 -59
  278. data/demo/tools/ScriptRunner +15 -15
  279. data/demo/tools/ScriptRunner.bat +59 -59
  280. data/demo/tools/TableManager +15 -15
  281. data/demo/tools/TableManager.bat +59 -59
  282. data/demo/tools/TestRunner +15 -15
  283. data/demo/tools/TestRunner.bat +59 -59
  284. data/demo/tools/TlmExtractor +15 -15
  285. data/demo/tools/TlmExtractor.bat +59 -59
  286. data/demo/tools/TlmGrapher +15 -15
  287. data/demo/tools/TlmGrapher.bat +59 -59
  288. data/demo/tools/TlmViewer +15 -15
  289. data/demo/tools/TlmViewer.bat +59 -59
  290. data/demo/tools/mac/CmdExtractor.app/Contents/Info.plist +38 -38
  291. data/demo/tools/mac/CmdExtractor.app/Contents/MacOS/CmdExtractor.rb +15 -15
  292. data/demo/tools/mac/CmdExtractor.app/Contents/MacOS/main.sh +6 -6
  293. data/demo/tools/mac/CmdSender.app/Contents/Info.plist +38 -38
  294. data/demo/tools/mac/CmdSender.app/Contents/MacOS/CmdSender.rb +15 -15
  295. data/demo/tools/mac/CmdSender.app/Contents/MacOS/main.sh +6 -6
  296. data/demo/tools/mac/CmdTlmServer.app/Contents/Info.plist +38 -38
  297. data/demo/tools/mac/CmdTlmServer.app/Contents/MacOS/CmdTlmServer.rb +15 -15
  298. data/demo/tools/mac/CmdTlmServer.app/Contents/MacOS/main.sh +6 -6
  299. data/demo/tools/mac/DataViewer.app/Contents/Info.plist +38 -38
  300. data/demo/tools/mac/DataViewer.app/Contents/MacOS/DataViewer.rb +15 -15
  301. data/demo/tools/mac/DataViewer.app/Contents/MacOS/main.sh +6 -6
  302. data/demo/tools/mac/HandbookCreator.app/Contents/Info.plist +38 -38
  303. data/demo/tools/mac/HandbookCreator.app/Contents/MacOS/HandbookCreator.rb +15 -15
  304. data/demo/tools/mac/HandbookCreator.app/Contents/MacOS/main.sh +6 -6
  305. data/demo/tools/mac/Launcher.app/Contents/Info.plist +38 -38
  306. data/demo/tools/mac/Launcher.app/Contents/MacOS/Launcher.rb +15 -15
  307. data/demo/tools/mac/Launcher.app/Contents/MacOS/main.sh +6 -6
  308. data/demo/tools/mac/LimitsMonitor.app/Contents/Info.plist +38 -38
  309. data/demo/tools/mac/LimitsMonitor.app/Contents/MacOS/LimitsMonitor.rb +15 -15
  310. data/demo/tools/mac/LimitsMonitor.app/Contents/MacOS/main.sh +6 -6
  311. data/demo/tools/mac/OpenGLBuilder.app/Contents/Info.plist +38 -38
  312. data/demo/tools/mac/OpenGLBuilder.app/Contents/MacOS/OpenGLBuilder.rb +15 -15
  313. data/demo/tools/mac/OpenGLBuilder.app/Contents/MacOS/main.sh +6 -6
  314. data/demo/tools/mac/PacketViewer.app/Contents/Info.plist +38 -38
  315. data/demo/tools/mac/PacketViewer.app/Contents/MacOS/PacketViewer.rb +15 -15
  316. data/demo/tools/mac/PacketViewer.app/Contents/MacOS/main.sh +6 -6
  317. data/demo/tools/mac/Replay.app/Contents/Info.plist +38 -38
  318. data/demo/tools/mac/Replay.app/Contents/MacOS/Replay.rb +15 -15
  319. data/demo/tools/mac/Replay.app/Contents/MacOS/main.sh +6 -6
  320. data/demo/tools/mac/ScriptRunner.app/Contents/Info.plist +38 -38
  321. data/demo/tools/mac/ScriptRunner.app/Contents/MacOS/ScriptRunner.rb +15 -15
  322. data/demo/tools/mac/ScriptRunner.app/Contents/MacOS/main.sh +6 -6
  323. data/demo/tools/mac/TableManager.app/Contents/Info.plist +38 -38
  324. data/demo/tools/mac/TableManager.app/Contents/MacOS/TableManager.rb +15 -15
  325. data/demo/tools/mac/TableManager.app/Contents/MacOS/main.sh +6 -6
  326. data/demo/tools/mac/TestRunner.app/Contents/Info.plist +38 -38
  327. data/demo/tools/mac/TestRunner.app/Contents/MacOS/TestRunner.rb +15 -15
  328. data/demo/tools/mac/TestRunner.app/Contents/MacOS/main.sh +6 -6
  329. data/demo/tools/mac/TlmExtractor.app/Contents/Info.plist +38 -38
  330. data/demo/tools/mac/TlmExtractor.app/Contents/MacOS/TlmExtractor.rb +15 -15
  331. data/demo/tools/mac/TlmExtractor.app/Contents/MacOS/main.sh +6 -6
  332. data/demo/tools/mac/TlmGrapher.app/Contents/Info.plist +38 -38
  333. data/demo/tools/mac/TlmGrapher.app/Contents/MacOS/TlmGrapher.rb +15 -15
  334. data/demo/tools/mac/TlmGrapher.app/Contents/MacOS/main.sh +6 -6
  335. data/demo/tools/mac/TlmViewer.app/Contents/Info.plist +38 -38
  336. data/demo/tools/mac/TlmViewer.app/Contents/MacOS/TlmViewer.rb +15 -15
  337. data/demo/tools/mac/TlmViewer.app/Contents/MacOS/main.sh +6 -6
  338. data/ext/cosmos/ext/array/array.c +111 -111
  339. data/ext/cosmos/ext/array/extconf.rb +13 -13
  340. data/ext/cosmos/ext/buffered_file/buffered_file.c +167 -167
  341. data/ext/cosmos/ext/buffered_file/extconf.rb +13 -13
  342. data/ext/cosmos/ext/config_parser/config_parser.c +237 -237
  343. data/ext/cosmos/ext/config_parser/extconf.rb +13 -13
  344. data/ext/cosmos/ext/cosmos_io/cosmos_io.c +117 -117
  345. data/ext/cosmos/ext/cosmos_io/extconf.rb +13 -13
  346. data/ext/cosmos/ext/crc/crc.c +341 -341
  347. data/ext/cosmos/ext/crc/extconf.rb +12 -12
  348. data/ext/cosmos/ext/line_graph/extconf.rb +13 -13
  349. data/ext/cosmos/ext/line_graph/line_graph.c +501 -501
  350. data/ext/cosmos/ext/low_fragmentation_array/extconf.rb +12 -12
  351. data/ext/cosmos/ext/low_fragmentation_array/low_fragmentation_array.c +261 -261
  352. data/ext/cosmos/ext/packet/extconf.rb +13 -13
  353. data/ext/cosmos/ext/packet/packet.c +339 -339
  354. data/ext/cosmos/ext/platform/extconf.rb +13 -13
  355. data/ext/cosmos/ext/platform/platform.c +81 -81
  356. data/ext/cosmos/ext/polynomial_conversion/extconf.rb +13 -13
  357. data/ext/cosmos/ext/polynomial_conversion/polynomial_conversion.c +73 -73
  358. data/ext/cosmos/ext/string/extconf.rb +13 -13
  359. data/ext/cosmos/ext/string/string.c +49 -49
  360. data/ext/cosmos/ext/structure/structure.c +894 -894
  361. data/ext/cosmos/ext/tabbed_plots_config/extconf.rb +13 -13
  362. data/ext/cosmos/ext/tabbed_plots_config/tabbed_plots_config.c +51 -51
  363. data/ext/cosmos/ext/telemetry/extconf.rb +13 -13
  364. data/ext/cosmos/ext/telemetry/telemetry.c +306 -306
  365. data/ext/mkrf_conf.rb +40 -40
  366. data/install/Gemfile +6 -6
  367. data/install/Launcher +14 -14
  368. data/install/Launcher.bat +59 -59
  369. data/install/Rakefile +61 -61
  370. data/install/config/data/crc.txt +134 -133
  371. data/install/config/system/system.txt +29 -29
  372. data/install/config/targets/COSMOS/cmd_tlm/cosmos_server_cmds.txt +41 -41
  373. data/install/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +15 -15
  374. data/install/config/targets/COSMOS/cmd_tlm_server.txt +6 -6
  375. data/install/config/targets/COSMOS/screens/limits_change.txt +20 -20
  376. data/install/config/targets/COSMOS/screens/version.txt +19 -19
  377. data/install/config/targets/COSMOS/target.txt +8 -8
  378. data/install/config/tools/cmd_tlm_server/cmd_tlm_server.txt +2 -2
  379. data/install/config/tools/data_viewer/data_viewer.txt +3 -3
  380. data/install/config/tools/handbook_creator/handbook_creator.txt +49 -49
  381. data/install/config/tools/handbook_creator/templates/command_packets.html.erb +86 -86
  382. data/install/config/tools/handbook_creator/templates/command_toc.html.erb +38 -38
  383. data/install/config/tools/handbook_creator/templates/footer.html.erb +9 -9
  384. data/install/config/tools/handbook_creator/templates/header.html.erb +25 -25
  385. data/install/config/tools/handbook_creator/templates/limits_groups.html.erb +13 -13
  386. data/install/config/tools/handbook_creator/templates/nav.html.erb +27 -27
  387. data/install/config/tools/handbook_creator/templates/overview.html.erb +1 -1
  388. data/install/config/tools/handbook_creator/templates/pdf_cover.html.erb +23 -23
  389. data/install/config/tools/handbook_creator/templates/pdf_footer.html.erb +33 -33
  390. data/install/config/tools/handbook_creator/templates/pdf_header.html.erb +41 -41
  391. data/install/config/tools/handbook_creator/templates/telemetry_packets.html.erb +80 -80
  392. data/install/config/tools/handbook_creator/templates/telemetry_toc.html.erb +38 -38
  393. data/install/config/tools/handbook_creator/templates/title.html.erb +1 -1
  394. data/install/config/tools/launcher/launcher.txt +39 -39
  395. data/install/config/tools/script_runner/script_runner.txt +3 -3
  396. data/install/config/tools/test_runner/test_runner.txt +8 -8
  397. data/install/config/tools/tlm_viewer/tlm_viewer.txt +5 -5
  398. data/install/lib/user_version.rb +3 -3
  399. data/install/tools/CmdExtractor +15 -15
  400. data/install/tools/CmdExtractor.bat +59 -59
  401. data/install/tools/CmdSender +15 -15
  402. data/install/tools/CmdSender.bat +59 -59
  403. data/install/tools/CmdTlmServer +15 -15
  404. data/install/tools/CmdTlmServer.bat +59 -59
  405. data/install/tools/DataViewer +15 -15
  406. data/install/tools/DataViewer.bat +59 -59
  407. data/install/tools/HandbookCreator +15 -15
  408. data/install/tools/HandbookCreator.bat +61 -61
  409. data/install/tools/Launcher +15 -15
  410. data/install/tools/Launcher.bat +59 -59
  411. data/install/tools/LimitsMonitor +15 -15
  412. data/install/tools/LimitsMonitor.bat +59 -59
  413. data/install/tools/OpenGLBuilder +15 -15
  414. data/install/tools/OpenGLBuilder.bat +59 -59
  415. data/install/tools/PacketViewer +15 -15
  416. data/install/tools/PacketViewer.bat +59 -59
  417. data/install/tools/Replay +15 -15
  418. data/install/tools/Replay.bat +59 -59
  419. data/install/tools/ScriptRunner +15 -15
  420. data/install/tools/ScriptRunner.bat +59 -59
  421. data/install/tools/TableManager +15 -15
  422. data/install/tools/TableManager.bat +59 -59
  423. data/install/tools/TestRunner +15 -15
  424. data/install/tools/TestRunner.bat +59 -59
  425. data/install/tools/TlmExtractor +15 -15
  426. data/install/tools/TlmExtractor.bat +59 -59
  427. data/install/tools/TlmGrapher +15 -15
  428. data/install/tools/TlmGrapher.bat +59 -59
  429. data/install/tools/TlmViewer +15 -15
  430. data/install/tools/TlmViewer.bat +59 -59
  431. data/install/tools/mac/CmdExtractor.app/Contents/Info.plist +38 -38
  432. data/install/tools/mac/CmdExtractor.app/Contents/MacOS/CmdExtractor.rb +15 -15
  433. data/install/tools/mac/CmdExtractor.app/Contents/MacOS/main.sh +6 -6
  434. data/install/tools/mac/CmdSender.app/Contents/Info.plist +38 -38
  435. data/install/tools/mac/CmdSender.app/Contents/MacOS/CmdSender.rb +15 -15
  436. data/install/tools/mac/CmdSender.app/Contents/MacOS/main.sh +6 -6
  437. data/install/tools/mac/CmdTlmServer.app/Contents/Info.plist +38 -38
  438. data/install/tools/mac/CmdTlmServer.app/Contents/MacOS/CmdTlmServer.rb +15 -15
  439. data/install/tools/mac/CmdTlmServer.app/Contents/MacOS/main.sh +6 -6
  440. data/install/tools/mac/DataViewer.app/Contents/Info.plist +38 -38
  441. data/install/tools/mac/DataViewer.app/Contents/MacOS/DataViewer.rb +15 -15
  442. data/install/tools/mac/DataViewer.app/Contents/MacOS/main.sh +6 -6
  443. data/install/tools/mac/HandbookCreator.app/Contents/Info.plist +38 -38
  444. data/install/tools/mac/HandbookCreator.app/Contents/MacOS/HandbookCreator.rb +15 -15
  445. data/install/tools/mac/HandbookCreator.app/Contents/MacOS/main.sh +6 -6
  446. data/install/tools/mac/Launcher.app/Contents/Info.plist +38 -38
  447. data/install/tools/mac/Launcher.app/Contents/MacOS/Launcher.rb +15 -15
  448. data/install/tools/mac/Launcher.app/Contents/MacOS/main.sh +6 -6
  449. data/install/tools/mac/LimitsMonitor.app/Contents/Info.plist +38 -38
  450. data/install/tools/mac/LimitsMonitor.app/Contents/MacOS/LimitsMonitor.rb +15 -15
  451. data/install/tools/mac/LimitsMonitor.app/Contents/MacOS/main.sh +6 -6
  452. data/install/tools/mac/OpenGLBuilder.app/Contents/Info.plist +38 -38
  453. data/install/tools/mac/OpenGLBuilder.app/Contents/MacOS/OpenGLBuilder.rb +15 -15
  454. data/install/tools/mac/OpenGLBuilder.app/Contents/MacOS/main.sh +6 -6
  455. data/install/tools/mac/PacketViewer.app/Contents/Info.plist +38 -38
  456. data/install/tools/mac/PacketViewer.app/Contents/MacOS/PacketViewer.rb +15 -15
  457. data/install/tools/mac/PacketViewer.app/Contents/MacOS/main.sh +6 -6
  458. data/install/tools/mac/Replay.app/Contents/Info.plist +38 -38
  459. data/install/tools/mac/Replay.app/Contents/MacOS/Replay.rb +15 -15
  460. data/install/tools/mac/Replay.app/Contents/MacOS/main.sh +6 -6
  461. data/install/tools/mac/ScriptRunner.app/Contents/Info.plist +38 -38
  462. data/install/tools/mac/ScriptRunner.app/Contents/MacOS/ScriptRunner.rb +15 -15
  463. data/install/tools/mac/ScriptRunner.app/Contents/MacOS/main.sh +6 -6
  464. data/install/tools/mac/TableManager.app/Contents/Info.plist +38 -38
  465. data/install/tools/mac/TableManager.app/Contents/MacOS/TableManager.rb +15 -15
  466. data/install/tools/mac/TableManager.app/Contents/MacOS/main.sh +6 -6
  467. data/install/tools/mac/TestRunner.app/Contents/Info.plist +38 -38
  468. data/install/tools/mac/TestRunner.app/Contents/MacOS/TestRunner.rb +15 -15
  469. data/install/tools/mac/TestRunner.app/Contents/MacOS/main.sh +6 -6
  470. data/install/tools/mac/TlmExtractor.app/Contents/Info.plist +38 -38
  471. data/install/tools/mac/TlmExtractor.app/Contents/MacOS/TlmExtractor.rb +15 -15
  472. data/install/tools/mac/TlmExtractor.app/Contents/MacOS/main.sh +6 -6
  473. data/install/tools/mac/TlmGrapher.app/Contents/Info.plist +38 -38
  474. data/install/tools/mac/TlmGrapher.app/Contents/MacOS/TlmGrapher.rb +15 -15
  475. data/install/tools/mac/TlmGrapher.app/Contents/MacOS/main.sh +6 -6
  476. data/install/tools/mac/TlmViewer.app/Contents/Info.plist +38 -38
  477. data/install/tools/mac/TlmViewer.app/Contents/MacOS/TlmViewer.rb +15 -15
  478. data/install/tools/mac/TlmViewer.app/Contents/MacOS/main.sh +6 -6
  479. data/lib/cosmos.rb +63 -63
  480. data/lib/cosmos/ccsds/ccsds_packet.rb +63 -63
  481. data/lib/cosmos/ccsds/ccsds_parser.rb +143 -143
  482. data/lib/cosmos/config/config_parser.rb +324 -324
  483. data/lib/cosmos/conversions.rb +13 -13
  484. data/lib/cosmos/conversions/conversion.rb +47 -47
  485. data/lib/cosmos/conversions/generic_conversion.rb +55 -55
  486. data/lib/cosmos/conversions/new_packet_log_conversion.rb +45 -45
  487. data/lib/cosmos/conversions/polynomial_conversion.rb +57 -57
  488. data/lib/cosmos/conversions/processor_conversion.rb +46 -46
  489. data/lib/cosmos/conversions/received_count_conversion.rb +33 -33
  490. data/lib/cosmos/conversions/received_time_formatted_conversion.rb +37 -37
  491. data/lib/cosmos/conversions/received_time_seconds_conversion.rb +37 -37
  492. data/lib/cosmos/conversions/segmented_polynomial_conversion.rb +128 -128
  493. data/lib/cosmos/conversions/unix_time_conversion.rb +50 -50
  494. data/lib/cosmos/conversions/unix_time_formatted_conversion.rb +44 -44
  495. data/lib/cosmos/conversions/unix_time_seconds_conversion.rb +44 -44
  496. data/lib/cosmos/core_ext.rb +18 -18
  497. data/lib/cosmos/core_ext/array.rb +354 -354
  498. data/lib/cosmos/core_ext/class.rb +51 -51
  499. data/lib/cosmos/core_ext/cosmos_io.rb +29 -29
  500. data/lib/cosmos/core_ext/exception.rb +52 -52
  501. data/lib/cosmos/core_ext/file.rb +75 -75
  502. data/lib/cosmos/core_ext/hash.rb +28 -28
  503. data/lib/cosmos/core_ext/io.rb +75 -75
  504. data/lib/cosmos/core_ext/kernel.rb +38 -38
  505. data/lib/cosmos/core_ext/math.rb +119 -119
  506. data/lib/cosmos/core_ext/matrix.rb +146 -146
  507. data/lib/cosmos/core_ext/objectspace.rb +29 -29
  508. data/lib/cosmos/core_ext/range.rb +22 -22
  509. data/lib/cosmos/core_ext/socket.rb +32 -32
  510. data/lib/cosmos/core_ext/string.rb +310 -310
  511. data/lib/cosmos/core_ext/stringio.rb +24 -24
  512. data/lib/cosmos/core_ext/time.rb +446 -446
  513. data/lib/cosmos/gui/choosers/combobox_chooser.rb +130 -130
  514. data/lib/cosmos/gui/choosers/file_chooser.rb +68 -68
  515. data/lib/cosmos/gui/choosers/float_chooser.rb +82 -82
  516. data/lib/cosmos/gui/choosers/integer_chooser.rb +80 -80
  517. data/lib/cosmos/gui/choosers/string_chooser.rb +53 -53
  518. data/lib/cosmos/gui/choosers/telemetry_chooser.rb +317 -317
  519. data/lib/cosmos/gui/dialogs/about_dialog.rb +128 -128
  520. data/lib/cosmos/gui/dialogs/calendar_dialog.rb +136 -136
  521. data/lib/cosmos/gui/dialogs/cmd_details_dialog.rb +52 -52
  522. data/lib/cosmos/gui/dialogs/cmd_tlm_raw_dialog.rb +149 -149
  523. data/lib/cosmos/gui/dialogs/details_dialog.rb +174 -174
  524. data/lib/cosmos/gui/dialogs/exception_dialog.rb +97 -97
  525. data/lib/cosmos/gui/dialogs/exception_list_dialog.rb +59 -59
  526. data/lib/cosmos/gui/dialogs/find_replace_dialog.rb +196 -196
  527. data/lib/cosmos/gui/dialogs/legal_dialog.rb +169 -168
  528. data/lib/cosmos/gui/dialogs/packet_log_dialog.rb +118 -118
  529. data/lib/cosmos/gui/dialogs/progress_dialog.rb +270 -262
  530. data/lib/cosmos/gui/dialogs/pry_dialog.rb +165 -161
  531. data/lib/cosmos/gui/dialogs/scroll_text_dialog.rb +37 -37
  532. data/lib/cosmos/gui/dialogs/select_dialog.rb +54 -54
  533. data/lib/cosmos/gui/dialogs/set_tlm_dialog.rb +131 -131
  534. data/lib/cosmos/gui/dialogs/splash.rb +113 -113
  535. data/lib/cosmos/gui/dialogs/tlm_details_dialog.rb +206 -206
  536. data/lib/cosmos/gui/dialogs/tlm_edit_dialog.rb +81 -81
  537. data/lib/cosmos/gui/line_graph/line_graph.rb +456 -456
  538. data/lib/cosmos/gui/line_graph/line_graph_dialog.rb +34 -34
  539. data/lib/cosmos/gui/line_graph/line_graph_drawing.rb +494 -494
  540. data/lib/cosmos/gui/line_graph/line_graph_popups.rb +116 -116
  541. data/lib/cosmos/gui/line_graph/line_graph_scaling.rb +460 -460
  542. data/lib/cosmos/gui/line_graph/line_graph_script.rb +26 -26
  543. data/lib/cosmos/gui/line_graph/lines.rb +290 -290
  544. data/lib/cosmos/gui/line_graph/overview_graph.rb +459 -459
  545. data/lib/cosmos/gui/opengl/earth_model.rb +22 -22
  546. data/lib/cosmos/gui/opengl/gl_bounds.rb +67 -67
  547. data/lib/cosmos/gui/opengl/gl_light.rb +39 -39
  548. data/lib/cosmos/gui/opengl/gl_material.rb +29 -29
  549. data/lib/cosmos/gui/opengl/gl_scene.rb +72 -72
  550. data/lib/cosmos/gui/opengl/gl_shape.rb +146 -146
  551. data/lib/cosmos/gui/opengl/gl_viewer.rb +724 -712
  552. data/lib/cosmos/gui/opengl/gl_viewport.rb +35 -35
  553. data/lib/cosmos/gui/opengl/moon_model.rb +22 -22
  554. data/lib/cosmos/gui/opengl/opengl.rb +8 -8
  555. data/lib/cosmos/gui/opengl/stl_reader.rb +211 -211
  556. data/lib/cosmos/gui/opengl/stl_shape.rb +124 -124
  557. data/lib/cosmos/gui/opengl/texture_mapped_sphere.rb +202 -202
  558. data/lib/cosmos/gui/qt.rb +813 -786
  559. data/lib/cosmos/gui/qt_tool.rb +378 -373
  560. data/lib/cosmos/gui/text/completion.rb +381 -381
  561. data/lib/cosmos/gui/text/completion_line_edit.rb +30 -30
  562. data/lib/cosmos/gui/text/completion_text_edit.rb +179 -179
  563. data/lib/cosmos/gui/text/ruby_editor.rb +395 -395
  564. data/lib/cosmos/gui/utilities/screenshot.rb +25 -25
  565. data/lib/cosmos/gui/utilities/script_module_gui.rb +203 -203
  566. data/lib/cosmos/gui/widgets/full_text_search_line_edit.rb +161 -161
  567. data/lib/cosmos/gui/widgets/packet_log_frame.rb +305 -305
  568. data/lib/cosmos/gui/widgets/realtime_button_bar.rb +98 -98
  569. data/lib/cosmos/interfaces.rb +11 -11
  570. data/lib/cosmos/interfaces/cmd_tlm_server_interface.rb +153 -149
  571. data/lib/cosmos/interfaces/interface.rb +213 -213
  572. data/lib/cosmos/interfaces/linc_interface.rb +360 -360
  573. data/lib/cosmos/interfaces/serial_interface.rb +76 -76
  574. data/lib/cosmos/interfaces/simulated_target_interface.rb +129 -128
  575. data/lib/cosmos/interfaces/stream_interface.rb +156 -156
  576. data/lib/cosmos/interfaces/tcpip_client_interface.rb +60 -60
  577. data/lib/cosmos/interfaces/tcpip_server_interface.rb +154 -154
  578. data/lib/cosmos/interfaces/udp_interface.rb +173 -173
  579. data/lib/cosmos/io/buffered_file.rb +11 -11
  580. data/lib/cosmos/io/cosmos_snmp.rb +50 -50
  581. data/lib/cosmos/io/io_multiplexer.rb +89 -89
  582. data/lib/cosmos/io/json_drb.rb +344 -320
  583. data/lib/cosmos/io/json_drb_object.rb +137 -137
  584. data/lib/cosmos/io/json_rpc.rb +365 -365
  585. data/lib/cosmos/io/posix_serial_driver.rb +145 -145
  586. data/lib/cosmos/io/raw_logger.rb +174 -174
  587. data/lib/cosmos/io/raw_logger_pair.rb +71 -71
  588. data/lib/cosmos/io/serial_driver.rb +85 -85
  589. data/lib/cosmos/io/stderr.rb +36 -36
  590. data/lib/cosmos/io/stdout.rb +36 -36
  591. data/lib/cosmos/io/tcpip_server.rb +583 -532
  592. data/lib/cosmos/io/udp_sockets.rb +152 -152
  593. data/lib/cosmos/io/win32_serial_driver.rb +147 -147
  594. data/lib/cosmos/packet_logs.rb +6 -6
  595. data/lib/cosmos/packet_logs/meta_packet_log_writer.rb +107 -107
  596. data/lib/cosmos/packet_logs/packet_log_reader.rb +441 -439
  597. data/lib/cosmos/packet_logs/packet_log_writer.rb +321 -309
  598. data/lib/cosmos/packet_logs/packet_log_writer_pair.rb +30 -30
  599. data/lib/cosmos/packets/binary_accessor.rb +921 -921
  600. data/lib/cosmos/packets/commands.rb +291 -291
  601. data/lib/cosmos/packets/limits.rb +263 -263
  602. data/lib/cosmos/packets/limits_response.rb +38 -38
  603. data/lib/cosmos/packets/packet.rb +714 -699
  604. data/lib/cosmos/packets/packet_config.rb +1034 -1034
  605. data/lib/cosmos/packets/packet_item.rb +317 -317
  606. data/lib/cosmos/packets/packet_item_limits.rb +128 -128
  607. data/lib/cosmos/packets/structure.rb +421 -386
  608. data/lib/cosmos/packets/structure_item.rb +233 -233
  609. data/lib/cosmos/packets/telemetry.rb +317 -317
  610. data/lib/cosmos/processors.rb +6 -6
  611. data/lib/cosmos/processors/new_packet_log_processor.rb +34 -34
  612. data/lib/cosmos/processors/processor.rb +71 -71
  613. data/lib/cosmos/processors/statistics_processor.rb +65 -65
  614. data/lib/cosmos/processors/watermark_processor.rb +44 -44
  615. data/lib/cosmos/script.rb +9 -9
  616. data/lib/cosmos/script/extract.rb +115 -115
  617. data/lib/cosmos/script/script.rb +1513 -1493
  618. data/lib/cosmos/streams/burst_stream_protocol.rb +25 -25
  619. data/lib/cosmos/streams/fixed_stream_protocol.rb +111 -111
  620. data/lib/cosmos/streams/length_stream_protocol.rb +140 -140
  621. data/lib/cosmos/streams/preidentified_stream_protocol.rb +118 -118
  622. data/lib/cosmos/streams/serial_stream.rb +152 -143
  623. data/lib/cosmos/streams/stream.rb +57 -57
  624. data/lib/cosmos/streams/stream_protocol.rb +369 -369
  625. data/lib/cosmos/streams/tcpip_client_stream.rb +77 -77
  626. data/lib/cosmos/streams/tcpip_socket_stream.rb +139 -139
  627. data/lib/cosmos/streams/template_stream_protocol.rb +140 -140
  628. data/lib/cosmos/streams/terminated_stream_protocol.rb +81 -81
  629. data/lib/cosmos/system.rb +4 -4
  630. data/lib/cosmos/system/system.rb +558 -558
  631. data/lib/cosmos/system/target.rb +178 -178
  632. data/lib/cosmos/tools/cmd_extractor/cmd_extractor.rb +254 -253
  633. data/lib/cosmos/tools/cmd_sender/cmd_sender.rb +716 -716
  634. data/lib/cosmos/tools/cmd_sender/cmd_sender_item_delegate.rb +77 -77
  635. data/lib/cosmos/tools/cmd_sender/cmd_sender_text_edit.rb +70 -70
  636. data/lib/cosmos/tools/cmd_tlm_server/api.rb +936 -940
  637. data/lib/cosmos/tools/cmd_tlm_server/background_task.rb +46 -46
  638. data/lib/cosmos/tools/cmd_tlm_server/background_tasks.rb +67 -63
  639. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server.rb +511 -497
  640. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +241 -241
  641. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_gui.rb +1033 -1008
  642. data/lib/cosmos/tools/cmd_tlm_server/commanding.rb +112 -112
  643. data/lib/cosmos/tools/cmd_tlm_server/connections.rb +176 -176
  644. data/lib/cosmos/tools/cmd_tlm_server/interface_thread.rb +241 -221
  645. data/lib/cosmos/tools/cmd_tlm_server/interfaces.rb +127 -127
  646. data/lib/cosmos/tools/cmd_tlm_server/packet_logging.rb +132 -132
  647. data/lib/cosmos/tools/cmd_tlm_server/router_thread.rb +66 -66
  648. data/lib/cosmos/tools/cmd_tlm_server/routers.rb +97 -97
  649. data/lib/cosmos/tools/data_viewer/data_viewer.rb +628 -600
  650. data/lib/cosmos/tools/data_viewer/data_viewer_component.rb +167 -167
  651. data/lib/cosmos/tools/data_viewer/dump_component.rb +40 -40
  652. data/lib/cosmos/tools/handbook_creator/handbook_creator.rb +149 -149
  653. data/lib/cosmos/tools/handbook_creator/handbook_creator_config.rb +360 -360
  654. data/lib/cosmos/tools/launcher/launcher.rb +184 -184
  655. data/lib/cosmos/tools/launcher/launcher_config.rb +175 -167
  656. data/lib/cosmos/tools/launcher/launcher_multitool.rb +40 -41
  657. data/lib/cosmos/tools/launcher/launcher_tool.rb +104 -104
  658. data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +796 -768
  659. data/lib/cosmos/tools/opengl_builder/opengl_builder.rb +416 -416
  660. data/lib/cosmos/tools/opengl_builder/scene_config.rb +118 -118
  661. data/lib/cosmos/tools/packet_viewer/packet_viewer.rb +525 -525
  662. data/lib/cosmos/tools/replay/replay.rb +495 -488
  663. data/lib/cosmos/tools/replay/replay_server.rb +91 -91
  664. data/lib/cosmos/tools/script_runner/script_audit.rb +147 -139
  665. data/lib/cosmos/tools/script_runner/script_runner.rb +914 -914
  666. data/lib/cosmos/tools/script_runner/script_runner_config.rb +40 -40
  667. data/lib/cosmos/tools/script_runner/script_runner_frame.rb +1892 -1859
  668. data/lib/cosmos/tools/table_manager/table.rb +70 -70
  669. data/lib/cosmos/tools/table_manager/table_config.rb +764 -764
  670. data/lib/cosmos/tools/table_manager/table_item.rb +74 -74
  671. data/lib/cosmos/tools/table_manager/table_manager.rb +1065 -1065
  672. data/lib/cosmos/tools/table_manager/table_manager_core.rb +539 -539
  673. data/lib/cosmos/tools/test_runner/results_writer.rb +283 -283
  674. data/lib/cosmos/tools/test_runner/test.rb +480 -480
  675. data/lib/cosmos/tools/test_runner/test_runner.rb +1157 -1157
  676. data/lib/cosmos/tools/test_runner/test_runner_chooser.rb +338 -338
  677. data/lib/cosmos/tools/tlm_extractor/text_item_chooser.rb +60 -60
  678. data/lib/cosmos/tools/tlm_extractor/tlm_extractor.rb +1008 -1008
  679. data/lib/cosmos/tools/tlm_extractor/tlm_extractor_config.rb +371 -371
  680. data/lib/cosmos/tools/tlm_extractor/tlm_extractor_processor.rb +60 -60
  681. data/lib/cosmos/tools/tlm_grapher/data_object_adders/housekeeping_data_object_adder.rb +75 -75
  682. data/lib/cosmos/tools/tlm_grapher/data_object_adders/singlexy_data_object_adder.rb +44 -44
  683. data/lib/cosmos/tools/tlm_grapher/data_object_adders/xy_data_object_adder.rb +94 -94
  684. data/lib/cosmos/tools/tlm_grapher/data_object_editors/data_object_editor.rb +61 -61
  685. data/lib/cosmos/tools/tlm_grapher/data_object_editors/housekeeping_data_object_editor.rb +180 -180
  686. data/lib/cosmos/tools/tlm_grapher/data_object_editors/linegraph_data_object_editor.rb +141 -141
  687. data/lib/cosmos/tools/tlm_grapher/data_object_editors/singlexy_data_object_editor.rb +30 -30
  688. data/lib/cosmos/tools/tlm_grapher/data_object_editors/xy_data_object_editor.rb +173 -173
  689. data/lib/cosmos/tools/tlm_grapher/data_objects/data_object.rb +177 -177
  690. data/lib/cosmos/tools/tlm_grapher/data_objects/housekeeping_data_object.rb +412 -409
  691. data/lib/cosmos/tools/tlm_grapher/data_objects/linegraph_data_object.rb +176 -176
  692. data/lib/cosmos/tools/tlm_grapher/data_objects/singlexy_data_object.rb +25 -25
  693. data/lib/cosmos/tools/tlm_grapher/data_objects/xy_data_object.rb +323 -320
  694. data/lib/cosmos/tools/tlm_grapher/plot_editors/linegraph_plot_editor.rb +181 -181
  695. data/lib/cosmos/tools/tlm_grapher/plot_editors/plot_editor.rb +28 -28
  696. data/lib/cosmos/tools/tlm_grapher/plot_editors/singlexy_plot_editor.rb +30 -30
  697. data/lib/cosmos/tools/tlm_grapher/plot_editors/xy_plot_editor.rb +59 -59
  698. data/lib/cosmos/tools/tlm_grapher/plot_gui_objects/linegraph_plot_gui_object.rb +172 -172
  699. data/lib/cosmos/tools/tlm_grapher/plot_gui_objects/singlexy_plot_gui_object.rb +27 -27
  700. data/lib/cosmos/tools/tlm_grapher/plot_gui_objects/xy_plot_gui_object.rb +74 -74
  701. data/lib/cosmos/tools/tlm_grapher/plots/linegraph_plot.rb +201 -201
  702. data/lib/cosmos/tools/tlm_grapher/plots/plot.rb +69 -69
  703. data/lib/cosmos/tools/tlm_grapher/plots/singlexy_plot.rb +20 -20
  704. data/lib/cosmos/tools/tlm_grapher/plots/xy_plot.rb +61 -61
  705. data/lib/cosmos/tools/tlm_grapher/tabbed_plots/overview_tabbed_plots.rb +1278 -1278
  706. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_config.rb +430 -430
  707. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_data_object_editor.rb +107 -107
  708. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_logfile_thread.rb +111 -95
  709. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_plot_editor.rb +101 -101
  710. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_realtime_thread.rb +72 -66
  711. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_tab.rb +57 -57
  712. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_tool.rb +1004 -1004
  713. data/lib/cosmos/tools/tlm_grapher/tlm_grapher.rb +87 -87
  714. data/lib/cosmos/tools/tlm_viewer/screen.rb +486 -458
  715. data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +563 -544
  716. data/lib/cosmos/tools/tlm_viewer/tlm_viewer_config.rb +287 -287
  717. data/lib/cosmos/tools/tlm_viewer/widgets.rb +53 -53
  718. data/lib/cosmos/tools/tlm_viewer/widgets/aging_widget.rb +110 -110
  719. data/lib/cosmos/tools/tlm_viewer/widgets/array_widget.rb +70 -70
  720. data/lib/cosmos/tools/tlm_viewer/widgets/block_widget.rb +61 -61
  721. data/lib/cosmos/tools/tlm_viewer/widgets/button_widget.rb +39 -39
  722. data/lib/cosmos/tools/tlm_viewer/widgets/canvas_widget.rb +62 -62
  723. data/lib/cosmos/tools/tlm_viewer/widgets/canvasimage_widget.rb +41 -41
  724. data/lib/cosmos/tools/tlm_viewer/widgets/canvasimagevalue_widget.rb +57 -57
  725. data/lib/cosmos/tools/tlm_viewer/widgets/canvaslabel_widget.rb +37 -37
  726. data/lib/cosmos/tools/tlm_viewer/widgets/canvaslabelvalue_widget.rb +56 -56
  727. data/lib/cosmos/tools/tlm_viewer/widgets/canvasline_widget.rb +55 -55
  728. data/lib/cosmos/tools/tlm_viewer/widgets/canvaslinevalue_widget.rb +66 -66
  729. data/lib/cosmos/tools/tlm_viewer/widgets/canvasvalue_widget.rb +124 -124
  730. data/lib/cosmos/tools/tlm_viewer/widgets/checkbutton_widget.rb +31 -31
  731. data/lib/cosmos/tools/tlm_viewer/widgets/combobox_widget.rb +30 -30
  732. data/lib/cosmos/tools/tlm_viewer/widgets/formatfontvalue_widget.rb +36 -36
  733. data/lib/cosmos/tools/tlm_viewer/widgets/formatvalue_widget.rb +35 -35
  734. data/lib/cosmos/tools/tlm_viewer/widgets/horizontal_widget.rb +27 -27
  735. data/lib/cosmos/tools/tlm_viewer/widgets/horizontalbox_widget.rb +31 -31
  736. data/lib/cosmos/tools/tlm_viewer/widgets/horizontalline_widget.rb +26 -26
  737. data/lib/cosmos/tools/tlm_viewer/widgets/label_widget.rb +29 -29
  738. data/lib/cosmos/tools/tlm_viewer/widgets/labelformatvalue_widget.rb +39 -39
  739. data/lib/cosmos/tools/tlm_viewer/widgets/labelprogressbar_widget.rb +38 -38
  740. data/lib/cosmos/tools/tlm_viewer/widgets/labeltrendlimitsbar_widget.rb +38 -38
  741. data/lib/cosmos/tools/tlm_viewer/widgets/labelvalue_widget.rb +39 -39
  742. data/lib/cosmos/tools/tlm_viewer/widgets/labelvaluedesc_widget.rb +42 -42
  743. data/lib/cosmos/tools/tlm_viewer/widgets/labelvaluelimitsbar_widget.rb +37 -37
  744. data/lib/cosmos/tools/tlm_viewer/widgets/labelvaluerangebar_widget.rb +37 -37
  745. data/lib/cosmos/tools/tlm_viewer/widgets/layout_widget.rb +34 -34
  746. data/lib/cosmos/tools/tlm_viewer/widgets/limitsbar_widget.rb +178 -178
  747. data/lib/cosmos/tools/tlm_viewer/widgets/linegraph_widget.rb +54 -54
  748. data/lib/cosmos/tools/tlm_viewer/widgets/matrixbycolumns_widget.rb +47 -47
  749. data/lib/cosmos/tools/tlm_viewer/widgets/multi_widget.rb +116 -116
  750. data/lib/cosmos/tools/tlm_viewer/widgets/progressbar_widget.rb +34 -34
  751. data/lib/cosmos/tools/tlm_viewer/widgets/radiobutton_widget.rb +30 -30
  752. data/lib/cosmos/tools/tlm_viewer/widgets/rangebar_widget.rb +57 -57
  753. data/lib/cosmos/tools/tlm_viewer/widgets/screenshotbutton_widget.rb +34 -34
  754. data/lib/cosmos/tools/tlm_viewer/widgets/scrollwindow_widget.rb +35 -35
  755. data/lib/cosmos/tools/tlm_viewer/widgets/sectionheader_widget.rb +33 -33
  756. data/lib/cosmos/tools/tlm_viewer/widgets/tabbook_widget.rb +26 -26
  757. data/lib/cosmos/tools/tlm_viewer/widgets/tabitem_widget.rb +28 -28
  758. data/lib/cosmos/tools/tlm_viewer/widgets/textbox_widget.rb +47 -47
  759. data/lib/cosmos/tools/tlm_viewer/widgets/textfield_widget.rb +26 -26
  760. data/lib/cosmos/tools/tlm_viewer/widgets/timegraph_widget.rb +88 -88
  761. data/lib/cosmos/tools/tlm_viewer/widgets/title_widget.rb +27 -27
  762. data/lib/cosmos/tools/tlm_viewer/widgets/trendbar_widget.rb +130 -130
  763. data/lib/cosmos/tools/tlm_viewer/widgets/trendlimitsbar_widget.rb +46 -46
  764. data/lib/cosmos/tools/tlm_viewer/widgets/value_widget.rb +43 -43
  765. data/lib/cosmos/tools/tlm_viewer/widgets/valuelimitsbar_widget.rb +37 -37
  766. data/lib/cosmos/tools/tlm_viewer/widgets/valuerangebar_widget.rb +37 -37
  767. data/lib/cosmos/tools/tlm_viewer/widgets/vertical_widget.rb +35 -35
  768. data/lib/cosmos/tools/tlm_viewer/widgets/verticalbox_widget.rb +37 -37
  769. data/lib/cosmos/tools/tlm_viewer/widgets/widget.rb +257 -257
  770. data/lib/cosmos/top_level.rb +647 -596
  771. data/lib/cosmos/utilities.rb +11 -10
  772. data/lib/cosmos/utilities/crc.rb +166 -166
  773. data/lib/cosmos/utilities/csv.rb +83 -83
  774. data/lib/cosmos/utilities/logger.rb +137 -137
  775. data/lib/cosmos/utilities/low_fragmentation_array.rb +11 -11
  776. data/lib/cosmos/utilities/message_log.rb +74 -74
  777. data/lib/cosmos/utilities/quaternion.rb +258 -258
  778. data/lib/cosmos/utilities/ruby_lex_utils.rb +313 -313
  779. data/lib/cosmos/utilities/simulated_target.rb +99 -99
  780. data/lib/cosmos/utilities/sleeper.rb +44 -0
  781. data/lib/cosmos/version.rb +12 -12
  782. data/lib/cosmos/win32/excel.rb +66 -66
  783. data/lib/cosmos/win32/win32.rb +387 -387
  784. data/lib/cosmos/win32/win32_main.rb +311 -311
  785. data/roodi.yml +24 -24
  786. data/run_gui_tests.bat +32 -32
  787. data/spec/ccsds/ccsds_packet_spec.rb +67 -67
  788. data/spec/ccsds/ccsds_parser_spec.rb +148 -148
  789. data/spec/config/config_parser_spec.rb +322 -322
  790. data/spec/conversions/conversion_spec.rb +31 -31
  791. data/spec/conversions/generic_conversion_spec.rb +45 -45
  792. data/spec/conversions/new_packet_log_conversion_spec.rb +39 -39
  793. data/spec/conversions/polynomial_conversion_spec.rb +40 -40
  794. data/spec/conversions/processor_conversion_spec.rb +45 -45
  795. data/spec/conversions/received_count_conversion_spec.rb +43 -43
  796. data/spec/conversions/received_time_formatted_conversion_spec.rb +49 -49
  797. data/spec/conversions/received_time_seconds_conversion_spec.rb +50 -50
  798. data/spec/conversions/segmented_polynomial_conversion_spec.rb +51 -51
  799. data/spec/conversions/unix_time_formatted_conversion_spec.rb +74 -74
  800. data/spec/conversions/unix_time_seconds_conversion_spec.rb +76 -76
  801. data/spec/core_ext/array_spec.rb +186 -186
  802. data/spec/core_ext/class_spec.rb +36 -36
  803. data/spec/core_ext/cosmos_io_spec.rb +77 -77
  804. data/spec/core_ext/exception_spec.rb +91 -91
  805. data/spec/core_ext/file_spec.rb +72 -72
  806. data/spec/core_ext/hash_spec.rb +24 -24
  807. data/spec/core_ext/io_spec.rb +46 -46
  808. data/spec/core_ext/kernel_spec.rb +54 -54
  809. data/spec/core_ext/math_spec.rb +116 -116
  810. data/spec/core_ext/matrix_spec.rb +66 -66
  811. data/spec/core_ext/objectspace_spec.rb +29 -29
  812. data/spec/core_ext/range_spec.rb +21 -21
  813. data/spec/core_ext/socket_spec.rb +32 -32
  814. data/spec/core_ext/string_spec.rb +223 -223
  815. data/spec/core_ext/stringio_spec.rb +21 -21
  816. data/spec/core_ext/time_spec.rb +151 -151
  817. data/spec/gui/line_graph/line_clip_spec.rb +322 -322
  818. data/spec/install/config/system/system.txt +33 -33
  819. data/spec/install/config/targets/COSMOS/cmd_tlm/cosmos_server_cmds.txt +41 -41
  820. data/spec/install/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +15 -15
  821. data/spec/install/config/targets/COSMOS/cmd_tlm_server.txt +6 -6
  822. data/spec/install/config/targets/COSMOS/screens/limits_change.txt +20 -20
  823. data/spec/install/config/targets/COSMOS/screens/version.txt +19 -19
  824. data/spec/install/config/targets/COSMOS/target.txt +5 -5
  825. data/spec/install/config/targets/INST/cmd_tlm/inst_cmd_linc.txt +30 -30
  826. data/spec/install/config/targets/INST/cmd_tlm/inst_cmds.txt +111 -111
  827. data/spec/install/config/targets/INST/cmd_tlm/inst_tlm.txt +236 -236
  828. data/spec/install/config/targets/INST/cmd_tlm/inst_tlm_linc.txt +25 -25
  829. data/spec/install/config/targets/INST/cmd_tlm_server.txt +5 -5
  830. data/spec/install/config/targets/INST/lib/sim_inst.rb +305 -294
  831. data/spec/install/config/targets/INST/target.txt +10 -10
  832. data/spec/install/config/targets/META/cmd_tlm/meta_cmd.txt +4 -4
  833. data/spec/install/config/targets/META/cmd_tlm/meta_tlm.txt +4 -4
  834. data/spec/install/config/targets/SYSTEM/cmd_tlm/limits_groups.txt +7 -7
  835. data/spec/interfaces/cmd_tlm_server_interface_spec.rb +150 -150
  836. data/spec/interfaces/interface_spec.rb +130 -131
  837. data/spec/interfaces/linc_interface_spec.rb +199 -199
  838. data/spec/interfaces/serial_interface_spec.rb +56 -56
  839. data/spec/interfaces/simulated_target_interface_spec.rb +128 -128
  840. data/spec/interfaces/stream_interface_spec.rb +157 -157
  841. data/spec/interfaces/tcpip_client_interface_spec.rb +54 -54
  842. data/spec/interfaces/tcpip_server_interface_spec.rb +151 -151
  843. data/spec/interfaces/udp_interface_spec.rb +175 -177
  844. data/spec/io/buffered_file_spec.rb +113 -113
  845. data/spec/io/io_multiplexer_spec.rb +94 -94
  846. data/spec/io/json_drb_object_spec.rb +99 -99
  847. data/spec/io/json_drb_spec.rb +311 -311
  848. data/spec/io/json_rpc_spec.rb +264 -264
  849. data/spec/io/raw_logger_pair_spec.rb +76 -76
  850. data/spec/io/raw_logger_spec.rb +133 -133
  851. data/spec/io/serial_driver_spec.rb +61 -61
  852. data/spec/io/stderr_spec.rb +32 -32
  853. data/spec/io/stdout_spec.rb +32 -32
  854. data/spec/io/tcpip_server_spec.rb +338 -338
  855. data/spec/io/udp_sockets_spec.rb +94 -94
  856. data/spec/io/win32_serial_driver_spec.rb +88 -88
  857. data/spec/packet_logs/meta_packet_log_writer_spec.rb +170 -170
  858. data/spec/packet_logs/packet_log_reader_spec.rb +408 -408
  859. data/spec/packet_logs/packet_log_writer_pair_spec.rb +30 -30
  860. data/spec/packet_logs/packet_log_writer_spec.rb +223 -223
  861. data/spec/packets/binary_accessor_spec.rb +2073 -2073
  862. data/spec/packets/commands_spec.rb +369 -369
  863. data/spec/packets/limits_response_spec.rb +25 -25
  864. data/spec/packets/limits_spec.rb +326 -326
  865. data/spec/packets/packet_config_spec.rb +1620 -1620
  866. data/spec/packets/packet_item_limits_spec.rb +161 -161
  867. data/spec/packets/packet_item_spec.rb +386 -386
  868. data/spec/packets/packet_spec.rb +1057 -949
  869. data/spec/packets/structure_item_spec.rb +195 -195
  870. data/spec/packets/structure_spec.rb +419 -419
  871. data/spec/packets/telemetry_spec.rb +535 -535
  872. data/spec/processors/new_packet_log_processor_spec.rb +39 -39
  873. data/spec/processors/processor_spec.rb +55 -55
  874. data/spec/processors/statistics_processor_spec.rb +60 -60
  875. data/spec/processors/watermark_processor_spec.rb +51 -51
  876. data/spec/script/script_spec.rb +654 -654
  877. data/spec/spec_helper.rb +154 -148
  878. data/spec/streams/burst_stream_protocol_spec.rb +32 -32
  879. data/spec/streams/fixed_stream_protocol_spec.rb +110 -110
  880. data/spec/streams/length_stream_protocol_spec.rb +297 -297
  881. data/spec/streams/preidentified_stream_protocol_spec.rb +118 -118
  882. data/spec/streams/serial_stream_spec.rb +105 -105
  883. data/spec/streams/stream_protocol_spec.rb +332 -332
  884. data/spec/streams/stream_spec.rb +29 -29
  885. data/spec/streams/tcpip_client_stream_spec.rb +54 -54
  886. data/spec/streams/tcpip_socket_stream_spec.rb +146 -146
  887. data/spec/streams/template_stream_protocol_spec.rb +151 -151
  888. data/spec/streams/terminated_stream_protocol_spec.rb +123 -123
  889. data/spec/system/system_spec.rb +645 -645
  890. data/spec/system/target_spec.rb +248 -248
  891. data/spec/tools/cmd_tlm_server/api_spec.rb +1087 -1113
  892. data/spec/tools/cmd_tlm_server/background_task_spec.rb +32 -32
  893. data/spec/tools/cmd_tlm_server/background_tasks_spec.rb +81 -81
  894. data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +411 -411
  895. data/spec/tools/cmd_tlm_server/cmd_tlm_server_spec.rb +415 -415
  896. data/spec/tools/cmd_tlm_server/commanding_spec.rb +123 -123
  897. data/spec/tools/cmd_tlm_server/connections_spec.rb +147 -147
  898. data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +306 -306
  899. data/spec/tools/cmd_tlm_server/interfaces_spec.rb +252 -238
  900. data/spec/tools/cmd_tlm_server/packet_logging_spec.rb +143 -143
  901. data/spec/tools/cmd_tlm_server/router_thread_spec.rb +98 -101
  902. data/spec/tools/cmd_tlm_server/routers_spec.rb +223 -208
  903. data/spec/top_level/top_level_spec.rb +334 -321
  904. data/spec/utilities/crc_spec.rb +45 -45
  905. data/spec/utilities/csv_spec.rb +97 -97
  906. data/spec/utilities/logger_spec.rb +102 -102
  907. data/spec/utilities/message_log_spec.rb +89 -89
  908. data/spec/utilities/quaternion_spec.rb +107 -107
  909. data/spec/utilities/ruby_lex_utils_spec.rb +86 -86
  910. data/tasks/manifest.rake +22 -22
  911. data/tasks/spec.rake +23 -23
  912. metadata +18 -2
@@ -1,69 +1,69 @@
1
- # encoding: ascii-8bit
2
-
3
- # Copyright 2014 Ball Aerospace & Technologies Corp.
4
- # All Rights Reserved.
5
- #
6
- # This program is free software; you can modify and/or redistribute it
7
- # under the terms of the GNU General Public License
8
- # as published by the Free Software Foundation; version 3 with
9
- # attribution addendums as found in the LICENSE.txt
10
-
11
- require 'cosmos'
12
-
13
- module Cosmos
14
-
15
- # Represents a plot
16
- class Plot
17
-
18
- # Tab containing this plot
19
- attr_accessor :tab
20
-
21
- # Array of data objects in the plot
22
- attr_accessor :data_objects
23
-
24
- # GUI object associated with this plot
25
- attr_accessor :gui_object
26
-
27
- # Type of plot
28
- attr_accessor :plot_type
29
-
30
- # Flag to indicate if plot redraw is needed
31
- attr_accessor :redraw_needed
32
-
33
- # Creates a new Plot
34
- def initialize
35
- @tab = nil
36
- @data_objects = []
37
- @gui_object = nil
38
- @redraw_needed = false
39
-
40
- # Type is classname without Plot
41
- @plot_type = self.class.to_s[0..-5].upcase
42
- @plot_type = @plot_type.split("::")[-1] # Remove Cosmos:: if present
43
- end # def initialize
44
-
45
- # Returns the configuration lines used to create this plot
46
- def configuration_string
47
- string = " PLOT #{@plot_type}\n"
48
- string << plot_configuration_string()
49
- @data_objects.each do |data_object|
50
- string << data_object.configuration_string
51
- end
52
- string
53
- end # def configuration_string
54
-
55
- # Handles plot specific keywords
56
- def handle_keyword(parser, keyword, parameters)
57
- raise ArgumentError, "Unknown keyword received by #{self.class}: #{keyword}"
58
- end # def handle_keyword
59
-
60
- protected
61
-
62
- # Plot specific configuration string
63
- def plot_configuration_string
64
- return ''
65
- end
66
-
67
- end # class Plot
68
-
69
- end # module Cosmos
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2014 Ball Aerospace & Technologies Corp.
4
+ # All Rights Reserved.
5
+ #
6
+ # This program is free software; you can modify and/or redistribute it
7
+ # under the terms of the GNU General Public License
8
+ # as published by the Free Software Foundation; version 3 with
9
+ # attribution addendums as found in the LICENSE.txt
10
+
11
+ require 'cosmos'
12
+
13
+ module Cosmos
14
+
15
+ # Represents a plot
16
+ class Plot
17
+
18
+ # Tab containing this plot
19
+ attr_accessor :tab
20
+
21
+ # Array of data objects in the plot
22
+ attr_accessor :data_objects
23
+
24
+ # GUI object associated with this plot
25
+ attr_accessor :gui_object
26
+
27
+ # Type of plot
28
+ attr_accessor :plot_type
29
+
30
+ # Flag to indicate if plot redraw is needed
31
+ attr_accessor :redraw_needed
32
+
33
+ # Creates a new Plot
34
+ def initialize
35
+ @tab = nil
36
+ @data_objects = []
37
+ @gui_object = nil
38
+ @redraw_needed = false
39
+
40
+ # Type is classname without Plot
41
+ @plot_type = self.class.to_s[0..-5].upcase
42
+ @plot_type = @plot_type.split("::")[-1] # Remove Cosmos:: if present
43
+ end # def initialize
44
+
45
+ # Returns the configuration lines used to create this plot
46
+ def configuration_string
47
+ string = " PLOT #{@plot_type}\n"
48
+ string << plot_configuration_string()
49
+ @data_objects.each do |data_object|
50
+ string << data_object.configuration_string
51
+ end
52
+ string
53
+ end # def configuration_string
54
+
55
+ # Handles plot specific keywords
56
+ def handle_keyword(parser, keyword, parameters)
57
+ raise ArgumentError, "Unknown keyword received by #{self.class}: #{keyword}"
58
+ end # def handle_keyword
59
+
60
+ protected
61
+
62
+ # Plot specific configuration string
63
+ def plot_configuration_string
64
+ return ''
65
+ end
66
+
67
+ end # class Plot
68
+
69
+ end # module Cosmos
@@ -1,20 +1,20 @@
1
- # encoding: ascii-8bit
2
-
3
- # Copyright 2014 Ball Aerospace & Technologies Corp.
4
- # All Rights Reserved.
5
- #
6
- # This program is free software; you can modify and/or redistribute it
7
- # under the terms of the GNU General Public License
8
- # as published by the Free Software Foundation; version 3 with
9
- # attribution addendums as found in the LICENSE.txt
10
-
11
- require 'cosmos'
12
- require 'cosmos/tools/tlm_grapher/plots/xy_plot'
13
-
14
- module Cosmos
15
-
16
- # Represents a X-Y plot with a single point on the graph
17
- class SinglexyPlot < XyPlot
18
- end
19
-
20
- end # module Cosmos
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2014 Ball Aerospace & Technologies Corp.
4
+ # All Rights Reserved.
5
+ #
6
+ # This program is free software; you can modify and/or redistribute it
7
+ # under the terms of the GNU General Public License
8
+ # as published by the Free Software Foundation; version 3 with
9
+ # attribution addendums as found in the LICENSE.txt
10
+
11
+ require 'cosmos'
12
+ require 'cosmos/tools/tlm_grapher/plots/xy_plot'
13
+
14
+ module Cosmos
15
+
16
+ # Represents a X-Y plot with a single point on the graph
17
+ class SinglexyPlot < XyPlot
18
+ end
19
+
20
+ end # module Cosmos
@@ -1,61 +1,61 @@
1
- # encoding: ascii-8bit
2
-
3
- # Copyright 2014 Ball Aerospace & Technologies Corp.
4
- # All Rights Reserved.
5
- #
6
- # This program is free software; you can modify and/or redistribute it
7
- # under the terms of the GNU General Public License
8
- # as published by the Free Software Foundation; version 3 with
9
- # attribution addendums as found in the LICENSE.txt
10
-
11
- require 'cosmos'
12
- require 'cosmos/tools/tlm_grapher/plots/linegraph_plot'
13
-
14
- module Cosmos
15
-
16
- # Represents an X-Y plot
17
- class XyPlot < LinegraphPlot
18
-
19
- # Manual x scale array of x_min and x_max
20
- attr_accessor :manual_x_scale
21
-
22
- # Creates a new plot
23
- def initialize
24
- super()
25
- @show_lines = false
26
- @x_axis_title = nil
27
- @manual_x_scale = nil
28
- @unix_epoch_x_values = false
29
- end # def initialize
30
-
31
- # Handles plot specific keywords
32
- def handle_keyword(parser, keyword, parameters)
33
- case keyword
34
- when 'MANUAL_X_AXIS_SCALE'
35
- # Expect 2 parameters
36
- parser.verify_num_parameters(2, 2, "MANUAL_X_AXIS_SCALE <X Min> <X Max>")
37
- manual_scale = []
38
- manual_scale[0] = parameters[0].to_f
39
- manual_scale[1] = parameters[1].to_f
40
- @manual_x_scale = manual_scale
41
-
42
- else
43
- # Unknown keywords are passed to parent data object
44
- super(parser, keyword, parameters)
45
-
46
- end # case keyword
47
-
48
- end # def handle_keyword
49
-
50
- protected
51
-
52
- # Returns the configuration lines used to create this plot
53
- def plot_configuration_string
54
- string = super()
55
- string << " MANUAL_X_AXIS_SCALE #{@manual_x_scale[0]} #{@manual_x_scale[1]}\n" if @manual_x_scale
56
- string
57
- end # def plot_configuration_string
58
-
59
- end # class XyPlot
60
-
61
- end # module Cosmos
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2014 Ball Aerospace & Technologies Corp.
4
+ # All Rights Reserved.
5
+ #
6
+ # This program is free software; you can modify and/or redistribute it
7
+ # under the terms of the GNU General Public License
8
+ # as published by the Free Software Foundation; version 3 with
9
+ # attribution addendums as found in the LICENSE.txt
10
+
11
+ require 'cosmos'
12
+ require 'cosmos/tools/tlm_grapher/plots/linegraph_plot'
13
+
14
+ module Cosmos
15
+
16
+ # Represents an X-Y plot
17
+ class XyPlot < LinegraphPlot
18
+
19
+ # Manual x scale array of x_min and x_max
20
+ attr_accessor :manual_x_scale
21
+
22
+ # Creates a new plot
23
+ def initialize
24
+ super()
25
+ @show_lines = false
26
+ @x_axis_title = nil
27
+ @manual_x_scale = nil
28
+ @unix_epoch_x_values = false
29
+ end # def initialize
30
+
31
+ # Handles plot specific keywords
32
+ def handle_keyword(parser, keyword, parameters)
33
+ case keyword
34
+ when 'MANUAL_X_AXIS_SCALE'
35
+ # Expect 2 parameters
36
+ parser.verify_num_parameters(2, 2, "MANUAL_X_AXIS_SCALE <X Min> <X Max>")
37
+ manual_scale = []
38
+ manual_scale[0] = parameters[0].to_f
39
+ manual_scale[1] = parameters[1].to_f
40
+ @manual_x_scale = manual_scale
41
+
42
+ else
43
+ # Unknown keywords are passed to parent data object
44
+ super(parser, keyword, parameters)
45
+
46
+ end # case keyword
47
+
48
+ end # def handle_keyword
49
+
50
+ protected
51
+
52
+ # Returns the configuration lines used to create this plot
53
+ def plot_configuration_string
54
+ string = super()
55
+ string << " MANUAL_X_AXIS_SCALE #{@manual_x_scale[0]} #{@manual_x_scale[1]}\n" if @manual_x_scale
56
+ string
57
+ end # def plot_configuration_string
58
+
59
+ end # class XyPlot
60
+
61
+ end # module Cosmos
@@ -1,1278 +1,1278 @@
1
- # encoding: ascii-8bit
2
-
3
- # Copyright 2014 Ball Aerospace & Technologies Corp.
4
- # All Rights Reserved.
5
- #
6
- # This program is free software; you can modify and/or redistribute it
7
- # under the terms of the GNU General Public License
8
- # as published by the Free Software Foundation; version 3 with
9
- # attribution addendums as found in the LICENSE.txt
10
-
11
- require 'cosmos'
12
- require 'cosmos/gui/utilities/screenshot'
13
- require 'cosmos/gui/line_graph/overview_graph'
14
- require 'cosmos/gui/choosers/integer_chooser'
15
- require 'cosmos/gui/choosers/float_chooser'
16
- require 'cosmos/gui/choosers/string_chooser'
17
- require 'cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_plot_editor'
18
- require 'cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_data_object_editor'
19
- require 'cosmos/tools/tlm_grapher/plot_gui_objects/linegraph_plot_gui_object'
20
- require 'cosmos/tools/tlm_grapher/plot_gui_objects/xy_plot_gui_object'
21
- require 'cosmos/tools/tlm_grapher/plot_gui_objects/singlexy_plot_gui_object'
22
- require 'cosmos/tools/tlm_grapher/data_object_adders/housekeeping_data_object_adder'
23
- require 'cosmos/tools/tlm_grapher/data_object_adders/xy_data_object_adder'
24
- require 'cosmos/tools/tlm_grapher/data_object_adders/singlexy_data_object_adder'
25
-
26
- module Cosmos
27
-
28
- # Implements a widget to display a set of plots in tabs with an overview graph
29
- class OverviewTabbedPlots < Qt::Widget
30
- slots 'handle_tab_change(int)'
31
- slots 'tab_context_menu(const QPoint&)'
32
- slots 'plot_context_menu(const QPoint&)'
33
- slots 'data_object_context_menu(const QPoint&)'
34
- slots 'data_object_moved(const QModelIndex&, int, int, const QModelIndex&, int)'
35
-
36
- # Minimum Overview Points Per Line
37
- MINIMUM_OVERVIEW_POINTS_PLOTTED = 100
38
-
39
- # Minimum delay between redraws
40
- MINIMUM_REFRESH_DELAY_MS = 10
41
-
42
- # Accessor to tabbed_plots_config
43
- attr_accessor :tabbed_plots_config
44
-
45
- # Accessor to adders
46
- attr_accessor :data_object_adders
47
-
48
- # Callback when right button is released on a tab item
49
- attr_accessor :tab_item_right_button_release_callback
50
-
51
- # Callback when right button is released on a plot
52
- attr_accessor :plot_right_button_release_callback
53
-
54
- # Callback when right button is released on a data object
55
- attr_accessor :data_object_right_button_release_callback
56
-
57
- # Callback when a change to modifies the configuration occurs
58
- attr_accessor :config_modified_callback
59
-
60
- # Give access to the status bar to other widgets
61
- attr_reader :status_bar
62
-
63
- def initialize(parent, left_frame, right_frame, status_bar)
64
- super(parent)
65
- # Save Constructor Arguments
66
- @left_frame = left_frame
67
- @right_frame = right_frame
68
- @status_bar = status_bar
69
-
70
- # Default startup arguments
71
- @tabbed_plots_config = nil
72
- @adder_orientation = Qt::Horizontal
73
-
74
- # Additional instance variables
75
- @data_object_adders = []
76
- @tab_item_right_button_release_callback = nil
77
- @plot_right_button_release_callback = nil
78
- @data_object_right_button_release_callback = nil
79
- @config_modified_callback = nil
80
- @paused = false
81
- @timeout = nil
82
- @refresh_rate_ms = (1000.0 / TabbedPlotsConfig::DEFAULT_REFRESH_RATE_HZ).round
83
- @context_menu_plot = nil
84
- end # def initialize
85
-
86
- # Startup GUI interaction
87
- def startup(tabbed_plots_config, adder_orientation, adder_types)
88
- # Save parameters
89
- @tabbed_plots_config = tabbed_plots_config
90
- @adder_orientation = adder_orientation
91
- @adder_types = adder_types
92
-
93
- # Create GUI elements
94
- build_right_frame()
95
- build_left_frame()
96
- create()
97
- end # def startup
98
-
99
- # Shutdown GUI interaction
100
- def shutdown
101
- # Shutdown drawing timeout
102
- @timeout.method_missing(:stop) if @timeout
103
-
104
- # Remove GUI elements
105
- @tabbed_plots_left_frame.removeAll
106
- @tabbed_plots_right_frame.removeAll
107
- end # def shutdown
108
-
109
- # Update
110
- def update
111
- @data_object_adders.each {|adder| adder.update}
112
- end
113
-
114
- ###############################################################################
115
- # Pause / Resume
116
- ###############################################################################
117
-
118
- # Pause plotting
119
- def pause
120
- @paused = true
121
- end # def pause
122
-
123
- # Resume plotting if paused
124
- def resume
125
- @paused = false
126
- end # def resume
127
-
128
- # Are we paused?
129
- def paused?
130
- @paused
131
- end # def paused?
132
-
133
- ###############################################################################
134
- # Tab Related Methods
135
- ###############################################################################
136
-
137
- # Add a new tab
138
- def add_tab(tab_text = nil)
139
- unless tab_text
140
- # If the last tab text is "Tab X" the next tab should be "Tab X+1"
141
- if (@tabbed_plots_config.tabs.length > 0) &&
142
- (@tabbed_plots_config.tabs[-1].tab_text =~ /Tab (\d*)/)
143
- tab_text = "Tab #{$1.to_i + 1}" # $1 is the match from the regexp
144
- else # Set text to the total number of tabs
145
- tab_text = "Tab #{@tabbed_plots_config.tabs.length + 1}"
146
- end
147
- end
148
- tab = @tabbed_plots_config.add_tab(tab_text)
149
-
150
- # Create tab item for the tab
151
- tab_item = Qt::Widget.new
152
- tab_item.setContextMenuPolicy(Qt::CustomContextMenu)
153
- connect(tab_item, SIGNAL('customContextMenuRequested(const QPoint&)'), self, SLOT('plot_context_menu(const QPoint&)'))
154
- tab.gui_item = tab_item
155
-
156
- # Create overall vertical layout manager for tab.
157
- tab_layout = Qt::VBoxLayout.new()
158
- tab_item.setLayout(tab_layout)
159
- tab.gui_frame = tab_layout
160
-
161
- # Create layout manager to hold plots based on number of plots
162
- layout = Qt::AdaptiveGridLayout.new
163
- tab_layout.addLayout(layout, 1) # Add with stretch factor 1 to give it priority over everything else
164
- # Add stretch in case they delete the last plot. This will force the overview graph (which doesn't get deleted)
165
- # to stay at the bottom of the layout instead of moving
166
- tab_layout.addStretch()
167
- tab.gui_layout = layout
168
-
169
- # Add an overview graph to the tab
170
- @overview_graphs << OverviewGraph.new(self)
171
- @overview_graphs[-1].callback = method(:overview_graph_callback)
172
- @overview_graphs[-1].window_size = @seconds_plotted.value
173
- tab_layout.addWidget(@overview_graphs[-1])
174
-
175
- # Add an initial plot to the tab
176
- add_plot(-1, false)
177
-
178
- # Add and select the new tab
179
- index = @tab_book.addTab(tab_item, tab_text)
180
- @tab_book.setCurrentIndex(index)
181
- @config_modified_callback.call() if @config_modified_callback
182
- end # def add_tab
183
-
184
- # Delete a tab - defaults to the current tab
185
- def delete_tab(tab_index = nil)
186
- # Select the current tab by default
187
- tab_index = current_tab_index() unless tab_index
188
-
189
- if tab_index
190
- # Remove from config
191
- @tabbed_plots_config.remove_tab(tab_index)
192
-
193
- # Remove knowledge of overview graph
194
- @overview_graphs.delete_at(tab_index)
195
-
196
- # Remove tab item and frame from tab book
197
- @tab_book.widget(tab_index).dispose
198
-
199
- # Call tab change callback @tab_book.current is not valid at this point
200
- if tab_index > (@tabbed_plots_config.tabs.length - 1)
201
- @tab_book.setCurrentIndex(tab_index - 1)
202
- else
203
- @tab_book.setCurrentIndex(tab_index)
204
- end
205
- end
206
- @config_modified_callback.call() if @config_modified_callback
207
- end # def delete_tab
208
-
209
- # Edit a tab - defaults to the current tab
210
- def edit_tab(tab_index = nil)
211
- edited = false
212
-
213
- # Select the current tab by default
214
- tab_index = current_tab_index() unless tab_index
215
-
216
- if tab_index
217
- # Get the tab object
218
- tab = @tabbed_plots_config.tabs[tab_index]
219
-
220
- # Create simple dialog box to edit the tab
221
- result = Qt::Boolean.new
222
- string = Qt::InputDialog::getText(self,
223
- "Edit Tab",
224
- "Tab Text:",
225
- Qt::LineEdit::Normal,
226
- tab.tab_text,
227
- result)
228
- if !result.nil? and not string.strip.empty? and @tab_book.tabText(tab_index) != string
229
- tab.tab_text = string
230
- @tab_book.setTabText(tab_index, string)
231
- edited = true
232
- @config_modified_callback.call() if @config_modified_callback
233
- end
234
- end
235
-
236
- return edited
237
- end # def edit_tab
238
-
239
- # Export all data objects on a tab - defaults to current tab
240
- def export_tab(filename, progress, tab_index = nil)
241
- # Select the current tab by default
242
- tab_index = current_tab_index() unless tab_index
243
-
244
- if tab_index
245
- # Export the tab's data objects
246
- export_data_objects(filename, progress, tab_index) if @tabbed_plots_config.tabs[tab_index]
247
- end
248
- end # def export_tab
249
-
250
- # Reset all data objects on a tab - defaults to current tab
251
- def reset_tab(tab_index = nil)
252
- # Select the current tab by default
253
- tab_index = current_tab_index() unless tab_index
254
-
255
- # Reset the data objects
256
- reset_data_objects(tab_index) if tab_index
257
- end
258
-
259
- # Take screenshot of current tab and write to filename
260
- def screenshot_tab(filename)
261
- # Select the current tab
262
- tab_index = current_tab_index()
263
-
264
- if tab_index
265
- # Take screenshot
266
- Screenshot.screenshot_window(@tab_book.currentWidget(), filename)
267
- end
268
- end # def screenshot_tab
269
-
270
- # Returns the index of the current tab or nil if no tabs exist
271
- def current_tab_index
272
- unless @tabbed_plots_config.tabs.empty?
273
- tab_index = @tab_book.currentIndex
274
- return tab_index if tab_index >= 0
275
- end
276
- nil
277
- end # def current_tab_index
278
-
279
- # Indicates if the tab has any data objects
280
- def tab_has_data_objects?(tab_index = nil)
281
- # Select the current tab by default
282
- tab_index = current_tab_index() unless tab_index
283
-
284
- return_value = false
285
- if tab_index
286
- @tabbed_plots_config.mu_synchronize do
287
- @tabbed_plots_config.tabs[tab_index].plots.each do |plot|
288
- if not plot.data_objects.empty?
289
- return_value = true
290
- break
291
- end
292
- end
293
- end
294
- end
295
-
296
- return_value
297
- end
298
-
299
- ###############################################################################
300
- # Plot Related Methods
301
- ###############################################################################
302
-
303
- # Add a new plot to a tab - defaults to the current tab
304
- def add_plot(tab_index = nil, dialog = true)
305
- # Select the current tab by default
306
- tab_index = current_tab_index() unless tab_index
307
-
308
- if tab_index
309
- # Get Tab
310
- tab = @tabbed_plots_config.tabs[tab_index]
311
-
312
- # Add to config
313
- if dialog
314
- plot_editor = TabbedPlotsPlotEditor.new(self,
315
- 'Add Plot',
316
- @tabbed_plots_config.plot_types)
317
- plot = plot_editor.execute
318
- plot_editor.dispose
319
- else
320
- plot = @tabbed_plots_config.create_plot(@tabbed_plots_config.plot_types[0])
321
- end
322
- if plot
323
- @tabbed_plots_config.add_plot(tab_index, plot)
324
- @status_bar.showMessage(tr("Add Plot Succeeded"))
325
- else
326
- @status_bar.showMessage(tr("Add Plot Canceled"))
327
- return false
328
- end
329
-
330
- # Create new plot gui object
331
- filename = plot.plot_type.downcase + '_plot_gui_object.rb'
332
- gui_object = Cosmos.require_class(filename).new(tab.gui_item, tab, plot, self)
333
- tab.gui_layout.addWidget(gui_object)
334
- plot.gui_object = gui_object
335
- #~ plot.gui_object.connect(SEL_RIGHTBUTTONRELEASE, method(:handle_plot_right_button_release))
336
- if plot.gui_object.respond_to? :mouse_left_button_press_callback
337
- current_tab = tab
338
- plot.gui_object.mouse_left_button_press_callback = lambda do |calling_gui_object|
339
- current_tab.plots.each_with_index do |current_plot, index|
340
- if current_plot.gui_object == calling_gui_object
341
- select_plot(current_plot)
342
- else
343
- unselect_plot(current_plot)
344
- end
345
- end
346
- @overview_graphs[@tab_book.currentIndex].setFocus
347
- end
348
- end
349
-
350
- # Auto-select plot
351
- unselect_all_plots(tab_index)
352
- select_plot(plot)
353
- end
354
- @config_modified_callback.call() if @config_modified_callback
355
- return true
356
- end # def add_plot
357
-
358
- # Delete a plot - defaults to the selected plot on the current tab
359
- def delete_plot(tab_index = nil, plot_index = nil)
360
- # Select the current tab by default
361
- tab_index = current_tab_index() unless tab_index
362
-
363
- # Select selected plot by default
364
- plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
365
-
366
- # Make sure the plot exists
367
- if plot_index
368
- # Get Tab
369
- tab = @tabbed_plots_config.tabs[tab_index]
370
-
371
- # Remove from config
372
- plot = @tabbed_plots_config.remove_plot(tab_index, plot_index)
373
-
374
- # Potentially clear data object list
375
- clear_data_object_list() if plot.gui_object.selected?
376
-
377
- # Remove the widget
378
- tab.gui_layout.removeWidget(plot.gui_object)
379
- plot.gui_object.dispose
380
-
381
- # Create new layout
382
- layout = Qt::AdaptiveGridLayout.new
383
-
384
- # Add existing gui objects into new layout
385
- (0...tab.gui_layout.count).each do |index|
386
- layout.addWidget(tab.gui_layout.takeAt(0).widget)
387
- end
388
-
389
- # Select the first plot just to be nice
390
- select_plot(tab.plots[0]) if tab.plots[0]
391
-
392
- # Remove existing layout from frame
393
- tab.gui_frame.removeItem(tab.gui_layout)
394
- # Assign new layout to tab
395
- tab.gui_frame.insertLayout(0, layout, 1)
396
- tab.gui_layout = layout
397
- #~ tab.gui_layout.connect(SEL_RIGHTBUTTONRELEASE, method(:handle_plot_right_button_release))
398
-
399
- @status_bar.showMessage(tr("Plot Deleted"))
400
- @config_modified_callback.call() if @config_modified_callback
401
- else
402
- Qt::MessageBox.information(self, 'Information', 'Please select a plot')
403
- end
404
- end # def delete_plot
405
-
406
- # Edit a plot - defaults to the selected plot on the current tab
407
- def edit_plot(tab_index = nil, plot_index = nil)
408
- edited = false
409
-
410
- # Select the current tab by default
411
- tab_index = current_tab_index() unless tab_index
412
-
413
- if tab_index
414
- # Get tab
415
- tab = @tabbed_plots_config.tabs[tab_index]
416
-
417
- # Select selected plot by default
418
- plot_index = selected_plot_index(tab_index) unless plot_index
419
- unless plot_index
420
- Qt::MessageBox.information(self, 'Information', 'Please select a plot')
421
- return
422
- end
423
- plot = tab.plots[plot_index]
424
-
425
- # Edit Plot
426
- plot_editor = TabbedPlotsPlotEditor.new(self,
427
- 'Edit Plot',
428
- @tabbed_plots_config.plot_types,
429
- plot)
430
- plot = plot_editor.execute
431
- plot_editor.dispose
432
- if plot
433
- plot.gui_object.update(true)
434
- @status_bar.showMessage(tr("Plot Edited"))
435
- edited = true
436
- @config_modified_callback.call() if @config_modified_callback
437
- else
438
- @status_bar.showMessage(tr("Plot Edit Canceled"))
439
- end
440
- end
441
-
442
- return edited
443
- end # def edit_plot
444
-
445
- # Exports data objects on a plot - defaults to selected plot on the current tab
446
- def export_plot(filename, progress, tab_index = nil, plot_index = nil)
447
- # Select the current tab by default
448
- tab_index = current_tab_index() unless tab_index
449
-
450
- # Select selected plot by default
451
- plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
452
- unless plot_index
453
- Qt::MessageBox.information(self, 'Information', 'Please select a plot')
454
- return
455
- end
456
-
457
- export_data_objects(filename, progress, tab_index, plot_index)
458
- end # def export_plot
459
-
460
- # Take screenshot of a plot on the current tab and write to filename - defaults to selected plot
461
- def screenshot_plot(filename, plot_index = nil)
462
- # Select the current tab by default
463
- tab_index = current_tab_index() unless tab_index
464
-
465
- # Select selected plot by default
466
- plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
467
-
468
- # Take screenshot
469
- Screenshot.screenshot_window(@tabbed_plots_config.tabs[tab_index].plots[plot_index].gui_object, filename) if plot_index
470
- end # def screenshot_plot
471
-
472
- # Reset all data objects on a plot - defaults to the selected plot on the current tab
473
- def reset_plot(tab_index = nil, plot_index = nil)
474
- # Select the current tab by default
475
- tab_index = current_tab_index() unless tab_index
476
-
477
- # Select selected plot by default
478
- plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
479
-
480
- # Reset the data objects
481
- reset_data_objects(tab_index, plot_index) if plot_index
482
- end
483
-
484
- # Returns the index of the selected plot or nil - looks at current tab by default
485
- def selected_plot_index(tab_index = nil)
486
- # Select the current tab by default
487
- tab_index = current_tab_index() unless tab_index
488
-
489
- if tab_index
490
- @tabbed_plots_config.tabs[tab_index].plots.each_with_index do |plot, index|
491
- return index if plot.gui_object.selected?
492
- end
493
- end
494
- nil
495
- end # def selected_plot_index
496
-
497
- # Indicates if the plot has any data objects
498
- def plot_has_data_objects?(tab_index = nil, plot_index = nil)
499
- # Select the current tab by default
500
- tab_index = current_tab_index() unless tab_index
501
-
502
- # Select selected plot by default
503
- plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
504
-
505
- return_value = false
506
- if plot_index
507
- @tabbed_plots_config.mu_synchronize do
508
- return_value = true unless @tabbed_plots_config.tabs[tab_index].plots[plot_index].data_objects.empty?
509
- end
510
- end
511
-
512
- return_value
513
- end
514
-
515
- ###############################################################################
516
- # Data Object Related Methods
517
- ###############################################################################
518
-
519
- # Adds a data object to a plot - defaults to selected plot on the current tab
520
- def add_data_object(tab_index = nil, plot_index = nil, data_object = nil)
521
- # Select the current tab by default
522
- tab_index = current_tab_index() unless tab_index
523
-
524
- # Select selected plot by default
525
- plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
526
- unless plot_index
527
- Qt::MessageBox.information(self, 'Information', 'Please select a plot')
528
- return false
529
- end
530
-
531
- # Get plot
532
- plot = @tabbed_plots_config.tabs[tab_index].plots[plot_index]
533
-
534
- # Start data object editor to create new data object
535
- unless data_object
536
- data_object_editor = TabbedPlotsDataObjectEditor.new(self,'Add Data Object', @tabbed_plots_config.plot_type_to_data_object_type_mapping[plot.plot_type])
537
- data_object = data_object_editor.execute
538
- data_object_editor.dispose
539
- unless data_object
540
- @status_bar.showMessage(tr("Add Data Object Canceled"))
541
- return false
542
- end
543
- end
544
-
545
- # Assign color to data object
546
- data_object.color = get_free_color(@tabbed_plots_config.tabs[tab_index]) unless data_object.assigned_color
547
-
548
- # Add to config
549
- @tabbed_plots_config.add_data_object(tab_index, plot_index, data_object)
550
- @tabbed_plots_config.update_max_points_saved(@points_saved.value)
551
-
552
- # Update Plot
553
- @tabbed_plots_config.tabs[tab_index].plots[plot_index].gui_object.update(true)
554
-
555
- # Update data object list
556
- fill_data_object_list_for_plot(@tabbed_plots_config.tabs[tab_index].plots[plot_index])
557
-
558
- @status_bar.showMessage(tr("Add Data Object Succeeded"))
559
- @config_modified_callback.call() if @config_modified_callback
560
- return true
561
- end # def add_data_object
562
-
563
- # Deletes a data object from a plot - defaults to the selected data objects on the selected plot on the current tab
564
- def delete_data_object(tab_index = nil, plot_index = nil, data_object_index = nil)
565
- # Select the current tab by default
566
- tab_index = current_tab_index() unless tab_index
567
-
568
- # Select selected plot by default
569
- plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
570
- plot = @tabbed_plots_config.tabs[tab_index].plots[plot_index]
571
-
572
- data_object_indexes = get_data_object_indexes(plot,
573
- tab_index,
574
- plot_index,
575
- data_object_index)
576
- data_object_indexes.reverse.each do |data_object_idx|
577
- @tabbed_plots_config.remove_data_object(tab_index, plot_index, data_object_idx)
578
- end
579
-
580
- if plot
581
- plot.gui_object.update(true)
582
- fill_data_object_list_for_plot(plot)
583
- end
584
- @config_modified_callback.call() if @config_modified_callback
585
- end # def delete_data_object
586
-
587
- # Edits a data object on a plot - defaults to the selected data objects on the selected plot on the current tab
588
- def edit_data_object(tab_index = nil, plot_index = nil, data_object_index = nil)
589
- edited = false
590
-
591
- # Select the current tab by default
592
- tab_index = current_tab_index() unless tab_index
593
-
594
- # Select selected plot by default
595
- plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
596
- if plot_index
597
- plot = @tabbed_plots_config.tabs[tab_index].plots[plot_index]
598
-
599
- data_object_indexes = get_data_object_indexes(plot,
600
- tab_index,
601
- plot_index,
602
- data_object_index)
603
- data_object_indexes.each do |data_object_idx|
604
- data_object = @tabbed_plots_config.tabs[tab_index].plots[plot_index].data_objects[data_object_idx]
605
- data_object_editor = TabbedPlotsDataObjectEditor.new(self, 'Edit Data Object', @tabbed_plots_config.plot_type_to_data_object_type_mapping[plot.plot_type], data_object)
606
- data_object = data_object_editor.execute
607
- data_object_editor.dispose
608
- if data_object
609
- @tabbed_plots_config.edit_data_object(tab_index, plot_index, data_object_idx, data_object)
610
- @status_bar.showMessage(tr("Data Object(s) Edited"))
611
- edited = true
612
- @config_modified_callback.call() if @config_modified_callback
613
- else
614
- @status_bar.showMessage(tr("Edit Data Object Canceled"))
615
- end
616
- end
617
-
618
- plot.gui_object.update(true)
619
- fill_data_object_list_for_plot(plot)
620
- end
621
-
622
- return edited
623
- end # def edit_data_object
624
-
625
- # Duplicates a data object on a plot - defaults to the selected data objects on the selected plot on the current tab
626
- def duplicate_data_object(tab_index = nil, plot_index = nil, data_object_index = nil)
627
- # Select the current tab by default
628
- tab_index = current_tab_index() unless tab_index
629
-
630
- # Select selected plot by default
631
- plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
632
- if plot_index
633
- plot = @tabbed_plots_config.tabs[tab_index].plots[plot_index]
634
-
635
- data_object_indexes = get_data_object_indexes(plot,
636
- tab_index,
637
- plot_index,
638
- data_object_index)
639
- data_object_indexes.each do |data_object_idx|
640
- data_object = @tabbed_plots_config.duplicate_data_object(tab_index, plot_index, data_object_idx)
641
- data_object.color = get_free_color(@tabbed_plots_config.tabs[tab_index]) unless data_object.assigned_color
642
- end
643
- @status_bar.showMessage(tr("Data Object(s) Duplicated"))
644
-
645
- plot.gui_object.update(true)
646
- fill_data_object_list_for_plot(@tabbed_plots_config.tabs[tab_index].plots[plot_index])
647
- @config_modified_callback.call() if @config_modified_callback
648
- end
649
- end # def duplicate_data_object
650
-
651
- # Exports a data object on a plot - defaults to the selected data objects on the selected plot on the current tab
652
- def export_data_object(filename, progress, tab_index = nil, plot_index = nil, data_object_index = nil)
653
- # Select the current tab by default
654
- tab_index = current_tab_index() unless tab_index
655
-
656
- # Select selected plot by default
657
- plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
658
- if plot_index
659
- plot = @tabbed_plots_config.tabs[tab_index].plots[plot_index]
660
-
661
- data_object_indexes = get_data_object_indexes(plot,
662
- tab_index,
663
- plot_index,
664
- data_object_index)
665
-
666
- columns = []
667
- data_object_indexes.each do |data_object_idx|
668
- columns.concat(@tabbed_plots_config.export_data_objects(progress, tab_index, plot_index, data_object_idx))
669
- end
670
- write_export_file(filename, columns, progress)
671
- end
672
- end # def export_data_object
673
-
674
- # Exports all data objects
675
- def export_all_data_objects(filename, progress)
676
- export_data_objects(filename, progress)
677
- end # def export_all_data_objects
678
-
679
- # Resets a data object on a plot - defaults to the selected data objects on the selected plot on the current tab
680
- def reset_data_object(tab_index = nil, plot_index = nil, data_object_index = nil)
681
- # Select the current tab by default
682
- tab_index = current_tab_index() unless tab_index
683
-
684
- # Select selected plot by default
685
- plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
686
-
687
- if plot_index
688
- data_object_indexes = selected_data_object_indexes()
689
- data_object_indexes.reverse.each do |data_object_idx|
690
- @tabbed_plots_config.reset_data_objects(tab_index, plot_index, data_object_idx)
691
- end
692
- redraw_plots(true, true)
693
- @status_bar.showMessage(tr("Data Object(s) Reset"))
694
- end
695
- end
696
-
697
- # Resets all data objects
698
- def reset_all_data_objects
699
- reset_data_objects()
700
- end # def reset_all_data_objects
701
-
702
- # Returns an array with the indexes of the selected data objects
703
- def selected_data_object_indexes
704
- selected = []
705
- index = 0
706
- @data_object_list.each do |list_item|
707
- selected << index if list_item.selected? and @data_object_list.item(index).text != 'No Plot Selected'
708
- index += 1
709
- end
710
- selected
711
- end # def selected_data_object_indexes
712
-
713
- # Redraws all plots that need to be redrawn
714
- def redraw_plots(force_redraw = false, force_move_window = false)
715
- if not @paused or force_redraw
716
- overview_redraw_needed = force_redraw
717
- move_window = force_move_window
718
- points_plotted = @points_plotted.value
719
-
720
- # Determine if overview redraws are needed
721
- @tabbed_plots_config.mu_synchronize do
722
- tab_index = @tab_book.currentIndex
723
- return if tab_index < 0 or tab_index > (@tabbed_plots_config.tabs.length - 1)
724
- @tabbed_plots_config.tabs[tab_index].plots.each do |plot|
725
- if plot.redraw_needed
726
- overview_redraw_needed = true
727
- move_window = true unless @paused
728
- break
729
- end
730
- end
731
- end
732
-
733
- # Redraw overview
734
- overview_graph = @overview_graphs[@tab_book.currentIndex]
735
- if overview_redraw_needed
736
- num_lines = 0
737
- @tabbed_plots_config.tabs[@tab_book.currentIndex].plots.each {|plot| num_lines += plot.data_objects.length}
738
- if num_lines > 0
739
- overview_points_plotted = points_plotted / num_lines
740
- overview_points_plotted = MINIMUM_OVERVIEW_POINTS_PLOTTED if overview_points_plotted < MINIMUM_OVERVIEW_POINTS_PLOTTED
741
- else
742
- overview_points_plotted = points_plotted
743
- end
744
-
745
- overview_graph.clear_lines
746
- @tabbed_plots_config.mu_synchronize do
747
- @tabbed_plots_config.tabs[@tab_book.currentIndex].plots.each {|plot| plot.gui_object.update_overview(overview_points_plotted, overview_graph)}
748
- end
749
-
750
- overview_graph.graph(move_window)
751
- end
752
-
753
- # Sync other overview graph positions
754
- @overview_graphs.each do |other_overview_graph|
755
- if overview_graph != other_overview_graph
756
- other_overview_graph.set_window_pos(overview_graph.window_min_x, overview_graph.window_max_x, false)
757
- end
758
- end
759
-
760
- # Determine if plot redraws needed
761
- gui_objects = []
762
- redraw_needed = []
763
- @tabbed_plots_config.mu_synchronize do
764
- @tabbed_plots_config.tabs[@tab_book.currentIndex].plots.each do |plot|
765
- gui_objects << plot.gui_object
766
- if force_redraw or overview_redraw_needed
767
- redraw_needed << true
768
- else
769
- redraw_needed << plot.redraw_needed
770
- end
771
- if redraw_needed[-1]
772
- plot.gui_object.update_plot(points_plotted, overview_graph.window_min_x, overview_graph.window_max_x)
773
- end
774
- end
775
- end
776
-
777
- # Redraw plots
778
- gui_objects.length.times do |index|
779
- if redraw_needed[index]
780
- gui_objects[index].redraw
781
- end
782
- end
783
-
784
- end
785
- end # def redraw_plots
786
-
787
- protected
788
-
789
- def get_data_object_indexes(plot, tab_index, plot_index, data_object_index)
790
- if data_object_index
791
- return unless (plot and @tabbed_plots_config.tabs[tab_index].plots[plot_index].data_objects[data_object_index])
792
- data_object_indexes = [data_object_index]
793
- else
794
- data_object_indexes = selected_data_object_indexes()
795
- end
796
- end
797
-
798
- # Resets data objects and redraws the plots
799
- def reset_data_objects(tab_index = nil, plot_index = nil, data_object_index = nil)
800
- @tabbed_plots_config.reset_data_objects(tab_index, plot_index, data_object_index)
801
- redraw_plots(true, true)
802
- end # def reset_data_objects
803
-
804
- def write_export_file(filename, columns, progress)
805
- max_column_size = 0
806
- columns.each {|column| max_column_size = column.length if column.length > max_column_size}
807
- File.open(filename, 'w') do |file|
808
- max_column_size.times do |index|
809
- string = ''
810
- columns.each {|column| string << column[index].to_s << "\t"}
811
- file.puts(string)
812
- progress.set_overall_progress(index.to_f / max_column_size)
813
- end
814
- end
815
- end
816
-
817
- # Exports data objects to a file
818
- def export_data_objects(filename, progress, tab_index = nil, plot_index = nil, data_object_index = nil)
819
- columns = @tabbed_plots_config.export_data_objects(progress, tab_index, plot_index, data_object_index)
820
- write_export_file(filename, columns, progress)
821
- end # def export_data_objects
822
-
823
- # Create GUI objects
824
- def create
825
- # Select first plot on each tab in reverse order
826
- @tabbed_plots_config.tabs.reverse.each {|tab| select_plot(tab.plots[0]) if tab.plots[0]}
827
-
828
- # Setup timeout to redraw graphs
829
- @timeout = Qt::Timer.new(self)
830
- @timeout.connect(SIGNAL('timeout()')) { redraw_plots() }
831
- @timeout.method_missing(:start, @refresh_rate_ms)
832
- end # def create
833
-
834
- # Clears the data object list
835
- def clear_data_object_list
836
- # Clear data object list
837
- @data_object_list.clearItems
838
- @data_object_list.addItemColor('No Plot Selected')
839
- end # def clear_data_object_list
840
-
841
- # Fills the data object list for the specified plot
842
- def fill_data_object_list_for_plot(plot)
843
- # List Data Objects for this plot
844
- @data_object_list.clearItems
845
- plot.data_objects.each do |data_object|
846
- @data_object_list.addItemColor(data_object.name, data_object.color)
847
- end
848
- end # def fill_data_object_list_for_plot
849
-
850
- # Gets an available color on a tab - if no colors are available a random color
851
- # is returned
852
- def get_free_color(tab)
853
- color = nil
854
- colors = []
855
- default_colors = DataObject::COLOR_LIST.clone
856
- tab.plots.each do |plot|
857
- plot.data_objects.each {|data_object| colors << data_object.color}
858
- end
859
- color = default_colors.shift
860
- while (color and colors.include?(color))
861
- color = default_colors.shift
862
- end
863
- color = get_random_color() unless color
864
- color
865
- end # def get_free_color
866
-
867
- # Gets a random color
868
- def get_random_color
869
- random_index = (rand() * DataObject::COLOR_LIST.length).floor
870
- random_index = (DataObject::COLOR_LIST.length - 1) if random_index >= DataObject::COLOR_LIST.length
871
- DataObject::COLOR_LIST[random_index].clone
872
- end # def get_random_color
873
-
874
- # Builds the left frame of the tool
875
- def build_left_frame
876
- # Frame around everything
877
- @tabbed_plots_left_frame = Qt::VBoxLayout.new
878
- @left_frame.addLayout(@tabbed_plots_left_frame)
879
-
880
- # Seconds Plotted
881
- @seconds_plotted = FloatChooser.new(self,
882
- 'Seconds Plotted:',
883
- @tabbed_plots_config.seconds_plotted,
884
- 0.0,
885
- nil,
886
- 15)
887
- @seconds_plotted.sel_command_callback = method(:handle_seconds_plotted_change)
888
- @tabbed_plots_left_frame.addWidget(@seconds_plotted)
889
-
890
- # Points Saved
891
- @points_saved = IntegerChooser.new(self, 'Points Saved:', @tabbed_plots_config.points_saved, 1, nil, 15)
892
- @points_saved.sel_command_callback = method(:handle_points_saved_change)
893
- @tabbed_plots_left_frame.addWidget(@points_saved)
894
-
895
- # Points Plotted
896
- @points_plotted = IntegerChooser.new(self,
897
- 'Points Plotted:',
898
- @tabbed_plots_config.points_plotted,
899
- 2,
900
- nil,
901
- 15)
902
- @points_plotted.sel_command_callback = method(:handle_points_plotted_change)
903
- @tabbed_plots_left_frame.addWidget(@points_plotted)
904
-
905
- # Refresh Rate Hz
906
- @refresh_rate_hz = FloatChooser.new(self,
907
- 'Refresh Rate Hz:',
908
- @tabbed_plots_config.refresh_rate_hz,
909
- 0.000001,
910
- 1000.0,
911
- 15)
912
- @refresh_rate_hz.sel_command_callback = method(:handle_refresh_rate_hz_change)
913
- @tabbed_plots_left_frame.addWidget(@refresh_rate_hz)
914
-
915
- # Update overview graphs
916
- @overview_graphs.each {|overview_graph| overview_graph.window_size = @tabbed_plots_config.seconds_plotted}
917
-
918
- # Adders
919
- add_adders(@tabbed_plots_left_frame) if @adder_orientation == Qt::Vertical
920
-
921
- # Separator before list
922
- sep = Qt::Frame.new
923
- sep.setFrameStyle(Qt::Frame::HLine | Qt::Frame::Sunken)
924
- @tabbed_plots_left_frame.addWidget(sep)
925
-
926
- # Data Object List
927
- @tabbed_plots_left_frame.addWidget(Qt::Label.new('Data Objects:'))
928
- @data_object_list = Qt::ColorListWidget.new(self, false)
929
- @data_object_list.setSelectionMode(Qt::AbstractItemView::ExtendedSelection)
930
- @data_object_list.setContextMenuPolicy(Qt::CustomContextMenu)
931
- @data_object_list.setDragDropMode(Qt::AbstractItemView::InternalMove)
932
- @data_object_list.define_singleton_method(:keyPressEvent) do |event|
933
- case event.key
934
- when Qt::Key_Delete, Qt::Key_Backspace
935
- otp = self.original_parent
936
- unless otp.selected_data_object_indexes.empty?
937
- paused = otp.paused?()
938
- otp.pause()
939
- result = Qt::MessageBox.warning(self,
940
- 'Warning!',
941
- "Are you sure you want to delete the selected data objects?",
942
- Qt::MessageBox::Yes | Qt::MessageBox::No, Qt::MessageBox::No)
943
- if result == Qt::MessageBox::No
944
- otp.status_bar.showMessage(tr("Data Object Deletion Canceled"))
945
- else
946
- otp.status_bar.showMessage(tr("Data Object Deleted"))
947
- otp.delete_data_object()
948
- end
949
- otp.resume() unless paused
950
- end
951
- end
952
- super(event)
953
- end
954
- connect(@data_object_list.model,
955
- SIGNAL('rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int)'),
956
- self,
957
- SLOT('data_object_moved(const QModelIndex&, int, int, const QModelIndex&, int)'))
958
- connect(@data_object_list,
959
- SIGNAL('customContextMenuRequested(const QPoint&)'),
960
- self,
961
- SLOT('data_object_context_menu(const QPoint&)'))
962
- @data_object_list.connect(SIGNAL('itemClicked(QListWidgetItem*)')) do
963
- @status_bar.showMessage(tr("Drag and drop to reorder. Items are drawn in order from top to bottom."))
964
- end
965
- @data_object_list.addItemColor('No Plot Selected')
966
- @tabbed_plots_left_frame.addWidget(@data_object_list)
967
- @tabbed_plots_config.update_max_points_saved(@points_saved.value)
968
- end # def build_left_frame
969
-
970
- # Handler for points saved changing
971
- def handle_points_saved_change(value_string, value_integer)
972
- if value_integer < @tabbed_plots_config.points_saved
973
- paused = paused?()
974
- pause()
975
- result = Qt::MessageBox.warning(self,
976
- 'Warning!',
977
- "Reducing Points Saved May Discard Data! Discard?",
978
- Qt::MessageBox::Yes | Qt::MessageBox::No, Qt::MessageBox::No)
979
- resume() unless paused
980
- if result == Qt::MessageBox::No
981
- @points_saved.value = @tabbed_plots_config.points_saved
982
- return
983
- end
984
- end
985
-
986
- @tabbed_plots_config.points_saved = value_integer
987
- @tabbed_plots_config.update_max_points_saved(value_integer)
988
-
989
- redraw_plots(true)
990
- @config_modified_callback.call() if @config_modified_callback
991
- end # def handle_points_saved_change
992
-
993
- # Handler for seconds plotted changing
994
- def handle_seconds_plotted_change(value_string, value_float)
995
- @overview_graphs.each {|overview_graph| overview_graph.window_size = value_float}
996
- @tabbed_plots_config.seconds_plotted = value_float
997
- @config_modified_callback.call() if @config_modified_callback
998
- end # def handle_seconds_plotted_change
999
-
1000
- # Handler for points plotted changing
1001
- def handle_points_plotted_change(value_string, value_integer)
1002
- redraw_plots(true)
1003
- @tabbed_plots_config.points_plotted = value_integer
1004
- @config_modified_callback.call() if @config_modified_callback
1005
- end # def handle_points_plotted_change
1006
-
1007
- # Handler for refresh rate hz changing
1008
- def handle_refresh_rate_hz_change(value_string, value_float)
1009
- redraw_plots(true)
1010
- @tabbed_plots_config.refresh_rate_hz = value_float
1011
- @refresh_rate_ms = (1000.0 / value_float).round
1012
-
1013
- @timeout.method_missing(:stop)
1014
- @timeout.method_missing(:start, @refresh_rate_ms)
1015
- @config_modified_callback.call() if @config_modified_callback
1016
- end # def handle_points_plotted_change
1017
-
1018
- # Adds the adders
1019
- def add_adders(layout)
1020
- # Data Object Adders
1021
- @data_object_adders = []
1022
-
1023
- if @adder_types
1024
- type_list = @adder_types
1025
- else
1026
- type_list = @tabbed_plots_config.data_object_types
1027
- end
1028
-
1029
- type_list.each do |data_object_type|
1030
- begin
1031
- filename = data_object_type.to_s.downcase + '_data_object_adder'
1032
- @data_object_adders << Cosmos.require_class(filename).new(self, @adder_orientation)
1033
- layout.addWidget(@data_object_adders[-1])
1034
- @data_object_adders[-1].add_data_object_callback = method(:adder_add_data_object)
1035
- @data_object_adders[-1].update
1036
- rescue Exception
1037
- # No adder for this type
1038
- end
1039
- end
1040
- end # def add_adders
1041
-
1042
- # Method called by adders to add a data object
1043
- def adder_add_data_object(data_object)
1044
- tab_index = current_tab_index()
1045
- plot_index = selected_plot_index(tab_index)
1046
- if plot_index
1047
- plot = @tabbed_plots_config.tabs[tab_index].plots[plot_index]
1048
- mapping = @tabbed_plots_config.plot_type_to_data_object_type_mapping[plot.plot_type]
1049
- if mapping.include?(data_object.data_object_type)
1050
- add_data_object(tab_index, plot_index, data_object)
1051
- else
1052
- paused = paused?()
1053
- pause()
1054
- Qt::MessageBox.critical(self, 'Error', "A #{data_object.data_object_type} data object cannot be added to a #{plot.plot_type} plot")
1055
- resume() unless paused
1056
- end
1057
- else
1058
- paused = paused?()
1059
- pause()
1060
- Qt::MessageBox.information(self, 'Information', 'Please select a plot')
1061
- resume() unless paused
1062
- end
1063
- end # def adder_add_data_object
1064
-
1065
- # Builds the GUI holding tabs and plots
1066
- def build_right_frame
1067
- # Frame around everything
1068
- @tabbed_plots_right_frame = Qt::VBoxLayout.new
1069
- @right_frame.addLayout(@tabbed_plots_right_frame)
1070
-
1071
- # Adders
1072
- add_adders(@tabbed_plots_right_frame) if @adder_orientation == Qt::Horizontal
1073
-
1074
- # Tabbook to hold tabs
1075
- @tab_book = Qt::TabWidget.new
1076
- @tab_book.setContextMenuPolicy(Qt::CustomContextMenu)
1077
- connect(@tab_book,
1078
- SIGNAL('customContextMenuRequested(const QPoint&)'),
1079
- self,
1080
- SLOT('tab_context_menu(const QPoint&)'))
1081
- @tabbed_plots_right_frame.addWidget(@tab_book)
1082
-
1083
- # Array of overview graphs and graph times
1084
- @overview_graphs = []
1085
- @graph_time_start = []
1086
- @graph_time_end = []
1087
-
1088
- # Create each tab
1089
- @tabbed_plots_config.mu_synchronize do
1090
- @tabbed_plots_config.tabs.each_with_index do |tab, tab_index|
1091
- # Maximize graph start and end times
1092
- @graph_time_start << -1.0e300
1093
- @graph_time_end << 1.0e300
1094
-
1095
- # Create tab item for the tab
1096
- tab_text = tab.tab_text
1097
- tab_text = "Tab #{tab_index + 1}" unless tab_text
1098
- tab_item = Qt::Widget.new
1099
- tab_item.setContextMenuPolicy(Qt::CustomContextMenu)
1100
- connect(tab_item, SIGNAL('customContextMenuRequested(const QPoint&)'), self, SLOT('plot_context_menu(const QPoint&)'))
1101
-
1102
- # Create overall vertical layout manager for tab.
1103
- tab_layout = Qt::VBoxLayout.new()
1104
- tab_item.setLayout(tab_layout)
1105
- tab.gui_item = tab_item
1106
- tab.gui_frame = tab_layout
1107
- tab.tab_text = tab_text
1108
-
1109
- # Create layout manager to hold plots based on number of plots
1110
- layout = Qt::AdaptiveGridLayout.new
1111
- tab.gui_layout = layout
1112
-
1113
- # Add with stretch factor 1 to give it priority over everything else
1114
- tab_layout.addLayout(layout, 1)
1115
- # Add stretch in case they delete the last plot.
1116
- # This will force the overview graph (which doesn't get deleted)
1117
- # to stay at the bottom of the layout instead of moving
1118
- tab_layout.addStretch()
1119
-
1120
- @tab_book.addTab(tab_item, tab_text)
1121
-
1122
- # Create gui object for each plot
1123
- default_colors = DataObject::COLOR_LIST.clone
1124
- tab.plots.each_with_index do |plot, index|
1125
- filename = plot.plot_type.downcase + '_plot_gui_object.rb'
1126
- gui_object = Cosmos.require_class(filename).new(tab_item, tab, plot, self)
1127
- tab.gui_layout.addWidget(gui_object)
1128
- plot.gui_object = gui_object
1129
- if plot.gui_object.respond_to? :mouse_left_button_press_callback
1130
- current_tab = tab
1131
- plot.gui_object.mouse_left_button_press_callback = lambda do |calling_gui_object|
1132
- current_tab.plots.each do |current_plot|
1133
- if current_plot.gui_object == calling_gui_object
1134
- select_plot(current_plot)
1135
- else
1136
- unselect_plot(current_plot)
1137
- end
1138
- end
1139
- @overview_graphs[@tab_book.currentIndex].setFocus
1140
- end
1141
- end
1142
-
1143
- # Configure colors
1144
- colors = []
1145
- plot.data_objects.each do |data_object|
1146
- if data_object.assigned_color
1147
- colors << data_object.assigned_color
1148
- else
1149
- color = default_colors.shift
1150
- while (color and colors.include?(color))
1151
- color = default_colors.shift
1152
- end
1153
- color = get_random_color() unless color
1154
- colors << color
1155
- data_object.color = color
1156
- end
1157
- end
1158
- end # tab.plots.each
1159
-
1160
- # Add an overview graph to the tab
1161
- @overview_graphs << OverviewGraph.new(tab_item)
1162
- @overview_graphs[-1].window_size = @tabbed_plots_config.seconds_plotted
1163
- @overview_graphs[-1].callback = method(:overview_graph_callback)
1164
- tab_layout.addWidget(@overview_graphs[-1])
1165
- end # tabs.each
1166
- end
1167
- # Attach this handler last so it doesn't fire when we create our first tab
1168
- connect(@tab_book,
1169
- SIGNAL('currentChanged(int)'),
1170
- self,
1171
- SLOT('handle_tab_change(int)'))
1172
- end # def build_right_frame
1173
-
1174
- # Function called by the overview graph on changes
1175
- def overview_graph_callback(modified_overview_graph)
1176
- if modified_overview_graph.window_size > 0.01
1177
- @seconds_plotted.value = sprintf("%0.2f", modified_overview_graph.window_size)
1178
- else
1179
- @seconds_plotted.value = modified_overview_graph.window_size
1180
- end
1181
- @overview_graphs.each do |overview_graph|
1182
- if overview_graph != modified_overview_graph
1183
- overview_graph.set_window_size(modified_overview_graph.window_size, false)
1184
- overview_graph.set_window_pos(modified_overview_graph.window_min_x, modified_overview_graph.window_max_x, false)
1185
- end
1186
- end
1187
- redraw_plots(true)
1188
- # Intentially not have adjusting the view window in the overview graph
1189
- # be considered a configuration change
1190
- end # def overview_graph_callback
1191
-
1192
- # Selects the specified plot
1193
- def select_plot(plot)
1194
- unless plot.gui_object.selected?
1195
- plot.gui_object.select
1196
- fill_data_object_list_for_plot(plot)
1197
- end
1198
- end # def select_plot
1199
-
1200
- # Unselects the specified plot
1201
- def unselect_plot(plot)
1202
- plot.gui_object.unselect if plot.gui_object.selected?
1203
- end # def unselect_plot
1204
-
1205
- # Unselects all plots on a tab
1206
- def unselect_all_plots(tab_index = nil)
1207
- tab_index = @tab_book.current unless tab_index
1208
- return if tab_index < 0 or @tabbed_plots_config.tabs[tab_index].nil?
1209
- @tabbed_plots_config.tabs[tab_index].plots.each do |plot|
1210
- unselect_plot(plot)
1211
- end
1212
- end # def unselect_all_plots
1213
-
1214
- ############################################################################
1215
- # Slot implementation
1216
- ############################################################################
1217
-
1218
- # Handles right clicks on a tab
1219
- def tab_context_menu(point)
1220
- index = 0
1221
- (0..@tab_book.tabBar.count).each do |bar|
1222
- index = bar
1223
- break if @tab_book.tabBar.tabRect(bar).contains(point)
1224
- end
1225
- return if (index == @tab_book.tabBar.count)
1226
- @tab_book.setCurrentIndex(index)
1227
-
1228
- @tab_item_right_button_release_callback.call(@tab_book.mapToGlobal(point)) if @tab_item_right_button_release_callback
1229
- end
1230
-
1231
- # Handles right clicks on a plot
1232
- def plot_context_menu(point)
1233
- tab_index = @tab_book.currentIndex
1234
- return if tab_index < 0 or @tabbed_plots_config.tabs[tab_index].nil?
1235
- plot_point = nil
1236
- @tabbed_plots_config.tabs[tab_index].plots.each do |plot|
1237
- plot_point = @tab_book.widget(tab_index).mapToGlobal(point) if plot.gui_object.selected?
1238
- end
1239
-
1240
- @plot_right_button_release_callback.call(plot_point) if @plot_right_button_release_callback and plot_point
1241
- end
1242
-
1243
- # Handles a right click on a data object
1244
- def data_object_context_menu(point)
1245
- @data_object_right_button_release_callback.call(@data_object_list.mapToGlobal(point)) if @data_object_right_button_release_callback
1246
- end
1247
-
1248
- # Handles data objects being moved
1249
- def data_object_moved(sourceParent, sourceStart, sourceEnd, destinationParent, destinationRow)
1250
- start_index = sourceStart
1251
- if sourceStart < destinationRow
1252
- end_index = destinationRow - 1
1253
- else
1254
- end_index = destinationRow
1255
- end
1256
- tab_index = current_tab_index()
1257
- plot_index = selected_plot_index(tab_index)
1258
- @tabbed_plots_config.move_data_object(tab_index, plot_index, start_index, end_index)
1259
- @config_modified_callback.call() if @config_modified_callback
1260
- end
1261
-
1262
- # Handles tab change events
1263
- def handle_tab_change(tab_index)
1264
- if @tab_book.count > 0
1265
- plot_index = selected_plot_index(tab_index)
1266
- if plot_index
1267
- plot = @tabbed_plots_config.tabs[tab_index].plots[plot_index]
1268
- fill_data_object_list_for_plot(plot)
1269
- else
1270
- clear_data_object_list()
1271
- end
1272
- redraw_plots(true)
1273
- end
1274
- end # def handle_tab_change
1275
-
1276
- end # class OverviewTabbedPlots
1277
-
1278
- end # module Cosmos
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2014 Ball Aerospace & Technologies Corp.
4
+ # All Rights Reserved.
5
+ #
6
+ # This program is free software; you can modify and/or redistribute it
7
+ # under the terms of the GNU General Public License
8
+ # as published by the Free Software Foundation; version 3 with
9
+ # attribution addendums as found in the LICENSE.txt
10
+
11
+ require 'cosmos'
12
+ require 'cosmos/gui/utilities/screenshot'
13
+ require 'cosmos/gui/line_graph/overview_graph'
14
+ require 'cosmos/gui/choosers/integer_chooser'
15
+ require 'cosmos/gui/choosers/float_chooser'
16
+ require 'cosmos/gui/choosers/string_chooser'
17
+ require 'cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_plot_editor'
18
+ require 'cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_data_object_editor'
19
+ require 'cosmos/tools/tlm_grapher/plot_gui_objects/linegraph_plot_gui_object'
20
+ require 'cosmos/tools/tlm_grapher/plot_gui_objects/xy_plot_gui_object'
21
+ require 'cosmos/tools/tlm_grapher/plot_gui_objects/singlexy_plot_gui_object'
22
+ require 'cosmos/tools/tlm_grapher/data_object_adders/housekeeping_data_object_adder'
23
+ require 'cosmos/tools/tlm_grapher/data_object_adders/xy_data_object_adder'
24
+ require 'cosmos/tools/tlm_grapher/data_object_adders/singlexy_data_object_adder'
25
+
26
+ module Cosmos
27
+
28
+ # Implements a widget to display a set of plots in tabs with an overview graph
29
+ class OverviewTabbedPlots < Qt::Widget
30
+ slots 'handle_tab_change(int)'
31
+ slots 'tab_context_menu(const QPoint&)'
32
+ slots 'plot_context_menu(const QPoint&)'
33
+ slots 'data_object_context_menu(const QPoint&)'
34
+ slots 'data_object_moved(const QModelIndex&, int, int, const QModelIndex&, int)'
35
+
36
+ # Minimum Overview Points Per Line
37
+ MINIMUM_OVERVIEW_POINTS_PLOTTED = 100
38
+
39
+ # Minimum delay between redraws
40
+ MINIMUM_REFRESH_DELAY_MS = 10
41
+
42
+ # Accessor to tabbed_plots_config
43
+ attr_accessor :tabbed_plots_config
44
+
45
+ # Accessor to adders
46
+ attr_accessor :data_object_adders
47
+
48
+ # Callback when right button is released on a tab item
49
+ attr_accessor :tab_item_right_button_release_callback
50
+
51
+ # Callback when right button is released on a plot
52
+ attr_accessor :plot_right_button_release_callback
53
+
54
+ # Callback when right button is released on a data object
55
+ attr_accessor :data_object_right_button_release_callback
56
+
57
+ # Callback when a change to modifies the configuration occurs
58
+ attr_accessor :config_modified_callback
59
+
60
+ # Give access to the status bar to other widgets
61
+ attr_reader :status_bar
62
+
63
+ def initialize(parent, left_frame, right_frame, status_bar)
64
+ super(parent)
65
+ # Save Constructor Arguments
66
+ @left_frame = left_frame
67
+ @right_frame = right_frame
68
+ @status_bar = status_bar
69
+
70
+ # Default startup arguments
71
+ @tabbed_plots_config = nil
72
+ @adder_orientation = Qt::Horizontal
73
+
74
+ # Additional instance variables
75
+ @data_object_adders = []
76
+ @tab_item_right_button_release_callback = nil
77
+ @plot_right_button_release_callback = nil
78
+ @data_object_right_button_release_callback = nil
79
+ @config_modified_callback = nil
80
+ @paused = false
81
+ @timeout = nil
82
+ @refresh_rate_ms = (1000.0 / TabbedPlotsConfig::DEFAULT_REFRESH_RATE_HZ).round
83
+ @context_menu_plot = nil
84
+ end # def initialize
85
+
86
+ # Startup GUI interaction
87
+ def startup(tabbed_plots_config, adder_orientation, adder_types)
88
+ # Save parameters
89
+ @tabbed_plots_config = tabbed_plots_config
90
+ @adder_orientation = adder_orientation
91
+ @adder_types = adder_types
92
+
93
+ # Create GUI elements
94
+ build_right_frame()
95
+ build_left_frame()
96
+ create()
97
+ end # def startup
98
+
99
+ # Shutdown GUI interaction
100
+ def shutdown
101
+ # Shutdown drawing timeout
102
+ @timeout.method_missing(:stop) if @timeout
103
+
104
+ # Remove GUI elements
105
+ @tabbed_plots_left_frame.removeAll
106
+ @tabbed_plots_right_frame.removeAll
107
+ end # def shutdown
108
+
109
+ # Update
110
+ def update
111
+ @data_object_adders.each {|adder| adder.update}
112
+ end
113
+
114
+ ###############################################################################
115
+ # Pause / Resume
116
+ ###############################################################################
117
+
118
+ # Pause plotting
119
+ def pause
120
+ @paused = true
121
+ end # def pause
122
+
123
+ # Resume plotting if paused
124
+ def resume
125
+ @paused = false
126
+ end # def resume
127
+
128
+ # Are we paused?
129
+ def paused?
130
+ @paused
131
+ end # def paused?
132
+
133
+ ###############################################################################
134
+ # Tab Related Methods
135
+ ###############################################################################
136
+
137
+ # Add a new tab
138
+ def add_tab(tab_text = nil)
139
+ unless tab_text
140
+ # If the last tab text is "Tab X" the next tab should be "Tab X+1"
141
+ if (@tabbed_plots_config.tabs.length > 0) &&
142
+ (@tabbed_plots_config.tabs[-1].tab_text =~ /Tab (\d*)/)
143
+ tab_text = "Tab #{$1.to_i + 1}" # $1 is the match from the regexp
144
+ else # Set text to the total number of tabs
145
+ tab_text = "Tab #{@tabbed_plots_config.tabs.length + 1}"
146
+ end
147
+ end
148
+ tab = @tabbed_plots_config.add_tab(tab_text)
149
+
150
+ # Create tab item for the tab
151
+ tab_item = Qt::Widget.new
152
+ tab_item.setContextMenuPolicy(Qt::CustomContextMenu)
153
+ connect(tab_item, SIGNAL('customContextMenuRequested(const QPoint&)'), self, SLOT('plot_context_menu(const QPoint&)'))
154
+ tab.gui_item = tab_item
155
+
156
+ # Create overall vertical layout manager for tab.
157
+ tab_layout = Qt::VBoxLayout.new()
158
+ tab_item.setLayout(tab_layout)
159
+ tab.gui_frame = tab_layout
160
+
161
+ # Create layout manager to hold plots based on number of plots
162
+ layout = Qt::AdaptiveGridLayout.new
163
+ tab_layout.addLayout(layout, 1) # Add with stretch factor 1 to give it priority over everything else
164
+ # Add stretch in case they delete the last plot. This will force the overview graph (which doesn't get deleted)
165
+ # to stay at the bottom of the layout instead of moving
166
+ tab_layout.addStretch()
167
+ tab.gui_layout = layout
168
+
169
+ # Add an overview graph to the tab
170
+ @overview_graphs << OverviewGraph.new(self)
171
+ @overview_graphs[-1].callback = method(:overview_graph_callback)
172
+ @overview_graphs[-1].window_size = @seconds_plotted.value
173
+ tab_layout.addWidget(@overview_graphs[-1])
174
+
175
+ # Add an initial plot to the tab
176
+ add_plot(-1, false)
177
+
178
+ # Add and select the new tab
179
+ index = @tab_book.addTab(tab_item, tab_text)
180
+ @tab_book.setCurrentIndex(index)
181
+ @config_modified_callback.call() if @config_modified_callback
182
+ end # def add_tab
183
+
184
+ # Delete a tab - defaults to the current tab
185
+ def delete_tab(tab_index = nil)
186
+ # Select the current tab by default
187
+ tab_index = current_tab_index() unless tab_index
188
+
189
+ if tab_index
190
+ # Remove from config
191
+ @tabbed_plots_config.remove_tab(tab_index)
192
+
193
+ # Remove knowledge of overview graph
194
+ @overview_graphs.delete_at(tab_index)
195
+
196
+ # Remove tab item and frame from tab book
197
+ @tab_book.widget(tab_index).dispose
198
+
199
+ # Call tab change callback @tab_book.current is not valid at this point
200
+ if tab_index > (@tabbed_plots_config.tabs.length - 1)
201
+ @tab_book.setCurrentIndex(tab_index - 1)
202
+ else
203
+ @tab_book.setCurrentIndex(tab_index)
204
+ end
205
+ end
206
+ @config_modified_callback.call() if @config_modified_callback
207
+ end # def delete_tab
208
+
209
+ # Edit a tab - defaults to the current tab
210
+ def edit_tab(tab_index = nil)
211
+ edited = false
212
+
213
+ # Select the current tab by default
214
+ tab_index = current_tab_index() unless tab_index
215
+
216
+ if tab_index
217
+ # Get the tab object
218
+ tab = @tabbed_plots_config.tabs[tab_index]
219
+
220
+ # Create simple dialog box to edit the tab
221
+ result = Qt::Boolean.new
222
+ string = Qt::InputDialog::getText(self,
223
+ "Edit Tab",
224
+ "Tab Text:",
225
+ Qt::LineEdit::Normal,
226
+ tab.tab_text,
227
+ result)
228
+ if !result.nil? and not string.strip.empty? and @tab_book.tabText(tab_index) != string
229
+ tab.tab_text = string
230
+ @tab_book.setTabText(tab_index, string)
231
+ edited = true
232
+ @config_modified_callback.call() if @config_modified_callback
233
+ end
234
+ end
235
+
236
+ return edited
237
+ end # def edit_tab
238
+
239
+ # Export all data objects on a tab - defaults to current tab
240
+ def export_tab(filename, progress, tab_index = nil)
241
+ # Select the current tab by default
242
+ tab_index = current_tab_index() unless tab_index
243
+
244
+ if tab_index
245
+ # Export the tab's data objects
246
+ export_data_objects(filename, progress, tab_index) if @tabbed_plots_config.tabs[tab_index]
247
+ end
248
+ end # def export_tab
249
+
250
+ # Reset all data objects on a tab - defaults to current tab
251
+ def reset_tab(tab_index = nil)
252
+ # Select the current tab by default
253
+ tab_index = current_tab_index() unless tab_index
254
+
255
+ # Reset the data objects
256
+ reset_data_objects(tab_index) if tab_index
257
+ end
258
+
259
+ # Take screenshot of current tab and write to filename
260
+ def screenshot_tab(filename)
261
+ # Select the current tab
262
+ tab_index = current_tab_index()
263
+
264
+ if tab_index
265
+ # Take screenshot
266
+ Screenshot.screenshot_window(@tab_book.currentWidget(), filename)
267
+ end
268
+ end # def screenshot_tab
269
+
270
+ # Returns the index of the current tab or nil if no tabs exist
271
+ def current_tab_index
272
+ unless @tabbed_plots_config.tabs.empty?
273
+ tab_index = @tab_book.currentIndex
274
+ return tab_index if tab_index >= 0
275
+ end
276
+ nil
277
+ end # def current_tab_index
278
+
279
+ # Indicates if the tab has any data objects
280
+ def tab_has_data_objects?(tab_index = nil)
281
+ # Select the current tab by default
282
+ tab_index = current_tab_index() unless tab_index
283
+
284
+ return_value = false
285
+ if tab_index
286
+ @tabbed_plots_config.mu_synchronize do
287
+ @tabbed_plots_config.tabs[tab_index].plots.each do |plot|
288
+ if not plot.data_objects.empty?
289
+ return_value = true
290
+ break
291
+ end
292
+ end
293
+ end
294
+ end
295
+
296
+ return_value
297
+ end
298
+
299
+ ###############################################################################
300
+ # Plot Related Methods
301
+ ###############################################################################
302
+
303
+ # Add a new plot to a tab - defaults to the current tab
304
+ def add_plot(tab_index = nil, dialog = true)
305
+ # Select the current tab by default
306
+ tab_index = current_tab_index() unless tab_index
307
+
308
+ if tab_index
309
+ # Get Tab
310
+ tab = @tabbed_plots_config.tabs[tab_index]
311
+
312
+ # Add to config
313
+ if dialog
314
+ plot_editor = TabbedPlotsPlotEditor.new(self,
315
+ 'Add Plot',
316
+ @tabbed_plots_config.plot_types)
317
+ plot = plot_editor.execute
318
+ plot_editor.dispose
319
+ else
320
+ plot = @tabbed_plots_config.create_plot(@tabbed_plots_config.plot_types[0])
321
+ end
322
+ if plot
323
+ @tabbed_plots_config.add_plot(tab_index, plot)
324
+ @status_bar.showMessage(tr("Add Plot Succeeded"))
325
+ else
326
+ @status_bar.showMessage(tr("Add Plot Canceled"))
327
+ return false
328
+ end
329
+
330
+ # Create new plot gui object
331
+ filename = plot.plot_type.downcase + '_plot_gui_object.rb'
332
+ gui_object = Cosmos.require_class(filename).new(tab.gui_item, tab, plot, self)
333
+ tab.gui_layout.addWidget(gui_object)
334
+ plot.gui_object = gui_object
335
+ #~ plot.gui_object.connect(SEL_RIGHTBUTTONRELEASE, method(:handle_plot_right_button_release))
336
+ if plot.gui_object.respond_to? :mouse_left_button_press_callback
337
+ current_tab = tab
338
+ plot.gui_object.mouse_left_button_press_callback = lambda do |calling_gui_object|
339
+ current_tab.plots.each_with_index do |current_plot, index|
340
+ if current_plot.gui_object == calling_gui_object
341
+ select_plot(current_plot)
342
+ else
343
+ unselect_plot(current_plot)
344
+ end
345
+ end
346
+ @overview_graphs[@tab_book.currentIndex].setFocus
347
+ end
348
+ end
349
+
350
+ # Auto-select plot
351
+ unselect_all_plots(tab_index)
352
+ select_plot(plot)
353
+ end
354
+ @config_modified_callback.call() if @config_modified_callback
355
+ return true
356
+ end # def add_plot
357
+
358
+ # Delete a plot - defaults to the selected plot on the current tab
359
+ def delete_plot(tab_index = nil, plot_index = nil)
360
+ # Select the current tab by default
361
+ tab_index = current_tab_index() unless tab_index
362
+
363
+ # Select selected plot by default
364
+ plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
365
+
366
+ # Make sure the plot exists
367
+ if plot_index
368
+ # Get Tab
369
+ tab = @tabbed_plots_config.tabs[tab_index]
370
+
371
+ # Remove from config
372
+ plot = @tabbed_plots_config.remove_plot(tab_index, plot_index)
373
+
374
+ # Potentially clear data object list
375
+ clear_data_object_list() if plot.gui_object.selected?
376
+
377
+ # Remove the widget
378
+ tab.gui_layout.removeWidget(plot.gui_object)
379
+ plot.gui_object.dispose
380
+
381
+ # Create new layout
382
+ layout = Qt::AdaptiveGridLayout.new
383
+
384
+ # Add existing gui objects into new layout
385
+ (0...tab.gui_layout.count).each do |index|
386
+ layout.addWidget(tab.gui_layout.takeAt(0).widget)
387
+ end
388
+
389
+ # Select the first plot just to be nice
390
+ select_plot(tab.plots[0]) if tab.plots[0]
391
+
392
+ # Remove existing layout from frame
393
+ tab.gui_frame.removeItem(tab.gui_layout)
394
+ # Assign new layout to tab
395
+ tab.gui_frame.insertLayout(0, layout, 1)
396
+ tab.gui_layout = layout
397
+ #~ tab.gui_layout.connect(SEL_RIGHTBUTTONRELEASE, method(:handle_plot_right_button_release))
398
+
399
+ @status_bar.showMessage(tr("Plot Deleted"))
400
+ @config_modified_callback.call() if @config_modified_callback
401
+ else
402
+ Qt::MessageBox.information(self, 'Information', 'Please select a plot')
403
+ end
404
+ end # def delete_plot
405
+
406
+ # Edit a plot - defaults to the selected plot on the current tab
407
+ def edit_plot(tab_index = nil, plot_index = nil)
408
+ edited = false
409
+
410
+ # Select the current tab by default
411
+ tab_index = current_tab_index() unless tab_index
412
+
413
+ if tab_index
414
+ # Get tab
415
+ tab = @tabbed_plots_config.tabs[tab_index]
416
+
417
+ # Select selected plot by default
418
+ plot_index = selected_plot_index(tab_index) unless plot_index
419
+ unless plot_index
420
+ Qt::MessageBox.information(self, 'Information', 'Please select a plot')
421
+ return
422
+ end
423
+ plot = tab.plots[plot_index]
424
+
425
+ # Edit Plot
426
+ plot_editor = TabbedPlotsPlotEditor.new(self,
427
+ 'Edit Plot',
428
+ @tabbed_plots_config.plot_types,
429
+ plot)
430
+ plot = plot_editor.execute
431
+ plot_editor.dispose
432
+ if plot
433
+ plot.gui_object.update(true)
434
+ @status_bar.showMessage(tr("Plot Edited"))
435
+ edited = true
436
+ @config_modified_callback.call() if @config_modified_callback
437
+ else
438
+ @status_bar.showMessage(tr("Plot Edit Canceled"))
439
+ end
440
+ end
441
+
442
+ return edited
443
+ end # def edit_plot
444
+
445
+ # Exports data objects on a plot - defaults to selected plot on the current tab
446
+ def export_plot(filename, progress, tab_index = nil, plot_index = nil)
447
+ # Select the current tab by default
448
+ tab_index = current_tab_index() unless tab_index
449
+
450
+ # Select selected plot by default
451
+ plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
452
+ unless plot_index
453
+ Qt::MessageBox.information(self, 'Information', 'Please select a plot')
454
+ return
455
+ end
456
+
457
+ export_data_objects(filename, progress, tab_index, plot_index)
458
+ end # def export_plot
459
+
460
+ # Take screenshot of a plot on the current tab and write to filename - defaults to selected plot
461
+ def screenshot_plot(filename, plot_index = nil)
462
+ # Select the current tab by default
463
+ tab_index = current_tab_index() unless tab_index
464
+
465
+ # Select selected plot by default
466
+ plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
467
+
468
+ # Take screenshot
469
+ Screenshot.screenshot_window(@tabbed_plots_config.tabs[tab_index].plots[plot_index].gui_object, filename) if plot_index
470
+ end # def screenshot_plot
471
+
472
+ # Reset all data objects on a plot - defaults to the selected plot on the current tab
473
+ def reset_plot(tab_index = nil, plot_index = nil)
474
+ # Select the current tab by default
475
+ tab_index = current_tab_index() unless tab_index
476
+
477
+ # Select selected plot by default
478
+ plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
479
+
480
+ # Reset the data objects
481
+ reset_data_objects(tab_index, plot_index) if plot_index
482
+ end
483
+
484
+ # Returns the index of the selected plot or nil - looks at current tab by default
485
+ def selected_plot_index(tab_index = nil)
486
+ # Select the current tab by default
487
+ tab_index = current_tab_index() unless tab_index
488
+
489
+ if tab_index
490
+ @tabbed_plots_config.tabs[tab_index].plots.each_with_index do |plot, index|
491
+ return index if plot.gui_object.selected?
492
+ end
493
+ end
494
+ nil
495
+ end # def selected_plot_index
496
+
497
+ # Indicates if the plot has any data objects
498
+ def plot_has_data_objects?(tab_index = nil, plot_index = nil)
499
+ # Select the current tab by default
500
+ tab_index = current_tab_index() unless tab_index
501
+
502
+ # Select selected plot by default
503
+ plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
504
+
505
+ return_value = false
506
+ if plot_index
507
+ @tabbed_plots_config.mu_synchronize do
508
+ return_value = true unless @tabbed_plots_config.tabs[tab_index].plots[plot_index].data_objects.empty?
509
+ end
510
+ end
511
+
512
+ return_value
513
+ end
514
+
515
+ ###############################################################################
516
+ # Data Object Related Methods
517
+ ###############################################################################
518
+
519
+ # Adds a data object to a plot - defaults to selected plot on the current tab
520
+ def add_data_object(tab_index = nil, plot_index = nil, data_object = nil)
521
+ # Select the current tab by default
522
+ tab_index = current_tab_index() unless tab_index
523
+
524
+ # Select selected plot by default
525
+ plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
526
+ unless plot_index
527
+ Qt::MessageBox.information(self, 'Information', 'Please select a plot')
528
+ return false
529
+ end
530
+
531
+ # Get plot
532
+ plot = @tabbed_plots_config.tabs[tab_index].plots[plot_index]
533
+
534
+ # Start data object editor to create new data object
535
+ unless data_object
536
+ data_object_editor = TabbedPlotsDataObjectEditor.new(self,'Add Data Object', @tabbed_plots_config.plot_type_to_data_object_type_mapping[plot.plot_type])
537
+ data_object = data_object_editor.execute
538
+ data_object_editor.dispose
539
+ unless data_object
540
+ @status_bar.showMessage(tr("Add Data Object Canceled"))
541
+ return false
542
+ end
543
+ end
544
+
545
+ # Assign color to data object
546
+ data_object.color = get_free_color(@tabbed_plots_config.tabs[tab_index]) unless data_object.assigned_color
547
+
548
+ # Add to config
549
+ @tabbed_plots_config.add_data_object(tab_index, plot_index, data_object)
550
+ @tabbed_plots_config.update_max_points_saved(@points_saved.value)
551
+
552
+ # Update Plot
553
+ @tabbed_plots_config.tabs[tab_index].plots[plot_index].gui_object.update(true)
554
+
555
+ # Update data object list
556
+ fill_data_object_list_for_plot(@tabbed_plots_config.tabs[tab_index].plots[plot_index])
557
+
558
+ @status_bar.showMessage(tr("Add Data Object Succeeded"))
559
+ @config_modified_callback.call() if @config_modified_callback
560
+ return true
561
+ end # def add_data_object
562
+
563
+ # Deletes a data object from a plot - defaults to the selected data objects on the selected plot on the current tab
564
+ def delete_data_object(tab_index = nil, plot_index = nil, data_object_index = nil)
565
+ # Select the current tab by default
566
+ tab_index = current_tab_index() unless tab_index
567
+
568
+ # Select selected plot by default
569
+ plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
570
+ plot = @tabbed_plots_config.tabs[tab_index].plots[plot_index]
571
+
572
+ data_object_indexes = get_data_object_indexes(plot,
573
+ tab_index,
574
+ plot_index,
575
+ data_object_index)
576
+ data_object_indexes.reverse.each do |data_object_idx|
577
+ @tabbed_plots_config.remove_data_object(tab_index, plot_index, data_object_idx)
578
+ end
579
+
580
+ if plot
581
+ plot.gui_object.update(true)
582
+ fill_data_object_list_for_plot(plot)
583
+ end
584
+ @config_modified_callback.call() if @config_modified_callback
585
+ end # def delete_data_object
586
+
587
+ # Edits a data object on a plot - defaults to the selected data objects on the selected plot on the current tab
588
+ def edit_data_object(tab_index = nil, plot_index = nil, data_object_index = nil)
589
+ edited = false
590
+
591
+ # Select the current tab by default
592
+ tab_index = current_tab_index() unless tab_index
593
+
594
+ # Select selected plot by default
595
+ plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
596
+ if plot_index
597
+ plot = @tabbed_plots_config.tabs[tab_index].plots[plot_index]
598
+
599
+ data_object_indexes = get_data_object_indexes(plot,
600
+ tab_index,
601
+ plot_index,
602
+ data_object_index)
603
+ data_object_indexes.each do |data_object_idx|
604
+ data_object = @tabbed_plots_config.tabs[tab_index].plots[plot_index].data_objects[data_object_idx]
605
+ data_object_editor = TabbedPlotsDataObjectEditor.new(self, 'Edit Data Object', @tabbed_plots_config.plot_type_to_data_object_type_mapping[plot.plot_type], data_object)
606
+ data_object = data_object_editor.execute
607
+ data_object_editor.dispose
608
+ if data_object
609
+ @tabbed_plots_config.edit_data_object(tab_index, plot_index, data_object_idx, data_object)
610
+ @status_bar.showMessage(tr("Data Object(s) Edited"))
611
+ edited = true
612
+ @config_modified_callback.call() if @config_modified_callback
613
+ else
614
+ @status_bar.showMessage(tr("Edit Data Object Canceled"))
615
+ end
616
+ end
617
+
618
+ plot.gui_object.update(true)
619
+ fill_data_object_list_for_plot(plot)
620
+ end
621
+
622
+ return edited
623
+ end # def edit_data_object
624
+
625
+ # Duplicates a data object on a plot - defaults to the selected data objects on the selected plot on the current tab
626
+ def duplicate_data_object(tab_index = nil, plot_index = nil, data_object_index = nil)
627
+ # Select the current tab by default
628
+ tab_index = current_tab_index() unless tab_index
629
+
630
+ # Select selected plot by default
631
+ plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
632
+ if plot_index
633
+ plot = @tabbed_plots_config.tabs[tab_index].plots[plot_index]
634
+
635
+ data_object_indexes = get_data_object_indexes(plot,
636
+ tab_index,
637
+ plot_index,
638
+ data_object_index)
639
+ data_object_indexes.each do |data_object_idx|
640
+ data_object = @tabbed_plots_config.duplicate_data_object(tab_index, plot_index, data_object_idx)
641
+ data_object.color = get_free_color(@tabbed_plots_config.tabs[tab_index]) unless data_object.assigned_color
642
+ end
643
+ @status_bar.showMessage(tr("Data Object(s) Duplicated"))
644
+
645
+ plot.gui_object.update(true)
646
+ fill_data_object_list_for_plot(@tabbed_plots_config.tabs[tab_index].plots[plot_index])
647
+ @config_modified_callback.call() if @config_modified_callback
648
+ end
649
+ end # def duplicate_data_object
650
+
651
+ # Exports a data object on a plot - defaults to the selected data objects on the selected plot on the current tab
652
+ def export_data_object(filename, progress, tab_index = nil, plot_index = nil, data_object_index = nil)
653
+ # Select the current tab by default
654
+ tab_index = current_tab_index() unless tab_index
655
+
656
+ # Select selected plot by default
657
+ plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
658
+ if plot_index
659
+ plot = @tabbed_plots_config.tabs[tab_index].plots[plot_index]
660
+
661
+ data_object_indexes = get_data_object_indexes(plot,
662
+ tab_index,
663
+ plot_index,
664
+ data_object_index)
665
+
666
+ columns = []
667
+ data_object_indexes.each do |data_object_idx|
668
+ columns.concat(@tabbed_plots_config.export_data_objects(progress, tab_index, plot_index, data_object_idx))
669
+ end
670
+ write_export_file(filename, columns, progress)
671
+ end
672
+ end # def export_data_object
673
+
674
+ # Exports all data objects
675
+ def export_all_data_objects(filename, progress)
676
+ export_data_objects(filename, progress)
677
+ end # def export_all_data_objects
678
+
679
+ # Resets a data object on a plot - defaults to the selected data objects on the selected plot on the current tab
680
+ def reset_data_object(tab_index = nil, plot_index = nil, data_object_index = nil)
681
+ # Select the current tab by default
682
+ tab_index = current_tab_index() unless tab_index
683
+
684
+ # Select selected plot by default
685
+ plot_index = selected_plot_index(tab_index) if tab_index and not plot_index
686
+
687
+ if plot_index
688
+ data_object_indexes = selected_data_object_indexes()
689
+ data_object_indexes.reverse.each do |data_object_idx|
690
+ @tabbed_plots_config.reset_data_objects(tab_index, plot_index, data_object_idx)
691
+ end
692
+ redraw_plots(true, true)
693
+ @status_bar.showMessage(tr("Data Object(s) Reset"))
694
+ end
695
+ end
696
+
697
+ # Resets all data objects
698
+ def reset_all_data_objects
699
+ reset_data_objects()
700
+ end # def reset_all_data_objects
701
+
702
+ # Returns an array with the indexes of the selected data objects
703
+ def selected_data_object_indexes
704
+ selected = []
705
+ index = 0
706
+ @data_object_list.each do |list_item|
707
+ selected << index if list_item.selected? and @data_object_list.item(index).text != 'No Plot Selected'
708
+ index += 1
709
+ end
710
+ selected
711
+ end # def selected_data_object_indexes
712
+
713
+ # Redraws all plots that need to be redrawn
714
+ def redraw_plots(force_redraw = false, force_move_window = false)
715
+ if not @paused or force_redraw
716
+ overview_redraw_needed = force_redraw
717
+ move_window = force_move_window
718
+ points_plotted = @points_plotted.value
719
+
720
+ # Determine if overview redraws are needed
721
+ @tabbed_plots_config.mu_synchronize do
722
+ tab_index = @tab_book.currentIndex
723
+ return if tab_index < 0 or tab_index > (@tabbed_plots_config.tabs.length - 1)
724
+ @tabbed_plots_config.tabs[tab_index].plots.each do |plot|
725
+ if plot.redraw_needed
726
+ overview_redraw_needed = true
727
+ move_window = true unless @paused
728
+ break
729
+ end
730
+ end
731
+ end
732
+
733
+ # Redraw overview
734
+ overview_graph = @overview_graphs[@tab_book.currentIndex]
735
+ if overview_redraw_needed
736
+ num_lines = 0
737
+ @tabbed_plots_config.tabs[@tab_book.currentIndex].plots.each {|plot| num_lines += plot.data_objects.length}
738
+ if num_lines > 0
739
+ overview_points_plotted = points_plotted / num_lines
740
+ overview_points_plotted = MINIMUM_OVERVIEW_POINTS_PLOTTED if overview_points_plotted < MINIMUM_OVERVIEW_POINTS_PLOTTED
741
+ else
742
+ overview_points_plotted = points_plotted
743
+ end
744
+
745
+ overview_graph.clear_lines
746
+ @tabbed_plots_config.mu_synchronize do
747
+ @tabbed_plots_config.tabs[@tab_book.currentIndex].plots.each {|plot| plot.gui_object.update_overview(overview_points_plotted, overview_graph)}
748
+ end
749
+
750
+ overview_graph.graph(move_window)
751
+ end
752
+
753
+ # Sync other overview graph positions
754
+ @overview_graphs.each do |other_overview_graph|
755
+ if overview_graph != other_overview_graph
756
+ other_overview_graph.set_window_pos(overview_graph.window_min_x, overview_graph.window_max_x, false)
757
+ end
758
+ end
759
+
760
+ # Determine if plot redraws needed
761
+ gui_objects = []
762
+ redraw_needed = []
763
+ @tabbed_plots_config.mu_synchronize do
764
+ @tabbed_plots_config.tabs[@tab_book.currentIndex].plots.each do |plot|
765
+ gui_objects << plot.gui_object
766
+ if force_redraw or overview_redraw_needed
767
+ redraw_needed << true
768
+ else
769
+ redraw_needed << plot.redraw_needed
770
+ end
771
+ if redraw_needed[-1]
772
+ plot.gui_object.update_plot(points_plotted, overview_graph.window_min_x, overview_graph.window_max_x)
773
+ end
774
+ end
775
+ end
776
+
777
+ # Redraw plots
778
+ gui_objects.length.times do |index|
779
+ if redraw_needed[index]
780
+ gui_objects[index].redraw
781
+ end
782
+ end
783
+
784
+ end
785
+ end # def redraw_plots
786
+
787
+ protected
788
+
789
+ def get_data_object_indexes(plot, tab_index, plot_index, data_object_index)
790
+ if data_object_index
791
+ return unless (plot and @tabbed_plots_config.tabs[tab_index].plots[plot_index].data_objects[data_object_index])
792
+ data_object_indexes = [data_object_index]
793
+ else
794
+ data_object_indexes = selected_data_object_indexes()
795
+ end
796
+ end
797
+
798
+ # Resets data objects and redraws the plots
799
+ def reset_data_objects(tab_index = nil, plot_index = nil, data_object_index = nil)
800
+ @tabbed_plots_config.reset_data_objects(tab_index, plot_index, data_object_index)
801
+ redraw_plots(true, true)
802
+ end # def reset_data_objects
803
+
804
+ def write_export_file(filename, columns, progress)
805
+ max_column_size = 0
806
+ columns.each {|column| max_column_size = column.length if column.length > max_column_size}
807
+ File.open(filename, 'w') do |file|
808
+ max_column_size.times do |index|
809
+ string = ''
810
+ columns.each {|column| string << column[index].to_s << "\t"}
811
+ file.puts(string)
812
+ progress.set_overall_progress(index.to_f / max_column_size)
813
+ end
814
+ end
815
+ end
816
+
817
+ # Exports data objects to a file
818
+ def export_data_objects(filename, progress, tab_index = nil, plot_index = nil, data_object_index = nil)
819
+ columns = @tabbed_plots_config.export_data_objects(progress, tab_index, plot_index, data_object_index)
820
+ write_export_file(filename, columns, progress)
821
+ end # def export_data_objects
822
+
823
+ # Create GUI objects
824
+ def create
825
+ # Select first plot on each tab in reverse order
826
+ @tabbed_plots_config.tabs.reverse.each {|tab| select_plot(tab.plots[0]) if tab.plots[0]}
827
+
828
+ # Setup timeout to redraw graphs
829
+ @timeout = Qt::Timer.new(self)
830
+ @timeout.connect(SIGNAL('timeout()')) { redraw_plots() }
831
+ @timeout.method_missing(:start, @refresh_rate_ms)
832
+ end # def create
833
+
834
+ # Clears the data object list
835
+ def clear_data_object_list
836
+ # Clear data object list
837
+ @data_object_list.clearItems
838
+ @data_object_list.addItemColor('No Plot Selected')
839
+ end # def clear_data_object_list
840
+
841
+ # Fills the data object list for the specified plot
842
+ def fill_data_object_list_for_plot(plot)
843
+ # List Data Objects for this plot
844
+ @data_object_list.clearItems
845
+ plot.data_objects.each do |data_object|
846
+ @data_object_list.addItemColor(data_object.name, data_object.color)
847
+ end
848
+ end # def fill_data_object_list_for_plot
849
+
850
+ # Gets an available color on a tab - if no colors are available a random color
851
+ # is returned
852
+ def get_free_color(tab)
853
+ color = nil
854
+ colors = []
855
+ default_colors = DataObject::COLOR_LIST.clone
856
+ tab.plots.each do |plot|
857
+ plot.data_objects.each {|data_object| colors << data_object.color}
858
+ end
859
+ color = default_colors.shift
860
+ while (color and colors.include?(color))
861
+ color = default_colors.shift
862
+ end
863
+ color = get_random_color() unless color
864
+ color
865
+ end # def get_free_color
866
+
867
+ # Gets a random color
868
+ def get_random_color
869
+ random_index = (rand() * DataObject::COLOR_LIST.length).floor
870
+ random_index = (DataObject::COLOR_LIST.length - 1) if random_index >= DataObject::COLOR_LIST.length
871
+ DataObject::COLOR_LIST[random_index].clone
872
+ end # def get_random_color
873
+
874
+ # Builds the left frame of the tool
875
+ def build_left_frame
876
+ # Frame around everything
877
+ @tabbed_plots_left_frame = Qt::VBoxLayout.new
878
+ @left_frame.addLayout(@tabbed_plots_left_frame)
879
+
880
+ # Seconds Plotted
881
+ @seconds_plotted = FloatChooser.new(self,
882
+ 'Seconds Plotted:',
883
+ @tabbed_plots_config.seconds_plotted,
884
+ 0.0,
885
+ nil,
886
+ 15)
887
+ @seconds_plotted.sel_command_callback = method(:handle_seconds_plotted_change)
888
+ @tabbed_plots_left_frame.addWidget(@seconds_plotted)
889
+
890
+ # Points Saved
891
+ @points_saved = IntegerChooser.new(self, 'Points Saved:', @tabbed_plots_config.points_saved, 1, nil, 15)
892
+ @points_saved.sel_command_callback = method(:handle_points_saved_change)
893
+ @tabbed_plots_left_frame.addWidget(@points_saved)
894
+
895
+ # Points Plotted
896
+ @points_plotted = IntegerChooser.new(self,
897
+ 'Points Plotted:',
898
+ @tabbed_plots_config.points_plotted,
899
+ 2,
900
+ nil,
901
+ 15)
902
+ @points_plotted.sel_command_callback = method(:handle_points_plotted_change)
903
+ @tabbed_plots_left_frame.addWidget(@points_plotted)
904
+
905
+ # Refresh Rate Hz
906
+ @refresh_rate_hz = FloatChooser.new(self,
907
+ 'Refresh Rate Hz:',
908
+ @tabbed_plots_config.refresh_rate_hz,
909
+ 0.000001,
910
+ 1000.0,
911
+ 15)
912
+ @refresh_rate_hz.sel_command_callback = method(:handle_refresh_rate_hz_change)
913
+ @tabbed_plots_left_frame.addWidget(@refresh_rate_hz)
914
+
915
+ # Update overview graphs
916
+ @overview_graphs.each {|overview_graph| overview_graph.window_size = @tabbed_plots_config.seconds_plotted}
917
+
918
+ # Adders
919
+ add_adders(@tabbed_plots_left_frame) if @adder_orientation == Qt::Vertical
920
+
921
+ # Separator before list
922
+ sep = Qt::Frame.new
923
+ sep.setFrameStyle(Qt::Frame::HLine | Qt::Frame::Sunken)
924
+ @tabbed_plots_left_frame.addWidget(sep)
925
+
926
+ # Data Object List
927
+ @tabbed_plots_left_frame.addWidget(Qt::Label.new('Data Objects:'))
928
+ @data_object_list = Qt::ColorListWidget.new(self, false)
929
+ @data_object_list.setSelectionMode(Qt::AbstractItemView::ExtendedSelection)
930
+ @data_object_list.setContextMenuPolicy(Qt::CustomContextMenu)
931
+ @data_object_list.setDragDropMode(Qt::AbstractItemView::InternalMove)
932
+ @data_object_list.define_singleton_method(:keyPressEvent) do |event|
933
+ case event.key
934
+ when Qt::Key_Delete, Qt::Key_Backspace
935
+ otp = self.original_parent
936
+ unless otp.selected_data_object_indexes.empty?
937
+ paused = otp.paused?()
938
+ otp.pause()
939
+ result = Qt::MessageBox.warning(self,
940
+ 'Warning!',
941
+ "Are you sure you want to delete the selected data objects?",
942
+ Qt::MessageBox::Yes | Qt::MessageBox::No, Qt::MessageBox::No)
943
+ if result == Qt::MessageBox::No
944
+ otp.status_bar.showMessage(tr("Data Object Deletion Canceled"))
945
+ else
946
+ otp.status_bar.showMessage(tr("Data Object Deleted"))
947
+ otp.delete_data_object()
948
+ end
949
+ otp.resume() unless paused
950
+ end
951
+ end
952
+ super(event)
953
+ end
954
+ connect(@data_object_list.model,
955
+ SIGNAL('rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int)'),
956
+ self,
957
+ SLOT('data_object_moved(const QModelIndex&, int, int, const QModelIndex&, int)'))
958
+ connect(@data_object_list,
959
+ SIGNAL('customContextMenuRequested(const QPoint&)'),
960
+ self,
961
+ SLOT('data_object_context_menu(const QPoint&)'))
962
+ @data_object_list.connect(SIGNAL('itemClicked(QListWidgetItem*)')) do
963
+ @status_bar.showMessage(tr("Drag and drop to reorder. Items are drawn in order from top to bottom."))
964
+ end
965
+ @data_object_list.addItemColor('No Plot Selected')
966
+ @tabbed_plots_left_frame.addWidget(@data_object_list)
967
+ @tabbed_plots_config.update_max_points_saved(@points_saved.value)
968
+ end # def build_left_frame
969
+
970
+ # Handler for points saved changing
971
+ def handle_points_saved_change(value_string, value_integer)
972
+ if value_integer < @tabbed_plots_config.points_saved
973
+ paused = paused?()
974
+ pause()
975
+ result = Qt::MessageBox.warning(self,
976
+ 'Warning!',
977
+ "Reducing Points Saved May Discard Data! Discard?",
978
+ Qt::MessageBox::Yes | Qt::MessageBox::No, Qt::MessageBox::No)
979
+ resume() unless paused
980
+ if result == Qt::MessageBox::No
981
+ @points_saved.value = @tabbed_plots_config.points_saved
982
+ return
983
+ end
984
+ end
985
+
986
+ @tabbed_plots_config.points_saved = value_integer
987
+ @tabbed_plots_config.update_max_points_saved(value_integer)
988
+
989
+ redraw_plots(true)
990
+ @config_modified_callback.call() if @config_modified_callback
991
+ end # def handle_points_saved_change
992
+
993
+ # Handler for seconds plotted changing
994
+ def handle_seconds_plotted_change(value_string, value_float)
995
+ @overview_graphs.each {|overview_graph| overview_graph.window_size = value_float}
996
+ @tabbed_plots_config.seconds_plotted = value_float
997
+ @config_modified_callback.call() if @config_modified_callback
998
+ end # def handle_seconds_plotted_change
999
+
1000
+ # Handler for points plotted changing
1001
+ def handle_points_plotted_change(value_string, value_integer)
1002
+ redraw_plots(true)
1003
+ @tabbed_plots_config.points_plotted = value_integer
1004
+ @config_modified_callback.call() if @config_modified_callback
1005
+ end # def handle_points_plotted_change
1006
+
1007
+ # Handler for refresh rate hz changing
1008
+ def handle_refresh_rate_hz_change(value_string, value_float)
1009
+ redraw_plots(true)
1010
+ @tabbed_plots_config.refresh_rate_hz = value_float
1011
+ @refresh_rate_ms = (1000.0 / value_float).round
1012
+
1013
+ @timeout.method_missing(:stop)
1014
+ @timeout.method_missing(:start, @refresh_rate_ms)
1015
+ @config_modified_callback.call() if @config_modified_callback
1016
+ end # def handle_points_plotted_change
1017
+
1018
+ # Adds the adders
1019
+ def add_adders(layout)
1020
+ # Data Object Adders
1021
+ @data_object_adders = []
1022
+
1023
+ if @adder_types
1024
+ type_list = @adder_types
1025
+ else
1026
+ type_list = @tabbed_plots_config.data_object_types
1027
+ end
1028
+
1029
+ type_list.each do |data_object_type|
1030
+ begin
1031
+ filename = data_object_type.to_s.downcase + '_data_object_adder'
1032
+ @data_object_adders << Cosmos.require_class(filename).new(self, @adder_orientation)
1033
+ layout.addWidget(@data_object_adders[-1])
1034
+ @data_object_adders[-1].add_data_object_callback = method(:adder_add_data_object)
1035
+ @data_object_adders[-1].update
1036
+ rescue Exception
1037
+ # No adder for this type
1038
+ end
1039
+ end
1040
+ end # def add_adders
1041
+
1042
+ # Method called by adders to add a data object
1043
+ def adder_add_data_object(data_object)
1044
+ tab_index = current_tab_index()
1045
+ plot_index = selected_plot_index(tab_index)
1046
+ if plot_index
1047
+ plot = @tabbed_plots_config.tabs[tab_index].plots[plot_index]
1048
+ mapping = @tabbed_plots_config.plot_type_to_data_object_type_mapping[plot.plot_type]
1049
+ if mapping.include?(data_object.data_object_type)
1050
+ add_data_object(tab_index, plot_index, data_object)
1051
+ else
1052
+ paused = paused?()
1053
+ pause()
1054
+ Qt::MessageBox.critical(self, 'Error', "A #{data_object.data_object_type} data object cannot be added to a #{plot.plot_type} plot")
1055
+ resume() unless paused
1056
+ end
1057
+ else
1058
+ paused = paused?()
1059
+ pause()
1060
+ Qt::MessageBox.information(self, 'Information', 'Please select a plot')
1061
+ resume() unless paused
1062
+ end
1063
+ end # def adder_add_data_object
1064
+
1065
+ # Builds the GUI holding tabs and plots
1066
+ def build_right_frame
1067
+ # Frame around everything
1068
+ @tabbed_plots_right_frame = Qt::VBoxLayout.new
1069
+ @right_frame.addLayout(@tabbed_plots_right_frame)
1070
+
1071
+ # Adders
1072
+ add_adders(@tabbed_plots_right_frame) if @adder_orientation == Qt::Horizontal
1073
+
1074
+ # Tabbook to hold tabs
1075
+ @tab_book = Qt::TabWidget.new
1076
+ @tab_book.setContextMenuPolicy(Qt::CustomContextMenu)
1077
+ connect(@tab_book,
1078
+ SIGNAL('customContextMenuRequested(const QPoint&)'),
1079
+ self,
1080
+ SLOT('tab_context_menu(const QPoint&)'))
1081
+ @tabbed_plots_right_frame.addWidget(@tab_book)
1082
+
1083
+ # Array of overview graphs and graph times
1084
+ @overview_graphs = []
1085
+ @graph_time_start = []
1086
+ @graph_time_end = []
1087
+
1088
+ # Create each tab
1089
+ @tabbed_plots_config.mu_synchronize do
1090
+ @tabbed_plots_config.tabs.each_with_index do |tab, tab_index|
1091
+ # Maximize graph start and end times
1092
+ @graph_time_start << -1.0e300
1093
+ @graph_time_end << 1.0e300
1094
+
1095
+ # Create tab item for the tab
1096
+ tab_text = tab.tab_text
1097
+ tab_text = "Tab #{tab_index + 1}" unless tab_text
1098
+ tab_item = Qt::Widget.new
1099
+ tab_item.setContextMenuPolicy(Qt::CustomContextMenu)
1100
+ connect(tab_item, SIGNAL('customContextMenuRequested(const QPoint&)'), self, SLOT('plot_context_menu(const QPoint&)'))
1101
+
1102
+ # Create overall vertical layout manager for tab.
1103
+ tab_layout = Qt::VBoxLayout.new()
1104
+ tab_item.setLayout(tab_layout)
1105
+ tab.gui_item = tab_item
1106
+ tab.gui_frame = tab_layout
1107
+ tab.tab_text = tab_text
1108
+
1109
+ # Create layout manager to hold plots based on number of plots
1110
+ layout = Qt::AdaptiveGridLayout.new
1111
+ tab.gui_layout = layout
1112
+
1113
+ # Add with stretch factor 1 to give it priority over everything else
1114
+ tab_layout.addLayout(layout, 1)
1115
+ # Add stretch in case they delete the last plot.
1116
+ # This will force the overview graph (which doesn't get deleted)
1117
+ # to stay at the bottom of the layout instead of moving
1118
+ tab_layout.addStretch()
1119
+
1120
+ @tab_book.addTab(tab_item, tab_text)
1121
+
1122
+ # Create gui object for each plot
1123
+ default_colors = DataObject::COLOR_LIST.clone
1124
+ tab.plots.each_with_index do |plot, index|
1125
+ filename = plot.plot_type.downcase + '_plot_gui_object.rb'
1126
+ gui_object = Cosmos.require_class(filename).new(tab_item, tab, plot, self)
1127
+ tab.gui_layout.addWidget(gui_object)
1128
+ plot.gui_object = gui_object
1129
+ if plot.gui_object.respond_to? :mouse_left_button_press_callback
1130
+ current_tab = tab
1131
+ plot.gui_object.mouse_left_button_press_callback = lambda do |calling_gui_object|
1132
+ current_tab.plots.each do |current_plot|
1133
+ if current_plot.gui_object == calling_gui_object
1134
+ select_plot(current_plot)
1135
+ else
1136
+ unselect_plot(current_plot)
1137
+ end
1138
+ end
1139
+ @overview_graphs[@tab_book.currentIndex].setFocus
1140
+ end
1141
+ end
1142
+
1143
+ # Configure colors
1144
+ colors = []
1145
+ plot.data_objects.each do |data_object|
1146
+ if data_object.assigned_color
1147
+ colors << data_object.assigned_color
1148
+ else
1149
+ color = default_colors.shift
1150
+ while (color and colors.include?(color))
1151
+ color = default_colors.shift
1152
+ end
1153
+ color = get_random_color() unless color
1154
+ colors << color
1155
+ data_object.color = color
1156
+ end
1157
+ end
1158
+ end # tab.plots.each
1159
+
1160
+ # Add an overview graph to the tab
1161
+ @overview_graphs << OverviewGraph.new(tab_item)
1162
+ @overview_graphs[-1].window_size = @tabbed_plots_config.seconds_plotted
1163
+ @overview_graphs[-1].callback = method(:overview_graph_callback)
1164
+ tab_layout.addWidget(@overview_graphs[-1])
1165
+ end # tabs.each
1166
+ end
1167
+ # Attach this handler last so it doesn't fire when we create our first tab
1168
+ connect(@tab_book,
1169
+ SIGNAL('currentChanged(int)'),
1170
+ self,
1171
+ SLOT('handle_tab_change(int)'))
1172
+ end # def build_right_frame
1173
+
1174
+ # Function called by the overview graph on changes
1175
+ def overview_graph_callback(modified_overview_graph)
1176
+ if modified_overview_graph.window_size > 0.01
1177
+ @seconds_plotted.value = sprintf("%0.2f", modified_overview_graph.window_size)
1178
+ else
1179
+ @seconds_plotted.value = modified_overview_graph.window_size
1180
+ end
1181
+ @overview_graphs.each do |overview_graph|
1182
+ if overview_graph != modified_overview_graph
1183
+ overview_graph.set_window_size(modified_overview_graph.window_size, false)
1184
+ overview_graph.set_window_pos(modified_overview_graph.window_min_x, modified_overview_graph.window_max_x, false)
1185
+ end
1186
+ end
1187
+ redraw_plots(true)
1188
+ # Intentially not have adjusting the view window in the overview graph
1189
+ # be considered a configuration change
1190
+ end # def overview_graph_callback
1191
+
1192
+ # Selects the specified plot
1193
+ def select_plot(plot)
1194
+ unless plot.gui_object.selected?
1195
+ plot.gui_object.select
1196
+ fill_data_object_list_for_plot(plot)
1197
+ end
1198
+ end # def select_plot
1199
+
1200
+ # Unselects the specified plot
1201
+ def unselect_plot(plot)
1202
+ plot.gui_object.unselect if plot.gui_object.selected?
1203
+ end # def unselect_plot
1204
+
1205
+ # Unselects all plots on a tab
1206
+ def unselect_all_plots(tab_index = nil)
1207
+ tab_index = @tab_book.current unless tab_index
1208
+ return if tab_index < 0 or @tabbed_plots_config.tabs[tab_index].nil?
1209
+ @tabbed_plots_config.tabs[tab_index].plots.each do |plot|
1210
+ unselect_plot(plot)
1211
+ end
1212
+ end # def unselect_all_plots
1213
+
1214
+ ############################################################################
1215
+ # Slot implementation
1216
+ ############################################################################
1217
+
1218
+ # Handles right clicks on a tab
1219
+ def tab_context_menu(point)
1220
+ index = 0
1221
+ (0..@tab_book.tabBar.count).each do |bar|
1222
+ index = bar
1223
+ break if @tab_book.tabBar.tabRect(bar).contains(point)
1224
+ end
1225
+ return if (index == @tab_book.tabBar.count)
1226
+ @tab_book.setCurrentIndex(index)
1227
+
1228
+ @tab_item_right_button_release_callback.call(@tab_book.mapToGlobal(point)) if @tab_item_right_button_release_callback
1229
+ end
1230
+
1231
+ # Handles right clicks on a plot
1232
+ def plot_context_menu(point)
1233
+ tab_index = @tab_book.currentIndex
1234
+ return if tab_index < 0 or @tabbed_plots_config.tabs[tab_index].nil?
1235
+ plot_point = nil
1236
+ @tabbed_plots_config.tabs[tab_index].plots.each do |plot|
1237
+ plot_point = @tab_book.widget(tab_index).mapToGlobal(point) if plot.gui_object.selected?
1238
+ end
1239
+
1240
+ @plot_right_button_release_callback.call(plot_point) if @plot_right_button_release_callback and plot_point
1241
+ end
1242
+
1243
+ # Handles a right click on a data object
1244
+ def data_object_context_menu(point)
1245
+ @data_object_right_button_release_callback.call(@data_object_list.mapToGlobal(point)) if @data_object_right_button_release_callback
1246
+ end
1247
+
1248
+ # Handles data objects being moved
1249
+ def data_object_moved(sourceParent, sourceStart, sourceEnd, destinationParent, destinationRow)
1250
+ start_index = sourceStart
1251
+ if sourceStart < destinationRow
1252
+ end_index = destinationRow - 1
1253
+ else
1254
+ end_index = destinationRow
1255
+ end
1256
+ tab_index = current_tab_index()
1257
+ plot_index = selected_plot_index(tab_index)
1258
+ @tabbed_plots_config.move_data_object(tab_index, plot_index, start_index, end_index)
1259
+ @config_modified_callback.call() if @config_modified_callback
1260
+ end
1261
+
1262
+ # Handles tab change events
1263
+ def handle_tab_change(tab_index)
1264
+ if @tab_book.count > 0
1265
+ plot_index = selected_plot_index(tab_index)
1266
+ if plot_index
1267
+ plot = @tabbed_plots_config.tabs[tab_index].plots[plot_index]
1268
+ fill_data_object_list_for_plot(plot)
1269
+ else
1270
+ clear_data_object_list()
1271
+ end
1272
+ redraw_plots(true)
1273
+ end
1274
+ end # def handle_tab_change
1275
+
1276
+ end # class OverviewTabbedPlots
1277
+
1278
+ end # module Cosmos