cosmos 3.1.1 → 3.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/Manifest.txt +6 -0
  3. data/autohotkey/config/tools/handbook_creator/templates/command_packets.html.erb +1 -1
  4. data/autohotkey/config/tools/handbook_creator/templates/footer.html.erb +2 -2
  5. data/autohotkey/config/tools/handbook_creator/templates/header.html.erb +4 -4
  6. data/autohotkey/tools/autohotkey.rb +1 -1
  7. data/autohotkey/tools/cmd_tlm_server.ahk +1 -0
  8. data/autohotkey/tools/packet_viewer.ahk +45 -2
  9. data/data/crc.txt +20 -15
  10. data/demo/Rakefile +16 -0
  11. data/demo/config/data/crc.txt +3 -3
  12. data/demo/config/tools/handbook_creator/templates/footer.html.erb +2 -2
  13. data/demo/config/tools/handbook_creator/templates/header.html.erb +4 -4
  14. data/demo/procedures/example_test.rb +1 -1
  15. data/install/Rakefile +16 -0
  16. data/install/config/data/crc.txt +2 -2
  17. data/install/config/tools/handbook_creator/templates/footer.html.erb +2 -2
  18. data/install/config/tools/handbook_creator/templates/header.html.erb +4 -4
  19. data/lib/cosmos/gui/dialogs/tlm_details_dialog.rb +64 -57
  20. data/lib/cosmos/gui/line_graph/line_graph_scaling.rb +0 -9
  21. data/lib/cosmos/gui/qt.rb +22 -18
  22. data/lib/cosmos/packet_logs/packet_log_writer.rb +6 -2
  23. data/lib/cosmos/script/script.rb +1 -1
  24. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_config.rb +0 -1
  25. data/lib/cosmos/tools/cmd_tlm_server/cmd_tlm_server_gui.rb +99 -784
  26. data/lib/cosmos/tools/cmd_tlm_server/gui/interfaces_tab.rb +189 -0
  27. data/lib/cosmos/tools/cmd_tlm_server/gui/logging_tab.rb +176 -0
  28. data/lib/cosmos/tools/cmd_tlm_server/gui/packets_tab.rb +144 -0
  29. data/lib/cosmos/tools/cmd_tlm_server/gui/status_tab.rb +240 -0
  30. data/lib/cosmos/tools/cmd_tlm_server/gui/targets_tab.rb +90 -0
  31. data/lib/cosmos/tools/launcher/launcher_config.rb +142 -110
  32. data/lib/cosmos/tools/test_runner/results_writer.rb +1 -1
  33. data/lib/cosmos/tools/test_runner/test_runner.rb +3 -2
  34. data/lib/cosmos/tools/tlm_grapher/data_objects/data_object.rb +18 -2
  35. data/lib/cosmos/tools/tlm_grapher/data_objects/housekeeping_data_object.rb +4 -9
  36. data/lib/cosmos/tools/tlm_grapher/data_objects/xy_data_object.rb +5 -5
  37. data/lib/cosmos/top_level.rb +1 -1
  38. data/lib/cosmos/version.rb +4 -4
  39. data/run_gui_tests.bat +33 -31
  40. data/spec/core_ext/time_spec.rb +51 -0
  41. data/spec/script/script_spec.rb +96 -0
  42. data/spec/tools/cmd_tlm_server/commanding_spec.rb +28 -0
  43. data/spec/tools/cmd_tlm_server/connections_spec.rb +88 -0
  44. data/spec/tools/cmd_tlm_server/router_thread_spec.rb +78 -25
  45. data/spec/tools/launcher/launcher_config_spec.rb +460 -0
  46. data/spec/top_level/top_level_spec.rb +1 -1
  47. metadata +8 -2
