Class: Roby::GUI::LogDisplay

Inherits:
Qt::Widget
  • Object
show all
Defined in:
lib/roby/gui/log_display.rb

Overview

Main UI for log display

It includes

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(parent = nil, plan_rebuilder = nil) ⇒ LogDisplay

Returns a new instance of LogDisplay.



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
70
71
72
73
74
75
76
77
# File 'lib/roby/gui/log_display.rb', line 42

def initialize(parent = nil, plan_rebuilder = nil)
    super

    plan_rebuilder ||= DRoby::PlanRebuilder.new
    @plan_rebuilder = plan_rebuilder

    @displays = Hash.new { |h, k| h[k] = Array.new }

    @btn_create_display = Qt::PushButton.new("New Display", self)
    @lbl_info = Qt::Label.new(self)
    @history_widget = PlanRebuilderWidget.new(self, plan_rebuilder)
    @layout = Qt::VBoxLayout.new(self)
    @layout.add_widget(@btn_create_display)
    @layout.add_widget(@lbl_info)
    @layout.add_widget(@history_widget)

    Qt::Object.connect(history_widget, SIGNAL('sourceChanged()'),
                       self, SLOT('updateWindowTitle()'))
    Qt::Object.connect(history_widget, SIGNAL('info(QString)'),
                       self, SLOT('info(QString)'))
    Qt::Object.connect(history_widget, SIGNAL('warn(QString)'),
                       self, SLOT('warn(QString)'))

    btn_create_display.text = "New Display"
    @menu_displays = Qt::Menu.new(@btn_create_display)
    self.class.available_displays.each do |name, klass_name|
        action = menu_displays.addAction(name)
        action.setData(Qt::Variant.new(klass_name))
    end
    btn_create_display.setMenu(menu_displays)
    menu_displays.connect(SIGNAL('triggered(QAction*)')) do |action|
        create_display(action.data.toString)
    end

    resize(300, 500)
end

Class Attribute Details

.available_displaysObject (readonly)

Registered plan displays

It is a mapping from the displayed name (shown to the users) to the name of the underlying class



36
37
38
# File 'lib/roby/gui/log_display.rb', line 36

def available_displays
  @available_displays
end

Instance Attribute Details

#btn_create_displayObject (readonly)

The Qt::PushButton object that allows to create new displays



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

def btn_create_display
  @btn_create_display
end

#displaysObject (readonly)

The set of displays that have been created so far

It is managed as a mapping from the view class name to an array of views. The array can contain nil elements. This is used to restore configurations across software restarts (i.e. the index is used as an ID for the widget)



22
23
24
# File 'lib/roby/gui/log_display.rb', line 22

def displays
  @displays
end

#history_widgetObject (readonly)

The history widget



15
16
17
# File 'lib/roby/gui/log_display.rb', line 15

def history_widget
  @history_widget
end

#lbl_infoObject (readonly)

The label widget that is used to display information/warning messages



27
28
29
# File 'lib/roby/gui/log_display.rb', line 27

def lbl_info
  @lbl_info
end

The menu button to create new displays



29
30
31
# File 'lib/roby/gui/log_display.rb', line 29

def menu_displays
  @menu_displays
end

#plan_rebuilderObject (readonly)

The PlanRebuilder object that gets the data



13
14
15
# File 'lib/roby/gui/log_display.rb', line 13

def plan_rebuilder
  @plan_rebuilder
end

Class Method Details

.from_file(filename, plan_rebuilder = nil) ⇒ Object

Creates a new display that will display the information present in filename

plan_rebuilder, if given, will be used to rebuild a complete data structure based on the information in filename



194
195
196
197
198
# File 'lib/roby/gui/log_display.rb', line 194

def self.from_file(filename, plan_rebuilder = nil)
    view = new(plan_rebuilder)
    view.open(filename)
    view
end

Instance Method Details

#allocate_id(klass_name) ⇒ Object



90
91
92
# File 'lib/roby/gui/log_display.rb', line 90

def allocate_id(klass_name)
    displays[klass_name].size
end

#apply_options(options) ⇒ Object



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
269
# File 'lib/roby/gui/log_display.rb', line 241

def apply_options(options)
    (options['plugins'] || Array.new).each do |plugin_name|
        begin
            Roby.app.using plugin_name
        rescue ArgumentError => e
            Roby.warn "the display configuration file mentions the #{plugin_name} plugin, but it is not available on this system. Some information might not be displayed"
        end
    end

    filters = options['plan_rebuilder'] || Hash.new
    apply_widget_state(options['main'] || Hash.new, self)
    (options['views'] || Array.new).each do |view_options|
        id = view_options['id']
        klass_name = view_options["class"]
        if w = display_from_id(klass_name, id)
            if w.class.name != klass_name
                next
            end
        else
            if !(w = create_display(klass_name, id))
                next
            end
        end
        apply_widget_state(view_options, w)
        if w.respond_to?(:apply_options)
            w.apply_options(view_options)
        end
    end
end

#apply_widget_state(options, widget) ⇒ Object



235
236
237
238
239
# File 'lib/roby/gui/log_display.rb', line 235

def apply_widget_state(options, widget)
    if geom = options['geometry']
        widget.set_geometry(*geom)
    end
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.



