progress-bar/lib/progress-bar.rb

264 lines
5.5 KiB
Ruby

require 'dbus'
require 'pathname'
#class DBus::Base
# def initialize object
# @object = object
# @object.interfaces.each do |intname|
# int = @object[intname]
# int.methods do |name, |
# meth
# end
# end
# end
#end
module ProgressBar
@klasses ||= []
class <<self
def register klass
@klasses.push klass
end
def new *a, **o
@klasses.map {|cl| cl.new *a, **o}.find &:possible?
end
end
end
class ProgressBar::Base
attr_reader :max, :i, :text
attr_accessor :startts
def initialize max = nil, text = nil, **_options
@startts, @max, @i, @text = nil, max || 100, 0, text || ''
end
def start
at_exit {finish}
@startts = Time.now
end
def i= x
@i = x.to_i
change_progress
end
def max= val
@max = val
change_progress
end
def increment!( x = nil) self.i += (x || 1) end
alias to_i i
alias inc! increment!
def done_rel() 100.0*i/max end
def done_dur() Time.now-@startts end
def total_dur
done_dur * max / i
end
def text= x
@text = x
change_text
end
def error( text) end
def change_progress() end
def change_text() end
def finish() end
def self.possible?() false end
end
class ProgressBar::Console < ProgressBar::Base
attr_reader :outfd, :errfd
def initialize *a, outfd: nil, errfd: nil, **_options
@outfd = outfd || STDERR
@errfd = errfd || @outfd
super *a, **_options
end
def possible?
@outfd.tty?
end
def start
super
change_text
end
def format_time t
if t.finite?
sprintf "%02d:%02d:%02d", t/3600, t/60 % 3600, t % 60
else
"--:--:--"
end
end
def change_text
l = [[100.0*i/max, 0].max, 100].min.to_i
dd, td = done_dur, total_dur
b = ?= * l
b[-1] = ?> unless 0 == l or 100 == l
@outfd.printf "\r\e[J%s / %s [%-*s] %s", format_time(dd), format_time(td), 100, b, text
end
alias change_progress change_text
def error text
@errfd.printf "\r\e[J%s\n", text
@errfd.flush
end
def finish
@outfd.puts
@outfd.flush
end
end
class ProgressBar::KDE < ProgressBar::Base
attr_reader :bus, :service, :view
def initialize max, text = nil, title: nil,
app_name: nil,
app_icon_name: nil,
unit: nil,
is_cancable: nil,
is_suspendable: nil,
**_options
super max, text
text = @text
text = nil if text.nil? or text.empty?
title = nil if title.nil? or title.empty?
unit = '' if unit.nil? or unit.empty?
@title, @text, @unit, @app_name, @app_icon_name, @is_cancable, @is_suspendable =
title, text, unit, app_name || $0, app_icon_name || '', is_cancable, is_suspendable
@errors = []
end
def possible?
'KDE' == ENV['XDG_CURRENT_DESKTOP']
end
def start
@finished = false
@bus = DBus::SessionBus.instance
@service = @bus['org.kde.JobViewServer']
jvs = @service['/JobViewServer']['org.kde.JobViewServer']
flags = (@is_cancable ? 0x1 : 0) | (@is_suspendable ? 0x2 : 0)
view_path = jvs.requestView @app_name, @app_icon_name, flags
@view = @service[view_path]['org.kde.JobViewV2']
super
@view.setTotalAmount @max, @unit
end
def change_text
@view.setInfoMessage text
end
def change_progress
@view.setProcessedAmount i, @unit
@view.setPercent done_rel
end
def error text
#STDERR.puts @view.object.introspect
#@view.setError text
@view.setDescriptionField 0, "Error", text
#@view.setInfoMessage "#{text}\nError: #{error}"
end
def finish
return if @finished
@view.terminate ''
@finished = true
end
def max= value
super value
@view.setTotalAmount value, @unit
end
end
class ProgressBar::KDialog < ProgressBar::Base
attr_reader :dialog_service_path, :dialog_object_path, :errors, :dialog_object
def initialize max, text = nil, title: nil, **_options
super max, text
text = @text
text = nil if text.nil? or text.empty?
title = nil if title.nil? or title.empty?
@title = title
@errors = []
end
def possible?
path = Pathname.new `which kdialog`.chomp
$?.exitstatus and path.executable?
end
def start
@finished = false
args = ['kdialog', @title ? ['--title', @title] : [], '--progressbar', @text || '.', @max].flatten.compact.map &:to_s
@dialog_service_path, @dialog_object_path =
IO.popen( args, 'r', &:readlines).join( "\n").split ' '
@dialog_bus = DBus.session_bus
@dialog_service = @dialog_bus[@dialog_service_path]
@dialog_object = @dialog_service[ @dialog_object_path]
#STDERR.puts "%p" %
@dialog_object.introspect
@dialog_object.showCancelButton 1
super
change_text if text.nil?
change_progress
rescue DBus::Error
raise Interrupt if $!.name == 'org.freedesktop.DBus.Error.ServiceUnknown'
raise
end
def self.kdialog *a
windowid = ENV['WINDOWID']
windowid = (windowid.is_a?(String) && !windowid.empty?) ? ['--attach', windowid] : []
system 'kdialog', *windowid, *a
end
def kdialog(*a) self.class.kdialog *a end
def change_progress()
#@dialog_object.Set 'org.kde.kdialog.ProgressDialog', 'value', i
@dialog_object['value'] = i
raise Interrupt if @dialog_object.wasCancelled
rescue DBus::Error
raise Interrupt if $!.name == 'org.freedesktop.DBus.Error.ServiceUnknown'
raise
end
def change_text()
@dialog_object.setLabelText text
raise Interrupt if @dialog_object.wasCancelled
rescue DBus::Error
raise Interrupt if $!.name == 'org.freedesktop.DBus.Error.ServiceUnknown'
raise
end
def error text
kdialog '--error', text
end
def finish()
return if @finished
@dialog_object.close rescue DBus::Error
@finished = true
end
def max= val
super val
@dialog_object['maximum'] = val
end
end
ProgressBar.register ProgressBar::Console
ProgressBar.register ProgressBar::KDE
ProgressBar.register ProgressBar::KDialog