Class: Roby::GUI::PlanRebuilderWidget
- Defined in:
- lib/roby/gui/plan_rebuilder_widget.rb
Overview
This widget displays information about the event history in a list, allowing to switch between the “important events” in this history
Defined Under Namespace
Classes: Snapshot
Constant Summary collapse
- DEFAULT_REMOTE_POLL_PERIOD =
0.05
Instance Attribute Summary collapse
-
#current_plan ⇒ Object
readonly
The current plan managed by the widget.
-
#history ⇒ Object
readonly
The history, as a mapping from the cycle index to a (time, snapshot, list_item) triple.
-
#last_cycle ⇒ Integer
readonly
The last processed cycle.
-
#list ⇒ Object
readonly
The list used to display all the cycles in the history.
-
#logfile ⇒ DRoby::Logfile::Reader
readonly
The underlying log file.
-
#plan_rebuilder ⇒ Object
readonly
The PlanRebuilder object we use to process the log data.
Class Method Summary collapse
Instance Method Summary collapse
- #add_missing_cycles(count) ⇒ Object
- #analyze(until_cycle: nil) ⇒ Object
- #append_to_history ⇒ Object
- #apply(snapshot) ⇒ Object
-
#connect(client, options = Hash.new) ⇒ Object
Displays the data incoming from
client. -
#connection_failed(e, client, options) ⇒ Object
Called when the connection to the log server failed, either because it has been closed or because creating the connection failed.
-
#current_time ⇒ Object
The end time of the last received cycle.
- #currentItemChanged(new_item, previous_item) ⇒ Object
- #cycle_start_time ⇒ Object
- #disconnect ⇒ Object
-
#display_time ⇒ Object
The time of the currently selected snapshot.
-
#initialize(parent, plan_rebuilder) ⇒ PlanRebuilderWidget
constructor
A new instance of PlanRebuilderWidget.
-
#job_placeholder_of(task, cycle) ⇒ Object
Returns the job information for the given task in the given cycle.
-
#open(filename) ⇒ Object
Opens
filenameand reads the data from there. - #push_cycle(snapshot: true) ⇒ Object
- #redraw(time = plan_rebuilder.current_time) ⇒ Object
- #seek(time) ⇒ Object
-
#start_time ⇒ Object
The start time of the first received cycle.
-
#tasks_info ⇒ (Set<Roby::Task>,Hash<Roby::Task,Roby::Task>)
Info about all tasks known within the stored history.
-
#tasks_info_of_snapshot(cycle) ⇒ Set<Roby::Task>
Returns the set of tasks that are present in the given snapshot.
Constructor Details
#initialize(parent, plan_rebuilder) ⇒ PlanRebuilderWidget
Returns a new instance of PlanRebuilderWidget.
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 35 def initialize(parent, plan_rebuilder) super(parent) @list = Qt::ListWidget.new(self) @layout = Qt::VBoxLayout.new(self) def list.mouseReleaseEvent(event) if event. == Qt::RightButton event.accept = Qt::Menu.new inspect_cycle = .add_action("Step-by-step from there") if action = .exec(event.globalPos) cycle_index = currentItem.data(Qt::UserRole).toInt = self.parentWidget stepping = Stepping.new( , .current_plan, .logfile.dup, cycle_index) stepping.exec end end end @layout.(@btn_create_display) @history = Hash.new @logfile = nil # set by #open @plan_rebuilder = plan_rebuilder @current_plan = DRoby::RebuiltPlan.new @layout.(list) Qt::Object.connect(list, SIGNAL('currentItemChanged(QListWidgetItem*,QListWidgetItem*)'), self, SLOT('currentItemChanged(QListWidgetItem*,QListWidgetItem*)')) end |
Instance Attribute Details
#current_plan ⇒ Object (readonly)
The current plan managed by the widget
18 19 20 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 18 def current_plan @current_plan end |
#history ⇒ Object (readonly)
The history, as a mapping from the cycle index to a (time, snapshot, list_item) triple
14 15 16 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 14 def history @history end |
#last_cycle ⇒ Integer (readonly)
The last processed cycle
24 25 26 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 24 def last_cycle @last_cycle end |
#list ⇒ Object (readonly)
The list used to display all the cycles in the history
11 12 13 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 11 def list @list end |
#logfile ⇒ DRoby::Logfile::Reader (readonly)
The underlying log file
21 22 23 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 21 def logfile @logfile end |
#plan_rebuilder ⇒ Object (readonly)
The PlanRebuilder object we use to process the log data
16 17 18 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 16 def plan_rebuilder @plan_rebuilder end |
Class Method Details
.analyze(plan_rebuilder, logfile, until_cycle: nil) ⇒ Object
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 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 213 def self.analyze(plan_rebuilder, logfile, until_cycle: nil) start_time, end_time = logfile.index.range start = Time.now puts "log file is #{(end_time - start_time).ceil}s long" dialog = Qt::ProgressDialog.new("Analyzing log file", "Quit", 0, (end_time - start_time)) dialog.setWindowModality(Qt::WindowModal) dialog.show while !logfile.eof? && (!until_cycle || !plan_rebuilder.cycle_index || plan_rebuilder.cycle_index < until_cycle) data = logfile.load_one_cycle plan_rebuilder.process_one_cycle(data) if block_given? needs_snapshot = (plan_rebuilder.has_structure_updates? || plan_rebuilder.has_event_propagation_updates?) yield(needs_snapshot, data) end plan_rebuilder.clear_integrated dialog.setValue(plan_rebuilder.cycle_start_time - start_time) if dialog.wasCanceled Kernel.raise Interrupt end end dialog.dispose puts "analyzed log file in %.2fs" % [Time.now - start] end |
Instance Method Details
#add_missing_cycles(count) ⇒ Object
117 118 119 120 121 122 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 117 def add_missing_cycles(count) item = Qt::ListWidgetItem.new(list) item.setBackground(Qt::Brush.new(Qt::Color::fromHsv(33, 111, 255))) item.flags = Qt::NoItemFlags item.text = "[#{count} cycles missing]" end |
#analyze(until_cycle: nil) ⇒ Object
241 242 243 244 245 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 241 def analyze(until_cycle: nil) PlanRebuilderWidget.analyze(plan_rebuilder, logfile, until_cycle: until_cycle) do push_cycle end end |
#append_to_history ⇒ Object
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 126 def append_to_history snapshot = Snapshot.new plan_rebuilder.stats.dup, DRoby::RebuiltPlan.new snapshot.plan.merge(plan_rebuilder.plan) if @last_snapshot snapshot.plan.dedupe(@last_snapshot.plan) end @last_snapshot = snapshot cycle = snapshot.stats[:cycle_index] time = Time.at(*snapshot.stats[:start]) + snapshot.stats[:actual_start] item = Qt::ListWidgetItem.new(list) item.text = "@#{cycle} - #{Roby.format_time(time)}" item.setData(Qt::UserRole, Qt::Variant.new(cycle)) history[cycle] = [time, snapshot, item] emit addedSnapshot(cycle) end |
#apply(snapshot) ⇒ Object
153 154 155 156 157 158 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 153 def apply(snapshot) @display_time = Time.at(*snapshot.stats[:start]) + snapshot.stats[:end] @current_plan.clear @current_plan.merge(snapshot.plan) emit appliedSnapshot(Qt::DateTime.new(@display_time)) end |
#connect(client, options = Hash.new) ⇒ Object
Displays the data incoming from client
client is assumed to be a DRoby::Logfile::Client instance
update_period is, in seconds, the period at which the display will check whether there is new data on the port.
280 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 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 280 def connect(client, = Hash.new) = Kernel. , port: DRoby::Logfile::Server::DEFAULT_PORT, update_period: DEFAULT_REMOTE_POLL_PERIOD if client.respond_to?(:to_str) self.window_title = "roby-display: #{client}" emit sourceChanged begin hostname = client client = DRoby::Logfile::Client.new(client, [:port]) rescue Exception => e connection_failed(e, client, ) return false end end @client = client client.add_listener do |data| plan_rebuilder.clear_integrated plan_rebuilder.process_one_cycle(data) time = push_cycle emit liveUpdate(Qt::DateTime.new(time)) cycle = plan_rebuilder.cycle_index time = plan_rebuilder.cycle_start_time emit info("@#{cycle} - #{time.strftime('%H:%M:%S.%3N')}") end @connection_pull = timer = Qt::Timer.new(self) timer.connect(SIGNAL('timeout()')) do begin client.read_and_process_pending(max: 0.1) rescue Exception => e disconnect emit warn("Disconnected: #{e.message}") puts e. puts " " + e.backtrace.join("\n ") if hostname connect(hostname, ) end end end timer.start(Integer([:update_period] * 1000)) return true end |
#connection_failed(e, client, options) ⇒ Object
Called when the connection to the log server failed, either because it has been closed or because creating the connection failed
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 250 def connection_failed(e, client, ) @connection_error = e emit warn("connection failed: #{e.message}") if @reconnection_timer return end @reconnection_timer = Qt::Timer.new(self) @connect_client = client.dup = .dup @reconnection_timer.connect(SIGNAL('timeout()')) do puts "trying to reconnect to #{@connect_client} #{@connect_options}" if connect(@connect_client, ) emit info("Connected") @reconnection_timer.stop @reconnection_timer.dispose @reconnection_timer = nil end end @reconnection_timer.start(1000) end |
#current_time ⇒ Object
The end time of the last received cycle
345 346 347 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 345 def current_time plan_rebuilder.current_time end |
#currentItemChanged(new_item, previous_item) ⇒ Object
148 149 150 151 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 148 def currentItemChanged(new_item, previous_item) data = new_item.data(Qt::UserRole).toInt apply(history[data][1]) end |
#cycle_start_time ⇒ Object
335 336 337 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 335 def cycle_start_time plan_rebuilder.cycle_start_time end |
#disconnect ⇒ Object
328 329 330 331 332 333 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 328 def disconnect @client.disconnect @connection_pull.stop @connection_pull.dispose @connection_pull = nil end |
#display_time ⇒ Object
The time of the currently selected snapshot
350 351 352 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 350 def display_time @display_time || start_time end |
#job_placeholder_of(task, cycle) ⇒ Object
Returns the job information for the given task in the given cycle
108 109 110 111 112 113 114 115 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 108 def job_placeholder_of(task, cycle) if task.kind_of?(Roby::Interface::Job) _, snapshot, * = history[cycle] task. enum_parent_objects(snapshot.relations[Roby::TaskStructure::PlannedBy]). first end end |
#open(filename) ⇒ Object
Opens filename and reads the data from there
201 202 203 204 205 206 207 208 209 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 201 def open(filename) @logfile = DRoby::Logfile::Reader.open(filename) self.window_title = "roby-display: #{filename}" emit sourceChanged analyze if !history.empty? apply(history[history.keys.sort.first][1]) end end |
#push_cycle(snapshot: true) ⇒ Object
180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 180 def push_cycle(snapshot: true) cycle = plan_rebuilder.stats[:cycle_index] if last_cycle && (cycle != last_cycle + 1) add_missing_cycles(cycle - last_cycle - 1) end needs_snapshot = (plan_rebuilder.has_structure_updates? || plan_rebuilder.has_event_propagation_updates?) if snapshot && needs_snapshot append_to_history end @last_cycle = cycle Time.at(*plan_rebuilder.stats[:start]) + plan_rebuilder.stats[:actual_start] end |
#redraw(time = plan_rebuilder.current_time) ⇒ Object
196 197 198 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 196 def redraw(time = plan_rebuilder.current_time) emit appliedSnapshot(Qt::DateTime.new(time)) end |
#seek(time) ⇒ Object
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 160 def seek(time) # Convert from QDateTime to allow seek() to be a slot if time.kind_of?(Qt::DateTime) time = Time.at(Float(time.toMSecsSinceEpoch) / 1000) end result = nil history.each_value do |cycle_time, snapshot, item| if cycle_time < time if !result || result[0] < cycle_time result = [cycle_time, snapshot] end end end if result apply(result[1]) end end |
#start_time ⇒ Object
The start time of the first received cycle
340 341 342 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 340 def start_time plan_rebuilder.start_time end |
#tasks_info ⇒ (Set<Roby::Task>,Hash<Roby::Task,Roby::Task>)
Info about all tasks known within the stored history
77 78 79 80 81 82 83 84 85 86 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 77 def tasks_info all_tasks = Set.new all_job_info = Hash.new history.each_key do |cycle_index| tasks, job_info = tasks_info_of_snapshot(cycle_index) all_tasks.merge(tasks) all_job_info.merge!(job_info) end return all_tasks, all_job_info end |
#tasks_info_of_snapshot(cycle) ⇒ Set<Roby::Task>
Returns the set of tasks that are present in the given snapshot
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 91 def tasks_info_of_snapshot(cycle) _, snapshot, * = history[cycle] tasks = snapshot.plan.tasks.to_set job_info = Hash.new tasks.each do |t| if t.kind_of?(Roby::Interface::Job) planned_by_graph = snapshot.plan.task_relation_graph_for(Roby::TaskStructure::PlannedBy) placeholder_task = planned_by_graph.enum_for(:each_out_neighbour, t).first if placeholder_task job_info[placeholder_task] = t end end end return tasks, job_info end |