cosmos 3.9.2 → 4.0.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 (438) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +23 -0
  3. data/.travis.yml +1 -0
  4. data/.yardopts +3 -0
  5. data/Gemfile +1 -1
  6. data/Manifest.txt +137 -52
  7. data/Rakefile +50 -44
  8. data/autohotkey/config/system/system.txt +0 -5
  9. data/autohotkey/config/targets/INST/cmd_tlm/inst_cmds.txt +6 -1
  10. data/autohotkey/config/targets/INST/screens/extra.txt +19 -0
  11. data/autohotkey/config/targets/INST/sequences/run_sequence.txt +1 -0
  12. data/autohotkey/config/targets/META/screens/data.txt +12 -0
  13. data/autohotkey/config/targets/SYSTEM/cmd_tlm/meta_cmd_tlm.txt +16 -0
  14. data/autohotkey/config/targets/{COSMOS/cmd_tlm/cosmos_server_cmds.txt → SYSTEM/cmd_tlm/system_cmds.txt} +8 -8
  15. data/autohotkey/config/targets/SYSTEM/cmd_tlm/system_tlm.txt +7 -0
  16. data/autohotkey/config/targets/SYSTEM/screens/limits_change.txt +14 -0
  17. data/autohotkey/config/targets/SYSTEM/screens/meta.txt +14 -0
  18. data/autohotkey/config/targets/SYSTEM/target.txt +12 -0
  19. data/autohotkey/config/tools/cmd_tlm_server/cmd_tlm_server.txt +2 -2
  20. data/autohotkey/config/tools/test_runner/test_runner2.txt +1 -1
  21. data/autohotkey/tools/CmdSequence +14 -0
  22. data/autohotkey/tools/CmdSequenceAHK +23 -0
  23. data/autohotkey/tools/CmdSequenceAHK2 +16 -0
  24. data/autohotkey/tools/cmd_extractor.ahk +2 -2
  25. data/autohotkey/tools/cmd_sender.ahk +4 -6
  26. data/autohotkey/tools/cmd_sequence.ahk +215 -0
  27. data/autohotkey/tools/cmd_sequence2.ahk +23 -0
  28. data/autohotkey/tools/data_viewer.ahk +2 -3
  29. data/autohotkey/tools/limits_monitor.ahk +9 -11
  30. data/autohotkey/tools/open_gl_builder.ahk +1 -2
  31. data/autohotkey/tools/packet_viewer.ahk +51 -35
  32. data/autohotkey/tools/replay.ahk +1 -2
  33. data/autohotkey/tools/script_runner.ahk +1 -2
  34. data/autohotkey/tools/script_runner2.ahk +1 -2
  35. data/autohotkey/tools/test_runner2.ahk +1 -5
  36. data/autohotkey/tools/test_runner3.ahk +1 -3
  37. data/autohotkey/tools/tlm_grapher.ahk +1 -3
  38. data/autohotkey/tools/tlm_grapher3.ahk +1 -2
  39. data/autohotkey/tools/tlm_viewer.ahk +8 -3
  40. data/autohotkey/tools/tlm_viewer2.ahk +2 -3
  41. data/autohotkey/tools/tlm_viewer5.ahk +1 -2
  42. data/cosmos.gemspec +26 -20
  43. data/data/cmd_sequence.png +0 -0
  44. data/data/config/_array_params.yaml +23 -0
  45. data/data/config/_id_items.yaml +24 -0
  46. data/data/config/_id_params.yaml +58 -0
  47. data/data/config/_interfaces.yaml +206 -0
  48. data/data/config/_items.yaml +20 -0
  49. data/data/config/_params.yaml +58 -0
  50. data/data/config/cmd_tlm_server.yaml +110 -0
  51. data/data/config/command.yaml +38 -0
  52. data/data/config/command_modifiers.yaml +127 -0
  53. data/data/config/command_telemetry.yaml +3 -0
  54. data/data/config/data_viewer.yaml +43 -0
  55. data/data/config/handbook_creator.yaml +23 -0
  56. data/data/config/housekeeping_params.yaml +71 -0
  57. data/data/config/interface_modifiers.yaml +44 -0
  58. data/data/config/item_modifiers.yaml +172 -0
  59. data/data/config/launcher.yaml +117 -0
  60. data/data/config/limits_monitor.yaml +53 -0
  61. data/data/config/linegraph_params.yaml +30 -0
  62. data/data/config/linegraph_plot.yaml +106 -0
  63. data/data/config/page_modifiers.yaml +128 -0
  64. data/data/config/param_item_modifiers.yaml +41 -0
  65. data/data/config/parameter_modifiers.yaml +144 -0
  66. data/data/config/protocols.yaml +257 -0
  67. data/data/config/screen.yaml +151 -0
  68. data/data/config/script_runner.yaml +15 -0
  69. data/data/config/system.yaml +153 -0
  70. data/data/config/table_manager.yaml +76 -0
  71. data/data/config/table_parameter_modifiers.yaml +9 -0
  72. data/data/config/target.yaml +71 -0
  73. data/data/config/telemetry.yaml +73 -0
  74. data/data/config/telemetry_modifiers.yaml +129 -0
  75. data/data/config/test_runner.yaml +118 -0
  76. data/data/config/tlm_extractor.yaml +109 -0
  77. data/data/config/tlm_grapher.yaml +78 -0
  78. data/data/config/tlm_viewer.yaml +107 -0
  79. data/data/config/unknown.yaml +3 -0
  80. data/data/config/widgets.yaml +1339 -0
  81. data/data/config/xy_params.yaml +50 -0
  82. data/data/config/xy_plot.yaml +12 -0
  83. data/data/config_editor.png +0 -0
  84. data/data/crc.txt +172 -161
  85. data/data/delete.png +0 -0
  86. data/demo/config/data/crc.txt +56 -36
  87. data/demo/config/data/meta_init.txt +1 -4
  88. data/demo/config/system/system.txt +15 -3
  89. data/demo/config/system/system2.txt +13 -3
  90. data/demo/config/targets/EXAMPLE/lib/example_interface.rb +2 -6
  91. data/demo/config/targets/EXAMPLE/target.txt +3 -1
  92. data/demo/config/targets/INST/cmd_tlm/inst_cmds.txt +1 -0
  93. data/demo/config/targets/INST/lib/inst_dump_component.rb +34 -0
  94. data/demo/config/targets/INST/screens/adcs.txt +39 -15
  95. data/demo/config/targets/INST/screens/commanding.txt +26 -19
  96. data/demo/config/targets/INST/screens/spacing_box.txt +44 -0
  97. data/demo/config/targets/INST/screens/spacing_grid.txt +78 -0
  98. data/demo/config/targets/INST/screens/tabs.txt +0 -2
  99. data/demo/config/targets/INST/sequences/sequence.tsv +3 -0
  100. data/demo/config/targets/INST/tables/EventAction.csv +9 -0
  101. data/demo/config/targets/INST/tables/EventAction.dat +0 -0
  102. data/demo/config/targets/INST/tables/McConfigTable.csv +20 -0
  103. data/demo/config/targets/INST/tables/McConfigTable.dat +0 -0
  104. data/demo/config/targets/INST/target.txt +4 -0
  105. data/demo/config/targets/INST/tools/data_viewer/data_viewer.txt +2 -0
  106. data/demo/config/targets/INST/tools/data_viewer/data_viewer2.txt +2 -0
  107. data/demo/config/targets/INST/tools/table_manager/EventAction_def.txt +6 -0
  108. data/demo/config/targets/INST/tools/table_manager/McConfigTable_def.txt +38 -0
  109. data/demo/config/targets/SYSTEM/cmd_tlm/limits_groups.txt +7 -3
  110. data/demo/config/targets/SYSTEM/cmd_tlm/meta_cmd_tlm.txt +16 -0
  111. data/demo/config/targets/{COSMOS/cmd_tlm/cosmos_server_cmds.txt → SYSTEM/cmd_tlm/system_cmds.txt} +8 -8
  112. data/demo/config/targets/SYSTEM/cmd_tlm/system_tlm.txt +7 -0
  113. data/demo/config/targets/{COSMOS → SYSTEM}/cmd_tlm_server.txt +2 -2
  114. data/demo/config/targets/SYSTEM/lib/limits_groups.rb +39 -0
  115. data/demo/config/targets/SYSTEM/screens/status.txt +1 -1
  116. data/demo/config/targets/SYSTEM/target.txt +12 -0
  117. data/demo/config/targets/TEMPLATED/cmd_tlm_server.txt +1 -1
  118. data/demo/config/targets/TEMPLATED/lib/templated_interface.rb +8 -5
  119. data/demo/config/targets/TEMPLATED/target.txt +2 -0
  120. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server.txt +15 -6
  121. data/demo/config/tools/cmd_tlm_server/cmd_tlm_server2.txt +13 -5
  122. data/demo/config/tools/data_viewer/data_viewer.txt +9 -0
  123. data/demo/config/tools/launcher/launcher.txt +9 -6
  124. data/demo/config/tools/launcher/launcher2.txt +16 -13
  125. data/demo/config/tools/launcher/launcher_mini.txt +45 -0
  126. data/demo/config/tools/table_manager/MCConfigurationTable_fsw1_def.txt +12 -11
  127. data/demo/config/tools/table_manager/MCConfigurationTable_fsw2_def.txt +12 -11
  128. data/demo/config/tools/test_runner/test_runner.txt +1 -1
  129. data/demo/config/tools/tlm_viewer/tlm_viewer.txt +5 -5
  130. data/demo/lib/example_background_task.rb +9 -5
  131. data/demo/lib/example_target.rb +5 -15
  132. data/demo/lib/scpi_target.rb +4 -10
  133. data/demo/procedures/cosmos_api_test.rb +17 -0
  134. data/demo/tools/CmdSequence +16 -0
  135. data/demo/tools/CmdSequence.bat +9 -0
  136. data/demo/tools/ConfigEditor +16 -0
  137. data/demo/tools/ConfigEditor.bat +9 -0
  138. data/demo/tools/mac/CmdSequence.app/Contents/Info.plist +38 -0
  139. data/demo/tools/mac/CmdSequence.app/Contents/MacOS/CmdSequence.rb +16 -0
  140. data/demo/tools/mac/CmdSequence.app/Contents/MacOS/main.sh +10 -0
  141. data/demo/tools/mac/CmdSequence.app/Contents/MacOS/tool_launch.rb +38 -0
  142. data/demo/tools/mac/CmdSequence.app/Contents/Resources/appIcon.icns +0 -0
  143. data/ext/cosmos/ext/packet/packet.c +5 -5
  144. data/install/config/data/crc.txt +12 -8
  145. data/install/config/system/system.txt +13 -3
  146. data/install/config/targets/SYSTEM/cmd_tlm/meta_cmd_tlm.txt +14 -0
  147. data/install/config/targets/SYSTEM/target.txt +12 -0
  148. data/install/tools/CmdSequence +16 -0
  149. data/install/tools/CmdSequence.bat +9 -0
  150. data/install/tools/ConfigEditor +16 -0
  151. data/install/tools/ConfigEditor.bat +9 -0
  152. data/install/tools/mac/CmdSequence.app/Contents/Info.plist +38 -0
  153. data/install/tools/mac/CmdSequence.app/Contents/MacOS/CmdSequence.rb +16 -0
  154. data/install/tools/mac/CmdSequence.app/Contents/MacOS/main.sh +10 -0
  155. data/install/tools/mac/CmdSequence.app/Contents/MacOS/tool_launch.rb +38 -0
  156. data/install/tools/mac/CmdSequence.app/Contents/Resources/appIcon.icns +0 -0
  157. data/lib/cosmos.rb +1 -1
  158. data/lib/cosmos/config/config_parser.rb +147 -59
  159. data/lib/cosmos/config/meta_config_parser.rb +57 -0
  160. data/lib/cosmos/conversions/polynomial_conversion.rb +20 -4
  161. data/lib/cosmos/conversions/unix_time_conversion.rb +4 -4
  162. data/lib/cosmos/core_ext/array.rb +45 -5
  163. data/lib/cosmos/core_ext/cosmos_io.rb +31 -15
  164. data/lib/cosmos/core_ext/file.rb +2 -2
  165. data/lib/cosmos/core_ext/kernel.rb +1 -6
  166. data/lib/cosmos/core_ext/objectspace.rb +0 -2
  167. data/lib/cosmos/core_ext/string.rb +27 -4
  168. data/lib/cosmos/core_ext/time.rb +39 -10
  169. data/lib/cosmos/gui/choosers/combobox_chooser.rb +37 -26
  170. data/lib/cosmos/gui/choosers/file_chooser.rb +23 -6
  171. data/lib/cosmos/gui/choosers/float_chooser.rb +13 -11
  172. data/lib/cosmos/gui/choosers/integer_chooser.rb +13 -11
  173. data/lib/cosmos/gui/choosers/string_chooser.rb +18 -36
  174. data/lib/cosmos/gui/choosers/telemetry_chooser.rb +64 -64
  175. data/lib/cosmos/gui/choosers/value_chooser.rb +15 -15
  176. data/lib/cosmos/gui/dialogs/about_dialog.rb +18 -13
  177. data/lib/cosmos/gui/dialogs/calendar_dialog.rb +11 -3
  178. data/lib/cosmos/gui/dialogs/cmd_tlm_raw_dialog.rb +1 -1
  179. data/lib/cosmos/gui/dialogs/details_dialog.rb +1 -1
  180. data/lib/cosmos/gui/dialogs/exception_dialog.rb +7 -7
  181. data/lib/cosmos/gui/dialogs/find_replace_dialog.rb +20 -15
  182. data/lib/cosmos/gui/dialogs/interface_raw_dialog.rb +143 -0
  183. data/lib/cosmos/gui/dialogs/legal_dialog.rb +6 -5
  184. data/lib/cosmos/gui/dialogs/packet_log_dialog.rb +5 -2
  185. data/lib/cosmos/gui/dialogs/progress_dialog.rb +1 -1
  186. data/lib/cosmos/gui/dialogs/pry_dialog.rb +4 -4
  187. data/lib/cosmos/gui/dialogs/scroll_text_dialog.rb +3 -0
  188. data/lib/cosmos/gui/dialogs/set_tlm_dialog.rb +7 -6
  189. data/lib/cosmos/gui/dialogs/splash.rb +1 -1
  190. data/lib/cosmos/gui/dialogs/tlm_details_dialog.rb +1 -1
  191. data/lib/cosmos/gui/dialogs/tlm_graph_dialog.rb +114 -0
  192. data/lib/cosmos/gui/line_graph/line_graph.rb +9 -10
  193. data/lib/cosmos/gui/line_graph/line_graph_dialog.rb +7 -5
  194. data/lib/cosmos/gui/line_graph/line_graph_drawing.rb +3 -7
  195. data/lib/cosmos/gui/line_graph/line_graph_popups.rb +3 -8
  196. data/lib/cosmos/gui/line_graph/line_graph_scaling.rb +2 -7
  197. data/lib/cosmos/gui/line_graph/overview_graph.rb +6 -1
  198. data/lib/cosmos/gui/opengl/earth_model.rb +6 -3
  199. data/lib/cosmos/gui/opengl/gl_bounds.rb +11 -23
  200. data/lib/cosmos/gui/opengl/gl_light.rb +3 -4
  201. data/lib/cosmos/gui/opengl/gl_material.rb +3 -4
  202. data/lib/cosmos/gui/opengl/gl_scene.rb +10 -4
  203. data/lib/cosmos/gui/opengl/gl_shape.rb +6 -2
  204. data/lib/cosmos/gui/opengl/gl_viewer.rb +5 -5
  205. data/lib/cosmos/gui/opengl/gl_viewport.rb +11 -12
  206. data/lib/cosmos/gui/opengl/moon_model.rb +6 -3
  207. data/lib/cosmos/gui/opengl/stl_reader.rb +8 -9
  208. data/lib/cosmos/gui/opengl/stl_shape.rb +4 -5
  209. data/lib/cosmos/gui/opengl/texture_mapped_sphere.rb +7 -7
  210. data/lib/cosmos/gui/qt.rb +1 -1
  211. data/lib/cosmos/gui/qt_tool.rb +21 -10
  212. data/lib/cosmos/gui/text/completion.rb +23 -2
  213. data/lib/cosmos/gui/text/completion_text_edit.rb +38 -23
  214. data/lib/cosmos/gui/utilities/analyze_log.rb +1 -1
  215. data/lib/cosmos/gui/utilities/screenshot.rb +2 -2
  216. data/lib/cosmos/gui/widgets/full_text_search_line_edit.rb +11 -1
  217. data/lib/cosmos/gui/widgets/packet_log_frame.rb +19 -6
  218. data/lib/cosmos/interfaces.rb +10 -0
  219. data/lib/cosmos/interfaces/cmd_tlm_server_interface.rb +28 -47
  220. data/lib/cosmos/interfaces/interface.rb +240 -22
  221. data/lib/cosmos/interfaces/linc_interface.rb +3 -5
  222. data/lib/cosmos/interfaces/protocols/burst_protocol.rb +173 -0
  223. data/lib/cosmos/interfaces/protocols/crc_protocol.rb +141 -0
  224. data/lib/cosmos/{streams/fixed_stream_protocol.rb → interfaces/protocols/fixed_protocol.rb} +40 -37
  225. data/lib/cosmos/{streams/length_stream_protocol.rb → interfaces/protocols/length_protocol.rb} +55 -48
  226. data/lib/cosmos/interfaces/protocols/override_protocol.rb +52 -0
  227. data/lib/cosmos/interfaces/protocols/preidentified_protocol.rb +141 -0
  228. data/lib/cosmos/interfaces/protocols/protocol.rb +60 -0
  229. data/lib/cosmos/interfaces/protocols/template_protocol.rb +209 -0
  230. data/lib/cosmos/interfaces/protocols/terminated_protocol.rb +81 -0
  231. data/lib/cosmos/interfaces/serial_interface.rb +28 -23
  232. data/lib/cosmos/interfaces/simulated_target_interface.rb +27 -16
  233. data/lib/cosmos/interfaces/stream_interface.rb +36 -108
  234. data/lib/cosmos/interfaces/tcpip_client_interface.rb +21 -21
  235. data/lib/cosmos/interfaces/tcpip_server_interface.rb +555 -94
  236. data/lib/cosmos/interfaces/udp_interface.rb +51 -83
  237. data/lib/cosmos/io/buffered_file.rb +92 -2
  238. data/lib/cosmos/io/json_drb.rb +2 -2
  239. data/lib/cosmos/io/posix_serial_driver.rb +3 -1
  240. data/lib/cosmos/io/raw_logger.rb +3 -3
  241. data/lib/cosmos/io/serial_driver.rb +14 -5
  242. data/lib/cosmos/io/win32_serial_driver.rb +16 -4
  243. data/lib/cosmos/packet_logs.rb +0 -1
  244. data/lib/cosmos/packet_logs/packet_log_reader.rb +11 -1
  245. data/lib/cosmos/packet_logs/packet_log_writer.rb +31 -13
  246. data/lib/cosmos/packets/binary_accessor.rb +599 -32
  247. data/lib/cosmos/packets/commands.rb +48 -24
  248. data/lib/cosmos/packets/packet.rb +140 -54
  249. data/lib/cosmos/packets/packet_config.rb +0 -2
  250. data/lib/cosmos/packets/parsers/packet_item_parser.rb +10 -2
  251. data/lib/cosmos/packets/structure.rb +81 -33
  252. data/lib/cosmos/packets/structure_item.rb +45 -5
  253. data/lib/cosmos/packets/telemetry.rb +149 -55
  254. data/lib/cosmos/script/api_shared.rb +1000 -0
  255. data/lib/cosmos/script/commands.rb +2 -2
  256. data/lib/cosmos/script/extract.rb +19 -4
  257. data/lib/cosmos/script/limits.rb +2 -0
  258. data/lib/cosmos/script/script.rb +1 -1
  259. data/lib/cosmos/script/scripting.rb +4 -784
  260. data/lib/cosmos/script/telemetry.rb +44 -23
  261. data/lib/cosmos/script/tools.rb +15 -69
  262. data/lib/cosmos/streams/serial_stream.rb +12 -19
  263. data/lib/cosmos/streams/stream.rb +2 -11
  264. data/lib/cosmos/streams/tcpip_socket_stream.rb +3 -13
  265. data/lib/cosmos/system/system.rb +187 -31
  266. data/lib/cosmos/system/target.rb +11 -2
  267. data/lib/cosmos/tools/cmd_extractor/cmd_extractor.rb +12 -11
  268. data/lib/cosmos/tools/cmd_sender/{cmd_sender_item_delegate.rb → cmd_param_table_item_delegate.rb} +11 -10
  269. data/lib/cosmos/tools/cmd_sender/cmd_sender.rb +209 -164
  270. data/lib/cosmos/tools/cmd_sequence/cmd_sequence.rb +652 -0
  271. data/lib/cosmos/tools/cmd_sequence/sequence_item.rb +510 -0
  272. data/lib/cosmos/tools/cmd_sequence/sequence_list.rb +194 -0
  273. data/lib/cosmos/tools/cmd_tlm_server/api.rb +179 -5
  274. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server.rb +31 -14
  275. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +23 -16
  276. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_gui.rb +92 -20
  277. data/lib/cosmos/tools/cmd_tlm_server/commanding.rb +1 -1
  278. data/lib/cosmos/tools/cmd_tlm_server/gui/interfaces_tab.rb +17 -4
  279. data/lib/cosmos/tools/cmd_tlm_server/gui/targets_tab.rb +0 -5
  280. data/lib/cosmos/tools/cmd_tlm_server/interface_thread.rb +1 -2
  281. data/lib/cosmos/tools/cmd_tlm_server/interfaces.rb +4 -4
  282. data/lib/cosmos/tools/cmd_tlm_server/limits_groups_background_task.rb +121 -0
  283. data/lib/cosmos/tools/cmd_tlm_server/routers.rb +8 -4
  284. data/lib/cosmos/tools/config_editor/config_editor.rb +720 -0
  285. data/lib/cosmos/tools/config_editor/config_editor_frame.rb +675 -0
  286. data/lib/cosmos/tools/data_viewer/data_viewer.rb +44 -27
  287. data/lib/cosmos/tools/data_viewer/data_viewer_component.rb +8 -22
  288. data/lib/cosmos/tools/launcher/launcher.rb +29 -12
  289. data/lib/cosmos/tools/launcher/launcher_config.rb +1 -1
  290. data/lib/cosmos/tools/limits_monitor/limits_monitor.rb +153 -42
  291. data/lib/cosmos/tools/packet_viewer/packet_viewer.rb +44 -6
  292. data/lib/cosmos/tools/replay/replay.rb +36 -20
  293. data/lib/cosmos/tools/replay/replay_server.rb +1 -1
  294. data/lib/cosmos/tools/script_runner/script_runner_config.rb +1 -1
  295. data/lib/cosmos/tools/script_runner/script_runner_frame.rb +31 -21
  296. data/lib/cosmos/tools/table_manager/table_config.rb +9 -3
  297. data/lib/cosmos/tools/table_manager/table_manager.rb +27 -7
  298. data/lib/cosmos/tools/test_runner/results_writer.rb +6 -6
  299. data/lib/cosmos/tools/test_runner/test_runner.rb +4 -6
  300. data/lib/cosmos/tools/tlm_extractor/tlm_extractor.rb +4 -5
  301. data/lib/cosmos/tools/tlm_extractor/tlm_extractor_config.rb +1 -1
  302. data/lib/cosmos/tools/tlm_extractor/tlm_extractor_processor.rb +1 -1
  303. data/lib/cosmos/tools/tlm_grapher/data_object_adders/housekeeping_data_object_adder.rb +23 -6
  304. data/lib/cosmos/tools/tlm_grapher/data_object_editors/housekeeping_data_object_editor.rb +44 -3
  305. data/lib/cosmos/tools/tlm_grapher/data_objects/housekeeping_data_object.rb +20 -7
  306. data/lib/cosmos/tools/tlm_grapher/tabbed_plots/overview_tabbed_plots.rb +1 -1
  307. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_config.rb +11 -4
  308. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_plot_editor.rb +2 -2
  309. data/lib/cosmos/tools/tlm_grapher/tabbed_plots_tool/tabbed_plots_realtime_thread.rb +1 -1
  310. data/lib/cosmos/tools/tlm_grapher/tlm_grapher.rb +16 -0
  311. data/lib/cosmos/tools/tlm_viewer/screen.rb +36 -32
  312. data/lib/cosmos/tools/tlm_viewer/tlm_viewer.rb +59 -50
  313. data/lib/cosmos/tools/tlm_viewer/tlm_viewer_config.rb +2 -2
  314. data/lib/cosmos/tools/tlm_viewer/widgets.rb +1 -0
  315. data/lib/cosmos/tools/tlm_viewer/widgets/canvasvalue_widget.rb +1 -0
  316. data/lib/cosmos/tools/tlm_viewer/widgets/labelvalue_widget.rb +22 -4
  317. data/lib/cosmos/tools/tlm_viewer/widgets/matrixbycolumns_widget.rb +9 -0
  318. data/lib/cosmos/tools/tlm_viewer/widgets/spacer_widget.rb +55 -0
  319. data/lib/cosmos/tools/tlm_viewer/widgets/vertical_widget.rb +3 -2
  320. data/lib/cosmos/tools/tlm_viewer/widgets/verticalbox_widget.rb +3 -2
  321. data/lib/cosmos/tools/tlm_viewer/widgets/widget.rb +12 -12
  322. data/lib/cosmos/top_level.rb +34 -24
  323. data/lib/cosmos/utilities/crc.rb +108 -6
  324. data/lib/cosmos/utilities/csv.rb +68 -14
  325. data/lib/cosmos/utilities/logger.rb +2 -2
  326. data/lib/cosmos/utilities/low_fragmentation_array.rb +9 -1
  327. data/lib/cosmos/version.rb +6 -6
  328. data/lib/cosmos/win32/win32_main.rb +50 -46
  329. data/run_gui_tests.bat +3 -1
  330. data/spec/conversions/unix_time_formatted_conversion_spec.rb +2 -2
  331. data/spec/conversions/unix_time_seconds_conversion_spec.rb +2 -2
  332. data/spec/core_ext/file_spec.rb +1 -1
  333. data/spec/core_ext/objectspace_spec.rb +12 -9
  334. data/spec/core_ext/string_spec.rb +6 -0
  335. data/spec/core_ext/time_spec.rb +10 -0
  336. data/spec/gui/line_graph/line_clip_spec.rb +226 -224
  337. data/spec/gui/qt_spec.rb +81 -79
  338. data/spec/install/config/system/system.txt +0 -6
  339. data/spec/install/config/targets/INST/cmd_tlm/inst_cmd_linc.txt +5 -5
  340. data/spec/install/config/targets/INST/cmd_tlm/inst_tlm_linc.txt +8 -8
  341. data/spec/install/config/targets/SYSTEM/cmd_tlm/meta_cmd_tlm.txt +16 -0
  342. data/{install/config/targets/COSMOS/cmd_tlm/cosmos_server_cmds.txt → spec/install/config/targets/SYSTEM/cmd_tlm/system_cmds.txt} +8 -8
  343. data/spec/install/config/targets/SYSTEM/cmd_tlm/system_tlm.txt +7 -0
  344. data/spec/install/config/targets/{COSMOS → SYSTEM}/cmd_tlm_server.txt +2 -2
  345. data/spec/install/config/targets/SYSTEM/screens/status.txt +12 -0
  346. data/spec/install/config/targets/SYSTEM/target.txt +12 -0
  347. data/spec/interfaces/cmd_tlm_server_interface_spec.rb +9 -13
  348. data/spec/interfaces/interface_spec.rb +402 -18
  349. data/spec/interfaces/linc_interface_spec.rb +37 -39
  350. data/spec/interfaces/protocols/burst_protocol_spec.rb +300 -0
  351. data/spec/interfaces/protocols/crc_protocol_spec.rb +709 -0
  352. data/spec/interfaces/protocols/fixed_protocol_spec.rb +119 -0
  353. data/spec/interfaces/protocols/length_protocol_spec.rb +499 -0
  354. data/spec/interfaces/protocols/override_protocol_spec.rb +158 -0
  355. data/spec/interfaces/protocols/preidentified_protocol_spec.rb +149 -0
  356. data/spec/interfaces/protocols/template_protocol_spec.rb +218 -0
  357. data/spec/interfaces/protocols/terminated_protocol_spec.rb +174 -0
  358. data/spec/interfaces/serial_interface_spec.rb +35 -34
  359. data/spec/interfaces/simulated_target_interface_spec.rb +13 -13
  360. data/spec/interfaces/tcpip_client_interface_spec.rb +21 -16
  361. data/spec/interfaces/tcpip_server_interface_spec.rb +66 -69
  362. data/spec/interfaces/udp_interface_spec.rb +120 -55
  363. data/spec/io/serial_driver_spec.rb +41 -39
  364. data/spec/io/udp_sockets_spec.rb +13 -8
  365. data/spec/io/win32_serial_driver_spec.rb +62 -59
  366. data/spec/packet_logs/packet_log_reader_spec.rb +68 -47
  367. data/spec/packet_logs/packet_log_writer_spec.rb +7 -5
  368. data/spec/packets/commands_spec.rb +5 -5
  369. data/spec/packets/packet_spec.rb +2 -14
  370. data/spec/script/extract_spec.rb +21 -7
  371. data/spec/script/scripting_spec.rb +261 -6
  372. data/spec/script/telemetry_spec.rb +17 -9
  373. data/spec/spec_helper.rb +26 -10
  374. data/spec/streams/serial_stream_spec.rb +87 -82
  375. data/spec/streams/tcpip_client_stream_spec.rb +12 -4
  376. data/spec/streams/tcpip_socket_stream_spec.rb +5 -0
  377. data/spec/system/system_spec.rb +66 -50
  378. data/spec/system/target_spec.rb +33 -11
  379. data/spec/tools/cmd_tlm_server/api_spec.rb +5 -5
  380. data/spec/tools/cmd_tlm_server/background_tasks_spec.rb +75 -15
  381. data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +125 -5
  382. data/spec/tools/cmd_tlm_server/cmd_tlm_server_spec.rb +244 -232
  383. data/spec/tools/cmd_tlm_server/commanding_spec.rb +18 -18
  384. data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +124 -29
  385. data/spec/tools/cmd_tlm_server/interfaces_spec.rb +2 -2
  386. data/spec/tools/cmd_tlm_server/limits_groups_background_task_spec.rb +145 -0
  387. data/spec/tools/cmd_tlm_server/router_thread_spec.rb +50 -10
  388. data/spec/tools/table_manager/tablemanager_core_spec.rb +0 -1
  389. data/spec/top_level/top_level_spec.rb +39 -11
  390. data/spec/utilities/csv_spec.rb +62 -20
  391. data/tasks/gemfile_stats.rake +6 -3
  392. data/test/performance/config/system/system_packets.txt +0 -1
  393. data/test/performance/config/system/system_threads.txt +0 -1
  394. metadata +177 -92
  395. data/autohotkey/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +0 -15
  396. data/autohotkey/config/targets/COSMOS/cmd_tlm_server.txt +0 -6
  397. data/autohotkey/config/targets/COSMOS/target.txt +0 -5
  398. data/autohotkey/userpath.txt +0 -1
  399. data/demo/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +0 -15
  400. data/demo/config/targets/COSMOS/screens/limits_change.txt +0 -20
  401. data/demo/config/targets/COSMOS/screens/version.txt +0 -19
  402. data/demo/config/targets/COSMOS/target.txt +0 -11
  403. data/demo/config/targets/META/cmd_tlm/meta_cmd.txt +0 -10
  404. data/demo/config/targets/META/cmd_tlm/meta_tlm.txt +0 -13
  405. data/demo/userpath.txt +0 -1
  406. data/install/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +0 -15
  407. data/install/config/targets/COSMOS/cmd_tlm_server.txt +0 -6
  408. data/install/config/targets/COSMOS/screens/limits_change.txt +0 -20
  409. data/install/config/targets/COSMOS/screens/version.txt +0 -19
  410. data/install/config/targets/COSMOS/target.txt +0 -9
  411. data/install/config/targets/SYSTEM/README.txt +0 -1
  412. data/install/userpath.txt +0 -1
  413. data/lib/cosmos/io/tcpip_server.rb +0 -571
  414. data/lib/cosmos/packet_logs/meta_packet_log_writer.rb +0 -107
  415. data/lib/cosmos/streams/burst_stream_protocol.rb +0 -25
  416. data/lib/cosmos/streams/preidentified_stream_protocol.rb +0 -118
  417. data/lib/cosmos/streams/stream_protocol.rb +0 -373
  418. data/lib/cosmos/streams/template_stream_protocol.rb +0 -140
  419. data/lib/cosmos/streams/terminated_stream_protocol.rb +0 -85
  420. data/spec/install/config/targets/COSMOS/cmd_tlm/cosmos_server_cmds.txt +0 -41
  421. data/spec/install/config/targets/COSMOS/cmd_tlm/cosmos_server_tlm.txt +0 -15
  422. data/spec/install/config/targets/COSMOS/screens/limits_change.txt +0 -20
  423. data/spec/install/config/targets/COSMOS/screens/version.txt +0 -19
  424. data/spec/install/config/targets/COSMOS/target.txt +0 -5
  425. data/spec/install/config/targets/META/cmd_tlm/meta_cmd.txt +0 -4
  426. data/spec/install/config/targets/META/cmd_tlm/meta_tlm.txt +0 -4
  427. data/spec/install/userpath.txt +0 -1
  428. data/spec/interfaces/stream_interface_spec.rb +0 -157
  429. data/spec/io/tcpip_server_spec.rb +0 -338
  430. data/spec/packet_logs/meta_packet_log_writer_spec.rb +0 -170
  431. data/spec/streams/burst_stream_protocol_spec.rb +0 -32
  432. data/spec/streams/fixed_stream_protocol_spec.rb +0 -113
  433. data/spec/streams/length_stream_protocol_spec.rb +0 -300
  434. data/spec/streams/preidentified_stream_protocol_spec.rb +0 -121
  435. data/spec/streams/stream_protocol_spec.rb +0 -346
  436. data/spec/streams/template_stream_protocol_spec.rb +0 -156
  437. data/spec/streams/terminated_stream_protocol_spec.rb +0 -127
  438. data/test/performance/userpath.txt +0 -1