@@ -0,0 +1,240 @@
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/qt'
13
+
14
+ module Cosmos
15
+
16
+ # Implements the status tab in the Command and Telemetry Server GUI
17
+ class StatusTab
18
+
19
+ # Create the status tab and add it to the tab_widget
20
+ #
21
+ # @param tab_widget [Qt::TabWidget] The tab widget to add the tab to
22
+ def populate(tab_widget)
23
+ scroll = Qt::ScrollArea.new
24
+ widget = Qt::Widget.new
25
+ layout = Qt::VBoxLayout.new(widget)
26
+
27
+ populate_limits_status(layout)
28
+ populate_api_status(layout)
29
+ populate_system_status(layout)
30
+ populate_background_status(layout)
31
+
32
+ # Set the scroll area widget last now that all the items have been layed out
33
+ scroll.setWidget(widget)
34
+ tab_widget.addTab(scroll, "Status")
35
+ end
36
+
37
+ # Update the status tab in the GUI
38
+ #
39
+ # @param previous_request_count [Integer] The previous number of
40
+ def update(previous_request_count)
41
+ update_limits_set
42
+ update_api_status(previous_request_count)
43
+ update_system_status
44
+ update_background_task_status
45
+ end
46
+
47
+ private
48
+
49
+ def populate_limits_status(layout)
50
+ limits = Qt::GroupBox.new(Qt::Object.tr("Limits Status"))
51
+ limits_layout = Qt::FormLayout.new(limits)
52
+ current_limits_set = System.limits_set.to_s
53
+
54
+ known_limits_sets = System.limits.sets
55
+ known_limits_sets = known_limits_sets.map {|x| x.to_s}.sort
56
+ current_index = known_limits_sets.index(current_limits_set.to_s)
57
+
58
+ @limits_set_combo = Qt::ComboBox.new
59
+ limits_layout.addRow("Limits Set:", @limits_set_combo)
60
+ layout.addWidget(limits)
61
+
62
+ known_limits_sets.sort.each do |limits_set|
63
+ @limits_set_combo.addItem(limits_set.to_s)
64
+ end
65
+ @limits_set_combo.setMaxVisibleItems(6)
66
+ @limits_set_combo.setCurrentIndex(current_index)
67
+ # Only connect to the signal that is sent when the user chooses an item.
68
+ # If the limits set is changed programatically the code in
69
+ # handle_status_tab will pick up the change.
70
+ @limits_set_combo.connect(SIGNAL('activated(int)')) do
71
+ selected_limits_set = @limits_set_combo.currentText
72
+ if selected_limits_set
73
+ System.limits_set = selected_limits_set.intern if System.limits_set != selected_limits_set.intern
74
+ end
75
+ end
76
+ end
77
+
78
+ def populate_api_status(layout)
79
+ api = Qt::GroupBox.new(Qt::Object.tr("API Status"))
80
+ api_layout = Qt::VBoxLayout.new(api)
81
+ @api_table = Qt::TableWidget.new()
82
+ @api_table.verticalHeader.hide()
83
+ @api_table.setRowCount(1)
84
+ @api_table.setColumnCount(6)
85
+ @api_table.setHorizontalHeaderLabels(["Port", "Num Clients", "Requests", "Requests/Sec", "Avg Request Time", "Estimated Utilization"])
86
+
87
+ @api_table.setItem(0, 0, Qt::TableWidgetItem.new(Qt::Object.tr(System.ports['CTS_API'].to_s)))
88
+ item0 = Qt::TableWidgetItem.new(Qt::Object.tr(CmdTlmServer.json_drb.num_clients.to_s))
89
+ item0.setTextAlignment(Qt::AlignCenter)
90
+ @api_table.setItem(0, 1, item0)
91
+ item = Qt::TableWidgetItem.new(Qt::Object.tr(CmdTlmServer.json_drb.request_count.to_s))
92
+ item.setTextAlignment(Qt::AlignCenter)
93
+ @api_table.setItem(0, 2, item)
94
+ item2 = Qt::TableWidgetItem.new("0.0")
95
+ item2.setTextAlignment(Qt::AlignCenter)
96
+ @api_table.setItem(0, 3, item2)
97
+ item3 = Qt::TableWidgetItem.new("0.0")
98
+ item3.setTextAlignment(Qt::AlignCenter)
99
+ @api_table.setItem(0, 4, item3)
100
+ item4 = Qt::TableWidgetItem.new("0.0")
101
+ item4.setTextAlignment(Qt::AlignCenter)
102
+ @api_table.setItem(0, 5, item4)
103
+ @api_table.displayFullSize
104
+ api_layout.addWidget(@api_table)
105
+ layout.addWidget(api)
106
+ end
107
+
108
+ def populate_system_status(layout)
109
+ system = Qt::GroupBox.new(Qt::Object.tr("System Status"))
110
+ system_layout = Qt::VBoxLayout.new(system)
111
+ @system_table = Qt::TableWidget.new()
112
+ @system_table.verticalHeader.hide()
113
+ @system_table.setRowCount(1)
114
+ @system_table.setColumnCount(4)
115
+ @system_table.setHorizontalHeaderLabels(["Threads", "Total Objs", "Free Objs", "Allocated Objs"])
116
+
117
+ item0 = Qt::TableWidgetItem.new("0")
118
+ item0.setTextAlignment(Qt::AlignCenter)
119
+ @system_table.setItem(0, 0, item0)
120
+ item1 = Qt::TableWidgetItem.new("0.0")
121
+ item1.setTextAlignment(Qt::AlignCenter)
122
+ @system_table.setItem(0, 1, item1)
123
+ item2 = Qt::TableWidgetItem.new("0.0")
124
+ item2.setTextAlignment(Qt::AlignCenter)
125
+ @system_table.setItem(0, 2, item2)
126
+ item3 = Qt::TableWidgetItem.new("0.0")
127
+ item3.setTextAlignment(Qt::AlignCenter)
128
+ @system_table.setItem(0, 3, item3)
129
+ @system_table.displayFullSize
130
+ system_layout.addWidget(@system_table)
131
+ layout.addWidget(system)
132
+ end
133
+
134
+ def populate_background_status(layout)
135
+ background_tasks_groupbox = Qt::GroupBox.new(Qt::Object.tr("Background Tasks"))
136
+ background_tasks_layout = Qt::VBoxLayout.new(background_tasks_groupbox)
137
+ @background_tasks_table = Qt::TableWidget.new()
138
+ @background_tasks_table.verticalHeader.hide()
139
+ @background_tasks_table.setRowCount(CmdTlmServer.background_tasks.all.length)
140
+ @background_tasks_table.setColumnCount(3)
141
+ @background_tasks_table.setHorizontalHeaderLabels(["Name", "State", "Status"])
142
+
143
+ background_tasks = CmdTlmServer.background_tasks.all
144
+ if background_tasks.length > 0
145
+ row = 0
146
+ background_tasks.each_with_index do |background_task, index|
147
+ background_task_name = background_task.name
148
+ background_task_name = "Background Task ##{index + 1}" unless background_task_name
149
+ background_task_name_widget = Qt::TableWidgetItem.new(background_task_name)
150
+ background_task_name_widget.setTextAlignment(Qt::AlignCenter)
151
+ @background_tasks_table.setItem(row, 0, background_task_name_widget)
152
+ if background_task.thread
153
+ status = background_task.thread.status
154
+ status = 'complete' if status == false
155
+ background_task_state_widget = Qt::TableWidgetItem.new(status.to_s)
156
+ else
157
+ background_task_state_widget = Qt::TableWidgetItem.new('no thread')
158
+ end
159
+ background_task_state_widget.setTextAlignment(Qt::AlignCenter)
160
+ background_task_state_widget.setSizeHint(Qt::Size.new(80, 30))
161
+ @background_tasks_table.setItem(row, 1, background_task_state_widget)
162
+ background_task_status_widget = Qt::TableWidgetItem.new(background_task.status.to_s)
163
+ background_task_status_widget.setTextAlignment(Qt::AlignCenter)
164
+ background_task_status_widget.setSizeHint(Qt::Size.new(500, 30))
165
+ @background_tasks_table.setItem(row, 2, background_task_status_widget)
166
+
167
+ row += 1
168
+ end
169
+ end
170
+ @background_tasks_table.displayFullSize
171
+ background_tasks_layout.addWidget(@background_tasks_table)
172
+ layout.addWidget(background_tasks_groupbox)
173
+ end
174
+
175
+ # Update the current limits set in the GUI
176
+ def update_limits_set
177
+ current_limits_set = System.limits_set.to_s
178
+ if @limits_set_combo.currentText != current_limits_set
179
+ known_limits_sets = System.limits.sets
180
+ known_limits_sets = known_limits_sets.map {|x| x.to_s}.sort
181
+ current_index = known_limits_sets.index(current_limits_set.to_s)
182
+ @limits_set_combo.clear
183
+ known_limits_sets.sort.each do |limits_set|
184
+ @limits_set_combo.addItem(limits_set.to_s)
185
+ end
186
+ @limits_set_combo.setCurrentIndex(current_index)
187
+ end
188
+ end
189
+
190
+ # Update the API statistics in the GUI
191
+ def update_api_status(previous_request_count)
192
+ if CmdTlmServer.json_drb
193
+ @api_table.item(0,1).setText(CmdTlmServer.json_drb.num_clients.to_s)
194
+ @api_table.item(0,2).setText(CmdTlmServer.json_drb.request_count.to_s)
195
+ request_count = CmdTlmServer.json_drb.request_count
196
+ requests_per_second = request_count - previous_request_count
197
+ @api_table.item(0,3).setText(requests_per_second.to_s)
198
+ previous_request_count = request_count
199
+ average_request_time = CmdTlmServer.json_drb.average_request_time
200
+ @api_table.item(0,4).setText(sprintf("%0.6f s", average_request_time))
201
+ estimated_utilization = requests_per_second * average_request_time * 100.0
202
+ @api_table.item(0,5).setText(sprintf("%0.2f %", estimated_utilization))
203
+ end
204
+ end
205
+
206
+ # Update the Ruby system statistics in the GUI
207
+ def update_system_status
208
+ @system_table.item(0,0).setText(Thread.list.length.to_s)
209
+ objs = ObjectSpace.count_objects
210
+ @system_table.item(0,1).setText(objs[:TOTAL].to_s)
211
+ @system_table.item(0,2).setText(objs[:FREE].to_s)
212
+ total = 0
213
+ objs.each do |key, val|
214
+ next if key == :TOTAL || key == :FREE
215
+ total += val
216
+ end
217
+ @system_table.item(0,3).setText(total.to_s)
218
+ end
219
+
220
+ # Update the background task status in the GUI
221
+ def update_background_task_status
222
+ background_tasks = CmdTlmServer.background_tasks.all
223
+ if background_tasks.length > 0
224
+ row = 0
225
+ background_tasks.each_with_index do |background_task, index|
226
+ if background_task.thread
227
+ status = background_task.thread.status
228
+ status = 'complete' if status == false
229
+ @background_tasks_table.item(row, 1).setText(status.to_s)
230
+ else
231
+ @background_tasks_table.item(row, 1).setText('no thread')
232
+ end
233
+ @background_tasks_table.item(row, 2).setText(background_task.status.to_s)
234
+ row += 1
235
+ end
236
+ end
237
+ end
238
+
239
+ end
240
+ end # module Cosmos
@@ -0,0 +1,90 @@
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/qt'
13
+
14
+ module Cosmos
15
+
16
+ # Implements the targets tab in the Command and Telemetry Server GUI
17
+ class TargetsTab
18
+
19
+ # Create the targets tab and add it to the tab_widget
20
+ #
21
+ # @param tab_widget [Qt::TabWidget] The tab widget to add the tab to
22
+ def populate(tab_widget)
23
+ num_targets = System.targets.length
24
+ if num_targets > 0
25
+ return if num_targets == 1 and System.targets['SYSTEM']
26
+ num_targets -= 1 if System.targets['SYSTEM']
27
+
28
+ scroll = Qt::ScrollArea.new
29
+ widget = Qt::Widget.new
30
+ layout = Qt::VBoxLayout.new(widget)
31
+ # Since the layout will be inside a scroll area make sure it respects the sizes we set
32
+ layout.setSizeConstraint(Qt::Layout::SetMinAndMaxSize)
33
+
34
+ @targets_table = Qt::TableWidget.new()
35
+ @targets_table.verticalHeader.hide()
36
+ @targets_table.setRowCount(num_targets)
37
+ @targets_table.setColumnCount(4)
38
+ @targets_table.setHorizontalHeaderLabels(["Target Name", "Interface", "Command Count", "Telemetry Count"])
39
+
40
+ populate_targets_table()
41
+
42
+ @targets_table.displayFullSize
43
+
44
+ layout.addWidget(@targets_table)
45
+ scroll.setWidget(widget)
46
+ tab_widget.addTab(scroll, "Targets")
47
+ end
48
+ end
49
+
50
+ # Update the targets tab gui
51
+ def update
52
+ row = 0
53
+ System.targets.sort.each do |target_name, target|
54
+ next if target_name == 'SYSTEM'
55
+ @targets_table.item(row,2).setText(target.cmd_cnt.to_s)
56
+ @targets_table.item(row,3).setText(target.tlm_cnt.to_s)
57
+ row += 1
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ def populate_targets_table
64
+ row = 0
65
+ System.targets.sort.each do |target_name, target|
66
+ next if target_name == 'SYSTEM'
67
+ target_name_widget = Qt::TableWidgetItem.new(Qt::Object.tr(target_name))
68
+ target_name_widget.setTextAlignment(Qt::AlignCenter)
69
+ @targets_table.setItem(row, 0, target_name_widget)
70
+ if target.interface
71
+ interface_name_widget = Qt::TableWidgetItem.new(Qt::Object.tr(target.interface.name.to_s))
72
+ else
73
+ interface_name_widget = Qt::TableWidgetItem.new(Qt::Object.tr(''))
74
+ end
75
+ interface_name_widget.setTextAlignment(Qt::AlignCenter)
76
+ @targets_table.setItem(row, 1, interface_name_widget)
77
+ cmd_cnt = Qt::TableWidgetItem.new(Qt::Object.tr(target.cmd_cnt.to_s))
78
+ cmd_cnt.setTextAlignment(Qt::AlignCenter)
79
+ @targets_table.setItem(row, 2, cmd_cnt)
80
+
81
+ tlm_cnt = Qt::TableWidgetItem.new(Qt::Object.tr(target.tlm_cnt.to_s))
82
+ tlm_cnt.setTextAlignment(Qt::AlignCenter)
83
+ @targets_table.setItem(row, 3, tlm_cnt)
84
+
85
+ row += 1
86
+ end
87
+ end
88
+
89
+ end
90
+ end # module Cosmos
@@ -10,6 +10,7 @@
10
10
 
