Class: MetaRuby::GUI::ModelBrowser

Inherits:
Qt::Widget
  • Object
show all
Defined in:
lib/metaruby/gui/model_browser.rb

Overview

Widget that allows to browse the currently available models and display information about them

It contains a model selection widget, which lists all available models and allows to select them, and a visualization pane in which the corresponding model visualizations are rendered as HTML

The object display itself is delegated to rendering objects. These objects must respond to:

#enable: enable this renderer. This is called so that the rendering
  object listens to relevant Qt signals if it has e.g. the ability to
  interact with the user through HTML buttons
#disable: disables this renderer. This is called so that the rendering
  object can stop listening to relevant Qt signals if it has e.g. the ability to
  interact with the user through HTML buttons
#clear: clear existing data
#render(model): render the given model

Defined Under Namespace

Classes: Page

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(main = nil, exception_view: nil) ⇒ ModelBrowser

Returns a new instance of ModelBrowser.



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/metaruby/gui/model_browser.rb', line 77

def initialize(main = nil, exception_view: nil)
    super(main)

    @available_renderers = Hash.new
    @registered_exceptions = Array.new

    @history = Array.new
    @history_index = -1

    @manager = RenderingManager.new

    @main_layout = Qt::VBoxLayout.new(self)
    @vertical_splitter = Qt::Splitter.new(Qt::Vertical, self)
    main_layout.add_widget(vertical_splitter)

    @central_splitter = Qt::Splitter.new(vertical_splitter)
    @exception_view = (exception_view ||= ExceptionView.new)
    exception_view.parent = vertical_splitter
    connect(exception_view, SIGNAL('fileOpenClicked(const QUrl&)'), self, SLOT('fileOpenClicked(const QUrl&)'))
    add_central_widgets(central_splitter)

    vertical_splitter.add_widget(central_splitter)
    vertical_splitter.add_widget(exception_view)
    setTabOrder(model_selector, display)

    update_exceptions
end

Instance Attribute Details

#central_splitterQt::Splitter (readonly)

Returns the horizontal splitter between the model browser and the model view.

Returns:

  • (Qt::Splitter)

    the horizontal splitter between the model browser and the model view



55
56
57
# File 'lib/metaruby/gui/model_browser.rb', line 55

def central_splitter
  @central_splitter
end

#displayQt::WebView (readonly)

Returns the HTML view widget.

Returns:

  • (Qt::WebView)

    the HTML view widget



31
32
33
# File 'lib/metaruby/gui/model_browser.rb', line 31

def display
  @display
end

#exception_viewExceptionView (readonly)

Returns view that allows to display errors to the user.

Returns:

  • (ExceptionView)

    view that allows to display errors to the user



34
35
36
# File 'lib/metaruby/gui/model_browser.rb', line 34

def exception_view
  @exception_view
end

#historyArray<Model,[String]> (readonly)

