Class: Ruber::OutputWidget
- Inherits:
-
Qt::Widget
- Object
- Qt::Widget
- Ruber::OutputWidget
- Includes:
- GuiStatesHandler
- Defined in:
- lib/ruber/output_widget.rb
Overview
Widget meant to be used as tool widget to display the output of a program. It is based on Qt Model/View classes and provides the following facitlities:
- an easy way to display in different colors items with different meaning (for example, error message are displayed in a different color from output messages)
- a centralized way in which the user can choose the colors for different types of items
- a context menu with some standard actions, which can be enhanced with custom ones and is automatically (under certain conditions) shown to the user
- autoscrolling (which means that whenever new text is added, the view scrolls so that the text becomes visible)
- a centralized way for the user to turn on and off word wrapping (which can be ignored by widgets for which it doesn’t make sense)
- a mechanism which allows the user to click on an entry containing a file name in the widget to open the file in the editor. The mechanism can be customized by plugins to be better tailored to their needs (and can also be turned off)
- a model class, derived from Qt::StandardItemModel, which provides a couple of convenience methods to make text insertion even easier.
Note that OutputWidget is not (and doesn’t derive from) one of the View classes.
Rather, it’s a normal Qt::Widget
which has the view as its only child.
You can add other widgets to the OutputWidget as you would with any other widget:
create the widget with the OutputWidget as parent and add it to the OutputWidget’s
layout (which is a Qt::GridLayout
where the view is at position 0,0).
Note: this class defines two new roles (OutputTypeRole
and IsTitleRole
),
which correspond to Qt::UserRole
and Qt::UserRole+1
. Therefore,
if you need to define other custom roles, please have them start from
Ruber::OutputWidget::IsTitleRole+1
.
Output types
The output_type
of an entry in the model can be set using the #set_output_type
method. This has two effects: first, the item will be displayed using the color
chosen by the user for that output type; second, the name of the output type will
be stored in that item under the custom role OutputTypeRole
.
There are several predefined output types: message
, message_good
,
message_bad
, output
,
output1
, output2
, warning
, warning1
, warning2
, error
, error1
and error2
.
The types ending with a number
can be used when you need different types with similar meaning.
The message
type
(and its variations) are meant to display messages which don’t come from the external
program but from Ruber itself (for example, a message telling that the external
problem exited successfully or exited with an error). Its good and bad version are
meant to display messages with good news and bad news respectively (for example:
“the program exited successfully” could be displayed using the message_good
type, while “the program crashed” could be displayed using the message_bad
type).
The output
type is meant
to be used to show the text written by the external program on standard output,
while the error
type is used to display the text written on standard error. If
you can distinguish between warning and errors, you can use the warning
type
for the latter.
The colors for the default output types are chosen by the user from the configuration dialog and are used whenever those output types are requested.
New output types (and their associated colors) can be make known to the output
widget by using the set_color_for
method. There’s no need to remove the
color, for example when the plugin is unloaded (indeed, there’s no way to do so).
The context menu
This widget automatically creates a context menu containing three actions: Copy, Copy Selected and Clear. Copy and Copy Selected copy the text contained respectively in all the items and in the selected items to the clipboard. The clear action removes all the entries from the model.
You can add other actions to the menu by performing the following steps:
- add an entry in the appropriate position of #action_list. Note
that this is an instance of ActionList, so it provides the insert_after
and insert_before methods which allow to easily put the actions in the
correct place. #action_list contains the
object_name
of the actions (and nil for the separators), not the action themselves - create the actions (setting their
object_name
to the values inserted in #action_list) and put them into the #actions hash, using theobject_name
as keys. Of course, you also need to define the appropriate slots and connect them to the actions’ signals.
Note that actions can only be added before the menu is first shown (usually, you do that in the widget’s constructor). The #about_to_fill_menu signal is emitted just before the menu is built: this is the last time you can add entries to it.
OutputWidget mixes in the GuiStatesHandler module, which means you can define states
to enable and disable actions as usual. By default, two states are defined: no_text
and no_selection
. As the names imply, the former is true when the model
is empty and false when there’s at least one item; the second is true when no
item is selected and false when there are selected items.
For the menu to be displayed automatically, the view should have a context_menu_requested(QPoint)
signal. The menu will be displayed in response to that signal, at the point given
as argument. For convenience, there are three classes ListView,
TreeView and TableView, derived
respectively from Qt::ListView
, Qt::TreeView
and Qt::TableView
which emit that signal from their contextMenuEvent
method. If you use
one of these classes as view, the menu will work automatically.
Autoscrolling
Whenever an item is added to the list, the view will be scrolled so that the added item is visible. Plugins which don’t want this feature can disable it by setting #auto_scroll to false. Note that auto scrolling won’t happen if an item is modified or removed
Word wrapping
If the user has enabled word wrapping for output widgets in the config dialog
(the general/wrap_output
option), word wrapping will be automatically enabled for
all output widgets. If the user has disabled it, it will be disabled for all
widgets.
Subclasses can avoid the automatic behaviour by setting the #ignore_word_wrap_option attribute to true and managing word wrap by themselves. This is mostly useful for output widgets for which word wrap is undesirable or meaningless.
Opening files in the editor
Whenever the user activates an item, the text of the item is searched for a filename
(and optionally for a line number). If it’s found, a new editor view is opened
and the file is displayed in it. The editor can be an already existing editor
or a new one created by splitting the current editor or in a new tab, according to
the general/tool_open_files
option.
This process uses four methods:
- #maybe_open_file
- the method connected to the view’s
activated(QModelIndex)
signal. It starts the search for the filename and, if successful, opens the editor view - #find_filename_in_index
- performs the search of the filename. By default, it uses #find_filename_in_string, but subclasses can override it to change the behaviour
- #find_filename_in_string
- the method used by default by #find_filename_in_index to find the filename.
- #display_file
- opens the file in an editor. By default uses the
general/tool_open_files
to decide how the editor should be created, but this behaviour can be overridden by subclasses.
If a relative filename is found, it’s considered relative to the directory contained in the #working_dir attribute.
Model
The Model class behaves as a standard Qt::StandardItemModel
, but
provides two methods, insert and
insert_lines which make easier adding items. You
aren’t forced to use this model, however: if you want to use another class,
pass it to the constructor.
Direct Known Subclasses
Defined Under Namespace
Classes: ActionList, ListView, Model, TableView, TreeView
Constant Summary
- OutputTypeRole =
The role which contains a string with the output type of the index
Qt::UserRole
- IsTitleRole =
The role which contains whether an item is or not the title
OutputTypeRole + 1
Instance Attribute Summary (collapse)
-
- (ActionList) action_list
readonly
private
The names of the action to use to build the menu.
-
- (Hash{String => KDE::Action}) actions
readonly
private
The actions to insert in the menu.
-
- (Boolean) auto_scroll
Whether auto scrolling should be enabled or not (default: true).
-
- (Boolean) ignore_word_wrap_option
Whether or not word wrapping should respect the
general/wrap_output
option (default: false). -
- (Qt::AbstractItemModel) model
readonly
The model used by the OutputWidget.
-
- (Boolean) skip_first_file_in_title
Whether or not to #find_filename_in_index should skip the first file name in the title.
-
- (Qt::AbstractItemView) view
readonly
The view used by the OutputWidget.
-
- (String) working_dir
(also: #working_directory)
The directory used to resolve relative paths when opening a file (default nil).
Instance Method Summary (collapse)
-
- (nil) clear_output
slot
Removes all the entries from the model.
-
- (nil) copy
slot
private
Slot connected to the ‘Copy’ action.
-
- (nil) copy_selected
slot
private
Slot connected to the ‘Copy Selection’ action.
-
- (nil) create_standard_actions
private
Creates the default actions for the context menu.
-
- (nil) create_widgets(view)
private
Creates the layout and the view.
-
- (nil) do_auto_scroll(parent, start_idx, end_idx)
slot
private
Slot called whenever rows are inserted in the model.
-
- (nil) fill_menu
private
Creates the context menu.
-
- (Array(String,Integer)?) find_filename_in_index(idx)
private
Searches in the display role of the given index for a file name.
-
- (Array(String,Integer), ...) find_filename_in_string(str)
private
Searches the given string for the first occurrence of a file name.
-
- (Boolean) has_title?
Whether or not the output widget has a title.
-
- (Hash) hints
private
The hints to pass to MainWindow#display_document.
-
- (OutputWidget) initialize(parent = nil, opts = {})
constructor
A new instance of OutputWidget.
-
- (nil) load_settings
slot
Loads the settings from the configuration file.
-
- (EditorView?) maybe_open_file(idx)
slot
private
Attempts to display the file whose name is contained in the given index.
- - (Boolean) pinned_down?
-
- (nil) rows_changed
slot
private
Slot called whenever rows are added to or removed from the model.
-
- (nil) scroll_to(idx)
Scrolls the view so that the item corresponding the given index is visible.
-
- (nil) selection_changed(sel, desel)
slot
private
Slot connected to the view’s selection model’s
selectionChanged
signal. -
- (nil) set_color_for(name, color)
Associates a color with an output type.
-
- (Symbol?) set_output_type(idx, type)
Changes the output type of a given index.
-
- (nil) setup_model(mod)
private
Prepares the model to use.
-
- (ni;) show_menu(pt)
slot
private
Shows the menu.
-
- (String) text_for_clipboard(indexes)
private
Retrieves the text to copy to the clipboard from the given indexes.
-
- (nil) title(text)
Gives a title to the widget.
-
- (nil) update_index_color(idx)
private
Updates the color of an index and its children so that it matches their output types.
-
- (Object) with_auto_scrolling(val) { ... }
Executes a block while temporarily turning autoscrolling on or off.
Methods included from GuiStatesHandler
#change_state, included, #initialize_states_handler, #register_action_handler, #remove_action_handler_for, #state
Signal Summary
-
- about_to_fill_menu
Signal emitted immediately before the menu is created.
Constructor Details
- (OutputWidget) initialize(parent = nil, opts = {})
A new instance of OutputWidget
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 |
# File 'lib/ruber/output_widget.rb', line 275 def initialize parent = nil, opts = {} @ignore_word_wrap_option = false @working_dir = nil @skip_first_file_in_title = true @use_default_font = opts[:use_default_font] super parent initialize_states_handler (opts[:view] || :list) setup_model opts[:model] connect @view.selection_model, SIGNAL('selectionChanged(QItemSelection, QItemSelection)'), self, SLOT('selection_changed(QItemSelection, QItemSelection)') connect @view, SIGNAL('activated(QModelIndex)'), self, SLOT('maybe_open_file(QModelIndex)') @auto_scroll = true @colors = {} @action_list = ActionList.new @action_list << 'copy' << 'copy_selected' << nil << 'clear' @actions = {} connect @view, SIGNAL('context_menu_requested(QPoint)'), self, SLOT('show_menu(QPoint)') @menu = Qt::Menu.new self create_standard_actions change_state 'no_text', true change_state 'no_selection', true end |
Instance Attribute Details
- (ActionList) action_list (readonly, private)
The names of the action to use to build the menu
Separators are represented by nil entries. The default is
['copy', 'copy_selected', nil, 'clear']
.
238 239 240 |
# File 'lib/ruber/output_widget.rb', line 238 def action_list @action_list end |
- (Hash{String => KDE::Action}) actions (readonly, private)
The actions to insert in the menu
Each action is inserted using its object_name
as key. By default, the hash
contains the ‘copy’, ‘copy_selected’ and ‘clear’ actions.
246 247 248 |
# File 'lib/ruber/output_widget.rb', line 246 def actions @actions end |
- (Boolean) auto_scroll
Whether auto scrolling should be enabled or not (default: true)
212 213 214 |
# File 'lib/ruber/output_widget.rb', line 212 def auto_scroll @auto_scroll end |
- (Boolean) ignore_word_wrap_option
Whether or not word wrapping should respect the general/wrap_output
option (default: false)
217 218 219 |
# File 'lib/ruber/output_widget.rb', line 217 def ignore_word_wrap_option @ignore_word_wrap_option end |
- (Qt::AbstractItemModel) model (readonly)
The model used by the Ruber::OutputWidget
251 252 253 |
# File 'lib/ruber/output_widget.rb', line 251 def model @model end |
- (Boolean) skip_first_file_in_title
Whether or not to #find_filename_in_index should skip the first file name in the title
230 231 232 |
# File 'lib/ruber/output_widget.rb', line 230 def skip_first_file_in_title @skip_first_file_in_title end |
- (Qt::AbstractItemView) view (readonly)
The view used by the OutputWidget
256 257 258 |
# File 'lib/ruber/output_widget.rb', line 256 def view @view end |
- (String) working_dir Also known as: working_directory
The directory used to resolve relative paths when opening a file (default nil)
222 223 224 |
# File 'lib/ruber/output_widget.rb', line 222 def working_dir @working_dir end |
Instance Method Details
- (nil) clear_output
Removes all the entries from the model
459 460 461 462 |
# File 'lib/ruber/output_widget.rb', line 459 def clear_output @model.remove_rows 0, @model.row_count nil end |
Slot Signature:
clear_output()
- (nil) copy (private)
Slot connected to the ‘Copy’ action.
It copies the content of all the items to the clipboard. The text is obtained from the items by calling #text_for_clipboard.
631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 |
# File 'lib/ruber/output_widget.rb', line 631 def copy items = [] stack = [] @model.row_count.times do |r| @model.column_count.times{|c| stack << @model.index(r, c)} end until stack.empty? it = stack.shift items << it (@model.row_count(it)-1).downto(0) do |r| (@model.column_count(it)-1).downto(0){|c| stack.unshift it.child(r, c)} end end clp = KDE::Application.clipboard clp.text = text_for_clipboard items nil end |
Slot Signature:
copy()
- (nil) copy_selected (private)
Slot connected to the ‘Copy Selection’ action.
It copies the content of all the items to the clipboard. The text is obtained from the items by calling #text_for_clipboard.
656 657 658 659 |
# File 'lib/ruber/output_widget.rb', line 656 def copy_selected clp = KDE::Application.clipboard clp.text = text_for_clipboard @view.selection_model.selected_indexes end |
Slot Signature:
copy_selected()
- (nil) create_standard_actions (private)
Creates the default actions for the context menu
It also sets up the gui state handlers for them
609 610 611 612 613 614 615 616 617 618 619 620 621 622 |
# File 'lib/ruber/output_widget.rb', line 609 def create_standard_actions @actions['copy'] = KDE::Action.new(self){|a| a.text = '&Copy'} @actions['copy_selected'] = KDE::Action.new(self){|a| a.text = '&Copy Selection'} @actions['clear'] = KDE::Action.new(self){|a| a.text = 'C&lear'} register_action_handler @actions['copy'], '!no_text' register_action_handler @actions['copy_selected'], ['no_text', 'no_selection'] do |s| !(s['no_text'] || s['no_selection']) end register_action_handler @actions['clear'], '!no_text' connect @actions['copy'], SIGNAL(:triggered), self, SLOT(:copy) connect @actions['copy_selected'], SIGNAL(:triggered), self, SLOT(:copy_selected) connect @actions['clear'], SIGNAL(:triggered), self, SLOT(:clear_output) nil end |
- (nil) create_widgets(view) (private)
Creates the layout and the view
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 |
# File 'lib/ruber/output_widget.rb', line 585 def view self.layout = Qt::GridLayout.new(self) if view.is_a?(Qt::Widget) @view = view @view.parent = self else @view = self.class.const_get(view.to_s.capitalize + 'View').new self end @view.selection_mode = Qt::AbstractItemView::ExtendedSelection @pin_button = Qt::ToolButton.new self @pin_button.tool_tip = i18n("Don't hide the tool widget when clicking on a file name") @pin_button.auto_raise = true @pin_button.icon = Qt::Icon.new KDE::Global.dirs.find_resource('icon', 'pin.png') @pin_button.checkable = true layout. @view, 1, 0 layout. @pin_button, 0, 0, 1, -1, Qt::AlignRight | Qt::AlignVCenter nil end |
- (nil) do_auto_scroll(parent, start_idx, end_idx) (private)
all indexes are considered relative to the model associated with the view, not to the model returned by #model. This doesn’ matter for Ruber::OutputWidget itself, but makes a difference in sublclasses where the two models are different (for example, FilteredOutputWidget)
Slot called whenever rows are inserted in the model
If autoscrolling is enabled, it scrolls so that the last row inserted is at the bottom of the widget. It does nothing if autoscrolling is disabled.
If the scrollbar slider is not at the bottom of the scroll bar, autoscrolling isn’t done, regardless of the option. This is because it’s likely that the user moved the slider, which may mean he’s looking at some particular lines of output and he wouldn’t like them to scroll away.
534 535 536 537 538 539 540 |
# File 'lib/ruber/output_widget.rb', line 534 def do_auto_scroll parent, start_idx, end_idx if @auto_scroll = @view. scroll_to @view.model.index(end_idx, 0, parent) if .value == .maximum end nil end |
Slot Signature:
do_auto_scroll(QModelIndex, int, int)
Creates the context menu
The menu is created using the values returned by #action_list and #actions.
Before creating the menu, the #about_to_fill_menu signal is emitted. Connecting to this signal allows to do some last-minute changes to the actions which will be inserted in the menu.
552 553 554 555 556 557 558 559 |
# File 'lib/ruber/output_widget.rb', line 552 def emit @action_list.each do |a| if a then @menu.add_action @actions[a] else @menu.add_separator end end end |
- (Array(String,Integer)?) find_filename_in_index(idx) (private)
Searches in the display role of the given index for a file name
This method is used by #maybe_open_file to find out the name of the file to open (if any) when an item is activated.
The actual search for the file name is done by #find_filename_in_string. If it reports a success, this method makes sure the file actually exists, expanding it relative to #working_dir if it’s not an absolute path. If #working_dir is not set, the current directory will be used. However, you’re advised not to relay on this behaviour and always set the working directory.
If the given index is the title of the widget (see #title=) and #skip_first_file_in_title
is true, all the text from the beginning of the title up to the first whitespace
or colon is ignored. Since often the first word of the title is the name of the
program being run (which may as well be compiled), it doesn’t make sense to attempt
to open it. This behaviour allows the user to activate on a title like
/usr/bin/ruby /path/to/script.rb
and see the file /path/to/script.rb
in the
editor. Without it, /usr/bin/ruby
would be opened instead.
Subclasses can override this method to extend or change its functionality. They have two choices on how to do this. The simplest is useful if they want to alter the string. In this case they can retrieve the text from the index, change it then call super passing the modified string as argument. The other way is to reimplement this method from scratch.
A subclass can also decide to completely disallow opening a file by activating the corresponding item by overriding this method to always return nil.
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 |
# File 'lib/ruber/output_widget.rb', line 819 def find_filename_in_index idx str = if idx.is_a?(String) then idx elsif @skip_first_file_in_title and idx.data(IsTitleRole).to_bool idx.data.to_string.sub(/^[^\s:]+/, '') else idx.data.to_string end res = find_filename_in_string str return unless res res = Array res res << 0 if res.size == 1 res[0].sub!(%r{^file://},'') unless res[0].match(%r{^.+://}) path = Pathname.new(res[0]) begin res[0] = path.realpath(@working_dir).to_s return nil unless File.file? res[0] rescue Errno::ENOENT return nil end end res end |
- (Array(String,Integer), ...) find_filename_in_string(str) (private)
Searches the given string for the first occurrence of a file name
The file name can optionally be followed by a colon and a line number.
What is a file name and what isn’t is a bit arbitrary. Here’s what this method recognizes as a filename:
- an absolute path not containing spaces and colons starting with ‘/’
- an absolute path not containing spaces and colons starting with ‘~’ or ‘~user’
(they’re expanded using
File.expand_path
) - a relative path starting with
./
or../
(either followed by a slash or not) - a relative path of the form
.filename
or.dirname/dir/file
- absolute URLs with an authority component
- any string not containing spaces or colons followed by a colon and a line number (in this case, the line number is required)
File names enclosed in quotes or parentheses are recognized.
863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 |
# File 'lib/ruber/output_widget.rb', line 863 def find_filename_in_string str #This ensures that file names inside quotes or brackets are found. It's #easier replacing quotes and brackets with spaces than to modify the main #regexp to take them into account str = str.gsub %r|['"`<>\(\)\[\]\{\}]|, ' ' matches = [] attempts = [ %r{(?:^|\s)([\w+.-]+:/{1,2}(?:/[^/:\s]+)+)(?::(\d+))?(?:$|[,.;:\s])}, #URLS %r{(?:^|\s)((?:/[^/\s:]+)+)(?::(\d+))?(?:$|[,.;:\s])}, #absolute files #absolute files referring to user home directory: ~/xyz or ~user/xyz %r{(?:^|\s)(~[\w_-]*(?:/[^/\s:]+)+)(?::(\d+))?(?:$|[,.;:\s])}, #relative files starting with ./ and ../ %r{(?:^|\s)(\.{1,2}(?:/[^/\s:]+)+)(?::(\d+))?(?:$|[,.;:\s])}, #hidden files or directories (.filename or .dir/filename) %r{(?:^|\s)(\.[^/\s:]+(?:/[^/\s:]+)*)(?::(\d+))?(?:$|[,.;:\s])}, #relative files containing, but not ending with a slash %r{(?:^|\s)([^/\s:]+/[^\s:]*[^\s/:])(?::(\d+))?(?:$|[,.;:\s])}, #relative files not containing slashes but ending with the line number %r{(?:^|\s)([^/\s:]+):(\d+)(?:$|[,.;:\s])} ] attempts.each do |a| m = str.match a matches << [m.begin(0),[$1,$2]] if m end match = matches.sort_by{|i| i[0]}[0] return unless match file, line = *match[1] file = File.(file) if file.start_with? '~' res = [file] res << line.to_i if line res end |
- (Boolean) has_title?
Whether or not the output widget has a title
See #title= for what is meant here by title
426 427 428 |
# File 'lib/ruber/output_widget.rb', line 426 def has_title? @model.index(0,0).data(IsTitleRole).to_bool end |
- (Hash) hints (private)
The hints to pass to MainWindow#display_document
This method determines the hints to use according to the general/tool_open_files
option. Derived classes may override this method to provide different hints. The
values which can be used are the ones described for MainWindow#editor_for!. Note,
however, that the :existing
entry won’t be used.
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 |
# File 'lib/ruber/output_widget.rb', line 773 def hints hints = {:new => :new_tab} choice = Ruber[:config][:general, :tool_open_files] case choice when :split_horizontally then hints[:split] = :horizontal when :split_vertically then hints[:split] = :vertical end if hints[:split] env = Ruber[:world].active_environment view = env.active_editor n_views = view ? env.tab(view).views.count : 0 if n_views == 1 then hints[:new] = :current_tab else hints.delete :split end end hints end |
- (nil) load_settings
Loads the settings from the configuration file.
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 |
# File 'lib/ruber/output_widget.rb', line 435 def load_settings cfg = Ruber[:config] colors = [:message, :message_good, :message_bad, :output, :output1, :output2, :error, :error1, :error2, :warning, :warning1, :warning2] colors.each{|c| set_color_for c, cfg[:output_colors, c]} @model.row_count.times do |r| @model.column_count.times do |c| update_index_color @model.index(r, c) end end @view.font = cfg[:general, :output_font] unless @use_default_font unless @ignore_word_wrap_option # Not all the views support word wrapping begin @view.word_wrap = cfg[:general, :wrap_output] rescue NoMethodError end end nil end |
Slot Signature:
load_settings()
- (EditorView?) maybe_open_file(idx) (private)
Attempts to display the file whose name is contained in the given index
Searches for a filename in the DisplayRole of the index using the #find_filename_in_index method. If a filename is found, an editor for it is displayed.
The behaviour of this method (which usually is only called via a signal-slot connection
to the views’ activated(QModelindex)
signal) changes according to the active
keyboard modifiers and to whether the Pinned tool button is on or off:
- if Ctrl or Shift are pressed and the view allows selection (that is, its selection mode is not NoSelection), then this method does nothing. The reason for this behaviour is that Ctrl and Shift are used to select items, so the user is most likely doing that, not requesting to open a file
- if the Pinned button is pressed, then the tool widget won’t be closed (but the focus will be moved to the editor)
- if Meta is pressed, then the file will be opened in a new editor, regardless of whether an editor for that file already exists
If a new editor should be created (either because the Meta key is pressed or because
no editor exists for the given file), the hints returned by #hints are used.
Unless the #hints method has been overloaded, this means that the general/tool_open_files
option is used.
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 |
# File 'lib/ruber/output_widget.rb', line 749 def maybe_open_file idx modifiers = Application.keyboard_modifiers if @view.selection_mode != Qt::AbstractItemView::NoSelection return if Qt::ControlModifier & modifiers != 0 or Qt::ShiftModifier & modifiers != 0 end file, line = find_filename_in_index idx return unless file line -= 1 unless line == 0 existing = (Qt::MetaModifier & modifiers) == 0 ? :always : :never display_hints = hints.merge(:line => line, :existing => existing) ed = Ruber[:main_window].display_document file, display_hints = pinned_down? and Qt::Application. != Qt::MidButton Ruber[:main_window]. self if ed.set_focus if ed ed end |
Slot Signature:
maybe_open_file(QModelIndex)
- (Boolean) pinned_down?
464 465 466 |
# File 'lib/ruber/output_widget.rb', line 464 def pinned_down? @pin_button.checked? end |
- (nil) rows_changed (private)
Slot called whenever rows are added to or removed from the model
Turns the no_text
gui state on or off depending on whether the model
is empty or not
715 716 717 718 |
# File 'lib/ruber/output_widget.rb', line 715 def rows_changed change_state 'no_text', @model.row_count == 0 nil end |
Slot Signature:
rows_changed()
- (nil) scroll_to(idx)
Scrolls the view so that the item corresponding the given index is visible
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 |
# File 'lib/ruber/output_widget.rb', line 329 def scroll_to idx case idx when Numeric rc = @model.row_count if idx >= rc then idx = rc -1 elsif idx < 0 and idx.abs < rc then idx = rc + idx elsif idx < 0 then idx = 0 end mod_idx = @model.index idx, 0 @view.scroll_to mod_idx, Qt::AbstractItemView::PositionAtBottom when Qt::ModelIndex idx = @model.index(@model.row_count - 1, 0) unless idx.valid? @view.scroll_to idx, Qt::AbstractItemView::PositionAtBottom when nil @view.scroll_to @model.index(@model.row_count - 1, 0), Qt::AbstractItemView::PositionAtBottom end nil end |
- (nil) selection_changed(sel, desel) (private)
Slot connected to the view’s selection model’s selectionChanged
signal
Turns the no_selection
gui state on or off according to whether the selection
is empty or not.
703 704 705 706 |
# File 'lib/ruber/output_widget.rb', line 703 def selection_changed sel, desel change_state 'no_selection', !@view.selection_model.has_selection nil end |
Slot Signature:
selection_changed(QItemSelection, QItemSelection)
- (nil) set_color_for(name, color)
Associates a color with an output type
If a color had already been associated with the given output type, it’ll be overwritten.
This method is useful to define new output types.
314 315 316 317 |
# File 'lib/ruber/output_widget.rb', line 314 def set_color_for name, color @colors[name] = color nil end |
- (Symbol?) set_output_type(idx, type)
Changes the output type of a given index
If a color has been associated with that output type, the foreground role and the output type role of that index are updated accordingly.
If no color has been associated with the output type, nothing is done
360 361 362 363 364 365 366 367 |
# File 'lib/ruber/output_widget.rb', line 360 def set_output_type idx, type color = @colors[type] if color @model.set_data idx, Qt::Variant.from_value(color), Qt::ForegroundRole @model.set_data idx, Qt::Variant.new(type.to_s), OutputTypeRole type end end |
- (nil) setup_model(mod) (private)
Prepares the model to use
After a call to this method, the model will become a child of the Ruber::OutputWidget
501 502 503 504 505 506 507 508 509 510 |
# File 'lib/ruber/output_widget.rb', line 501 def setup_model mod @model = mod || Model.new(self) @model.insert_column 0 if @model.column_count < 1 @model.parent = @view @view.model = @model connect @model, SIGNAL('rowsInserted(QModelIndex, int, int)'), self, SLOT(:rows_changed) connect @model, SIGNAL('rowsRemoved(QModelIndex, int, int)'), self, SLOT(:rows_changed) connect @model, SIGNAL('rowsInserted(QModelIndex, int, int)'), self, SLOT('do_auto_scroll(QModelIndex, int, int)') nil end |
Shows the menu
If the menu hasn’t as yet been created, it creates it.
The menu is shown asynchronously. This means that this method doesn’t wait for the user to choose an action but returns immediately.
572 573 574 575 576 |
# File 'lib/ruber/output_widget.rb', line 572 def pt if @menu.empty? @menu.popup pt nil end |
Slot Signature:
show_menu(QPoint)
- (String) text_for_clipboard(indexes) (private)
Retrieves the text to copy to the clipboard from the given indexes
The string is created by joining the text of toplevel items on the same row and different columns using tabs as separators. Different rows are separated with newlines. Child items are ignored.
Derived class can override this method (and, if they plan to put child items in the view, they’re advised to do so).
The reason the default behaviour ignores child items is that their meaning (and therefore the way their contents should be inserted into the string) depends very much on the specific content, so there’s no way to have a sensible default behaviour.
679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 |
# File 'lib/ruber/output_widget.rb', line 679 def text_for_clipboard indexes indexes = indexes.select{|i| !i.parent.valid?} rows = indexes.group_by{|idx| idx.row} rows = rows.sort text = rows.inject("") do |res, r| idxs = r[1].sort_by{|i| i.column} idxs.each{|i| res << i.data.to_string << "\t"} # The above line gives \t as last character, while a \n is needed res[-1] = "\n" res end # The above block leaves a \n at the end of the string which shouldn't be # there text[0..-2] end |
- (nil) title=(text)
Gives a title to the widget.
A title is a toplevel entry at position 0, 0 with output type :message
and has
the IsTitleRole
set to true. Of course, there can be only one item which is
a title.
If the item in position 0, 0 is not a title, a new row with title role and the given text is inserted.
If the item in position 0,0 is a title, then its display role is replaced with the given text.
Usually, the title is created when the external program is started and changed later if needed.
405 406 407 408 409 410 411 412 413 414 415 416 417 418 |
# File 'lib/ruber/output_widget.rb', line 405 def title= text idx = @model.index 0, 0 if idx.data(IsTitleRole).to_bool @model.set_data idx, Qt::Variant.new(text) else @model.insert_column 0 if @model.column_count == 0 @model.insert_row 0 idx = @model.index 0, 0 @model.set_data idx, Qt::Variant.new(text) @model.set_data idx, Qt::Variant.new(true), IsTitleRole end set_output_type idx, :message nil end |
- (nil) update_index_color(idx) (private)
Updates the color of an index and its children so that it matches their output types
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 |
# File 'lib/ruber/output_widget.rb', line 476 def update_index_color idx type = idx.data(OutputTypeRole).to_string.to_sym rescue nil color = @colors[type] if color @model.set_data idx, Qt::Variant.from_value(color), Qt::ForegroundRole end if @model.has_children idx @model.row_count(idx).times do |r| @model.column_count(idx).times do |c| update_index_color idx.child(r, c) end end end nil end |
- (Object) with_auto_scrolling(val) { ... }
Executes a block while temporarily turning autoscrolling on or off
After the block has been executed, autoscrolling returns to the original state.
378 379 380 381 382 383 384 |
# File 'lib/ruber/output_widget.rb', line 378 def with_auto_scrolling val old = @auto_scroll @auto_scroll = val begin yield ensure @auto_scroll = old end end |
Signal Details
Signal emitted immediately before the menu is created
You should connect to this signal if you want to add actions to the menu at the last possible time. Usually, however, you don’t need it, as actions are usually created in the constructor.