Class: Cosmos::Screen

Inherits:
Qt::MainWindow
  • Object
show all
Includes:
ClassificationBanner
Defined in:
lib/cosmos/tools/tlm_viewer/screen.rb

Defined Under Namespace

Classes: Widgets

Constant Summary collapse

@@open_screens =

The list of all open screens so they can be shutdown when close_all_screens is called

[]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(full_name, filename_or_screen_def, notify_on_close = nil, mode = :REALTIME, x_pos = nil, y_pos = nil, original_target_name = nil, substitute = nil, force_substitute = false, single_screen = false, local_binding = nil) ⇒ Screen

Returns a new instance of Screen.



232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 232

def initialize(full_name, filename_or_screen_def, notify_on_close = nil, mode = :REALTIME, x_pos = nil, y_pos = nil, original_target_name = nil, substitute = nil, force_substitute = false, single_screen = false, local_binding = nil)
  super(nil)
  # The full name of the widget which goes in the title
  @full_name = full_name
  # The method 'notify' will be called on this object if it is given
  @notify_on_close = notify_on_close
  # X position to display the screen
  @x_pos = x_pos
  # Y position to display the screen
  @y_pos = y_pos
  # Original target name where this screen is defined
  @original_target_name = original_target_name.to_s.upcase
  # Substitute target name to use when actually retrieving data
  @substitute = substitute
  # Whether to automatically substitute the target name when requesting
  # telemetry
  @force_substitute = force_substitute
  # Whether this screen was launched as a command line option to be
  # displayed as a stand alone screen and not launched as a part of the
  # regular TlmViewer application
  @single_screen = single_screen
  # Binding for use with LOCAL LOCAL
  @local_binding = local_binding

  # Read the application wide stylesheet if it exists
  app_style = File.join(Cosmos::USERPATH, 'config', 'tools', 'application.css')
  setStyleSheet(File.read(app_style)) if File.exist? app_style

  @replay_flag = nil
  @widgets = Widgets.new(self, mode, @local_binding)
  @window = process(filename_or_screen_def)
  @@open_screens << self if @window

  # Add a banner based on system configuration
  add_classification_banner
end

Instance Attribute Details

#full_nameObject

Returns the value of attribute full_name.



26
27
28
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 26

def full_name
  @full_name
end

#heightObject

Returns the value of attribute height.



26
27
28
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 26

def height
  @height
end

#original_target_nameObject

Returns the value of attribute original_target_name.



26
27
28
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 26

def original_target_name
  @original_target_name
end

#replay_flagObject

Returns the value of attribute replay_flag.



26
27
28
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 26

def replay_flag
  @replay_flag
end

#widthObject

Returns the value of attribute width.



26
27
28
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 26

def width
  @width
end

#windowObject

Returns the value of attribute window.



26
27
28
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 26

def window
  @window
end

Class Method Details

.close_all_screens(closer) ⇒ Object



557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 557

def self.close_all_screens(closer)
  Widgets.closing_all = true
  screens = @@open_screens.clone
  screens.each do |screen|
    screen.window.graceful_kill if screen.window
  end
  screens.each do |screen|
    begin
      screen.window.close
    rescue
      # Screen probably already closed - continue
    end
  end
  Widgets.closing_all = false
end

.open_screensObject



553
554
555
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 553

def self.open_screens
  @@open_screens
end

.update_replay_modeObject



573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 573

def self.update_replay_mode
  screens = @@open_screens.clone
  replay_mode = get_replay_mode()
  screens.each do |screen|
    begin
      if replay_mode
        screen.replay_flag.show if screen.replay_flag
      else
        screen.replay_flag.hide if screen.replay_flag
      end
    rescue
      # Oh well
    end
  end
end

Instance Method Details

#closeObject



544
545
546
547
548
549
550
551
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 544

def close
  Qt.execute_in_main_thread(true) do
    if @window
      super()
      @window = nil
    end
  end
end

#closeEvent(event) ⇒ Object



506
507
508
509
510
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 506

def closeEvent(event)
  super(event)
  @@open_screens.delete(self)
  shutdown()
end

#get_named_widget(widget_name) ⇒ Object



528
529
530
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 528

def get_named_widget(widget_name)
  @widgets.named[widget_name.upcase]
end

#get_target_name(target_name) ⇒ Object



532
533
534
535
536
537
538
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 532

def get_target_name(target_name)
  if @substitute and (@original_target_name == target_name.upcase or @force_substitute)
    @substitute
  else
    target_name
  end