@@ -38,6 +38,8 @@ module Cosmos
38
38
  router = TcpipServerInterface.new(port, port, 10.0, nil, 'PREIDENTIFIED')
39
39
  router.name = router_name
40
40
  router.disable_disconnect = true
41
+ router.set_option('LISTEN_ADDRESS', [System.listen_hosts['CTS_PREIDENTIFIED']])
42
+ router.set_option('AUTO_SYSTEM_META', [true])
41
43
  @config.routers[router_name] = router
42
44
  @config.interfaces.each do |interface_name, interface|
43
45
  router.interfaces << interface
@@ -56,6 +58,8 @@ module Cosmos
56
58
  cmd_router = TcpipServerInterface.new(port, nil, 10.0, nil, 'PREIDENTIFIED')
57
59
  cmd_router.name = cmd_router_name
58
60
  cmd_router.disable_disconnect = true
61
+ cmd_router.set_option('LISTEN_ADDRESS', [System.listen_hosts['CTS_CMD_ROUTER']])
62
+ cmd_router.set_option('AUTO_SYSTEM_META', [true])
59
63
  @config.routers[cmd_router_name] = cmd_router
60
64
  @config.interfaces.each do |interface_name, interface|
61
65
  interface.cmd_routers << cmd_router
@@ -92,15 +96,15 @@ module Cosmos
92
96
 