11
11
  require 'cosmos'
12
12
  require 'cosmos/config/config_parser'
13
+ require 'ostruct'
13
14
 
14
15
  module Cosmos
15
16
 
@@ -33,8 +34,9 @@ module Cosmos
33
34
  attr_reader :num_columns
34
35
 
35
36
  # Processes a file and adds in the configuration defined in the file
37
+ #
38
+ # @param filename [String] Name of the configuration file to parse
36
39
  def initialize(filename)
37
- # Initialize instance variables
38
40
  @title = 'COSMOS Launcher'
39
41
  @tool_font_settings = ['Arial', 12]
40
42
  @label_font_settings = ['Arial', 16]
@@ -42,132 +44,162 @@ module Cosmos
42
44
  @items = []
43
45
 
44
46
  if File.exist?(filename.to_s)
45
- multitool = false
46
- multitool_text = nil
47
- multitool_icon_filename = nil
48
- multitool_settings = nil
49
-
50
- # Loop over each line of the configuration file
51
- parser = ConfigParser.new
52
- parser.parse_file(filename) do |keyword, params|
53
- # Handle each keyword
54
- case keyword
55
-
56
- when 'TOOL'
57
- if multitool
58
- parser.verify_num_parameters(1, 1, "TOOL <Shell command>")
59
- multitool_settings << [:TOOL, format_shell_command(params[0]), true]
60
- else
61
- parser.verify_num_parameters(2, nil, "TOOL <Button Text> <Shell command> <Icon Filename (optional)> <Parameter Name #1 (optional)> <Parameter Value #1 (optional)> ...")
62
- variable_params = nil
63
- if params.length > 3
64
- raise parser.error("Unbalanced variable params for #{params[0]}") if (params.length % 2) != 1
65
- variable_params = []
66
- params[3..-1].each_slice(2) { |variable_parameter| variable_params << variable_parameter }
67
- end
68
- @items << [:TOOL, params[0], format_shell_command(params[1]), true, ConfigParser.handle_nil(params[2]), variable_params]
69
- end
47
+ parse_file(filename)
48
+ else
49
+ raise "Launcher configuration file does not exist: #{filename}"
50
+ end
51
+ end # def initialize
70
52
 
