Class: Replay

Inherits:
Qt::MainWindow
  • Object
show all
Defined in:
lib/roby/log/gui/replay.rb

Constant Summary collapse

KEY_GOTO =
Qt::KeySequence.new('g')
BASE_TIME_SLICE =
0.5

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeReplay

Returns a new instance of Replay.



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/roby/log/gui/replay.rb', line 53

def initialize
  super()
  @play_speed    = 1.0
  @play_now      = nil
  @logdir        = nil
  @goto          = nil
  @initial_setup = []
  @bookmarks     = Hash.new

  # Create the vertical layout for this window
  central_widget = Qt::Widget.new(self)
  self.central_widget = central_widget
  layout = Qt::VBoxLayout.new(central_widget)
  layout.spacing = 6
  layout.margin  = 0

  # Add support for the data streams and display setup
  @streams = Array.new
  @streams_model = OfflineStreamListModel.new(streams)
  displays_holder = Qt::Widget.new(central_widget)
  layout.add_widget displays_holder
  @ui_displays = Ui_DataDisplays.new
  ui_displays.setupUi(displays_holder)
  ui_displays.streams.model = streams_model
  connect(ui_displays.add_stream, SIGNAL("clicked()"), self, SLOT("add_stream()"))
  connect(ui_displays.remove_stream, SIGNAL("clicked()"), self, SLOT("remove_stream()"))
  connect(ui_displays.display_add, SIGNAL("clicked()"), self, SLOT("add_display()"))

  controls_holder = Qt::Widget.new(central_widget)
  @ui_controls = Ui::ReplayControls.new
  ui_controls.setupUi(self, controls_holder)
  layout.add_widget controls_holder
end

Instance Attribute Details

#bookmarksObject (readonly)

The set of bookmarks as a name => time map



40
41
42
# File 'lib/roby/log/gui/replay.rb', line 40

def bookmarks
  @bookmarks
end

#first_sampleObject (readonly)

Time of the first known sample



111
112
113
# File 'lib/roby/log/gui/replay.rb', line 111

def first_sample
  @first_sample
end

#initial_setupObject

A set of procs which are to be called to set up the display



51
52
53
# File 'lib/roby/log/gui/replay.rb', line 51

def initial_setup
  @initial_setup
end

#initial_timeObject

Set to a time at which we should go to



49
50
51
# File 'lib/roby/log/gui/replay.rb', line 49

def initial_time
  @initial_time
end

#last_sampleObject (readonly)

Time of the last known sample



113
114
115
# File 'lib/roby/log/gui/replay.rb', line 113

def last_sample
  @last_sample
end

#log_dirObject

The log directory, or Roby.app.log_dir



47
48
49
# File 'lib/roby/log/gui/replay.rb', line 47

def log_dir
  @log_dir
end

#play_nowObject

True if we should start playing right away



45
46
47
# File 'lib/roby/log/gui/replay.rb', line 45

def play_now
  @play_now
end

#play_speedObject

Returns the value of attribute play_speed.



162
163
164
# File 'lib/roby/log/gui/replay.rb', line 162

def play_speed
  @play_speed
end

#play_timerObject (readonly)

Returns the value of attribute play_timer.



162
163
164
# File 'lib/roby/log/gui/replay.rb', line 162

def play_timer
  @play_timer
end

#streamsObject (readonly)

Returns the value of attribute streams.



30
31
32
# File 'lib/roby/log/gui/replay.rb', line 30

def streams
  @streams
end

#streams_modelObject (readonly)

Returns the value of attribute streams_model.



31
32
33
# File 'lib/roby/log/gui/replay.rb', line 31

def streams_model
  @streams_model
end

#timeObject (readonly)

Returns the value of attribute time.



153
154
155
# File 'lib/roby/log/gui/replay.rb', line 153

def time
  @time
end

#ui_controlsObject (readonly)

The widget which hold the replay controls (play, pause, …)



37
38
39
# File 'lib/roby/log/gui/replay.rb', line 37

def ui_controls
  @ui_controls
end

#ui_displaysObject (readonly)

The widget which controls the data stream => display mapping, and display control



35
36
37
# File 'lib/roby/log/gui/replay.rb', line 35

def ui_displays
  @ui_displays
end

Class Method Details

.setup(argv) {|replay, parser, args| ... } ⇒ Object

Yields:



265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'lib/roby/log/gui/replay.rb', line 265

def self.setup(argv)
  replay = self.new

  parser = OptionParser.new do |opt|
 Ui_DataDisplays::DISPLAYS.each_value do |config_ui|
    config_ui.setup_optparse(opt, replay)
 end

 opt.on("--logdir=DIR", String, "the log directory in which we initialize the data streams") do |dir|
    replay.log_dir = dir
 end
 opt.on("--play", "start playing after loading the event log") do 
    replay.play_now = true
 end

 opt.on("--speed=SPEED", Integer, "play speed") do |speed|
    replay.play_speed = speed
 end
 opt.on("--goto=TIME", String, "go to TIME before playing normally. Time is given relatively to the simulation start") do |goto| 
    replay.initial_time = goto
 end
 opt.on('--bookmarks=FILE', String, "load the bookmarks in FILE") do |file|
    replay.ui_controls.load_bookmarks(file)
 end
  end
  args = argv.dup
  parser.parse!(args)

  yield(replay, parser, args) if block_given?

  replay
end

Instance Method Details

#add_display(kind = nil) ⇒ Object



