Class: Roby::GUI::ChronicleWidget

Inherits:
Qt::AbstractScrollArea
  • Object
show all
Defined in:
lib/roby/gui/chronicle_widget.rb

Overview

Widget to display tasks on a chronicle (i.e. timelines)

Use ChronicleView when using a PlanRebuilderWidget

The following interactions are available:

* CTRL + wheel: change time scale
* ALT + wheel: horizontal scroll
* wheel: vertical scroll
* double-click: task info view

Defined Under Namespace

Classes: TaskLayout

Constant Summary collapse

SCALES =
[1, 2, 5, 10, 20, 30, 60, 90, 120, 300, 600, 1200, 1800, 3600]
TIMELINE_GRAY_PEN =
Qt::Pen.new(Qt::Color.new('gray'))
TIMELINE_BLACK_PEN =
Qt::Pen.new(Qt::Color.new('black'))

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(parent = nil) ⇒ ChronicleWidget

Returns a new instance of ChronicleWidget.



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
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/roby/gui/chronicle_widget.rb', line 214

def initialize(parent = nil)
    super(parent)

    @layout_cache = Hash.new
    @messages_per_task = Hash.new { |h, k| h[k] = Array.new }
    @current_tasks = Array.new
    @current_tasks_dirty = true
    self.time_scale = 10
    @task_height = 10
    @task_separation = 10
    @live_update_margin = 10
    @start_line = 0
    @all_tasks = Set.new
    @all_job_info = Hash.new
    @scheduler_state = Schedulers::State.new
    @task_layout = Array.new
    @sort_mode = :start_time
    @reverse_sort = false
    @show_mode = :all
    @show_future_events = true
    @live = true
    @track_current_time = true
    @horizontal_scroll_bar_down = false
    @display_point = viewport.size.width - live_update_margin

    viewport = Qt::Widget.new
    pal = Qt::Palette.new(viewport.palette)
    pal.setColor(Qt::Palette::Background, Qt::Color.new('white'))
    viewport.setAutoFillBackground(true);
    viewport.setPalette(pal)
    self.viewport = viewport

    horizontal_scroll_bar.connect(SIGNAL('sliderMoved(int)')) do
        value = horizontal_scroll_bar.value
        self.track_current_time = live? && (value == horizontal_scroll_bar.maximum)
        time = base_time + Float(value) * pixel_to_time
        update_display_time(time)
        emit timeChanged(time - base_time)
    end
    horizontal_scroll_bar.connect(SIGNAL('sliderPressed()')) do
        self.horizontal_scroll_bar_down = true
    end
    horizontal_scroll_bar.connect(SIGNAL('sliderReleased()')) do
        self.track_current_time = live? && (horizontal_scroll_bar.value == horizontal_scroll_bar.maximum)
        self.horizontal_scroll_bar_down = false
        update_scroll_ranges
    end
    vertical_scroll_bar.connect(SIGNAL('valueChanged(int)')) do
        value = vertical_scroll_bar.value
        if value < current_tasks.size
            self.start_line = value
            update
        end
    end
end

Instance Attribute Details

#all_job_infoObject

Job information about all known tasks

See Also:



92
93
94
# File 'lib/roby/gui/chronicle_widget.rb', line 92

def all_job_info
  @all_job_info
end

#all_tasksObject

All known tasks

See Also:



88
89
90
# File 'lib/roby/gui/chronicle_widget.rb', line 88

def all_tasks
  @all_tasks
end

#base_timeObject

The startup time



77
78
79
# File 'lib/roby/gui/chronicle_widget.rb', line 77

def base_time
  @base_time
end

#current_tasksObject (readonly)

The set of tasks that should currently be managed by the view.

It is updated in #update(), i.e. when the view gets something to display



103
104
105
# File 'lib/roby/gui/chronicle_widget.rb', line 103

def current_tasks
  @current_tasks
end

#current_timeObject

The system’s current time



75
76
77
# File 'lib/roby/gui/chronicle_widget.rb', line 75

def current_time
  @current_time
end

#display_pointObject