93
97
  # Get info about an router by name
94
98
  #
95
- # @return [Array<String, Numeric, Numeric, Numeric, Numeric, Numeric,
96
- # Numeric, Numeric>] Array containing \[state, num_clients,
97
- # write_queue_size, read_queue_size, bytes_written, bytes_read,
99
+ # @return [Array<String, Numeric, Numeric, Numeric, Numeric, Numeric,
100
+ # Numeric, Numeric>] Array containing \[state, num_clients,
101
+ # write_queue_size, read_queue_size, bytes_written, bytes_read,
98
102
  # read_count, write_count] for the interface
99
103
  def get_info(router_name)
100
104
  router = @config.routers[router_name.upcase]
101
105
  raise "Unknown router: #{router_name}" unless router
102
106
 
103
- return [state(router_name), router.num_clients,
107
+ return [state(router_name), router.num_clients,
104
108
  router.write_queue_size, router.read_queue_size,
105
109
  router.bytes_written, router.bytes_read,
106
110
  router.read_count, router.write_count]
@@ -0,0 +1,720 @@
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
+ Cosmos.catch_fatal_exception do
13
+ require 'cosmos/gui/qt_tool'
14
+ require 'cosmos/tools/config_editor/config_editor_frame'
15
+ require 'cosmos/gui/dialogs/progress_dialog'
16
+ require 'cosmos/gui/dialogs/scroll_text_dialog'
17
+ end
18
+
19
+ module Cosmos
20
+
21
+ class ConfigEditor < QtTool
22
+ slots 'handle_tab_change(int)'
23
+ slots 'context_menu(const QPoint&)'
24
+ slots 'undo_available(bool)'
25
+
26
+ UNTITLED = 'Untitled'
27
+ UNTITLED_TAB_TEXT = " #{UNTITLED} "
28
+ # Mapping of the human readable configuration name to an array containing the
29
+ # yaml file name and typical location of the configuration file
30
+ CONFIGURATION_FILES = {
31
+ "System Configuration" =>
32
+ ["system", "/config/system/system.txt"],
33
+ "Target Configuration" =>
34
+ ["target", "/config/targets/TARGET/target.txt"],
35
+ "Server Configuration" =>
36
+ ["cmd_tlm_server", "/config/tools/cmd_tlm_server/cmd_tlm_server.txt"],
37
+ "Command and Telemetry Configuration" =>
38
+ ["command_telemetry", "/config/targets/TARGET/cmd_tlm/*.txt"],
39
+ "Screen Definition" =>
40
+ ["screen", "/config/targets/TARGET/screens/*.txt"],
41
+ "Separator" => [nil, nil],
42
+ "Data Viewer Configuration" =>
43
+ ["data_viewer", "/config/tools/data_viewer/data_viewer.txt"],
44
+ "Handbook Creator Configuration" =>
45
+ ["handbook_creator", "/config/tools/handbook_creator/handbook_creator.txt"],
46
+ "Launcher Configuration" =>
47
+ ["launcher", "/config/tools/launcher/launcher.txt"],
48
+ "Limits Monitor Configuration" =>
49
+ ["limits_monitor", "/config/tools/limits_monitor/limits_monitor.txt"],
50
+ "Script Runner Configuration" =>
51
+ ["script_runner", "/config/tools/script_runner/script_runner.txt"],
52
+ "Table Manager Configuration" =>
53
+ ["table_manager", "/config/tools/table_manager/table_manager.txt"],
54
+ "Test Runner Configuration" =>
55
+ ["test_runner", "/config/tools/test_runner/test_runner.txt"],
56
+ "Telemetry Extractor Configuration" =>
57
+ ["tlm_extractor", "/config/tools/tlm_extractor/tlm_extractor.txt"],
58
+ "Telemetry Grapher Configuration" =>
59
+ ["tlm_grapher", "/config/tools/tlm_grapher/tlm_grapher.txt"],
60
+ "Telemetry Viewer Configuration" =>
61
+ ["tlm_viewer", "/config/tools/tlm_viewer/tlm_viewer.txt"],
62
+ }
63
+
64
+ def initialize(options)
65
+ # All code before super is executed twice in RubyQt Based classes
66
+ super(options) # MUST BE FIRST
67
+ Cosmos.load_cosmos_icon("config_editor.png")
68
+ setAcceptDrops(true) # Allow dropping in files
69
+
70
+ @procedure_dir = Cosmos::USERPATH
71
+ @file_type = "none"
72
+
73
+ initialize_actions()
74
+ initialize_menus()
75
+ initialize_central_widget()
76
+ complete_initialize()
77
+
78
+ create_tab()
79
+ end
80
+
81
+ def initialize_actions
82
+ super()
83
+
84
+ # File actions
85
+ @file_new = Qt::Action.new(Cosmos.get_icon('file.png'), tr('&New'), self)
86
+ @file_new_keyseq = Qt::KeySequence.new(tr('Ctrl+N'))
87
+ @file_new.shortcut = @file_new_keyseq
88
+ @file_new.statusTip = tr('Start a new file')
89
+ @file_new.connect(SIGNAL('triggered()')) { file_new() }
90
+
91
+ @file_close = Qt::Action.new(tr('&Close'), self)
92
+ @file_close_keyseq = Qt::KeySequence.new(tr('Ctrl+W'))
93
+ @file_close.shortcut = @file_close_keyseq
94
+ @file_close.statusTip = tr('Close the file')
95
+ @file_close.connect(SIGNAL('triggered()')) { file_close() }
96
+
97
+ @file_reload = Qt::Action.new(tr('&Reload'), self)
98
+ @file_reload_keyseq = Qt::KeySequence.new(tr('Ctrl+R'))
99
+ @file_reload.shortcut = @file_reload_keyseq
100
+ @file_reload.statusTip = tr('Reload a file')
101
+ @file_reload.connect(SIGNAL('triggered()')) { file_reload() }
102
+
103
+ @file_save = Qt::Action.new(Cosmos.get_icon('save.png'), tr('&Save'), self)
104
+ @file_save_keyseq = Qt::KeySequence.new(tr('Ctrl+S'))
105
+ @file_save.shortcut = @file_save_keyseq
106
+ @file_save.statusTip = tr('Save the file')
107
+ @file_save.connect(SIGNAL('triggered()')) { file_save(false) }
108
+
109
+ @file_save_as = Qt::Action.new(Cosmos.get_icon('save_as.png'), tr('Save &As'), self)
110
+ @file_save_as.statusTip = tr('Save the file')
111
+ @file_save_as.connect(SIGNAL('triggered()')) { file_save(true) }
112
+
113
+ # Edit actions
114
+ @edit_undo = Qt::Action.new(Cosmos.get_icon('undo.png'), tr('&Undo'), self)
115
+ @edit_undo_keyseq = Qt::KeySequence.new(tr('Ctrl+Z'))
116
+ @edit_undo.shortcut = @edit_undo_keyseq
117
+ @edit_undo.statusTip = tr('Undo')
118
+ @edit_undo.connect(SIGNAL('triggered()')) { active_config_editor_frame().undo }
119
+
120
+ @edit_redo = Qt::Action.new(Cosmos.get_icon('redo.png'), tr('&Redo'), self)
121
+ @edit_redo_keyseq = Qt::KeySequence.new(tr('Ctrl+Y'))
122
+ @edit_redo.shortcut = @edit_redo_keyseq
123
+ @edit_redo.statusTip = tr('Redo')
124
+ @edit_redo.connect(SIGNAL('triggered()')) { active_config_editor_frame().redo }
125
+
126
+ @edit_cut = Qt::Action.new(Cosmos.get_icon('cut.png'), tr('Cu&t'), self)
127
+ @edit_cut_keyseq = Qt::KeySequence.new(tr('Ctrl+X'))
128
+ @edit_cut.shortcut = @edit_cut_keyseq
129
+ @edit_cut.statusTip = tr('Cut')
130
+ @edit_cut.connect(SIGNAL('triggered()')) { active_config_editor_frame().cut }
131
+
132
+ @edit_copy = Qt::Action.new(Cosmos.get_icon('copy.png'), tr('&Copy'), self)
133
+ @edit_copy_keyseq = Qt::KeySequence.new(tr('Ctrl+C'))
134
+ @edit_copy.shortcut = @edit_copy_keyseq
135
+ @edit_copy.statusTip = tr('Copy')
136
+ @edit_copy.connect(SIGNAL('triggered()')) { active_config_editor_frame().copy }
137
+
138
+ @edit_paste = Qt::Action.new(tr('&Paste'), self)
139
+ @edit_paste_keyseq = Qt::KeySequence.new(tr('Ctrl+V'))
140
+ @edit_paste.shortcut = @edit_paste_keyseq
141
+ @edit_paste.statusTip = tr('Paste')
142
+ @edit_paste.connect(SIGNAL('triggered()')) { active_config_editor_frame().paste }
143
+
144
+ @edit_select_all = Qt::Action.new(tr('Select &All'), self)
145
+ @edit_select_all_keyseq = Qt::KeySequence.new(tr('Ctrl+A'))
146
+ @edit_select_all.shortcut = @edit_select_all_keyseq
147
+ @edit_select_all.statusTip = tr('Select All')
148
+ @edit_select_all.connect(SIGNAL('triggered()')) { active_config_editor_frame().select_all }
149
+
150
+ @edit_comment = Qt::Action.new(tr('Comment/Uncomment &Lines'), self)
151
+ @edit_comment_keyseq = Qt::KeySequence.new(tr('Ctrl+K'))
152
+ @edit_comment.shortcut = @edit_comment_keyseq
153
+ @edit_comment.statusTip = tr('Comment/Uncomment Lines')
154
+ @edit_comment.connect(SIGNAL('triggered()')) { active_config_editor_frame().comment_or_uncomment_lines }
155
+
156
+ # Search Actions
157
+ @search_find = Qt::Action.new(Cosmos.get_icon('search.png'), tr('&Find'), self)
158
+ @search_find_keyseq = Qt::KeySequence.new(tr('Ctrl+F'))
159
+ @search_find.shortcut = @search_find_keyseq
160
+ @search_find.statusTip = tr('Find text')
161
+ @search_find.connect(SIGNAL('triggered()')) do
162
+ FindReplaceDialog.show_find(self)
163
+ end
164
+
165
+ @search_find_next = Qt::Action.new(tr('Find &Next'), self)
166
+ @search_find_next_keyseq = Qt::KeySequence.new(tr('F3'))
167
+ @search_find_next.shortcut = @search_find_next_keyseq
168
+ @search_find_next.statusTip = tr('Find next instance')
169
+ @search_find_next.connect(SIGNAL('triggered()')) do
170
+ FindReplaceDialog.find_next(self)
171
+ end
172
+
173
+ @search_find_previous = Qt::Action.new(tr('Find &Previous'), self)
174
+ @search_find_previous_keyseq = Qt::KeySequence.new(tr('Shift+F3'))
175
+ @search_find_previous.shortcut = @search_find_previous_keyseq
176
+ @search_find_previous.statusTip = tr('Find previous instance')
177
+ @search_find_previous.connect(SIGNAL('triggered()')) do
178
+ FindReplaceDialog.find_previous(self)
179
+ end
180
+
181
+ @search_replace = Qt::Action.new(tr('&Replace'), self)
182
+ @search_replace_keyseq = Qt::KeySequence.new(tr('Ctrl+H'))
183
+ @search_replace.shortcut = @search_replace_keyseq
184
+ @search_replace.statusTip = tr('Replace')
185
+ @search_replace.connect(SIGNAL('triggered()')) do
186
+ FindReplaceDialog.show_replace(self)
187
+ end
188
+
189
+ @type_group = Qt::ActionGroup.new(self)
190
+ CONFIGURATION_FILES.each do |name, info|
191
+ if name == 'Separator'
192
+ action = Qt::Action.new(@type_group)
193
+ action.setSeparator(true)
194
+ else
195
+ action = Qt::Action.new(name, @type_group)
196
+ action.statusTip = info[1] # Path
197
+ action.setCheckable(true)
198
+ end
199
+ end
200
+ # Throw Unknown on the end after a separator
201
+ action = Qt::Action.new(@type_group)
202
+ action.setSeparator(true)
203
+ action = Qt::Action.new("Unknown", @type_group)
204
+ action.setCheckable(true)
205
+
206
+ @type_group.connect(SIGNAL('triggered(QAction*)')) do |action|
207
+ active_config_editor_frame.set_file_type(action.text)
208
+ update_cursor()
209
+ end
210
+ end
211
+
212
+ def initialize_menus
213
+ # File Menu
214
+ @file_menu = menuBar.addMenu(tr('&File'))
215
+ @file_menu.addAction(@file_new)
216
+
217
+ open_action = Qt::Action.new(self)
218
+ open_action.shortcut = Qt::KeySequence.new(tr('Ctrl+O'))
219
+ open_action.connect(SIGNAL('triggered()')) { file_open(@procedure_dir) }
220
+ self.addAction(open_action)
221
+
222
+ @file_open = @file_menu.addMenu(tr('&Open'))
223
+ @file_open.setIcon(Cosmos.get_icon('open.png'))
224
+ target_dirs_action(@file_open, File.join(Cosmos::USERPATH,'config'), '', method(:file_open))
225
+
226
+ @file_menu.addAction(@file_close)
227
+ @file_menu.addAction(@file_reload)
228
+ @file_menu.addSeparator()
229
+ @file_menu.addAction(@file_save)
230
+ @file_menu.addAction(@file_save_as)
231
+ @file_menu.addSeparator()
232
+ @file_menu.addAction(@exit_action)
233
+
234
+ # Edit Menu
235
+ mode_menu = menuBar.addMenu(tr('&Edit'))
236
+ mode_menu.addAction(@edit_undo)
237
+ mode_menu.addAction(@edit_redo)
238
+ mode_menu.addSeparator()
239
+ mode_menu.addAction(@edit_cut)
240
+ mode_menu.addAction(@edit_copy)
241
+ mode_menu.addAction(@edit_paste)
242
+ mode_menu.addSeparator()
243
+ mode_menu.addAction(@edit_select_all)
244
+ mode_menu.addSeparator()
245
+ mode_menu.addAction(@edit_comment)
246
+
247
+ # Search Menu
248
+ view_menu = menuBar.addMenu(tr('&Search'))
249
+ view_menu.addAction(@search_find)
250
+ view_menu.addAction(@search_find_next)
251
+ view_menu.addAction(@search_find_previous)
252
+ view_menu.addAction(@search_replace)
253
+
254
+ # File Type Menu
255
+ type_menu = menuBar.addMenu(tr('File &Type'))
256
+ type_menu.addActions(@type_group.actions)
257
+
258
+ # Help Menu
259
+ @about_string = "Config Editor allows the user to edit COSMOS configuration "\
260
+ "files with contextual help. "\
261
+
262
+ initialize_help_menu()
263
+ end
264
+
265
+ def initialize_central_widget
266
+ # Create a splitter to hold the file tree and tab widget
267
+ @splitter = Qt::Splitter.new(Qt::Horizontal, self)
268
+
269
+ @fs_model = Qt::FileSystemModel.new
270
+ @fs_model.setRootPath(Cosmos::USERPATH)
271
+ @tree_view = Qt::TreeView.new(@splitter)
272
+ @tree_view.setModel(@fs_model)
273
+ @tree_view.setRootIndex(@fs_model.index(Cosmos::USERPATH))
274
+ @tree_view.setColumnHidden(1, true) # Size
275
+ @tree_view.setColumnHidden(2, true) # Type
276
+ @tree_view.setColumnHidden(3, true) # Date Modified
277
+ @tree_view.connect(SIGNAL('activated(const QModelIndex&)')) do |index|
278
+ select_or_load_file(@fs_model.filePath(index))
279
+ end
280
+ @tree_view.connect(SIGNAL('clicked(const QModelIndex&)')) do |index|
281
+ select_or_load_file(@fs_model.filePath(index))
282
+ end
283
+
284
+ @tab_book = Qt::TabWidget.new(@splitter)
285
+ @tab_book.setMovable(true)
286
+ @tab_book.setContextMenuPolicy(Qt::CustomContextMenu)
287
+ connect(@tab_book,
288
+ SIGNAL('customContextMenuRequested(const QPoint&)'),
289
+ self,
290
+ SLOT('context_menu(const QPoint&)'))
291
+ connect(@tab_book,
292
+ SIGNAL('currentChanged(int)'),
293
+ self,
294
+ SLOT('handle_tab_change(int)'))
295
+ @splitter.setSizes([200, 800]) # Rough split of the widget
296
+ setCentralWidget(@splitter)
297
+
298
+ # Display a blank message to force the statusBar to show
299
+ statusBar.showMessage("")
300
+ @status_bar_right_label = Qt::Label.new
301
+ statusBar.addPermanentWidget(@status_bar_right_label)
302
+ end
303
+
304
+ def select_or_load_file(file_path)
305
+ return if File.directory?(file_path)
306
+ found = false
307
+ # If the file is already open select the tab
308
+ @tab_book.tabs.each_with_index do |tab, index|
309
+ if tab.filename == file_path
310
+ found = true
311
+ @tab_book.setCurrentIndex(index)
312
+ end
313
+ end
314
+ file_open(file_path) unless found
315
+ end
316
+
317
+ def dragEnterEvent(event)
318
+ if event.mimeData.hasUrls
319
+ event.acceptProposedAction();
320
+ end
321
+ end
322
+
323
+ def dragMoveEvent(event)
324
+ if event.mimeData.hasUrls
325
+ event.acceptProposedAction();
326
+ end
327
+ end
328
+
329
+ def dropEvent(event)
330
+ event.mimeData.urls.each do |url|
331
+ filename = url.toLocalFile
332
+ extension = File.extname(filename).to_s.downcase
333
+ if extension == '.rb' or extension == '.txt'
334
+ file_open(filename)
335
+ end
336
+ end
337
+ end
338
+
339
+ ###########################################
340
+ # File Menu Options
341
+ ###########################################
342
+
343
+ # File->New
344
+ def file_new
345
+ create_tab()
346
+ end
347
+
348
+ # File->Open
349
+ def file_open(filename = nil)
350
+ if File.directory?(filename)
351
+ filename = Qt::FileDialog.getOpenFileName(self, "Select File", filename)
352
+ end
353
+ unless filename.nil? || filename.empty?
354
+ # If the user opens a file we already have open
355
+ # just set the current tab to that file and return
356
+ @tab_book.tabs.each_with_index do |tab, index|
357
+ if tab.filename == filename
358
+ @tab_book.setCurrentIndex(index)
359
+ @tab_book.currentTab.set_text_from_file(filename)
360
+ @tab_book.currentTab.filename = filename
361
+ return
362
+ end
363
+ end
364
+
365
+ if ((@tab_book.count == 1) &&
366
+ @tab_book.currentTab.filename.empty? &&
367
+ !@tab_book.currentTab.modified)
368
+ # Active Tab is an unmodified Untitled so just open the file in it
369
+ @tab_book.currentTab.set_text_from_file(filename)
370
+ @tab_book.currentTab.filename = filename
371
+ @tab_book.setTabText(@tab_book.currentIndex, File.basename(filename))
372
+ else
373
+ create_tab(filename)
374
+ end
375
+
376
+ update_title()
377
+ @procedure_dir = File.dirname(filename)
378
+ @procedure_dir << '/' if @procedure_dir[-1..-1] != '/' and @procedure_dir[-1..-1] != '\\'
379
+ end
380
+ end
381
+
382
+ # File->Reload
383
+ def file_reload
384
+ safe_to_continue = true
385
+ if @tab_book.currentTab.modified
386
+ case Qt::MessageBox.question(self, # parent
387
+ 'Discard Changes?', # title
388
+ 'Warning: Changes will be lost. Continue?', # text
389
+ Qt::MessageBox::Yes | Qt::MessageBox::No, # buttons
390
+ Qt::MessageBox::No) # default button
391
+ when Qt::MessageBox::No
392
+ safe_to_continue = false
393
+ end
394
+ end
395
+
396
+ if safe_to_continue
397
+ if active_config_editor_frame().filename.empty?
398
+ active_config_editor_frame().set_text('')
399
+ else
400
+ active_config_editor_frame().set_text_from_file(active_config_editor_frame().filename)
401
+ end
402
+ @tab_book.currentTab.modified = false
403
+ update_title()
404
+ end
405
+ end
406
+
407
+ # File->Save and File->Save As
408
+ def file_save(save_as = false)
409
+ saved = false
410
+ filename = active_config_editor_frame().filename
411
+ if filename.empty?
412
+ filename = Qt::FileDialog::getSaveFileName(self, # parent
413
+ 'Save As...', # caption
414
+ @procedure_dir + '/procedure.rb', # dir
415
+ 'Procedure Files (*.rb)') # filter
416
+ elsif save_as
417
+ filename = Qt::FileDialog::getSaveFileName(self, # parent
418
+ 'Save As...', # caption
419
+ filename, # dir
420
+ 'Procedure Files (*.rb)') # filter
421
+ end
422
+ if not filename.nil? and not filename.empty?
423
+ begin
424
+ @tab_book.currentTab.filename = filename
425
+ @tab_book.currentTab.modified = false
426
+ @tab_book.setTabText(@tab_book.currentIndex, File.basename(filename))
427
+ active_config_editor_frame().filename = filename
428
+ File.open(filename, "w") {|file| file.write(active_config_editor_frame().text)}
429
+ saved = true
430
+ update_title()
431
+ statusBar.showMessage(tr("#{filename} saved"))
432
+ @procedure_dir = File.dirname(filename)
433
+ @procedure_dir << '/' if @procedure_dir[-1..-1] != '/' and @procedure_dir[-1..-1] != '\\'
434
+ rescue => error
435
+ statusBar.showMessage(tr("Error Saving File : #{error.class} : #{error.message}"))
436
+ end
437
+ end
438
+
439
+ return saved
440
+ end
441
+
442
+ # File->Close
443
+ def file_close
444
+ if prompt_for_save_if_needed('Save Current File?')
445
+ if @tab_book.count > 1
446
+ close_active_tab()
447
+ else
448
+ @tab_book.setTabText(0, UNTITLED_TAB_TEXT)
449
+ @tab_book.currentTab.clear
450
+ end
451
+ update_title()
452
+ end
453
+ end
454
+
455
+ ###########################################
456
+ # Callbacks
457
+ ###########################################
458
+
459
+ # Called by the FindReplaceDialog to get the text to search
460
+ def search_text
461
+ active_config_editor_frame().editor
462
+ end
463
+
464
+ def undo_available(bool)
465
+ update_title()
466
+ end
467
+
468
+ def closeEvent(event)
469
+ if prompt_for_save_if_needed_on_close()
470
+ super(event)
471
+ else
472
+ event.ignore()
473
+ end
474
+ end
475
+
476
+ def enable_menu_items
477
+ # Enable File Menu Items
478
+ @file_new.setEnabled(true)
479
+ @file_open.setEnabled(true)
480
+ @file_close.setEnabled(true)
481
+ @file_reload.setEnabled(true)
482
+ @file_save.setEnabled(true)
483
+ @file_save_as.setEnabled(true)
484
+ @file_options.setEnabled(true)
485
+
486
+ # Enable Edit Menu Items
487
+ @edit_undo.setEnabled(true)
488
+ @edit_redo.setEnabled(true)
489
+ @edit_cut.setEnabled(true)
490
+ @edit_copy.setEnabled(true)
491
+ @edit_paste.setEnabled(true)
492
+ @edit_select_all.setEnabled(true)
493
+ @edit_comment.setEnabled(true)
494
+ end
495
+
496
+ def disable_menu_items
497
+ # Disable File Menu Items
498
+ @file_new.setEnabled(false)
499
+ @file_open.setEnabled(false)
500
+ @file_close.setEnabled(false)
501
+ @file_reload.setEnabled(false)
502
+ @file_save.setEnabled(false)
503
+ @file_save_as.setEnabled(false)
504
+ @file_options.setEnabled(false)
505
+
506
+ # Disable Edit Menu Items
507
+ @edit_undo.setEnabled(false)
508
+ @edit_redo.setEnabled(false)
509
+ @edit_cut.setEnabled(false)
510
+ @edit_copy.setEnabled(false)
511
+ @edit_paste.setEnabled(false)
512
+ @edit_select_all.setEnabled(false)
513
+ @edit_comment.setEnabled(false)
514
+ end
515
+
516
+ # Handle the user changing tabs
517
+ def handle_tab_change(index)
518
+ update_title()
519
+ update_type_group()
520
+ update_tree()
521
+ end
522
+
523
+ def handle_script_keypress(event)
524
+ update_title()
525
+ if event.matches(Qt::KeySequence::NextChild)
526
+ index = @tab_book.currentIndex + 1
527
+ index = 0 if index >= @tab_book.count
528
+ @tab_book.setCurrentIndex(index)
529
+ elsif event.matches(Qt::KeySequence::PreviousChild)
530
+ index = @tab_book.currentIndex - 1
531
+ index = @tab_book.count - 1 if index < 0
532
+ @tab_book.setCurrentIndex(index)
533
+ end
534
+ end
535
+
536
+ def context_menu(point)
537
+ index = 0
538
+ @tab_book.tabBar.count.times do
539
+ break if @tab_book.tabBar.tabRect(index).contains(point)
540
+ index += 1
541
+ end
542
+
543
+ return if (index == @tab_book.tabBar.count)
544
+
545
+ # Bring the right clicked tab to the front
546
+ @tab_book.setCurrentIndex(index)
547
+
548
+ menu = Qt::Menu.new()
549
+
550
+ new_action = Qt::Action.new(tr("&New"), self)
551
+ new_action.statusTip = tr("Create a new file")
552
+ new_action.connect(SIGNAL('triggered()')) { file_new() }
553
+ menu.addAction(new_action)
554
+
555
+ close_action = Qt::Action.new(tr("&Close"), self)
556
+ close_action.statusTip = tr("Close the file")
557
+ close_action.connect(SIGNAL('triggered()')) { file_close() }
558
+ menu.addAction(close_action)
559
+
560
+ save_action = Qt::Action.new(tr("&Save"), self)
561
+ save_action.statusTip = tr("Save the file")
562
+ save_action.connect(SIGNAL('triggered()')) { file_save(false) }
563
+ menu.addAction(save_action)
564
+
565
+ save_action = Qt::Action.new(tr("Save &As"), self)
566
+ save_action.statusTip = tr("Save the file as")
567
+ save_action.connect(SIGNAL('triggered()')) { file_save(true) }
568
+ menu.addAction(save_action)
569
+
570
+ menu.exec(@tab_book.mapToGlobal(point))
571
+ menu.dispose
572
+ end
573
+
574
+ #############################################################
575
+ # Helper Methods
576
+ #############################################################
577
+
578
+ def show_message(message, right_label = nil)
579
+ statusBar.showMessage(message)
580
+ if right_label
581
+ @status_bar_right_label.text = right_label
582
+ else
583
+ @status_bar_right_label.text = ''
584
+ end
585
+ end
586
+
587
+ def update_cursor
588
+ num = active_config_editor_frame.line_number
589
+ col = active_config_editor_frame.column_number
590
+ status = "#{num}:#{col} #{active_config_editor_frame.line_keyword}"
591
+ show_message(status, active_config_editor_frame.file_type)
592
+ end
593
+
594
+ def update_type_group
595
+ @type_group.actions[-1].setChecked(true)
596
+ @type_group.actions.each do |action|
597
+ if action.text == active_config_editor_frame.file_type
598
+ action.setChecked(true)
599
+ end
600
+ end
601
+ update_cursor()
602
+ end
603
+
604
+ # Updates the title appropriately to show the tabs filename and modified status
605
+ def update_title
606
+ if @tab_book.currentTab.filename.empty?
607
+ self.setWindowTitle("Config Editor : #{UNTITLED}")
608
+ else
609
+ self.setWindowTitle("Config Editor : #{@tab_book.currentTab.filename}")
610
+ end
611
+ self.setWindowTitle(self.windowTitle << '*') if @tab_book.currentTab.modified
612
+ update_cursor()
613
+ end
614
+
615
+ def update_tree
616
+ @tree_view.setCurrentIndex(@fs_model.index(@tab_book.currentTab.filename))
617
+ end
618
+
619
+ # Returns the frame of the active tab
620
+ def active_config_editor_frame
621
+ @tab_book.currentTab
622
+ end
623
+
624
+ # Creates a new tab
625
+ def create_tab(filename = '')
626
+ if filename.empty?
627
+ tab_item_name = UNTITLED_TAB_TEXT
628
+ else
629
+ tab_item_name = ' ' + File.basename(filename) + ' '
630
+ end
631
+
632
+ config_editor_frame = ConfigEditorFrame.new(self)
633
+ config_editor_frame.setContentsMargins(5,5,5,5)
634
+ connect(config_editor_frame,
635
+ SIGNAL('undoAvailable(bool)'),
636
+ self,
637
+ SLOT('undo_available(bool)'))
638
+ config_editor_frame.set_text_from_file(filename) unless filename.empty?
639
+ config_editor_frame.filename = filename
640
+ # Register a keypress handler so we can Ctrl-Tab our way through the tabs
641
+ config_editor_frame.key_press_callback = method(:handle_script_keypress)
642
+ # Update the title if the frame changes so we can add/remove the asterix
643
+ config_editor_frame.connect(SIGNAL('modificationChanged(bool)')) { update_title() }
644
+ config_editor_frame.connect(SIGNAL('cursorPositionChanged()')) { update_cursor() }
645
+ config_editor_frame.connect(SIGNAL('file_type_changed()')) { update_type_group() }
646
+
647
+ @tab_book.addTab(config_editor_frame, tab_item_name)
648
+ @tab_book.setCurrentIndex(@tab_book.count-1) # index is 0 based
649
+ # Set the focus on the input now that we've added the tab
650
+ config_editor_frame.setFocus
651
+ update_title()
652
+ end
653
+
654
+ # Closes the active tab
655
+ def close_active_tab
656
+ if @tab_book.count > 1
657
+ tab_index = @tab_book.currentIndex
658
+ @tab_book.removeTab(tab_index)
659
+ if tab_index >= 1
660
+ @tab_book.setCurrentIndex(tab_index - 1)
661
+ else
662
+ @tab_book.setCurrentIndex(0)
663
+ end
664
+ end
665
+ end
666
+
667
+ # Prompts for save if the current tab has been modified
668
+ def prompt_for_save_if_needed(message = 'Save?')
669
+ safe_to_continue = true
670
+ if @tab_book.currentTab.modified
671
+ case Qt::MessageBox.question(
672
+ self, # parent
673
+ 'Save?', # title
674
+ message, # text
675
+ Qt::MessageBox::Yes | Qt::MessageBox::No | Qt::MessageBox::Cancel, # buttons
676
+ Qt::MessageBox::Cancel) # default button
677
+ when Qt::MessageBox::Cancel
678
+ safe_to_continue = false
679
+ when Qt::MessageBox::Yes
680
+ saved = file_save(false)
681
+ if not saved
682
+ safe_to_continue = false
683
+ end
684
+ end
685
+ end
686
+ return safe_to_continue
687
+ end
688
+
689
+ # Prompts the user that unsaved changes have been made before they close the app
690
+ def prompt_for_save_if_needed_on_close
691
+ safe_to_continue = true
692
+ @tab_book.tabs.each_with_index do |tab, index|
693
+ if tab.modified
694
+ @tab_book.setCurrentIndex(index)
695
+ if tab.filename.empty?
696
+ message = "Save changes to '#{UNTITLED}'?"
697
+ else
698
+ message = "Save changes to '#{tab.filename}'?"
699
+ end
700
+ safe_to_continue = prompt_for_save_if_needed(message)
701
+ #~ break unless safe_to_continue
702
+ end
703
+ end
704
+ return safe_to_continue
705
+ end
706
+
707
+ def self.run(option_parser = nil, options = nil)
708
+ Cosmos.catch_fatal_exception do
709
+ unless option_parser and options
710
+ option_parser, options = create_default_options()
711
+ options.width = 80
712
+ options.height = 600
713
+ options.title = "Config Editor : #{UNTITLED}"
714
+ options.auto_size = false
715
+ end
716
+ super(option_parser, options)
717
+ end
718
+ end
719
+ end
720
+ end