71
- when 'MULTITOOL_START'
72
- parser.verify_num_parameters(1, 2, "MULTITOOL_START <Button Text> <Icon Filename (optional)>")
73
- multitool = true
74
- multitool_text = params[0]
75
- multitool_icon_filename = ConfigParser.handle_nil(params[1])
76
- multitool_icon_filename = 'multi.png' unless multitool_icon_filename
77
- multitool_settings = []
78
-
79
- when 'MULTITOOL_END'
80
- parser.verify_num_parameters(0, 0, "MULTITOOL_END")
81
- @items << [:MULTITOOL, multitool_text, multitool_settings, true, multitool_icon_filename, nil]
82
- multitool = false
83
- multitool_text = nil
84
- multitool_icon_filename = nil
85
- multitool_settings = nil
86
-
87
- when 'DELAY'
88
- if multitool
89
- parser.verify_num_parameters(1, 1, "DELAY <Delay in seconds>")
90
- multitool_settings << [:DELAY, Float(params[0]), true]
91
- else
92
- raise parser.error("DELAY keyword only valid within MULTITOOL")
53
+ # Create a ConfigParser and parse all the lines in the configuration file
54
+ #
55
+ # @param filename [String] Name of the configuration file to parse
56
+ def parse_file(filename)
57
+ multitool = nil
58
+
59
+ # Loop over each line of the configuration file
60
+ parser = ConfigParser.new
61
+ parser.parse_file(filename) do |keyword, params|
62
+ # Handle each keyword
63
+ case keyword
64
+
65
+ when 'TOOL'
66
+ parse_tool(parser, params, multitool)
67
+
68
+ when 'MULTITOOL_START'
69
+ parser.verify_num_parameters(1, 2, "MULTITOOL_START <Button Text> <Icon Filename (optional)>")
70
+ multitool = OpenStruct.new
71
+ multitool.text = params[0]
72
+ multitool.icon_filename = ConfigParser.handle_nil(params[1])
73
+ multitool.icon_filename = 'multi.png' unless multitool.icon_filename
74
+ multitool.settings = []
75
+
76
+ when 'MULTITOOL_END'
77
+ parser.verify_num_parameters(0, 0, "MULTITOOL_END")
78
+ raise parser.error("No TOOLs defined within the MULTITOOL") if multitool.settings.select {|setting| setting[0] == :TOOL }.empty?
79
+ @items << [:MULTITOOL, multitool.text, multitool.settings, true, multitool.icon_filename, nil]
80
+ multitool = nil
81
+
82
+ when 'DELAY'
83
+ if multitool
84
+ parser.verify_num_parameters(1, 1, "DELAY <Delay in seconds>")
85
+ multitool.settings << [:DELAY, Float(params[0]), true]
86
+ else
87
+ raise parser.error("DELAY keyword only valid within MULTITOOL")
88
+ end
89
+
90
+ when 'DIVIDER'
91
+ parser.verify_num_parameters(0, 0, "DIVIDER")
92
+ @items << [:DIVIDER, nil, nil, nil, nil]
93
+
94
+ when 'LABEL'
95
+ parser.verify_num_parameters(1, 1, "LABEL <Label Text>")
96
+ @items << [:LABEL, params[0], nil, nil, nil]
97
+
98
+ when 'TOOL_FONT', 'LABEL_FONT'
99
+ usage = "#{keyword} <Font Name> <Font Size>"
100
+ parser.verify_num_parameters(2, 2, usage)
101
+ begin
102
+ @tool_font_settings = [params[0], Integer(params[1])] if keyword == 'TOOL_FONT'
103
+ @label_font_settings = [params[0], Integer(params[1])] if keyword == 'LABEL_FONT'
104
+ rescue ArgumentError
105
+ raise parser.error("#{usage} passed '#{params[0]} #{params[1]}'")
106
+ end
107
+
108
+ when 'TITLE'
109
+ parser.verify_num_parameters(1, 1, "TITLE <Title Text>")
110
+ @title = params[0]
111
+
112
+ when 'NUM_COLUMNS'
113
+ usage = "NUM_COLUMNS <Num Columns>"
114
+ parser.verify_num_parameters(1, 1, usage)
115
+ begin
116
+ @num_columns = Integer(params[0])
117
+ rescue ArgumentError
118
+ raise parser.error("#{usage} passed '#{params[0]}'")
119
+ end
120
+
121
+ when 'DONT_CAPTURE_IO'
122
+ parser.verify_num_parameters(0, 0, "DONT_CAPTURE_IO")
123
+ if multitool
124
+ if multitool.settings[-1].nil? || multitool.settings[-1][0] != :TOOL
125
+ raise parser.error("DONT_CAPTURE_IO must follow a TOOL")
93
126
  end