185
186
187
# File 'lib/roby/gui/log_display.rb', line 185

def connect(client, options = Hash.new)
    history_widget.connect(client, options)
end

#connect_display(history_widget, view) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/roby/gui/log_display.rb', line 142

def connect_display(history_widget, view)
    if history_widget.start_time && history_widget.current_time
        view.update_time_range(history_widget.start_time, history_widget.current_time)
        view.update_display_time(history_widget.display_time)
    end
    Qt::Object.connect(history_widget, SIGNAL('appliedSnapshot(QDateTime)'),
                       view, SLOT('setDisplayTime(QDateTime)'))
    Qt::Object.connect(history_widget, SIGNAL('liveUpdate(QDateTime)'),
                       view, SLOT('setCurrentTime(QDateTime)'))
    Qt::Object.connect(history_widget, SIGNAL('sourceChanged()'),
                       view, SLOT('updateWindowTitle()'))
end

#create_all_displaysObject



84
85
86
87
88
# File 'lib/roby/gui/log_display.rb', line 84

def create_all_displays
    self.class.available_displays.each do |user_name, klass_name|
        create_display(klass_name)
    end
end

#create_display(name, id = nil) ⇒ Object



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/roby/gui/log_display.rb', line 98

def create_display(name, id = nil)
    # Check whether +klass_name+ is not a user-visible string
    self.class.available_displays.each do |user_name, klass_name|
        if user_name.downcase == name.downcase
            name = klass_name
            break
        end
    end

    id ||= allocate_id(name)
    if displays[name][id]
        raise ArgumentError, "there is already a view of type #{name} with ID #{id}"
    end

    klass = begin constant(name)
            rescue NameError => e
                Roby.warn "cannot create display of class #{name}: #{e}"
                return
            end

    log_display = self
    view = klass.new(@history_widget)
    view.singleton_class.class_eval do
        define_method :closeEvent do |event|
            log_display.remove_display(name, id)
            event.accept
        end
    end
    if view.respond_to?(:live=)
        view.live = false
    end
    connect_display(history_widget, view)
    view.setAttribute(Qt::WA_QuitOnClose, false)

    view.show
    displays[name][id] = view
end

#disconnect_display(history_widget, view) ⇒ Object



155
156
157
158
159
160
161
162
# File 'lib/roby/gui/log_display.rb', line 155

def disconnect_display(history_widget, view)
    Qt::Object.disconnect(history_widget, SIGNAL('appliedSnapshot(QDateTime)'),
                       view, SLOT('setDisplayTime(QDateTime)'))
    Qt::Object.disconnect(history_widget, SIGNAL('liveUpdate(QDateTime)'),
                       view, SLOT('setCurrentTime(QDateTime)'))
    Qt::Object.disconnect(history_widget, SIGNAL('sourceChanged()'),
                       view, SLOT('updateWindowTitle()'))
end

#display_from_id(klass_name, id) ⇒ Object



94
95
96
# File 'lib/roby/gui/log_display.rb', line 94

def display_from_id(klass_name, id)
    displays[klass_name][id]
end

#info(message) ⇒ Object



164
165
166
# File 'lib/roby/gui/log_display.rb', line 164

def info(message)
    lbl_info.text = message
end

#load_options(path) ⇒ Object



200
201
202
203
204
# File 'lib/roby/gui/log_display.rb', line 200

def load_options(path)
    if new_options = YAML.load(File.read(path))
        apply_options(new_options)
    end
end

#open(filename) ⇒ Object

Opens filename and reads the data from there



175
176
177
# File 'lib/roby/gui/log_display.rb', line 175

def open(filename)
    history_widget.open(filename)
end

#remove_display(name, id) ⇒ Object



136
137
138
139
140
# File 'lib/roby/gui/log_display.rb', line 136

def remove_display(name, id)
    view = displays[name][id]
    displays[name][id] = nil
    disconnect_display(history_widget, view)
end

#save_optionsObject



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/roby/gui/log_display.rb', line 206

def save_options
    options = Hash.new
    options['main'] = Hash.new
    options['plugins'] = Roby.app.plugins.map(&:first)
    save_widget_state(options['main'], self)
    options['views'] = Array.new
    displays.each do |klass_name, views|
        views.each_with_index do |view, id|
            next if !view
            view_options = Hash.new
            view_options["class"] = view.class.name
            view_options['id'] = id
            save_widget_state(view_options, view)

            if view.respond_to?(:save_options)
                view_options.merge!(view.save_options)
            end
            options['views'] << view_options
        end
    end
    options
end

#save_widget_state(options, widget) ⇒ Object



229
230
231
232
233
# File 'lib/roby/gui/log_display.rb', line 229

def save_widget_state(options, widget)
    options['geometry'] =
        [widget.geometry.x, widget.geometry.y,
            widget.geometry.width, widget.geometry.height]
end

#updateWindowTitleObject



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

def updateWindowTitle
    self.window_title = history_widget.window_title
end

#warn(message) ⇒ Object



169
170
171
# File 'lib/roby/gui/log_display.rb', line 169

def warn(message)
    lbl_info.setText("<font color=\"red\">#{message}</font>")
end