The point (in pixels) where the current display time should be located on the display



71
72
73
# File 'lib/roby/gui/chronicle_widget.rb', line 71

def display_point
  @display_point
end

#display_timeObject

The time that is currently at the middle of the view



73
74
75
# File 'lib/roby/gui/chronicle_widget.rb', line 73

def display_time
  @display_time
end

#displayed_time_range(Time,Time)? (readonly)

The range, in absolute time, currently visible in the view

Returns:

  • ((Time,Time), nil)

    either said range, or nil if nothing has ever been displayed so far



459
460
461
# File 'lib/roby/gui/chronicle_widget.rb', line 459

def displayed_time_range
  @displayed_time_range
end

#filterObject

Inclusion filter on task names

If it contains a regular expression, only the task names that match the expression will be displayed



187
188
189
# File 'lib/roby/gui/chronicle_widget.rb', line 187

def filter
  @filter
end

#filter_outObject

Exclusion filter on task names

If it contains a regular expression, the task names that match the expression will not be displayed



200
201
202
# File 'lib/roby/gui/chronicle_widget.rb', line 200

def filter_out
  @filter_out
end

#layout_cacheHash<Task,TaskLayout> (readonly)

Per-task visual layout information

Returns:



151
152
153
# File 'lib/roby/gui/chronicle_widget.rb', line 151

def layout_cache
  @layout_cache
end

#live_update_marginObject (readonly)

How many pixels should there be between the ‘now’ line and the right side, in pixels



68
69
70
# File 'lib/roby/gui/chronicle_widget.rb', line 68

def live_update_margin
  @live_update_margin
end

#messages_per_taskObject (readonly)

Per-task messages to be displayed



154
155
156
# File 'lib/roby/gui/chronicle_widget.rb', line 154

def messages_per_task
  @messages_per_task
end

#pixel_to_timeObject (readonly)

Scale factor to convert seconds to pixels

pixel = time_to_pixel * time


64
65
66
# File 'lib/roby/gui/chronicle_widget.rb', line 64

def pixel_to_time
  @pixel_to_time
end

#position_to_taskObject (readonly)

An ordered set of [y, task], where y is the position in Y of the bottom of a task line and task the corresponding task object

It is updated on display



108
109
110
# File 'lib/roby/gui/chronicle_widget.rb', line 108

def position_to_task
  @position_to_task
end

#scheduler_stateSchedulers::State

Scheduler information

Returns:



96
97
98
# File 'lib/roby/gui/chronicle_widget.rb', line 96

def scheduler_state
  @scheduler_state
end

#show_modeObject

High-level filter on the list of shown tasks. Can either be :all, :running, :current. Defaults to :all

In :all mode, all tasks that are included in a plan in a certain point in time are displayed.

In :running mode, only the tasks that are running within the display time window are shown.

In :current mode, only the tasks that have emitted events within the display time window are shown

In :in_range mode, only the tasks that would display something within the display time window are shown



146
147
148
# File 'lib/roby/gui/chronicle_widget.rb', line 146

def show_mode
  @show_mode
end

#sort_modeObject

The current sorting mode. Can be :start_time or :last_event. Defaults to :start_time

In :start mode, the tasks are sorted by the time at which they started. In :last_event, by the time of the last event emitted before the current displayed time: it shows the last active tasks first)



116
117
118
# File 'lib/roby/gui/chronicle_widget.rb', line 116

def sort_mode
  @sort_mode
end

#start_lineObject

The index of the task that is currently at the top of the view. It is an index in #current_tasks



84
85
86
# File 'lib/roby/gui/chronicle_widget.rb', line 84

def start_line
  @start_line
end

#task_heightObject

The base height of a task line



79
80
81
# File 'lib/roby/gui/chronicle_widget.rb', line 79

def task_height
  @task_height
end

#task_layoutObject (readonly)

The task layout as computed in the last call to #paintEvent



98
99
100
# File 'lib/roby/gui/chronicle_widget.rb', line 98

def task_layout
  @task_layout
end

#task_separationObject

The separation, in pixels, between tasks