94
-
95
- when 'DIVIDER'
96
- parser.verify_num_parameters(0, 0, "DIVIDER")
97
- @items << [:DIVIDER, nil, nil, nil, nil]
98
-
99
- when 'LABEL'
100
- parser.verify_num_parameters(1, 1, "LABEL <Label Text>")
101
- @items << [:LABEL, params[0], nil, nil, nil]
102
-
103
- when 'TOOL_FONT'
104
- parser.verify_num_parameters(2, 2, "TOOL_FONT <Font Name> <Font Size>")
105
- @tool_font_settings = [params[0], Integer(params[1])]
106
-
107
- when 'LABEL_FONT'
108
- parser.verify_num_parameters(2, 2, "LABEL_FONT <Font Name> <Font Size>")
109
- @label_font_settings = [params[0], Integer(params[1])]
110
-
111
- when 'TITLE'
112
- parser.verify_num_parameters(1, 1, "TITLE <Title Text>")
113
- @title = params[0]
114
-
115
- when 'NUM_COLUMNS'
116
- parser.verify_num_parameters(1, 1, "NUM_COLUMNS <Num Columns>")
117
- @num_columns = params[0].to_i
118
-
119
- when 'DONT_CAPTURE_IO'
120
- parser.verify_num_parameters(0, 0, "DONT_CAPTURE_IO")
121
- if multitool
122
- if multitool_settings[-1].nil? || multitool_settings[-1][0] != :TOOL
123
- raise parser.error("DONT_CAPTURE_IO must follow a TOOL")
124
- end
125
- multitool_settings[-1][2] = false
126
- else
127
- if @items[-1].nil? || @items[-1][0] != :TOOL
128
- raise parser.error("DONT_CAPTURE_IO must follow a TOOL")
129
- end
130
- @items[-1][3] = false
127
+ multitool.settings[-1][2] = false
128
+ else
129
+ if @items[-1].nil? || @items[-1][0] != :TOOL
130
+ raise parser.error("DONT_CAPTURE_IO must follow a TOOL")
131
131
  end
