Class: Syskit::GUI::ComponentNetworkBaseView

Inherits:
Qt::Object
  • Object
show all
Defined in:
lib/syskit/gui/component_network_base_view.rb

Overview

Base functionality to display plans that contain component networks

Direct Known Subclasses

ComponentNetworkView, ModelViews::Component

Constant Summary collapse

Button =
MetaRuby::GUI::HTML::Button
DATA_SERVICE_WITHOUT_NAMES_TEMPLATE =

Template used in #render_data_services if the with_names argument is false

<<-EOD
<table>
<% services.each do |service_name, provided_services| %>
<tr><td>
  <%= provided_services.map do |srv_model, srv_port_mappings|
        if srv_port_mappings.empty? 
            page.link_to(srv_model)
        else
            "\#{page.link_to(srv_model)}: \#{srv_port_mappings}"
        end
      end.join("</td></tr><tr><td>")
  %>
</td></tr>
<% end %>
</table>
EOD
DATA_SERVICE_WITH_NAMES_TEMPLATE =

Template used in #render_data_services if the with_names argument is true

<<-EOD
<table>
<% services.each do |service_name, provided_services| %>
<tr><th><%= service_name %></th><td>
  <%= provided_services.map do |srv_model, srv_port_mappings|
        if srv_port_mappings.empty? 
            page.link_to(srv_model)
        else
            "\#{page.link_to(srv_model)}: \#{srv_port_mappings}"
        end
      end.join("</td></tr><tr><td>&nbsp;</td><td>")
  %>
</td></tr>
<% end %>
</table>
EOD

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(page) ⇒ ComponentNetworkBaseView

Returns a new instance of ComponentNetworkBaseView



72
73
74
75
# File 'lib/syskit/gui/component_network_base_view.rb', line 72

def initialize(page)
    super()
    @page = page
end

Instance Attribute Details

#current_modelObject (readonly)

The last model given to #render



6
7
8
# File 'lib/syskit/gui/component_network_base_view.rb', line 6

def current_model
  @current_model
end

#pagePage (readonly)

The page on which the rendered HTML is pushed

Returns:



11
12
13
# File 'lib/syskit/gui/component_network_base_view.rb', line 11

def page
  @page
end

#planObject (readonly)

The last generated plan



14
15
16
# File 'lib/syskit/gui/component_network_base_view.rb', line 14

def plan
  @plan
end

Class Method Details

.common_graph_buttons(namespace) ⇒ Object

Generate common list of buttons

Parameters:

  • namespace (String)

    the button namespace, i.e. a string that is prefixed before the button ID. The final button ID are #namespace/#button_name (e.g. #namespace/zoom)



39
40
41
42
43
# File 'lib/syskit/gui/component_network_base_view.rb', line 39

def self.common_graph_buttons(namespace)
    [Button.new("#{namespace}/zoom", text: "Zoom +"),
     Button.new("#{namespace}/unzoom", text: "Zoom -"),
     Button.new("#{namespace}/save", text: "Save SVG")]
end

.find_definition_place(model) ⇒ (String,Integer,String)?

Find the file, line number and method name where a model was defined

Parameters:

Returns:

  • ((String,Integer,String), nil)

    the definition place or nil if one cannot be determined



227
228
229
230
231
232
233
234
235
# File 'lib/syskit/gui/component_network_base_view.rb', line 227

def self.find_definition_place(model)
    location = model.definition_location.find do |location|
        return if location.label == 'require' || location.label == 'using_task_library'
        Roby.app.app_file?(location.absolute_path)
    end
    if location
        return location.absolute_path, location.lineno
    end
end

.graph_annotation_buttons(namespace, defaults) ⇒ Object

Generate the list of buttons that allows to display or hide graph annotations, as enumerated by Syskit::Graphviz.available_graph_annotations

Parameters:

  • namespace (String)

    the button namespace, i.e. a string that is prefixed before the button ID. The final button ID is #namespace/annotations/#annotation_name

  • the (Set<String>)

    set of annotations that are initially shown

See Also:



68
69
70
# File 'lib/syskit/gui/component_network_base_view.rb', line 68

def self.graph_annotation_buttons(namespace, defaults)
    make_annotation_buttons(namespace, Graphviz.available_graph_annotations, defaults)
end

.html_defined_in(page, model, with_require: true, definition_location: nil, format: "<b>Defined in</b> %s") ⇒ Object

Render the snippet that represents the definition place of a model