81
82
83
# File 'lib/roby/gui/chronicle_widget.rb', line 81

def task_separation
  @task_separation
end

#time_scaleObject

Internal representation of the desired time scale. Don’t use it directly, but use #time_to_pixel or #pixel_to_time



34
35
36
# File 'lib/roby/gui/chronicle_widget.rb', line 34

def time_scale
  @time_scale
end

#time_to_pixelObject (readonly)

Scale factor to convert seconds to pixels

pixels = time_to_pixel * time


59
60
61
# File 'lib/roby/gui/chronicle_widget.rb', line 59

def time_to_pixel
  @time_to_pixel
end

Instance Method Details

#add_tasks_info(tasks, job_info) ⇒ Object

Add information to the chronicle for the next display update

Parameters:



339
340
341
342
343
344
345
346
347
348
# File 'lib/roby/gui/chronicle_widget.rb', line 339

def add_tasks_info(tasks, job_info)
    tasks.each do |t|
        if base_time && t.addition_time < base_time
            update_base_time(t.addition_time)
        end
    end

    all_tasks.merge(tasks)
    all_job_info.merge!(job_info)
end

#clearObject



888
889
890
891
# File 'lib/roby/gui/chronicle_widget.rb', line 888

def clear
    all_tasks.clear
    all_job_info.clear
end

#clear_tasks_infoObject



305
306
307
308
309
# File 'lib/roby/gui/chronicle_widget.rb', line 305

def clear_tasks_info
    all_tasks.clear
    all_job_info.clear
    self.scheduler_state = Schedulers::State.new
end

#contents_heightObject



357
358
359
360
361
362
363
364
365
366
# File 'lib/roby/gui/chronicle_widget.rb', line 357

def contents_height
    update_current_tasks

    display_start, display_end = displayed_time_range
    fm = Qt::FontMetrics.new(font)
    height = current_tasks.inject(0) do |h, t|
        h + lay_out_task(fm, t).height(display_start, display_end)
    end
    height + current_tasks.size * task_separation + timeline_height
end

#current_tasks_dirty?Boolean

Returns:

  • (Boolean)


465
466
467
# File 'lib/roby/gui/chronicle_widget.rb', line 465

def current_tasks_dirty?
    @current_tasks_dirty
end

#invalidate_current_tasksObject



461
462
463
# File 'lib/roby/gui/chronicle_widget.rb', line 461

def invalidate_current_tasks
    @current_tasks_dirty = true
end

#invalidate_layout_cacheObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Clears #layout_cache because parameters changed that require to recompute the task layouts



160
161
162
# File 'lib/roby/gui/chronicle_widget.rb', line 160

def invalidate_layout_cache
    layout_cache.clear
end

#lay_out_task(fm, task) ⇒ Object



746
747
748
749
750
751
# File 'lib/roby/gui/chronicle_widget.rb', line 746

def lay_out_task(fm, task)
    layout = layout_cache[task] ||= TaskLayout.new(task, base_time, time_to_pixel, fm)
    layout.messages = messages_per_task.fetch(task, Array.new)
    layout.update
    layout
end

#live=(flag) ⇒ Object



24
25
26
27
# File 'lib/roby/gui/chronicle_widget.rb', line 24

def live=(flag)
    @live = flag
    self.track_current_time = live? && (value == horizontal_scroll_bar.maximum)
end

#massage_slot_time_argument(time, default) ⇒ Object



543
544
545
546
547
548
549
550
551
# File 'lib/roby/gui/chronicle_widget.rb', line 543

def massage_slot_time_argument(time, default)
    # Convert from QDateTime to allow update() to be a slot
    if time.kind_of?(Qt::DateTime)
        return Time.at(Float(time.toMSecsSinceEpoch) / 1000)
    elsif !time
        return default
    else time
    end
end

#mouseDoubleClickEvent(event) ⇒ Object



893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
# File 'lib/roby/gui/chronicle_widget.rb', line 893

