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
Modules: ContextMenuHandler 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 = {}) ⇒ 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, index_path: nil) ⇒ Object
Opens
filename
and 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.
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 59 def initialize(parent, plan_rebuilder) super(parent) @list = Qt::ListWidget.new(self) @list.extend ContextMenuHandler @layout = Qt::VBoxLayout.new(self) @layout.(@btn_create_display) @history = {} @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
20 21 22 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 20 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
16 17 18 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 16 def history @history end |
#last_cycle ⇒ Integer (readonly)
The last processed cycle
26 27 28 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 26 def last_cycle @last_cycle end |
#list ⇒ Object (readonly)
The list used to display all the cycles in the history
13 14 15 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 13 def list @list end |
#logfile ⇒ DRoby::Logfile::Reader (readonly)
The underlying log file
23 24 25 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 23 def logfile @logfile end |
#plan_rebuilder ⇒ Object (readonly)
The PlanRebuilder object we use to process the log data
18 19 20 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 18 def plan_rebuilder @plan_rebuilder end |
Class Method Details
.analyze(plan_rebuilder, logfile, until_cycle: nil) ⇒ Object
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 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 216 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 format("analyzed log file in %.2fs", Time.now - start) end |
Instance Method Details
#add_missing_cycles(count) ⇒ Object
121 122 123 124 125 126 127 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 121 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 # NOTE: 'item' gets registered on the list by its constructor item.text = "[#{count} cycles missing]" # rubocop:disable Lint/UselessSetterCall end |
#analyze(until_cycle: nil) ⇒ Object
244 245 246 247 248 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 244 def analyze(until_cycle: nil) PlanRebuilderWidget.analyze(plan_rebuilder, logfile, until_cycle: until_cycle) do push_cycle end end |
#append_to_history ⇒ Object
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 131 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
158 159 160 161 162 163 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 158 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 = {}) ⇒ 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.
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 283 def connect(client, = {}) = 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.}") puts e. puts " #{e.backtrace.join("\n ")}" connect(hostname, ) if hostname end end timer.start(Integer([:update_period] * 1000)) 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
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 253 def connection_failed(e, client, ) @connection_error = e emit warn("connection failed: #{e.}") if @reconnection_timer return end @reconnection_timer = Qt::Timer.new(self) @connect_client = client.dup @connect_options = .dup @reconnection_timer.connect(SIGNAL("timeout()")) do puts "trying to reconnect to #{@connect_client} #{@connect_options}" if connect(@connect_client, @connect_options) 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
153 154 155 156 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 153 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
112 113 114 115 116 117 118 119 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 112 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, index_path: nil) ⇒ Object
Opens filename
and reads the data from there
204 205 206 207 208 209 210 211 212 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 204 def open(filename, index_path: nil) @logfile = DRoby::Logfile::Reader.open(filename, index_path: index_path) self.window_title = "roby-display: #{filename}" emit sourceChanged analyze unless history.empty? apply(history[history.keys.min][1]) end end |
#push_cycle(snapshot: true) ⇒ Object
183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 183 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
199 200 201 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 199 def redraw(time = plan_rebuilder.current_time) emit appliedSnapshot(Qt::DateTime.new(time)) end |
#seek(time) ⇒ Object
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 165 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) && (!result || result[0] < cycle_time) result = [cycle_time, snapshot] 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
81 82 83 84 85 86 87 88 89 90 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 81 def tasks_info all_tasks = Set.new all_job_info = {} 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 [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
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/roby/gui/plan_rebuilder_widget.rb', line 95 def tasks_info_of_snapshot(cycle) _, snapshot, * = history[cycle] tasks = snapshot.plan.tasks.to_set job_info = {} 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 [tasks, job_info] end |