132
+ @items[-1][3] = false
133
+ end
132
134
 
133
- else # UNKNOWN
134
- raise parser.error("Unknown keyword '#{keyword}'.") if keyword
135
+ else # UNKNOWN
136
+ raise parser.error("Unknown keyword '#{keyword}'.") if keyword
137
+ end # case keyword
138
+ end # parser.parse_file
139
+ end
135
140
 
136
- end # case keyword
141
+ protected
137
142
 
138
- end # parser.parse_file
143
+ def parse_tool(parser, params, multitool)
144
+ if multitool
145
+ parser.verify_num_parameters(1, 1, "TOOL <Shell command>")
146
+ multitool.settings << [:TOOL, format_shell_command(parser, params[0]), true]
147
+ else
148
+ parser.verify_num_parameters(2, nil, "TOOL <Button Text> <Shell command> <Icon Filename (optional)> <Parameter Name #1 (optional)> <Parameter Value #1 (optional)> ...")
149
+ variable_params = nil
150
+ # Determine if there are parameters which will be displayed in a GUI
151
+ # dialog when the tool starts
152
+ if params.length > 3
153
+ raise parser.error("Unbalanced variable params for #{params[0]}") if (params.length % 2) != 1
154
+ variable_params = []
155
+ params[3..-1].each_slice(2) { |variable_parameter| variable_params << variable_parameter }
156
+ end
157
+ @items << [:TOOL, params[0], format_shell_command(parser, params[1]), true, ConfigParser.handle_nil(params[2]), variable_params]
158
+ end
159
+ end
139
160
 