def mouseDoubleClickEvent(event)
    click_y = event.pos.y
    layout = task_layout.find { |layout| layout.top_y < click_y && layout.top_y + layout.height > click_y }
    if layout
        if !@info_view
            @info_view = ObjectInfoView.new
            Qt::Object.connect(@info_view, SIGNAL('selectedTime(QDateTime)'),
                               self, SIGNAL('selectedTime(QDateTime)'))
        end

        if @info_view.display(layout.task)
            @info_view.activate
        end
    end
    event.accept
end

#paint_tasks(painter, fm, layout, top_y) ⇒ Object



753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
# File 'lib/roby/gui/chronicle_widget.rb', line 753

def paint_tasks(painter, fm, layout, top_y)
    current_point  = Integer((current_time -  base_time) * time_to_pixel)
    display_offset = Integer(display_point - (display_time - base_time) * time_to_pixel)
    display_start_time, display_end_time = displayed_time_range
    view_height = viewport.size.height

    fm = Qt::FontMetrics.new(font)
    text_height  = fm.height
    text_ascent  = fm.ascent
    text_descent = fm.descent

    update_current_tasks
    current_tasks[start_line..-1].each do |task|
        break if top_y > view_height

        task_layout = lay_out_task(fm, task)
        add_point, start_point, end_point, finalization_point =
            task_layout.add_point, task_layout.start_point, task_layout.end_point, task_layout.finalization_point
        state         = task_layout.state
        task          = task_layout.task
        event_height  = task_layout.event_height

        task_line_height = event_height
        if events = task_layout.events_in_range(display_start_time, display_end_time)
            task_line_height += events.max_by { |_, _, y, _| y }[2]
        end
        if task_height > task_line_height
            task_line_height = task_height
        end

        # Paint the pending stage, i.e. before the task started
        top_task_line = top_y
        painter.brush = TASK_BRUSHES[:pending]
        painter.pen   = TASK_PENS[:pending]
        painter.drawRect(
            add_point + display_offset, top_task_line,
            (start_point || finalization_point || current_point) - add_point, task_line_height)

        if start_point
            painter.brush = TASK_BRUSHES[:running]
            painter.pen   = TASK_PENS[:running]
            painter.drawRect(
                start_point + display_offset, top_task_line,
                (end_point || current_point) - start_point, task_line_height)

            if state && state != :running
                # Final state is shown by "eating" a few pixels at the task
                painter.brush = TASK_BRUSHES[state]
                painter.pen   = TASK_PENS[state]
                painter.drawRect(
                    end_point - 2 + display_offset, top_task_line,
                    4, task_height)
            end
        end

        # Display the emitted events
        event_baseline = top_task_line + event_height / 2
        if events
            events.each do |_, x, y, text|
                x += display_offset
                y += event_baseline
                painter.brush, painter.pen = EVENT_STYLES[EVENT_CONTROLABLE | EVENT_EMITTED]
                painter.drawEllipse(Qt::Point.new(x, y),
                                    EVENT_CIRCLE_RADIUS, EVENT_CIRCLE_RADIUS)
                painter.pen = EVENT_NAME_PEN
                painter.drawText(Qt::Point.new(x + 2 * EVENT_CIRCLE_RADIUS, y), text)
            end
        end

        # Add the title
        painter.pen = TASK_NAME_PEN
        title_baseline = top_task_line + task_line_height + text_ascent
        task_layout.title ||= task_timeline_title(task)
        painter.drawText(Qt::Point.new(0, title_baseline), task_layout.title)

        # And finally display associated messages
        messages_baseline = title_baseline + text_height
        painter.pen = TASK_MESSAGE_PEN
        task_layout.messages.each_with_index do |msg|
            messages_baseline += text_height
            painter.drawText(Qt::Point.new(TASK_MESSAGE_MARGIN, messages_baseline), msg)
        end

        top_y = messages_baseline + text_descent
    end
end

#paint_timeline(painter, fm) ⇒ Object



575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
# File 'lib/roby/gui/chronicle_widget.rb', line 575

