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.



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

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

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

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

    @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



38
39
40
# File 'lib/roby/gui/log_display.rb', line 38

def available_displays
  @available_displays
end

Instance Attribute Details

#btn_create_displayObject (readonly)

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



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

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)



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

def displays
  @displays
end

#history_widgetObject (readonly)

The history widget



17
18
19
# File 'lib/roby/gui/log_display.rb', line 17

def history_widget
  @history_widget
end

#lbl_infoObject (readonly)

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



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

def lbl_info
  @lbl_info
end

The menu button to create new displays



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

def menu_displays
  @menu_displays
end

#plan_rebuilderObject (readonly)

The PlanRebuilder object that gets the data



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

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



196
197
198
199
200
# File 'lib/roby/gui/log_display.rb', line 196

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



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

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

#apply_options(options) ⇒ Object



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
270
271
272
273
274
# File 'lib/roby/gui/log_display.rb', line 244

def apply_options(options)
    (options["plugins"] || []).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"] || {}
    apply_widget_state(options["main"] || {}, self)
    (options["views"] || []).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
        elsif !(w = create_display(klass_name, id))
            next
        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



238
239
240
241
242
# File 'lib/roby/gui/log_display.rb', line 238

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



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

def connect(client, options = {})
    history_widget.connect(client, options)
end

#connect_display(history_widget, view) ⇒ Object



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

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



86
87
88
89
90
# File 'lib/roby/gui/log_display.rb', line 86

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



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

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



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

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



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

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

#info(message) ⇒ Object



166
167
168
# File 'lib/roby/gui/log_display.rb', line 166

def info(message)
    lbl_info.text = message
end

#load_options(path) ⇒ Object



202
203
204
205
206
# File 'lib/roby/gui/log_display.rb', line 202

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

#open(filename, index_path: nil) ⇒ Object

Opens filename and reads the data from there



177
178
179
# File 'lib/roby/gui/log_display.rb', line 177

def open(filename, index_path: nil)
    history_widget.open(filename, index_path: index_path)
end

#remove_display(name, id) ⇒ Object



138
139
140
141
142
# File 'lib/roby/gui/log_display.rb', line 138

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

#save_optionsObject



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

def save_options
    options = {}
    options["main"] = {}
    options["plugins"] = Roby.app.plugins.map(&:first)
    save_widget_state(options["main"], self)
    options["views"] = []
    displays.each do |(_, views)|
        views.each_with_index do |view, id|
            next unless view

            view_options = {}
            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



232
233
234
235
236
# File 'lib/roby/gui/log_display.rb', line 232

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

#updateWindowTitleObject



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

def updateWindowTitle
    self.window_title = history_widget.window_title
end

#warn(message) ⇒ Object



171
172
173
# File 'lib/roby/gui/log_display.rb', line 171

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