161
+ def format_shell_command(parser, shell_command)
162
+ formatted_command = ''
163
+ case shell_command.split[0]
164
+ when 'LAUNCH'
165
+ formatted_command = parse_launch(shell_command)
166
+ when 'LAUNCH_TERMINAL'
167
+ formatted_command = parse_launch_terminal(shell_command)
140
168
  else
141
- raise "Launcher configuration file does not exist: #{filename}"
169
+ # Nothing to do if they aren't using our keywords
170
+ formatted_command = shell_command
142
171
  end
172
+ formatted_command
173
+ end
143
174
 
144
- end # def initialize
175
+ def parse_launch(command)
176
+ split = command.split
177
+ if Kernel.is_mac? and File.exist?(File.join(USERPATH, 'tools', 'mac'))
178
+ formatted = "open tools/mac/#{split[1]}.app --args #{split[2..-1].join(' ')}".strip
179
+ else
180
+ formatted = "RUBYW tools/#{split[1]} #{split[2..-1].join(' ')}".strip
181
+ end
182
+ formatted
183
+ end
184
+
185
+ def parse_launch_terminal(command)
186
+ split = command.split
187
+ if Kernel.is_mac?
188
+ formatted = "osascript -e 'tell application \"Terminal\" to do script \"cd #{File.expand_path(USERPATH)} && ruby tools/#{split[1]} #{split[2..-1].join(' ')}\"' -e 'return'"
189
+ elsif Kernel.is_windows?
190
+ formatted = "start ruby tools/#{split[1]} #{split[2..-1].join(' ')}".strip
191
+ else
192
+ formatted = "gnome-terminal -e \"ruby tools/#{split[1]} #{split[2..-1].join(' ')}\""
193
+ end
145
194
 