def paint_timeline(painter, fm)
    text_height = fm.height
    window_size = viewport.size

    # Display the current cycle time
    central_label = Roby.format_time(display_time)
    central_label_width = fm.width(central_label)
    central_time_max = display_point + central_label_width / 2
    if central_time_max + 3 > window_size.width
        central_time_max = window_size.width - 3
    end
    central_time_min = central_time_max - central_label_width
    if central_time_min < 3
        central_time_min = 3
        central_time_max = central_time_min + central_label_width
    end
    painter.pen = TIMELINE_GRAY_PEN
    painter.drawText(central_time_min, text_height, central_label)
    painter.drawRect(central_time_min - 2, 0, central_label_width + 4, text_height + 2)

    # First, decide on the scale. We compute a "normal" text width
    # for the time labels, and check what would be a round time-step
    min_step_size = pixel_to_time * 1.5 * central_label_width
    step_size = SCALES.find do |scale|
        scale > min_step_size
    end
    step_size ||= SCALES.last
    # Now display the timeline itself. If a normal ruler collides
    # with the current time, just ignore it
    start_time, end_time = displayed_time_range
    painter.pen = TIMELINE_BLACK_PEN
    ruler_base_time = (start_time.to_f / step_size).floor * step_size
    ruler_base_x    = (ruler_base_time - start_time.to_f) * time_to_pixel
    step_count = ((end_time.to_f - ruler_base_time) / step_size).ceil
    step_count.times do |i|
        time = step_size * i + ruler_base_time
        pos  = step_size * i * time_to_pixel + ruler_base_x
        time_as_text = Roby.format_time(Time.at(time))
        time_as_text_width = fm.width(time_as_text)
        min_x = pos - time_as_text_width / 2
        max_x = pos + time_as_text_width / 2
        if central_time_min > max_x || central_time_max < min_x
            painter.drawText(min_x, text_height, time_as_text)
        end
        painter.drawLine(pos, text_height + fm.descent, pos, text_height + fm.descent + TIMELINE_RULER_LINE_LENGTH)
    end
end

#paintEvent(event) ⇒ Object



848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
# File 'lib/roby/gui/chronicle_widget.rb', line 848

def paintEvent(event)
    return if !display_time

    painter = Qt::Painter.new(viewport)
    font = painter.font
    font.point_size = 8
    painter.font = font

    fm = Qt::FontMetrics.new(font)
    update_current_tasks
    paint_timeline(painter, fm)
    paint_tasks(painter, fm, task_layout, timeline_height)

    # Draw the "zero" line
    painter.pen = TIMELINE_GRAY_PEN
    painter.drawLine(display_point, fm.height + 2, display_point, size.height)

ensure
    if painter
        painter.end
    end
end

#remove_tasks(tasks) ⇒ Object



350
351
352
353
354
355
# File 'lib/roby/gui/chronicle_widget.rb', line 350

def remove_tasks(tasks)
    tasks.each do |t|
        all_tasks.delete(t)
        all_job_info.delete(t)
    end
end

#resizeEvent(event) ⇒ Object



434
435
436
437
438
439
440
441
442
443
# File 'lib/roby/gui/chronicle_widget.rb', line 434

def resizeEvent(event)
    if track_current_time?
        @display_point = event.size.width - live_update_margin
    elsif display_time && current_time
        update_display_point
    end
    update_displayed_time_range
    invalidate_current_tasks
    event.accept
end

#restrict_to_jobs=(set) ⇒ Object

Sets whether only the toplevel job tasks should be shown



177
178
179
180
181
# File 'lib/roby/gui/chronicle_widget.rb', line 177

def restrict_to_jobs=(set)
    @restrict_to_jobs = set
    setDisplayTime
    update
end

#restrict_to_jobs?Boolean

Returns true if only the action’s toplevel tasks are shown.

Returns:

  • (Boolean)

    true if only the action’s toplevel tasks are shown



174
# File 'lib/roby/gui/chronicle_widget.rb', line 174

attr_predicate :restrict_to_jobs?

#reverse_sort=(flag) ⇒ Object

Whether the order defined by #sort_mode should be inverted



129
130
131
# File 'lib/roby/gui/chronicle_widget.rb', line 129

