Class: Ruber::ExternalProgramPlugin

Inherits:
GuiPlugin show all
Defined in:
lib/ruber/external_program_plugin.rb

Overview

Base class for plugins whose main task is to run an external program and maybe (not necessarily) to display the output in a tool widget.

Basically, this class is a wrapper for KDE::Process providing a more integrated API for the most common functions. In particular, it provides the following functionality:

  • automatic creation of the process

  • automatic cleanup at shutdown

  • automatic managing of buffered output

  • nicer API to read from standard output and standard error

  • simplified API to start the process

  • automatic display of standard output and standard error in a tool widget (if required)

  • display of the command line and of the process status in a tool widget (if required)

To start the process, you simply call the run_process method, passing it the name of the program to run, the working directory and the arguments.

When the process emits the readyReadStandardOutput() or the readyReadStandardError(), the contents of the appropriate stream are read and split into lines. The resulting array are passed to the process_standard_output or process_standard_error method. Derived classes can override these methods to do what they want with the output.

In general, you can’t be sure whether the data contained read from standard output or error contains complete lines. To deal with this issue, whenob reading from a stream, only full lines (that is, lines which end in “n”) are passed to process_standard_output or process_standard_error. If the last line isn’t complete, it is stored in a buffer. The next time characters are read from the process, if they came from the same channel, the buffer is added at the beginning of the new stream; if they came from the other channel, they’re passed to the appropriate process_standard_* method. This behaviour can be changed by passing the appropriate arguments to the constructor.

Some methods in this class have the ability to insert data in a OutputWidget. They will do so if the @output_widget instance variable (which is created in the constructor, if it doesn’t already exist) is not nil. Note that those methods don’t check if @output_widget actually is an OutputWidget or not. If it is something else, you’ll get errors. In all the following documentation it is assumed that:

  • the expression the output widget refers to the object the @output_widget instance variable refers to, unless it’s nil

  • everything concerning the output widget will be ignored (without giving any error) if the output widget doesn’t exist

Signals

process_finished(int code, QString reason)

Signal emitted when the process finishes. code is the exit code of the process, while reason is a string which can have one of the values “killed”, “crash” or be empty. If it’s empty, it means that the program finished normally; “killed” means that it was killed by the user and “crash” means that the program crashed.

process_started()

Signal emitted when the process has started

process_failed_to_start()

Signal emitted if the process couldn’t be started (for example, because the given program doesn’t exist)

Slots

  • slot_process_finished(int, QProcess::ExitStatus)

  • stop_process()

Constant Summary

Constants inherited from Plugin

Plugin::LICENSES

Instance Attribute Summary collapse

Attributes included from PluginLike

#plugin_description

Instance Method Summary collapse

Methods inherited from GuiPlugin

#action_collection, #execute_action, #unload

Methods inherited from Plugin

#about_data

Methods included from PluginLike

#add_extensions_to_project, #add_options_to_project, #add_widgets_to_project, #plugin_name, #query_close, #register_with_project, #remove_extensions_from_project, #remove_from_project, #remove_options_from_project, #remove_widgets_from_project, #restore_session, #save_settings, #session_data, #unload, #update_project

Constructor Details

#initialize(pdf, line_buffered = true) ⇒ ExternalProgramPlugin

Creates a new ExternalProgramPlugin.

pdf is the plugin info object for the plugin. If line_buffered is false, buffering won’t be used (all the characters read from the process will be passed to process_standard_output or process_standard_error even if they don’t end in a newline).

Note: the process’ channel mode will be set to Qt::Process::SeparateChannels. You can set it to any value you want later



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/ruber/external_program_plugin.rb', line 108

def initialize pdf, line_buffered = true
  super pdf
  @buffer = nil
  @buffer_content_channel = nil
  @line_buffered = line_buffered
  @output_widget = nil unless defined? @output_widget
  @process = KDE::Process.new self
  @process.process_channel_mode = Qt::Process::SeparateChannels
  @process.output_channel_mode = KDE::Process::SeparateChannels
  @process.connect SIGNAL(:readyReadStandardOutput) do
    do_stdout @process.read_all_standard_output.to_s
  end
  @process.connect SIGNAL(:readyReadStandardError) do
    do_stderr @process.read_all_standard_error.to_s
  end
  connect @process, SIGNAL('finished(int, QProcess::ExitStatus)'), self, SLOT('slot_process_finished(int, QProcess::ExitStatus)')
  connect self, SIGNAL('process_finished(int, QString)'), self, SLOT('display_exit_message(int, QString)')
  @process.connect SIGNAL('error(QProcess::ProcessError)') do |e|
    failed_to_start if e == Qt::Process::FailedToStart
  end
  connect @process, SIGNAL('started()'), self, SIGNAL('process_started()')
end

Instance Attribute Details

#processObject (readonly)

The KDE::Process used by the plugin



95
96
97
# File 'lib/ruber/external_program_plugin.rb', line 95

def process
  @process
end

Instance Method Details

#run_process(prog, dir, args, title = '') ⇒ Object

Starts the program.

prog is the name of the program (you don’t need to specify the absolute path if it’s in PATH). args is an array containing the arguments. dir is the working directory.

title is the string to display in the output widget. If it is an empty string, the name of the program followed by its arguments will be used. If it is nil or false, the title won’t be set.



142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/ruber/external_program_plugin.rb', line 142

def run_process prog, dir, args, title = ''
  @buffer = nil
  @buffer_content_channel = nil
  @process.clear_program
  @process.working_directory = dir
  program = [prog] + args
  @process.program = program
  if @output_widget and title
    title = program.join ' ' if title.empty?
    @output_widget.title = title
  end
  @process.start
end

#shutdownObject

Prepares the plugin to be unloaded by killing the process (no signal will be emitted from the process or the plugin from now on).

If you reimplement this method, don’t forget to call super. If you don’t you might cause a crash when Ruber is closed



172
173
174
175
176
# File 'lib/ruber/external_program_plugin.rb', line 172

def shutdown
  @process.block_signals true
  @process.kill
  super
end

#stop_processObject

Stops the process.

It’s a shortcut for process.kill



161
162
163
# File 'lib/ruber/external_program_plugin.rb', line 161

def stop_process
  @process.kill
end