end

#graceful_killObject



540
541
542
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 540

def graceful_kill
  @widgets.graceful_kill
end

#modeObject



277
278
279
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 277

def mode
  @widgets.mode
end

#named_widgetsObject



273
274
275
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 273

def named_widgets
  @widgets.named
end

#process(filename_or_screen_def) ⇒ Object



281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 281

def process(filename_or_screen_def)
  layout_stack = []
  layout_stack[0] = nil

  top_widget = nil
  current_widget = nil
  global_settings = {}
  global_subsettings = {}

  if File.exist?(filename_or_screen_def) or !filename_or_screen_def.to_s.index("SCREEN")
    tempfile = false
    filename = filename_or_screen_def
  else
    tempfile = Tempfile.new('screen')
    tempfile.write(filename_or_screen_def)
    tempfile.close
    filename = tempfile.path
  end

  begin
    parser = ConfigParser.new("http://cosmosrb.com/docs/screens/")
    parser.instance_variable_set(:@original_target_name, @original_target_name)
    name = @substitute ? @substitute : @original_target_name
    parser.instance_variable_set(:@target_name, name)
    parser.parse_file(filename) do |keyword, parameters|

      if keyword
        case keyword
        when 'SCREEN'
          parser.verify_num_parameters(3, 4, "#{keyword} <Width or AUTO> <Height or AUTO> <Polling Period> <FIXED>")
          @width = parameters[0].to_i
          @height = parameters[1].to_i
          @widgets.polling_period = parameters[2].to_f
          if parameters.length == 4
            @fixed = true
          else
            @fixed = false
          end

          setWindowTitle(@full_name)
          top_widget = Qt::Widget.new()
          setCentralWidget(top_widget)
          frame = Qt::VBoxLayout.new()
          top_widget.setLayout(frame)

          @replay_flag = Qt::Label.new("Replay Mode")
          @replay_flag.setStyleSheet("background:green;color:white;padding:5px;font-weight:bold;")
          frame.addWidget(@replay_flag)
          @replay_flag.hide unless get_replay_mode()

          layout_stack[0] = frame
          Cosmos.load_cosmos_icon if @single_screen
        when 'END'
          parser.verify_num_parameters(0, 0, "#{keyword}")
          current_widget = layout_stack.pop()
          # Call the complete method to allow layout widgets to do things
          # once all their children have been added
          # Need the respond_to? to protect against the top level widget
          # added by the SCREEN code above. It adds a Qt::VBoxLayout
          # to the stack and that class doesn't have a complete method.
          current_widget.complete() if current_widget.respond_to? :complete
        when 'SETTING'
          next unless current_widget
          parser.verify_num_parameters(1, nil, "#{keyword} <Setting Name> <Setting Values... (optional)>")
          if parameters.length > 1
            current_widget.set_setting(parameters[0], parameters[1..-1])
          else
            current_widget.set_setting(parameters[0], [])
          end
        when 'SUBSETTING'
          next unless current_widget
          parser.verify_num_parameters(2, nil, "#{keyword} <Widget Index (0..?)> <Setting Name> <Setting Values... (optional)>")
          if parameters.length > 2
            current_widget.set_subsetting(parameters[0], parameters[1], parameters[2..-1])
          else
            current_widget.set_subsetting(parameters[0], parameters[1], [])
          end
        when 'GLOBAL_SETTING'
          parser.verify_num_parameters(2, nil, "#{keyword} <Widget Type> <Setting Name> <Setting Values... (optional)>")
          klass = Cosmos.require_class(parameters[0].to_s.downcase + '_widget')
          global_settings[klass] ||= []
          global_settings[klass] << parameters[1..-1]
        when 'GLOBAL_SUBSETTING'
          parser.verify_num_parameters(3, nil, "#{keyword} <Widget Type> <Widget Index (0..?)> <Setting Name> <Setting Values... (optional)>")
          klass = Cosmos.require_class(parameters[0].to_s.downcase + '_widget')
          global_subsettings[klass] ||= []
          global_subsettings[klass] << [parameters[1]].concat(parameters[2..-1])
        when 'STAY_ON_TOP'
          setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint)
        else
          current_widget = process_widget(parser, keyword, parameters, layout_stack, global_settings, global_subsettings)
        end # case keyword
      end # if keyword

    end # parser.parse_file
  rescue Exception => err
    begin
      raise $!, "In file #{filename} at line #{parser.line_number}:\n\n#{$!}", $!.backtrace
    rescue Exception => err
      ExceptionDialog.new(self, err, "Screen #{File.basename(filename)}", false)
    end
    shutdown()
    return nil
  ensure
    tempfile.unlink if tempfile
  end

  unless @widgets.invalid.empty?
    Qt::MessageBox.information(self, "Screen #{@full_name}", "In #{filename}, the following telemetry items could not be created: \n" + @widgets.invalid.join("\n"))
  end

  # Process all settings before we show the screen
  @widgets.process_settings

  if @width > 0 and @height > 0
    resize(@width, @height)
  elsif @width <= 0 and height > 0
    resize(self.width, @height)
  elsif @width > 0 and height <= 0
    resize(@width, self.height)
  end
  if @fixed
    setWindowFlags(windowFlags() | Qt::MSWindowsFixedSizeDialogHint)
    setFixedSize(self.width, self.height)
  end

  if @x_pos or @y_pos
    x = @x_pos || 0
    y = @y_pos || 0
    move(x,y)
  end
  show()

  # Start the update thread now that the screen is displayed
  @widgets.start_updates()

  return self