def reverse_sort=(flag)
    @reverse_sort = flag
end

#reverse_sort?Boolean

Whether the order defined by #sort_mode should be inverted

Returns:

  • (Boolean)


125
126
127
# File 'lib/roby/gui/chronicle_widget.rb', line 125

def reverse_sort?
    !!@reverse_sort
end

#setCurrentTime(time = nil) ⇒ Object



564
565
566
567
568
569
570
571
# File 'lib/roby/gui/chronicle_widget.rb', line 564

def setCurrentTime(time = nil)
    time = massage_slot_time_argument(time, current_time)
    return if !time

    update_base_time(time) if !base_time
    update_current_time(time)
    update
end

#setDisplayTime(time = nil) ⇒ Object



553
554
555
556
557
558
559
560
561
# File 'lib/roby/gui/chronicle_widget.rb', line 553

def setDisplayTime(time = nil)
    time = massage_slot_time_argument(time, display_time)
    return if !time

    update_base_time(time) if !base_time
    update_current_time(time) if !current_time
    update_display_time(time)
    update
end

#task_timeline_title(task) ⇒ Object



871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
# File 'lib/roby/gui/chronicle_widget.rb', line 871

def task_timeline_title(task)
    text = task.to_s
    if job_task = all_job_info[task]
        job_text = ["[#{job_task.job_id}]"]
        if job_task.action_model
            job_text << job_task.action_model.name.to_s
        end
        if job_task.action_arguments
            job_text << "(" + job_task.action_arguments.map do |k,v|
                "#{k} => #{v}"
            end.join(", ") + ")"
        end
        text = "#{job_text.join(" ")} / #{text}"
    end
    text
end

#timeline_heightObject



843
844
845
846
# File 'lib/roby/gui/chronicle_widget.rb', line 843

def timeline_height
    fm = Qt::FontMetrics.new(font)
    fm.height + fm.descent + TIMELINE_RULER_LINE_LENGTH
end

#update_base_time(time) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Update the time at the start of the chronicle



382
383
384
385
386
# File 'lib/roby/gui/chronicle_widget.rb', line 382

def update_base_time(time)
    @base_time = time
    invalidate_current_tasks
    invalidate_layout_cache
end

#update_current_tasks(force: false) ⇒ Object



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
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
# File 'lib/roby/gui/chronicle_widget.rb', line 469

def update_current_tasks(force: false)
    return if !force && !current_tasks_dirty?

    current_tasks = all_tasks.dup
    if restrict_to_jobs?
        current_tasks = all_job_info.keys.to_set
    end
    if filter
        current_tasks = current_tasks.find_all { |t| t.to_s =~ filter }
    end
    if filter_out
        current_tasks.delete_if { |t| t.to_s =~ filter_out }
    end
    started_tasks, pending_tasks = current_tasks.partition { |t| t.start_time }

    if sort_mode == :last_event
        not_yet_started, started_tasks = started_tasks.partition { |t| t.start_time > display_time }
        current_tasks =
            started_tasks.sort_by do |t|
                last_event = nil
                t.history.each do |ev|
                    if ev.time < display_time
                        last_event = ev
                    else break
                    end
                end
                last_event.time
            end
        current_tasks = current_tasks.reverse
        current_tasks.concat(not_yet_started.sort_by { |t| t.start_time })
        if show_mode == :all
            current_tasks.
                concat(pending_tasks.sort_by { |t| t.addition_time })
        end
    else
        current_tasks =
            (started_tasks + pending_tasks).sort_by { |t| t.start_time || t.addition_time }
    end

    start_time, end_time = displayed_time_range

    if start_time && (show_mode == :running || show_mode == :current)
        current_tasks = current_tasks.find_all do |t|
            (t.start_time && t.start_time < end_time) &&
                (!t.end_time || t.end_time > start_time)
        end

        if show_mode == :current
            current_tasks = current_tasks.find_all do |t|
                t.history.any? { |ev| ev.time > start_time && ev.time < end_time }
            end
        end
    end

    tasks_in_range, tasks_outside_range =
        current_tasks.partition do |t|
            (t.addition_time <= end_time) &&
                (!t.finalization_time || t.finalization_time >= start_time)
        end

    if reverse_sort?
        tasks_in_range = tasks_in_range.reverse
        tasks_outside_range = tasks_outside_range.reverse
    end

    @current_tasks_dirty = false
    if show_mode == :in_range
        @current_tasks = tasks_in_range
    else
        @current_tasks = tasks_in_range + tasks_outside_range
    end
    vertical_scroll_bar.setRange(0, current_tasks.size)
