#!/usr/bin/ruby # so my editor will like the file...
=begin
Copyright 2010, Roger Pack
This file is part of Sensible Cinema.
Sensible Cinema is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Sensible Cinema is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Sensible Cinema. If not, see .
=end
alias system_original system
require 'fileutils'
class String
def snake_case
self.gsub(/::/, '/').
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
gsub(/([a-z\d])([A-Z])/,'\1_\2').
tr("-", "_").
downcase
end
end
# shared
require_relative '../jruby-swing-helpers/swing_helpers'
require_relative '../jruby-swing-helpers/drive_info'
# attempt to load on demand...i.e. faster...
for kls in [:MencoderWrapper, :MplayerEdl, :PlayAudio, :SubtitleProfanityFinder, :ConvertThirtyFps, :RubyClip]
autoload kls, "./lib/#{kls.to_s.snake_case}"
end
# a few I'll always need eventually...
require_relative '../storage'
require_relative '../edl_parser'
require 'tmpdir'
require 'whichr'
require 'os'
if OS.doze?
autoload :WMI, 'ruby-wmi'
autoload :EightThree, './lib/eight_three'
end
if OS.windows?
vendor_cache = File.expand_path(File.dirname(__FILE__)) + '/../../vendor/cache'
for name in ['.', 'mencoder', 'ffmpeg']
# put them all before the old path
ENV['PATH'] = (vendor_cache + '/' + name).to_filename + ';' + ENV['PATH']
end
installed_smplayer_folders = Dir['{c,d,e,f,g}:/program files*/MPlayer for Windows*'] # sometimes ends with UI? huh?
for folder in installed_smplayer_folders
ENV['PATH'] = ENV['PATH'] + ";#{folder.gsub('/', "\\")}"
end
else
ENV['PATH'] = ENV['PATH'] + ':' + '/opt/local/bin' # add macports' bin in, just in case...
end
import 'javax.swing.ImageIcon'
require_relative './sensible-cinema-dependencies'
module SensibleSwing
include SwingHelpers # various swing classes
JFrame
VERSION = File.read(File.dirname(__FILE__) + "/../../VERSION").strip
puts "v. " + VERSION
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()) #
class MainWindow < JFrame
include SwingHelpers # work-around?
def initialize be_visible = true
super "Sensible-Cinema #{VERSION} (GPL)"
force_accept_license_first
setDefaultCloseOperation JFrame::EXIT_ON_CLOSE # default is exit on close
@panel = JPanel.new
@buttons = []
@panel.set_layout nil
add @panel # why can't I just slap these down? panel? huh?
@starting_button_y = 40
@button_width = 400
add_text_line "Welcome to Sensible Cinema!"
@starting_button_y += 10 # kinder ugly...
add_text_line " Rest mouse over buttons for \"help\" type descriptions (tooltips)."
add_text_line ""
setIconImage(ImageIcon.new(__DIR__ + "/../vendor/profs.png").getImage())
check_for_various_dependencies
set_visible be_visible
end
def we_are_in_create_mode
ARGV.index("--create-mode")
end
def new_jbutton title, tooltip = nil
button = JButton.new title
button.tool_tip = tooltip
button.set_bounds(44, @starting_button_y, @button_width, 23)
@panel.add button
@buttons << button
if block_given? # allow for new_jbutton("xx") do ... end [this is possible through some miraculous means LOL]
button.on_clicked { yield }
end
increment_button_location
button
end
def add_text_line line
jlabel = JLabel.new line
happy = Font.new("Tahoma", Font::PLAIN, 11)
jlabel.setFont(happy)
jlabel.set_bounds(44,@starting_button_y ,460,14)
@panel.add jlabel
increment_button_location 18
jlabel
end
def increment_button_location how_much = 30
@starting_button_y += how_much
setSize @button_width+80, @starting_button_y + 50
end
def force_accept_license_first
if !(LocalStorage['main_license_accepted'] == VERSION)
require_blocking_license_accept_dialog 'Sensible Cinema', 'gplv3', 'http://www.gnu.org/licenses/gpl.html', 'Sensible Cinema license agreement',
"Sensible Cinema is distributed under the gplv3 (http://www.gnu.org/licenses/gpl.html).\nBY CLICKING \"accept\" YOU SIGNIFY THAT YOU HAVE READ, UNDERSTOOD AND AGREED TO ABIDE BY THE TERMS OF THIS AGREEMENT"
require_blocking_license_accept_dialog 'Sensible Cinema', 'is_it_legal_to_copy_dvds.txt file', File.expand_path(File.dirname(__FILE__) + "/../documentation/is_it_legal_to_copy_dvds.txt"),
'is_it_legal_to_copy_dvds.txt file', 'I acknowledge that I have read, understand, accept and agree to abide by the implications noted in the documentation/is_it_legal_to_copy_dvds.txt file'
LocalStorage['main_license_accepted'] = VERSION
end
end
LocalStorage = Storage.new("sensible_cinema_storage")
def when_thread_done(thread)
Thread.new {thread.join; yield }
end
# a window that when closed doesn't bring the whole app down
def new_child_window
child = MainWindow.new
child.setDefaultCloseOperation(JFrame::DISPOSE_ON_CLOSE)
child.parent=self # this should have failed in the PPL
# make both windows visible z-wise
x, y = self.get_location.x, self.get_location.y
child.set_location(x + 100, y + 100)
child
end
def run_smplayer_non_blocking *args
pp caller
@background_thread = Thread.new {
run_smplayer_blocking *args
}
end
def run_smplayer_blocking play_this, title_track_maybe_nil, passed_in_extra_options, force_use_mplayer, show_subs, start_full_screen
unless File.exist?(File.expand_path(play_this))
raise play_this + ' non existing?' # till these go away in mac :)
end
extra_options = ""
# -framedrop is for slow CPU's
# same with -autosync to try and help it stay in sync... -mc 0.03 is to A/V correct 1s audio per 2s video
# -hardframedrop might help but hurts just too much
extra_options << " -framedrop "
# ?? extra_mplayer_commands << "-mc 0.016" ??
extra_options << " -autosync 15 "
unless show_subs
# disable subtitles
extra_options << " -nosub -noautosub -forcedsubsonly -sid 1000 "
end
extra_options << " -alang en "
extra_options += " -slang en "
parent_parent = File.basename(File.dirname(play_this))
force_use_mplayer ||= OS.mac?
if parent_parent == 'VIDEO_TS'
# case d:\yo\VIDEO_TS\title0.vob
dvd_device_dir = normalize_path(File.dirname(play_this))
if force_use_mplayer
extra_options += " -dvd-device \"#{dvd_device_dir}/..\""
else
# smplayer
raise if dvd_device_dir =~ / / && OS.mac? # not accomodated
extra_options += " -dvd-device #{dvd_device_dir}/.."
end
play_this = "dvdnav://#{title_track_maybe_nil}"
elsif File.exist?(play_this + '/VIDEO_TS')
# case d:\ where d:\VIDEO_TS exists [DVD mounted in drive] or mac's /Volumes/YO
raise if play_this =~ / / # unexpected
extra_options += " -nocache -dvd-device #{play_this}"
play_this = "dvdnav://#{title_track_maybe_nil}"
else
# case g:\video\filename.mpg
# leave it the same...
end
if play_this =~ /dvdnav/ && title_track_maybe_nil
extra_options << " -msglevel identify=4 " # prevent smplayer from using *forever* to look up info on DVD's with -identify ...
end
extra_options += " -mouse-movements #{get_upconvert_secondary_settings} " # just in case smplayer also needs -mouse-movements... :) LODO
extra_options += " -lavdopts threads=#{OS.cpu_count} " # just in case this helps [supposed to with h.264] # fast *crashes* doze...
if force_use_mplayer
show_mplayer_instructions_once
conf_file = File.expand_path './mplayer_input_conf'
File.write conf_file, "ENTER {dvdnav} dvdnav select\nMOUSE_BTN0 {dvdnav} dvdnav select\nMOUSE_BTN0_DBL vo_fullscreen\nMOUSE_BTN2 vo_fullscreen\nKP_ENTER dvdnav select\n" # that KP_ENTER doesn't actually work. Nor the MOUSE_BTN0 on windows. Weird.
extra_options += " -font #{File.expand_path('subfont.ttf')} "
extra_options += " -volume 100 " # why start low? mplayer why oh why LODO
if OS.windows?
# direct3d for windows 7 old nvidia cards' sake [yipes] and also dvdnav sake
extra_options += " -vo direct3d "
conf_file = conf_file[2..-1] # strip off drive letter, which it doesn't seem to like no sir
end
if start_full_screen
extra_options += " -fs "
upconv = get_upconvert_vf_settings
upconv = "-vf #{upconv}" if upconv.present?
else
upconv = ""
end
c = "mplayer #{extra_options} #{upconv} -input conf=\"#{conf_file}\" #{passed_in_extra_options} \"#{play_this}\" "
else
if OS.windows?
extra_options += " -vo direct3d " # more light nvidia...should be ok...
end
set_smplayer_opts extra_options + " " + passed_in_extra_options, get_upconvert_vf_settings, show_subs
c = "smplayer_portable \"#{play_this}\" -config-path \"#{File.dirname SMPlayerIniFile}\" "
c += " -fullscreen " if start_full_screen
if !we_are_in_create_mode
#c += " -close-at-end " # we're still too unstable, mate...
end
end
puts c
system_blocking c
end
SMPlayerIniFile = File.expand_path("~/.smplayer/smplayer.ini")
def set_smplayer_opts to_this, video_, show_subs = false
p 'set smplayer extra opts to this:' + to_this
old_prefs = File.read(SMPlayerIniFile) rescue ''
unless old_prefs.length > 0
# LODO double check the rest here...
old_prefs = "[advanced]\nmplayer_additional_options=\nmplayer_additional_video_filters=\n[subtitles]\nautoload_sub=false\n[performance]\npriority=3"
end
raise to_this if to_this =~ /"/ # unexpected, unfortunately...
assert new_prefs = old_prefs.gsub(/mplayer_additional_options=.*/, "mplayer_additional_options=#{to_this}")
assert new_prefs.gsub!(/autoload_sub=.*$/, "autoload_sub=#{show_subs.to_s}")
raise if get_upconvert_vf_settings =~ /"/
assert new_prefs.gsub!(/mplayer_additional_video_filters=.*$/, "mplayer_additional_video_filters=\"#{get_upconvert_vf_settings}\"")
new_prefs.gsub!(/priority=.*$/, "priority=3") # normal priority...scary otherwise! lodo tell smplayer...
# enable dvdnav navigation, just for kicks I guess.
new_prefs.gsub!(/use_dvdnav=.*$/, "use_dvdnav=true")
FileUtils.mkdir_p File.dirname(SMPlayerIniFile) # case it doesn't yet exist
File.write(SMPlayerIniFile, new_prefs)
new_prefs.each_line{|l| print l if l =~ /additional_video/} # debug
end
def system_blocking command, low_prio = false
return true if command =~ /^@rem/ # JRUBY-5890 bug
if low_prio
out = IO.popen(command) # + " 2>&1"
low_prio = 64 # from msdn
if command =~ /(ffmpeg|mencoder)/
# XXXX not sure if there's a better way...because some *are* complex and have ampersands...
# unfortunately have to check for nil because it could exit too early [?]
exe_name = $1 + '.exe'
begin
p = proc{ ole = WMI::Win32_Process.find(:first, :conditions => {'Name' => exe_name}); sleep 1 unless ole; ole }
piddy = p.call || p.call || p.call # we actually do need this to loop...guess we're too quick
# but the first time through this still inexplicably fails all 3...odd
piddys = WMI::Win32_Process.find(:all, :conditions => {'Name' => exe_name})
for piddy in piddys
# piddy.SetPriority low_prio # this call can seg fault at times...JRUBY-5422
pid = piddy.ProcessId # this doesn't seg fault, tho
system_original("vendor\\setpriority -lowest #{pid}") # uses PID for the command line
end
rescue Exception => e
p 'warning, got exception trying to set priority [jruby prob? ...]', e
end
end
print out.read # let it finish
out.close
$?.exitstatus == 0 # 0 means success
else
raise command + " failed env #{ENV['PATH']}" unless system_original command
end
end
def system_non_blocking command
@background_thread = Thread.new { system_original command }
end
# make them choose which system call to use explicitly
undef system
def play_dvd_smplayer_unedited use_mplayer_instead, show_instructions, show_subs
drive_or_file, dvd_volume_name, dvd_id, edl_path_maybe_nil, descriptors_maybe_nil = choose_dvd_or_file_and_edl_for_it false
if descriptors_maybe_nil
title_track_maybe_nil = get_title_track(descriptors_maybe_nil, false)
end
if show_instructions
# want these even with smplayer sometimes I guess, if in power user mode anyway
show_mplayer_instructions_once
end
run_smplayer_non_blocking drive_or_file, title_track_maybe_nil, "-osd-fractions 2", use_mplayer_instead, show_subs, false
end
if OS.doze? # avoids spaces in filenames :)
EdlTempFile = EightThree.convert_path_to_8_3(Dir.tmpdir) + '\\mplayer.temp.edl'
else
raise if Dir.tmpdir =~ / / # that would be unexpected, and probably cause problems...
EdlTempFile = Dir.tmpdir + '/mplayer.temp.edl'
end
def show_mplayer_instructions_once
@_show_mplayer_instructions_once ||= show_non_blocking_message_dialog <<-EOL
About to run mplayer. To control it, use
spacebar : pause,
double clicky/right click : toggle full screen,
arrow keys (left, right, up down, pg up, pg dn) to seek/scan
/ and * : inc/dec volume.
'o' key: turn on on-screen-display timestamps (note: the OSD timestamps [upper left] are 30 fps so will need to be converted to use).
'v' key: turn off subtitles.
'.' key: step one frame.
# key: change audio language track
EOL
end
def choose_dvd_or_file_and_edl_for_it force_choose_edl_file_if_no_easy_match = true
drive_or_file, dvd_volume_name, dvd_id = choose_dvd_drive_or_file false
unless @_edit_list_path # cache file selection...
edit_list_path = EdlParser.single_edit_list_matches_dvd(dvd_id)
if !edit_list_path && force_choose_edl_file_if_no_easy_match
edit_list_path = new_existing_file_selector_and_select_file("Please pick a DVD Edit List File (none or more than one were found that seem to match #{dvd_volume_name})--may need to create one for it", EdlParser::EDL_DIR)
raise 'cancelled choosing an EDL' unless edit_list_path
end
@_edit_list_path = edit_list_path
end
p 'reloading'
if @_edit_list_path
# reload it every time just in case it has changed on disk
descriptors = nil
begin
descriptors = parse_edl @_edit_list_path
rescue SyntaxError => e
show_non_blocking_message_dialog("this file has an error--please fix then hit ok: \n" + @_edit_list_path + "\n " + e)
raise e
end
end
[drive_or_file, dvd_volume_name, dvd_id, @_edit_list_path, descriptors]
end
MplayerBeginingBuffer = 1.0
MplayerEndBuffer = 0.0
def play_mplayer_edl_non_blocking optional_file_with_edl_path = nil, extra_mplayer_commands_array = [], force_mplayer = false, start_full_screen = true
if optional_file_with_edl_path
drive_or_file, edl_path = optional_file_with_edl_path
dvd_id = NonDvd # fake it out...LODO a bit smelly
else
drive_or_file, dvd_volume_name, dvd_id, edl_path, descriptors = choose_dvd_or_file_and_edl_for_it
end
start_add_this_to_all_ts = 0
if edl_path # some don't care...
descriptors = EdlParser.parse_file edl_path
title_track = get_title_track(descriptors)
splits = descriptors['mplayer_dvd_splits']
end
if dvd_id == NonDvd && !(File.basename(File.dirname(drive_or_file)) == 'VIDEO_TS') # VOB's...always start at 0
# check if starts offset...
all = `ffmpeg -i "#{drive_or_file}" 2>&1`
# Duration: 01:35:49.59, start: 600.000000
all =~ /Duration.*start: ([\d\.]+)/
start = $1.to_f
if start > 1 # LODO huh? dvd's themselves start at 0.3 [sintel]?
show_non_blocking_message_dialog "Warning: file seems to start at an extra offset, adding it to the timestamps... #{start}
maybe not compatible with XBMC, if that's what you use, and you probably don't" # TODO test it XBMC...
start_add_this_to_all_ts = start
end
splits = []
else
if splits == nil
show_blocking_message_dialog("warning: edit list does not contain mplayer replay information [mplayer_dvd_splits] so edits past a certain time period might not won't work ( http://goo.gl/yMfqX ).")
splits = []
end
end
if edl_path
splits.map!{|s| EdlParser.translate_string_to_seconds(s) }
edl_contents = MplayerEdl.convert_to_edl descriptors, add_secs_end = MplayerEndBuffer, add_secs_begin = MplayerBeginingBuffer, splits, start_add_this_to_all_ts # add a sec to mutes to accomodate for mplayer's oddness..
File.write(EdlTempFile, edl_contents)
extra_mplayer_commands_array << "-edl #{File.expand_path EdlTempFile}"
end
run_smplayer_non_blocking drive_or_file, title_track, extra_mplayer_commands_array.join(' '), force_mplayer, false, start_full_screen
end
def assert_ownership_dialog
message = "Do you certify you own the DVD this came of and have it in your possession?"
title = "Verify ownership"
returned = JOptionPane.show_select_buttons_prompt(message, {})
assert_confirmed_dialog returned, nil
end
def require_blocking_license_accept_dialog program, license_name, license_url_should_also_be_embedded_by_you_in_message,
title = 'Confirm Acceptance of License Agreement', message = nil
puts 'Please confirm license agreement in open window.'
message ||= "Sensible Cinema requires a separately installed program (#{program}), not yet installed.
You can install this program manually to the vendor/cache subdirectory, or Sensible Cinema can download it for you.
By clicking accept, below, you are confirming that you have read and agree to be bound by the
terms of its license (the #{license_name}), located at #{license_url_should_also_be_embedded_by_you_in_message}.
Click 'View License' to view it. If you do not agree to these terms, click 'Cancel'. You also agree that this is a
separate program, with its own distribution, license, ownership and copyright.
You agree that you are responsible for the download and use of this program, within sensible cinema or otherwise."
answer = JOptionPane.show_select_buttons_prompt message, :yes => 'Accept', :no => "View #{license_name}"
assert_confirmed_dialog answer, license_url_should_also_be_embedded_by_you_in_message
p 'confirmation of sensible cinema related license noted of: ' + license_name # LODO require all licenses together :P
throw unless answer == :yes
end
def assert_confirmed_dialog returned, license_url_should_also_be_embedded_by_you_in_message
# :yes, :no, :cancel
# 1 is view button was clicked
# 0 is accept
# 2 is cancel
if returned == :no
if license_url_should_also_be_embedded_by_you_in_message
system_non_blocking("start #{license_url_should_also_be_embedded_by_you_in_message}")
puts "Please restart after reading license agreement, to be able to then accept it."
end
System.exit 0
elsif returned == :cancel
p 'license not accepted...exiting'
System.exit 1
elsif returned == :exited
p 'license exited early...exiting'
System.exit 1
elsif returned == :yes
# ok
else
raise 'unknown'
end
end
def print *args
Kernel.print *args # avoid bin\sensible-cinema.rb:83:in `system_blocking': cannot convert instance of class org.jruby.RubyString to class java.awt.Graphics (TypeError)
end
def download_7zip
Dir.mkdir('./vendor/cache') unless File.directory? 'vendor/cache' # development may not have it created yet... [?]
unless File.exist? 'vendor/cache/7za.exe'
Dir.chdir('vendor/cache') do
print 'downloading unzipper (7zip--400K) ...'
MainWindow.download("http://downloads.sourceforge.net/project/sevenzip/7-Zip/9.20/7za920.zip", "7za920.zip")
system_blocking("../unzip.exe -o 7za920.zip") # -o means "overwrite" without prompting
end
end
end
def download_zip_file_and_extract english_name, url, to_this
download_7zip
Dir.chdir('vendor/cache') do
file_name = url.split('/')[-1]
print "downloading #{english_name} ..."
MainWindow.download(url, file_name)
system_blocking("7za e #{file_name} -y -o#{to_this}")
puts 'done ' + english_name
# creates vendor/cache/mencoder/mencoder.exe...
end
end
def check_for_exe windows_full_loc, unix_name
# in windows, that exe *at that location* must exist...
if OS.windows?
File.exist?(windows_full_loc)
else
require 'lib/check_installed_mac.rb'
if !CheckInstalledMac.check_for_installed(unix_name)
exit 1 # it'll have already displayed a message...
else
true
end
end
end
def check_for_various_dependencies
if we_are_in_create_mode
if !check_for_exe('vendor/cache/mencoder/mencoder.exe', 'mencoder')
require_blocking_license_accept_dialog 'mplayer', 'gplv2', 'http://www.gnu.org/licenses/gpl-2.0.html', "Appears that you need to install a dependency: mplayer with mencoder."
download_zip_file_and_extract "Mplayer/mencoder (6MB)", "http://sourceforge.net/projects/mplayer-win32/files/MPlayer%20and%20MEncoder/revision%2033883/MPlayer-rtm-svn-33883.7z", "mencoder"
end
end
# runtime dependencies, at least as of today...
ffmpeg_exe_loc = File.expand_path('vendor/cache/ffmpeg/ffmpeg.exe')
if !check_for_exe(ffmpeg_exe_loc, 'ffmpeg')
require_blocking_license_accept_dialog 'ffmpeg', 'gplv2', 'http://www.gnu.org/licenses/gpl-2.0.html', "Appears that you need to install a dependency: ffmpeg."
download_zip_file_and_extract "ffmpeg (5MB)", "http://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-git-335bbe4-win32-static.7z", "ffmpeg"
end
if OS.mac?
check_for_exe("mplayer", "mplayer") # mencoder and mplayer are separate for mac... [this checks for mac's mplayerx, too]
else
path = RubyWhich.new.which('smplayer_portable')
if(path.length == 0)
# this one has its own installer...
show_blocking_message_dialog("It appears that you need to install a pre-requisite dependency: MPlayer for Windows (MPUI).
Click ok to be directed to its download website, where you can download and install it (recommend: MPUI....Full-Package.exe),
then restart sensible cinema. NB that it takes awhile to install. Sorry about that.",
"Lacking dependency", JOptionPane::ERROR_MESSAGE)
open_url_to_view_it_non_blocking "http://code.google.com/p/mulder/downloads/list?can=2&q=MPlayer&sort=-uploaded&colspec=Filename%20Summary%20Type%20Uploaded%20Size%20DownloadCount"
System.exit 0
end
end
end
def open_url_to_view_it_non_blocking url
if OS.windows?
system_non_blocking("start #{url.gsub('&', '^&')}") # LODO would launchy help/work here with the full url?
else
system_non_blocking "#{OS.open_file_command} \"#{url}\"" # LODO test
end
end
def open_file_to_edit_it filename, options = {} # :start_minimized
if OS.windows?
if options[:start_minimized]
system_non_blocking "start /min notepad \"#{filename}\""
else
system_non_blocking "notepad \"#{filename}\""
end
else
# ignore minimized :P
system_non_blocking "open -a TextEdit \"#{filename}\""
end
end
def new_nonexisting_filechooser_and_go title = nil, default_dir = nil, default_file = nil
bring_to_front
JFileChooser.new_nonexisting_filechooser_and_go title, default_dir, default_file
end
def show_blocking_message_dialog(message, title = message.split("\n")[0], style= JOptionPane::INFORMATION_MESSAGE)
bring_to_front
SwingHelpers.show_blocking_message_dialog message, title, style
end
# call dispose on this to close it if it hasn't been canceled yet...
def show_non_blocking_message_dialog message, close_button_text = 'Close'
bring_to_front
# lodo NonBlockingDialog it can get to the top instead of being so buried...
NonBlockingDialog.new(message, close_button_text)
end
include_class javax.swing.UIManager
def get_user_input(message, default = '', cancel_ok = false)
bring_to_front
SwingHelpers.get_user_input message, default, cancel_ok
end
def show_copy_pastable_string(message, value)
bring_to_front
RubyClip.set_clipboard value
get_user_input message + " (has been copied to clipboard)", value, true
end
# also caches directory previously selected ...
def new_existing_file_selector_and_select_file title, dir = nil
bring_to_front
dir ||= LocalStorage[caller.inspect]
got = FileDialog.new_previously_existing_file_selector_and_go title, dir
LocalStorage[caller.inspect] = File.dirname(got)
got
end
def show_in_explorer filename
SwingHelpers.show_in_explorer filename
end
def get_disk_chooser_window names
GetDisk.new(self, names)
end
end
class GetDisk < JDialog
attr_reader :selected_idx
def initialize parent, options_array
super parent, true
box = JComboBox.new
box.add_action_listener do |e|
idx = box.get_selected_index
if idx != 0
# don't count choosing the first as a real entry
@selected_idx = box.get_selected_index - 1
dispose
end
end
box.add_item "Click to select DVD drive" # put something in index 0
options_array.each{|drive|
box.add_item drive
}
add box
pack # how do you get this arbitrary size? what the...
end
end
end
# LODO move to sane :) also remove the andand dep.
class String
def present?
length > 0
end
end
class NilClass
def present?
false
end
end
class Object
def present?
true
end
end
class Array
def present?
length > 0
end
end
class File
def self.get_root_dir this_path
this_path = File.expand_path this_path
if OS.doze?
this_path[0..2]
else
this_path.split('/')[0]
end
end
def self.strip_drive_windows this_complete_path
if OS.doze?
this_complete_path[2..-1]
else
this_complete_path
end
end
end