Parameters:

  • the (#push)

    page on which the HTML should be pushed

  • the (Model<Component>)

    model

  • with_require (Boolean)

    whether a require '…' line should be rendered as well

  • definition_location

    the model's definition location. If nil, it will be determined by calling find_definition_place

  • format (String)

    a format string (usable with String#% used to render the definition place in HTML



247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/syskit/gui/component_network_base_view.rb', line 247

def self.html_defined_in(page, model, with_require: true, definition_location: nil, format: "<b>Defined in</b> %s")
    path, lineno = *definition_location || find_definition_place(model)
    if path
        path = Pathname.new(path)
        path_link = page.link_to(path, "#{path}:#{lineno}", lineno: lineno)
        page.push(nil, "<p>#{format % [path_link]}</p>")
        if with_require
            if req_base = $LOAD_PATH.find { |p| path.fnmatch?(File.join(p, "*")) }
                req = path.relative_path_from(Pathname.new(req_base))
                page.push(nil, "<code>require '#{req.sub_ext("")}'</code>")
            end
        end
    end
end

.make_annotation_buttons(namespace, annotations, defaults) ⇒ Object

Generate a list of buttons to show or hide annotations

Parameters:

  • namespace (String)

    the button namespace, i.e. a string that is prefixed before the button ID. The final button ID is #namespace/annotations/#annotation_name

  • the (Array<String>)

    list of annotations

  • the (Set<String>)

    set of annotations that are initially shown



25
26
27
28
29
30
31
32
# File 'lib/syskit/gui/component_network_base_view.rb', line 25

def self.make_annotation_buttons(namespace, annotations, defaults)
    annotations.sort.map do |ann_name|
        Button.new("#{namespace}/annotations/#{ann_name}",
                   on_text: "Show #{ann_name}",
                   off_text: "Hide #{ann_name}",
                   state: defaults.include?(ann_name))
    end
end

.task_annotation_buttons(namespace, defaults) ⇒ Object

Generate the list of buttons that allows to display or hide task annotations as enumerated by Syskit::Graphviz.available_task_annotations

Parameters:

  • namespace (String)

    the button namespace, i.e. a string that is prefixed before the button ID. The final button ID is #namespace/annotations/#annotation_name

  • the (Set<String>)

    set of annotations that are initially shown

See Also:



54
55
56
# File 'lib/syskit/gui/component_network_base_view.rb', line 54

def self.task_annotation_buttons(namespace, defaults)
    make_annotation_buttons(namespace, Graphviz.available_task_annotations, defaults)
end

Instance Method Details

#buttonClicked(button_id, new_state) ⇒ 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.

Slot called when a HTML button is clicked by the user

It handles the common component view buttons



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
327
328
329
330
# File 'lib/syskit/gui/component_network_base_view.rb', line 299

def buttonClicked(button_id, new_state)
    button_id =~ /\/(\w+)(.*)/
    namespace, button_id = $1, $2
    config = send("#{namespace}_options")
    case button_id
    when /\/show_compositions/
        config[:remove_compositions] = !new_state
    when /\/show_all_ports/
        config[:show_all_ports] = new_state
    when /\/show_logger/
        if new_state
            config[:excluded_models].delete(OroGen::Logger::Logger)
        else
            config[:excluded_models] << OroGen::Logger::Logger
        end
    when /\/zoom/
        config[:zoom] += 0.1
    when /\/unzoom/
        if config[:zoom] > 0.1
            config[:zoom] -= 0.1
        end
    when /\/save/
        save_svg namespace
    when  /\/annotations\/(\w+)/
        ann_name = $1
        if new_state then config[:annotations] << ann_name
        else config[:annotations].delete(ann_name)
        end
    end
    push_plan(namespace, plan)
    emit updated
end

#clearObject



129
130
# File 'lib/syskit/gui/component_network_base_view.rb', line 129

def clear
end

#compute_system_network(model, main_plan = nil) ⇒ Roby::Task

Compute the system network for a model

Parameters:

  • model (Model<Component>)

    the model whose representation is needed

  • main_plan (Roby::Plan, nil) (defaults to: nil)

    the plan in which we need to generate the network, if nil a new plan object is created

Returns:

  • (Roby::Task)

    the toplevel task that represents the deployed model



140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/syskit/gui/component_network_base_view.rb', line 140

def compute_system_network(model, main_plan = nil)
    main_plan ||= Roby::Plan.new
    main_plan.add(original_task = model.as_plan)
    base_task = original_task.as_service
    engine = Syskit::NetworkGeneration::Engine.new(main_plan)
    engine.compute_system_network([base_task.task.planning_task])
    base_task.task
ensure
    if engine && engine.work_plan.respond_to?(:commit_transaction)
        engine.work_plan.commit_transaction
        main_plan.remove_task(original_task)
    end
end

#disableObject

Disable this HTML renderer

This is usually not called directly, it is used by MetaRuby::GUI::ModelBrowser



89
90
91
# File 'lib/syskit/gui/component_network_base_view.rb', line 89

def disable
    disconnect(page, SIGNAL('buttonClicked(const QString&,bool)'), self, SLOT('buttonClicked(const QString&,bool)'))
end

#enableObject

Enable this HTML renderer

This is usually not called directly, it is used by MetaRuby::GUI::ModelBrowser



81
82
83
# File 'lib/syskit/gui/component_network_base_view.rb', line 81

def enable
    connect(page, SIGNAL('buttonClicked(const QString&,bool)'), self, SLOT('buttonClicked(const QString&,bool)'))
end

#instanciate_model(model, main_plan = nil, options = Hash.new) ⇒ Roby::Task

Instanciate a model

Parameters:

  • model (Model<Component>)

    the model whose instanciation is needed

  • main_plan (Roby::Plan, nil) (defaults to: nil)

    the plan in which we need to generate the network, if nil a new plan object is created

  • options (Hash) (defaults to: Hash.new)

    options to be passed to InstanceRequirements#instanciate

Returns:

  • (Roby::Task)

    the toplevel task that represents the deployed model



164
165
166
167
168
169
170
171
172
173
# File 'lib/syskit/gui/component_network_base_view.rb', line 164

def instanciate_model(model, main_plan = nil, options = Hash.new)
    main_plan ||= Roby::Plan.new
    requirements = model.to_instance_requirements
    task = requirements.instanciate(
        main_plan,
        Syskit::DependencyInjectionContext.new,
        options)
    main_plan.add(task)
    task
end

#list_services(task) ⇒ Object

List the services provided by a component

Parameters:



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/syskit/gui/component_network_base_view.rb', line 178

def list_services(task)
    services = []
    task.model.each_data_service.sort_by(&:first).each do |service_name, service|
        model_hierarchy = service.model.ancestors.
            find_all do |m|
            m.kind_of?(Syskit::Models::DataServiceModel) &&
                m != Syskit::DataService &&
                m != Syskit::Device &&
                m != task.model
        end

        provided_services = []
        model_hierarchy.each do |m|
            port_mappings = service.port_mappings_for(m).dup
            port_mappings.delete_if do |from, to|
                from == to
            end
            provided_services << [m, port_mappings]
        end
        services << [service_name, provided_services]
    end
    services
end

#push_plan(kind, plan, interactive: true, **push_options) ⇒ Object

Adds or updates a plan representation on the HTML page

Parameters:

  • kind (String)

    either 'dataflow' or 'hierarchy'

  • plan (Roby::Plan)
  • interactive (Boolean)

    whether the display is going to be interactive



341
342
343
344
345
346
347
348
# File 'lib/syskit/gui/component_network_base_view.rb', line 341

def push_plan(kind, plan, interactive: true, **push_options)
    config = send("#{kind}_options").merge(push_options)
    if !interactive
        config.delete(:buttons)
    end
    title = config.delete(:title)
    page.push_plan(title, config.delete(:mode) || kind, plan, config.merge(id: kind))
end

#render(model, options = Hash.new) ⇒ Object



268
269
270
271
# File 'lib/syskit/gui/component_network_base_view.rb', line 268

def render(model, options = Hash.new)
    render_require_section(model)
    @current_model = model
end

#render_data_services(task, with_names = true) ⇒ Object

Render the data services of task into HTML

Parameters:

  • task (Component)

    the component

  • with_names (Boolean) (defaults to: true)

    whether the output should contain the service names or not



207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/syskit/gui/component_network_base_view.rb', line 207

def render_data_services(task, with_names = true)
    services = list_services(task)
    if services.empty?
        html = ""
    else
        if with_names
            html = ERB.new(DATA_SERVICE_WITH_NAMES_TEMPLATE).result(binding)
        else
            html = ERB.new(DATA_SERVICE_WITHOUT_NAMES_TEMPLATE).result(binding)
        end
    end

    page.push("Provided Services", html, id: 'provided_services')
end

#render_require_section(model) ⇒ Object



262
263
264
265
266
# File 'lib/syskit/gui/component_network_base_view.rb', line 262

def render_require_section(model)
    if model.respond_to?(:definition_location)
        ComponentNetworkBaseView.html_defined_in(page, model, with_require: true)
    end
end

#save_svg(id) ⇒ Object

Save a SVG fragment to a file

This basically saves the content of a fragment to a file. It does not validate that the data passed to Page#push is actually SVG content.

Parameters:

  • id (String)

    the fragment id as given to Page#push



280
281
282
283
284
285
286
287
288
289
290
291
292
# File 'lib/syskit/gui/component_network_base_view.rb', line 280

def save_svg(id)
    page.fragments.each do |f|
        if f.id == id
            file_name = Qt::FileDialog::getSaveFileName @parent, 
                "Save #{id} as SVG", ".", "SVG (*.svg)"
            if file_name
                File.open(file_name,"w") do |file|
                    file.write f.html
                end
            end
        end
    end
end