260
261
262
# File 'lib/roby/log/gui/replay.rb', line 260

def add_display(kind = nil)
  ui_displays.add_display(streams_model, kind)
end

#add_stream(stream = nil) ⇒ Object



249
250
251
# File 'lib/roby/log/gui/replay.rb', line 249

def add_stream(stream = nil)
  streams_model.add_new(stream)
end

#displayed_streamsObject



104
105
106
107
108
# File 'lib/roby/log/gui/replay.rb', line 104

def displayed_streams
  streams.find_all do |s| 
 s.displayed?
  end
end

#next_timeObject



155
156
157
158
159
# File 'lib/roby/log/gui/replay.rb', line 155

def next_time
  displayed_streams.
 map { |s| s.next_time }.
 compact.min 
end

#playObject



163
164
165
166
167
168
169
# File 'lib/roby/log/gui/replay.rb', line 163

def play
  seek(nil) unless first_sample

  @play_timer = Qt::Timer.new(self)
  connect(play_timer, SIGNAL("timeout()"), self, SLOT("play_step_timer()"))
  play_timer.start(Integer(time_slice * 1000))
end

#play_stepObject



179
180
181
182
# File 'lib/roby/log/gui/replay.rb', line 179

def play_step
  seek(nil) unless first_sample
    play_until(next_time) 
end

#play_step_timerObject



184
185
186
187
# File 'lib/roby/log/gui/replay.rb', line 184

def play_step_timer
  start = Time.now
  play_until(time + time_slice * play_speed)
end

#play_until(max_time, integrate = true) ⇒ Object



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/roby/log/gui/replay.rb', line 190

def play_until(max_time, integrate = true)
  start_at = Time.now
  displayed_streams.inject(timeline = []) do |timeline, s| 
 if s.next_time
    timeline << [s.next_time, s]
 end
 timeline
  end

  if timeline.empty?
 stop
 return
  end

  updated_streams = Set.new

  timeline.sort_by { |t, _| t }
  while !timeline.empty? && (timeline[0][0] - max_time) < 0.001
 @time, stream = timeline.first

 stream.advance
 stream.clear_integrated unless integrate
 updated_streams << stream
 if next_time = stream.next_time
    timeline[0] = [next_time, stream]
 else
    timeline.shift
 end
 timeline.sort_by { |t, _| t }
  end

  replayed = Time.now

  updated_streams.each do |stream|
 stream.display
  end

  STDERR.puts "replay #{replayed - start_at}, display #{Time.now-replayed}"

  if timeline.empty? then stop
  else @time = max_time
  end

  if time > last_sample
 @last_sample = time

 time_display = time.to_i
 if ui_controls.progress.maximum < time_display
    ui_controls.progress.maximum = (first_sample + (last_sample - first_sample) * 4 / 3).to_i
 end
  end
  update_time_display

rescue Exception => e
  message = "<html>#{Qt.escape(e.message)}<ul><li>#{e.backtrace.join("</li><li>")}</li></ul></html>"
  Qt::MessageBox.critical self, "Replay failure", message
  stop
end

#remove_streamObject



254
255
256
257
# File 'lib/roby/log/gui/replay.rb', line 254

def remove_stream
  index = ui_displays.streams.current_index.row
  streams.removeRow(index, Qt::ModelIndex.new)
end

#seek(time, integrate = true) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/roby/log/gui/replay.rb', line 115

def seek(time, integrate = true)
  if time && !first_sample
 seek(nil) 
  elsif time && first_sample && time < first_sample
 time = nil
  end

  displayed_streams.each { |s| s.prepare_seek(time) }
  if !time || time == Time.at(0)
 min, max = displayed_streams.inject([nil, nil]) do |(min, max), stream|
    stream_min, stream_max = stream.range
    if !min || stream_min < min
  min = stream_min
    end
    if !max || stream_max > max
  max = stream_max
    end
    [min, max]
 end

 @first_sample = @time = min
 @last_sample  = max

 ui_controls.progress.minimum = min.to_i
 ui_controls.progress.maximum = max.to_i
 ui_controls.update_bookmarks_menu
  else
 play_until time, integrate
  end

  update_time_display
end

#setupObject



298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/roby/log/gui/replay.rb', line 298

def setup
  initial_setup.each do |prc|
 prc.call(self)
  end

  show
  if initial_time
 seek(nil)

 seek_time = if initial_time[0] == ?@
   Time.from_hms(initial_time[1..-1])
      else
   first_sample + (Time.from_hms(initial_time) - Time.at(0))
      end
 seek(seek_time, false)
  end

  if play_now
 ui_controls.play.checked = true
  end
end

#stopObject



171
172
173
174
175
176
177
# File 'lib/roby/log/gui/replay.rb', line 171

def stop
  if play_timer
 ui_controls.play.checked = false
 play_timer.stop
 @play_timer = nil
  end
end

#time_sliceObject



96
97
98
99
100
101
102
# File 'lib/roby/log/gui/replay.rb', line 96

def time_slice
  if play_speed < 1
 BASE_TIME_SLICE / play_speed
  else
 BASE_TIME_SLICE
  end
end

#update_time_displayObject



148
149
150
151
# File 'lib/roby/log/gui/replay.rb', line 148

def update_time_display
  ui_controls.time_lcd.display(((self.time - first_sample) * 1000.0).round / 1000.0)
  ui_controls.progress.value = self.time.to_i
end