end

#process_widget(parser, keyword, parameters, layout_stack, global_settings, global_subsettings) ⇒ Object



420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 420

def process_widget(parser, keyword, parameters, layout_stack, global_settings, global_subsettings)
  widget_name = nil
  if keyword == 'NAMED_WIDGET'
    parser.verify_num_parameters(2, nil, "#{keyword} <Widget Name> <Widget Type> <Widget Settings... (optional)>")
    widget_name = parameters[0].upcase
    keyword = parameters[1].upcase
    parameters = parameters[2..-1]
  else
    parser.verify_num_parameters(0, nil, "#{keyword} <Widget Settings... (optional)>")
  end

  widget = nil
  klass = Cosmos.require_class(keyword.downcase + '_widget')
  if klass.takes_value?
    parser.verify_num_parameters(3, nil, "#{keyword} <Target Name> <Packet Name> <Item Name> <Widget Settings... (optional)>")
    begin
      if @substitute and (@original_target_name == parameters[0].upcase or @force_substitute)
        if @substitute != 'LOCAL' or parameters[1] != 'LOCAL'
          System.telemetry.packet_and_item(@substitute, parameters[1], parameters[2])
        end
        widget = klass.new(layout_stack[-1], @substitute, *parameters[1..(parameters.length - 1)])
      else
        if parameters[0] != 'LOCAL' or parameters[1] != 'LOCAL'
          System.telemetry.packet_and_item(*parameters[0..2])
        end
        widget = klass.new(layout_stack[-1], *parameters)
      end
    rescue => err
      @widgets.invalid << "#{parser.line_number}: #{parameters.join(" ").strip} due to #{err.message}"
      return nil
    end
  else
    if parameters[0] != nil
      widget = klass.new(layout_stack[-1], *parameters)
    else
      widget = klass.new(layout_stack[-1])
    end
  end

  # Assign screen
  widget.screen = self

  # Assign polling period
  if @widgets.polling_period
    widget.polling_period = @widgets.polling_period
  else
    raise "SCREEN keyword must appear before any widgets"
  end

  # Add to Layout Stack if Necessary
  if klass.layout_manager?
    layout_stack.push(widget)
  end

  # Apply Global Settings
  global_settings.each do |global_klass, settings|
    if widget.class == global_klass
      settings.each do |setting|
        if setting.length > 1
          widget.set_setting(setting[0], setting[1..-1])
        else
          widget.set_setting(setting[0], [])
        end
      end
    end
  end

  # Apply Global Subsettings
  global_subsettings.each do |global_klass, settings|
    if widget.class == global_klass
      settings.each do |setting|
        widget_index = setting[0]
        if setting.length > 2
          widget.set_subsetting(widget_index, setting[1], setting[2..-1])
        else
          widget.set_subsetting(widget_index, setting[1], [])
        end
      end
    end
  end

  @widgets.add_widget(klass, parameters, widget, widget_name, @substitute, @original_target_name, @force_substitute)

  return widget
end

#shutdownObject



512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 512

def shutdown
  # Shutdown Value Gathering Thread
  @widgets.shutdown

  # Notify Owner if Necessary
  @notify_on_close.notify(self) if @notify_on_close

  if @single_screen
    QtTool.restore_io
  end

  self.dispose

  @window = nil
end

#widgetsObject



269
270
271
# File 'lib/cosmos/tools/tlm_viewer/screen.rb', line 269

def widgets
  @widgets.widgets
end