end

#update_current_time(time) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Update the time at the end of the chronicle



390
391
392
393
394
395
396
397
398
399
400
401
# File 'lib/roby/gui/chronicle_widget.rb', line 390

def update_current_time(time)
    @current_time = time
    if !base_time
        update_base_time(time)
    end
    if !display_time || track_current_time?
        update_display_time(time)
    else
        update_scroll_ranges
        invalidate_current_tasks
    end
end

#update_display_pointObject



422
423
424
425
426
427
428
429
430
431
432
# File 'lib/roby/gui/chronicle_widget.rb', line 422

def update_display_point
    display_point = viewport.size.width - live_update_margin -
        (current_time - display_time) * time_to_pixel
    display_point_min = viewport.size.width / 2
    if display_point < display_point_min
        display_point = display_point_min
    end
    @display_point = Integer(display_point)
    update_displayed_time_range
    invalidate_current_tasks
end

#update_display_time(time) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Update the currently displayed time



405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
# File 'lib/roby/gui/chronicle_widget.rb', line 405

def update_display_time(time)
    @display_time = time
    if !base_time
        update_base_time(time)
    end

    _, end_time = displayed_time_range
    update_display_point

    if !horizontal_scroll_bar_down?
        update_scroll_ranges
        horizontal_scroll_bar.value = time_to_pixel * (display_time - base_time)
    end

    invalidate_current_tasks
end

#update_displayed_time_rangeObject



445
446
447
448
449
450
451
452
453
# File 'lib/roby/gui/chronicle_widget.rb', line 445

def update_displayed_time_range
    if display_time
        display_point = self.display_point
        window_width  = viewport.size.width
        start_time = display_time - display_point * pixel_to_time
        end_time   = start_time   + window_width * pixel_to_time
        @displayed_time_range = [start_time, end_time]
    end
end

#update_scroll_rangesObject



912
913
914
915
916
917
918
919
920
921
# File 'lib/roby/gui/chronicle_widget.rb', line 912

def update_scroll_ranges
    vertical_scroll_bar.setRange(0, current_tasks.size - 1)
    return if horizontal_scroll_bar_down?

    if base_time && current_time && display_time
        horizontal_scroll_bar.value = time_to_pixel * (display_time - base_time)
        horizontal_scroll_bar.setRange(0, time_to_pixel * (current_time - base_time))
        horizontal_scroll_bar.setPageStep(size.width / 4)
    end
end

#update_time_range(start_time, current_time) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Updates the start and current time



371
372
373
374
375
376
377
378
# File 'lib/roby/gui/chronicle_widget.rb', line 371

def update_time_range(start_time, current_time)
    if start_time
        update_base_time(start_time)
    end
    if current_time
        update_current_time(current_time)
    end
end

#wheelEvent(event) ⇒ Object

Event handler for wheel event



275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
# File 'lib/roby/gui/chronicle_widget.rb', line 275

def wheelEvent(event)
    if event.modifiers != Qt::ControlModifier
        # Don't let the user scroll with the mouse if vertical
        # scrolling is off
        if vertical_scroll_bar_policy == Qt::ScrollBarAlwaysOff
            event.ignore
            return
        else
            return super
        end
    end

    # See documentation of wheelEvent
    degrees = event.delta / 8.0
    num_steps = degrees / 15

    old = self.time_scale
    new = old + num_steps
    if new == 0
        if old > 0
            self.time_scale = -1
        else
            self.time_scale = 1
        end
    else
        self.time_scale = new
    end
    event.accept
end