Returns the browsing history, as either direct modules or module name path (suitable to be given to #select_by_path).

Returns:

  • (Array<Model,[String]>)

    the browsing history, as either direct modules or module name path (suitable to be given to #select_by_path)



44
45
46
# File 'lib/metaruby/gui/model_browser.rb', line 44

def history
  @history
end

#history_indexInteger (readonly)

Returns the index of the current link in the history.

Returns:

  • (Integer)

    the index of the current link in the history



46
47
48
# File 'lib/metaruby/gui/model_browser.rb', line 46

def history_index
  @history_index
end

#main_layoutQt::BoxLayout (readonly)

Returns the main layout.

Returns:

  • (Qt::BoxLayout)

    the main layout



48
49
50
# File 'lib/metaruby/gui/model_browser.rb', line 48

def main_layout
  @main_layout
end

#managerRenderingManager (readonly)

Returns the object that manages all the rendering objects available.

Returns:

  • (RenderingManager)

    the object that manages all the rendering objects available



37
38
39
# File 'lib/metaruby/gui/model_browser.rb', line 37

def manager
  @manager
end

#model_selectorModelSelector (readonly)

Returns the widget that lists available models and allows to select them.

Returns:

  • (ModelSelector)

    the widget that lists available models and allows to select them



25
26
27
# File 'lib/metaruby/gui/model_browser.rb', line 25

def model_selector
  @model_selector
end

#pagePage

Returns the page object that handles compositing the results of different rendering objects, as well as the ability to e.g. handle buttons.

Returns:

  • (Page)

    the page object that handles compositing the results of different rendering objects, as well as the ability to e.g. handle buttons



29
30
31
# File 'lib/metaruby/gui/model_browser.rb', line 29

def page
  @page
end

#registered_exceptionsArray<Exception> (readonly)

Returns set of exceptions raised during the last rendering step.

Returns:

  • (Array<Exception>)

    set of exceptions raised during the last rendering step



40
41
42
# File 'lib/metaruby/gui/model_browser.rb', line 40

def registered_exceptions
  @registered_exceptions
end

#vertical_splitterQt::Splitter (readonly)

Returns the toplevel splitter (between model browser and exception view).

Returns:

  • (Qt::Splitter)

    the toplevel splitter (between model browser and exception view)



52
53
54
# File 'lib/metaruby/gui/model_browser.rb', line 52

def vertical_splitter
  @vertical_splitter
end

Instance Method Details

#add_central_widgets(splitter) ⇒ Object

Sets up the widgets that form the central part of the browser



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/metaruby/gui/model_browser.rb', line 167

def add_central_widgets(splitter)
    @model_selector = ModelSelector.new
    splitter.add_widget(model_selector)

    # Create a central stacked layout
    display = @display = Qt::WebView.new
    browser = self
    display.singleton_class.class_eval do
        define_method :contextMenuEvent do |event|
            menu = Qt::Menu.new(self)
            act = page.action(Qt::WebPage::Back)
            act.enabled = true
            menu.add_action act
            connect(act, SIGNAL(:triggered), browser, SLOT(:back))
            act = page.action(Qt::WebPage::Forward)
            act.enabled = true
            connect(act, SIGNAL(:triggered), browser, SLOT(:forward))
            menu.add_action act
            menu.popup(event.globalPos)
            event.accept
        end
    end
    splitter.add_widget(display)
    splitter.set_stretch_factor(1, 2)
    self.page = Page.new(@model_selector, display.page)

    model_selector.connect(SIGNAL('model_selected(QVariant)')) do |mod|
        mod = mod.to_ruby
        push_to_history(mod)
        render_model(mod)
    end
end

#backObject

Go back in the browsing history



295
296
297
298
299
# File 'lib/metaruby/gui/model_browser.rb', line 295

def back
    return if history_index <= 0
    @history_index -= 1
    select_by_history_element(history[history_index])
end

#current_selectionRubyModuleModel::ModuleInfo?

Returns the currently selected item

Returns:

  • (RubyModuleModel::ModuleInfo, nil)

    nil if there are no selections



272
273
274
# File 'lib/metaruby/gui/model_browser.rb', line 272

def current_selection
    model_selector.current_selection
end

#forwardObject

Go forward in the browsing history



288
289
290
291
292
# File 'lib/metaruby/gui/model_browser.rb', line 288

def forward
    return if history_index == history.size - 1
    @history_index += 1
    select_by_history_element(history[history_index])
end

#linkClicked(url) ⇒ Object



217
218
219
220
221
222
223
# File 'lib/metaruby/gui/model_browser.rb', line 217

def linkClicked(url)
    if url.scheme == "link"
        path = url.path
        path = path.split('/')[1..-1]
        select_by_path(*path)
    end
end

#push_to_history(object) ⇒ Object

Pushes one element in the history

If the history index is not at the end, the remainder is discarded



279
280
281
282
283
284
285
# File 'lib/metaruby/gui/model_browser.rb', line 279

def push_to_history(object)
    return if object == history[history_index]

    @history = history[0, history_index + 1]
    history << object
    @history_index = history.size - 1
end

#register_type(root_model, rendering_class, name, priority = 0, categories: [], resolver: ModelHierarchy::Resolver.new) ⇒ Object

Registers a certain kind of model as well as the information needed to display it

It registers the given type on the model browser so that it gets displayed there.

You must call #update_model_selector after this call for the modification to have any effect (i.e. for the newly registered models to appear on the selector)

Parameters:

  • type (Model)

    the base model class for the models that are considered here

  • rendering_class (Class)

    a class from which a relevant rendering object can be created. The generated instances must follow the rules described in the documentation of MetaRuby::GUI::ModelBrowser

  • name (String)

    the name that should be used for this category

  • priority (Integer) (defaults to: 0)

    the priority of this category. Some models might be submodels of various types at the same time (as e.g. when both a model and its supermodel are registered here). The one with the highest priority will be used.



159
160
161
162
163
164
# File 'lib/metaruby/gui/model_browser.rb', line 159

def register_type(root_model, rendering_class, name, priority = 0, categories: [], resolver: ModelHierarchy::Resolver.new)
    model_selector.register_type(
        root_model, name, priority,
        categories: categories, resolver: resolver)
    manager.register_type(root_model, rendering_class)
end

#reloadObject

Update the model list



312
313
314
# File 'lib/metaruby/gui/model_browser.rb', line 312

def reload
    model_selector.reload
end

#render_model(mod, options = Hash.new) ⇒ Object

Call to render the given model

Parameters:

  • mod (Model)

    the model that should be rendered

Raises:

  • (ArgumentError)

    if there is no view available for the given model



233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/metaruby/gui/model_browser.rb', line 233

def render_model(mod, options = Hash.new)
    page.clear
    @registered_exceptions.clear
    reference_model, _ = manager.find_renderer(mod)
    if mod
        page.title = "#{mod.name} (#{reference_model.name})"
        begin
            manager.render(mod, options)
        rescue ::Exception => e
            @registered_exceptions << e
        end
    else
        @registered_exceptions << ArgumentError.new("no view available for #{mod} (#{mod.class})")
    end
    update_exceptions
end

#restore_from_settings(settings) ⇒ Object

Restore the state of this widget from settings previously saved with #save_to_settings

Parameters:

  • settings (Qt::Settings)


109
110
111
112
113
114
115
116
117
118
119
# File 'lib/metaruby/gui/model_browser.rb', line 109

def restore_from_settings(settings)
    %w{central_splitter vertical_splitter}.each do |object_name|
        sizes = settings.value(object_name)
        if !sizes.null?
            sizes = sizes.to_list.map do |obj|
                obj.to_int
            end
            send(object_name).sizes = sizes
        end
    end
end

#save_to_settings(settings) ⇒ Object

Save the current state of this widget in the given settings

Parameters:

  • settings (Qt::Settings)


124
125
126
127
128
129
130
# File 'lib/metaruby/gui/model_browser.rb', line 124

def save_to_settings(settings)
    %w{central_splitter vertical_splitter}.each do |object_name|
        sizes = send(object_name).sizes
        sizes = sizes.map { |o| Qt::Variant.new(o) }
        settings.set_value(object_name, Qt::Variant.new(sizes))
    end
end

#select_by_history_element(h) ⇒ Object

Selects a given model based on a value in the history



304
305
306
307
308
309
# File 'lib/metaruby/gui/model_browser.rb', line 304

def select_by_history_element(h)
    if h.respond_to?(:to_ary)
        select_by_path(*h)
    else select_by_model(h)
    end
end

#select_by_model(model) ⇒ Boolean

Selects the given model if it registered in the model list This emits the model_selected signal

Returns:

  • (Boolean)

    true if the path resolved to something known, and false otherwise



265
266
267
268
269
# File 'lib/metaruby/gui/model_browser.rb', line 265

def select_by_model(model)
    if model_selector.select_by_model(model)
        push_to_history(model)
    end
end

#select_by_path(*path) ⇒ Boolean

Selects the given model if it registered in the model list This emits the model_selected signal

Returns:

  • (Boolean)

    true if the path resolved to something known, and false otherwise



258
259
260
261
262
# File 'lib/metaruby/gui/model_browser.rb', line 258

def select_by_path(*path)
    if model_selector.select_by_path(*path)
        push_to_history(path)
    end
end

#update_exceptionsObject

Updates #exception_view from the set of registered exceptions



251
252
253
254
# File 'lib/metaruby/gui/model_browser.rb', line 251

def update_exceptions
    exception_view.exceptions = registered_exceptions +
        manager.registered_exceptions
end

#update_model_selectorObject

Update the model selector after #register_type got called



133
134
135
# File 'lib/metaruby/gui/model_browser.rb', line 133

def update_model_selector
    model_selector.update
end