146
- def format_shell_command(shell_command)
147
195
  if Kernel.is_windows?
148
196
  rubyw_sub = 'rubyw'
149
197
  else
150
198
  rubyw_sub = 'ruby'
151
199
  end
152
200
 
153
- split_command = shell_command.split
154
- if split_command[0] == 'LAUNCH'
155
- if Kernel.is_mac? and File.exist?(File.join(USERPATH, 'tools', 'mac'))
156
- shell_command = "open tools/mac/#{split_command[1]}.app --args #{split_command[2..-1].join(' ')}"
157
- else
158
- shell_command = "RUBYW tools/#{split_command[1]} #{split_command[2..-1].join(' ')}"
159
- end
160
- elsif split_command[0] == 'LAUNCH_TERMINAL'
161
- if Kernel.is_mac?
162
- shell_command = "osascript -e 'tell application \"Terminal\" to do script \"cd #{File.expand_path(USERPATH)} && ruby tools/#{split_command[1]} #{split_command[2..-1].join(' ')}\"' -e 'return'"
163
- elsif Kernel.is_windows?
164
- shell_command = "start ruby tools/#{split_command[1]} #{split_command[2..-1].join(' ')}"
165
- else
166
- shell_command = "gnome-terminal -e \"ruby tools/#{split_command[1]} #{split_command[2..-1].join(' ')}\""
167
- end
168
- end
169
- shell_command.gsub!('RUBYW', rubyw_sub)
170
- shell_command
201
+ formatted.gsub!('RUBYW', rubyw_sub)
202
+ formatted
171
203
  end
172
204
 
173
205
  end # class LauncherConfig