require 'gio2' require 'gtk2' # gvfs file selector demo. # Requirements: ruby 1.8(.7) ruby-gnome2 (1.0.1) dialog (1.1-20110707-1) # Usage: ruby dgvfselect.rb [file|URI] # Result: prints the file URI selected by user on STDOUT/STDERR class Array def mapm_rev receiver, method self.map{|item| receiver.send method, item } end def mapm method, *args self.map{|item| item.send method, *args} end end READSIZE = 1024 * 32 def gather_out io, str begin while true do str << (io.readpartial READSIZE) end rescue EOFError end str end def waiton things things = [things] if !things.kind_of? Array things.collect{|thing| if thing.is_a? Thread then thing.join else Process::waitpid thing $?.exitstatus end } end def run_process cmd cmd = [cmd] if !cmd.kind_of? Array err, err_chld = IO.pipe pid = fork { err.close STDERR.reopen err_chld exec *cmd } err_chld.close errstr = "" thread = Thread.new { gather_out err, errstr } waiton thread (waiton pid) << errstr end def finfostr info if info.symlink? then '-> ' + info.symlink_target else fchar = if info.directory? then '/' elsif info.file_type == GLib::File::Type::SPECIAL then case info.content_type when /socket/ '=' when /blockdevice/ 'b' when /chardevice/ 'c' else '?' end else ' ' end fchar + ' ' + info.modification_time.to_s end end def max a, b a > b ? a : b end def g_mount file mop = GLib::MountOperation.new mop.anonymous = false mop.signal_connect('ask-password'){|mop, message, default_user, default_domain, flags| flen = '25' ilen = '255' fieldtypes = [ ["User name", '0', mop.username.to_s], ["Password", '1', mop.password.to_s], ["Domain", '0', mop.domain.to_s] ] llen = fieldtypes.inject(0){|memo,field| max memo, field[0].length} fields = (0...fieldtypes.length).inject([]){|list,i| label, type, init = fieldtypes[i] list << label << (i+1).to_s << '1' << init << (i+1).to_s << (llen +2).to_s << flen << ilen << type } message = message + "\n\nUse ↑↓ arrows to move between fields, ↵Enter to confirm, Esc to quit." cmd = ['dialog', '--mixedform', message, '0', '0', '0'] + fields result, answer = run_process(cmd) mop.anonymous=false mop.username, mop.password, mop.domain = (answer.lines.to_a.mapm :chomp) mop.reply ((result == 0) ? GLib::MountOperation::Result::HANDLED : GLib::MountOperation::Result::ABORTED) } res = file.mount_enclosing_volume(0, mop){|res| begin file.mount_enclosing_volume_finish res rescue STDERR.puts $!.to_s end Gtk.main_quit } Gtk.main end def select_file dir = nil, file = nil dir = '.' if !dir file = '' if !file dir = GLib::File.new_for_commandline_arg dir found = false while true do files = [] dir.each('*').map{|info| f = info.name found = true if info.name == file if f != '.' and f != '..' then ary = [1, f.downcase, f, (finfostr info)] ary[0] = 0 if ary[3][0..0] == '/' files << ary end } files = files.compact.sort.map{|_,_,f,i| [f,i]}.flatten cmd = ['dialog', '--default-item', file, "--menu", dir.parse_name, '0', '0', '0'] + ['..', ''] + files result, answer = run_process(cmd) exit result if result != 0 if answer == '..' then dir = dir.parent if dir.parent else answer = dir.get_child answer ainfo = answer.query_info '*' if ainfo.directory? then dir = answer else STDERR.puts answer.parse_name puts answer.parse_name return 0 end end end end file = ARGV[0] file = '.' if ! file file = GLib::File.new_for_commandline_arg file begin mount = file.find_enclosing_mount rescue GLib::IO::NotFoundError, GLib::IO::NotMountedError g_mount file if $!.is_a? GLib::IO::NotMountedError end info = file.query_info '*' rescue nil exit select_file file.parse_name if info and info.directory? parent = file.parent pinfo = parent.query_info '*' if parent rescue nil exit select_file parent.parse_name, file.basename if pinfo and pinfo.directory? exit -1