simple_gui_creator 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ChangeLog +7 -0
- data/README +26 -15
- data/Rakefile +4 -1
- data/TODO +10 -2
- data/VERSION +1 -1
- data/bin/simple_gui_creator +99 -56
- data/examples/absolute_positioning.rb +3 -1
- data/lib/simple_gui_creator/jframe_helper_methods.rb +120 -0
- data/lib/simple_gui_creator/parse_template.rb +11 -10
- data/lib/simple_gui_creator/simple_gui_creator.rb +44 -382
- data/lib/simple_gui_creator/swing_helpers.rb +221 -0
- data/lib/simple_gui_creator.rb +10 -4
- data/spec/parse_template.spec.rb +1 -1
- data/spec/swing_helpers.spec.rb +10 -9
- metadata +7 -3
data/ChangeLog
ADDED
data/README
CHANGED
@@ -10,29 +10,27 @@ You can specify "easy window layout" in ASCII text, example, if you have a layou
|
|
10
10
|
It will create a window that has buttons and text "like that," with reasonable spacing.
|
11
11
|
|
12
12
|
Here's how:
|
13
|
-
>> frame = ParseTemplate
|
13
|
+
>> frame = SimpleGuiCreator::ParseTemplate.new # or optionally subclass this instead, and call super in your constructor
|
14
14
|
>> frame.parse_setup_filename 'some_filename'
|
15
15
|
|
16
|
-
You can program
|
16
|
+
You can then program behaviors like this:
|
17
17
|
|
18
18
|
>> frame.elements['button1'].on_clicked {
|
19
|
-
|
19
|
+
SimpleGuiCreator.show_blocking_message_dialog "you clicked button1!"
|
20
20
|
}
|
21
21
|
|
22
|
-
This
|
23
|
-
an entirely separate file, or embedded in the code. "Normal humans" can edit the design layout files, for instance
|
24
|
-
and the separation allows for easy peace of mind.
|
22
|
+
This separates your views from your controllers, in this case, because you can store the layouts in
|
23
|
+
an entirely separate file, or embedded in the code. "Normal humans" can then edit the design layout files, for instance.
|
25
24
|
|
26
|
-
It also has helper methods for common GUI tasks, like the above show_blocking_message_dialog:
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
text_from_user = SimpleGui.get_user_input "Input your name:" # these raise an exception if the user cancels the dialog,
|
25
|
+
It also has helper methods for common GUI tasks, like the above show_blocking_message_dialog, and also:
|
26
|
+
SimpleGuiCreator.new_nonexisting_filechooser_and_go # select file or filename for a "new file" (not yet existing)
|
27
|
+
SimpleGuiCreator.new_existing_dir_chooser_and_go # select pre-existing directory
|
28
|
+
SimpleGuiCreator.show_in_explorer(filename) # reveals file in Explorer for windows, Finder for OS X
|
29
|
+
text_from_user = SimpleGuiCreator.get_user_input "Input your name:" # these raise an exception if the user cancels the dialog,
|
32
30
|
|
33
31
|
A select-button prompt dialog:
|
34
32
|
|
35
|
-
if(
|
33
|
+
if(SimpleGuiCreator.show_select_buttons_prompt("message title", :yes => 'text for the yes button', :no => 'text for the no button', :cancel => 'text for the cancel button') == :yes)
|
36
34
|
# they chose the "yes" equivalent button...
|
37
35
|
end
|
38
36
|
|
@@ -61,8 +59,21 @@ To install/use:
|
|
61
59
|
|
62
60
|
$ gem install simple-ruby-gui-creator
|
63
61
|
|
64
|
-
>> require '
|
65
|
-
>> ... [see
|
62
|
+
>> require 'simple_gui_creator'
|
63
|
+
>> ... [see other examples]
|
64
|
+
|
65
|
+
== GUI Editor ==
|
66
|
+
|
67
|
+
It also comes with its own "test as you go" design builder helper GUI, programmed, appropriately enough, using simple gui creator.
|
68
|
+
$ jruby -S simple_gui_creator
|
69
|
+
|
70
|
+
This pulls up a window with some demo code, and some links that let you save it. It's almost more of a "demo of how it works" than a
|
71
|
+
real editing tool, but feature requests/suggestions wanted!
|
72
|
+
|
73
|
+
== Documentation ==
|
74
|
+
|
75
|
+
Basically, see this file, the examples folder, the "bin/*" files, and also the specs and lib files themselves.
|
76
|
+
https://github.com/rdp/ruby_simple_gui_creator
|
66
77
|
|
67
78
|
== Known problems ==
|
68
79
|
|
data/Rakefile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
puts 'dont build this from a git submodule!'
|
2
|
+
|
1
3
|
require 'sane'
|
2
4
|
require 'jeweler2'
|
3
5
|
Jeweler::Tasks.new do |gem|
|
@@ -8,6 +10,7 @@ Jeweler::Tasks.new do |gem|
|
|
8
10
|
gem.homepage = "http://github.com/rdp/simple-ruby-gui-creator"
|
9
11
|
gem.authors = ["rogerdpack"]
|
10
12
|
gem.add_dependency 'sane'
|
13
|
+
# gem.add_dependency 'launchy'
|
11
14
|
end
|
12
15
|
|
13
|
-
Jeweler::RubygemsDotOrgTasks.new
|
16
|
+
Jeweler::RubygemsDotOrgTasks.new
|
data/TODO
CHANGED
@@ -1,4 +1,12 @@
|
|
1
|
-
|
1
|
+
if the window goes too low, they can't see it all?
|
2
|
+
|
3
|
+
Parsing failed on line " _ _\t \n" number: 5!
|
4
|
+
|
5
|
+
gets h,w of trivial text areas *wrong* oh so wrong
|
6
|
+
|
7
|
+
= never =
|
8
|
+
|
9
|
+
use launchy for url's in linux [?]
|
2
10
|
|
3
11
|
ask_should_allow_on_minimize {
|
4
|
-
}
|
12
|
+
}
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.2
|
data/bin/simple_gui_creator
CHANGED
@@ -1,88 +1,131 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# assumes has rubygems loaded...since we need the sane gem
|
3
|
-
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'os'
|
6
|
+
rescue LoadError # ease of development :P
|
7
|
+
require 'rubygems'
|
8
|
+
retry
|
9
|
+
end
|
10
|
+
|
4
11
|
if !OS.jruby?
|
5
12
|
$stderr.puts 'jruby only for now, you can request a change to this, exiting...'
|
6
13
|
exit 1
|
7
14
|
end
|
8
|
-
require File.dirname(__FILE__) + "/../lib/simple_gui_creator.rb"
|
15
|
+
require 'simple_gui_creator'#File.dirname(__FILE__) + "/../lib/simple_gui_creator.rb"
|
9
16
|
|
10
|
-
class TestWindow < ParseTemplate
|
17
|
+
class TestWindow < SimpleGuiCreator::ParseTemplate
|
11
18
|
|
12
19
|
def initialize
|
13
20
|
super
|
14
21
|
string = <<-EOL
|
15
|
-
---------- Simple Ruby Gui Creator Test Window
|
16
|
-
| "Edit this, then..."
|
17
|
-
| [Test it out! :
|
18
|
-
| [ :text_area_to_use, width=70chars, height=500, font=fixed_width]
|
19
|
-
| [ ]
|
20
|
-
| [ ]
|
21
|
-
| [ ]
|
22
|
-
| [ ]
|
23
|
-
| [ ]
|
24
|
-
| [ ]
|
25
|
-
| [ ]
|
26
|
-
|
|
27
|
-
| [
|
28
|
-
|
22
|
+
---------- Simple Ruby Gui Creator Test Window ----------------------------------------
|
23
|
+
| "Edit this, then..." |
|
24
|
+
| [Test it out! :test_it_out_button] [Insert code for this window:replace_button] |
|
25
|
+
| [ :text_area_to_use, width=70chars, height=500, font=fixed_width] |
|
26
|
+
| [ ] |
|
27
|
+
| [ ] |
|
28
|
+
| [ ] |
|
29
|
+
| [ ] |
|
30
|
+
| [ ] |
|
31
|
+
| [ ] |
|
32
|
+
| [ ] |
|
33
|
+
| |
|
34
|
+
| [Create code snippet :create_snippet] |
|
35
|
+
---------------------------------------------------------------------------------------
|
29
36
|
EOL
|
30
|
-
Kernel.print string
|
31
37
|
parse_setup_string string
|
32
|
-
elements[:text_area_to_use].text=
|
33
|
-
|
34
|
-
|
38
|
+
elements[:text_area_to_use].text = <<-EOL
|
39
|
+
-------------A Title-------------
|
40
|
+
"Some text"
|
41
|
+
[Button text :button1]
|
42
|
+
[a text area :text_area1,height=300]
|
43
|
+
[ ]
|
44
|
+
EOL
|
45
|
+
|
46
|
+
elements[:replace_button].on_clicked {
|
47
|
+
elements[:text_area_to_use].text = string
|
48
|
+
}
|
49
|
+
elements[:test_it_out_button].on_clicked {
|
50
|
+
frame = SimpleGuiCreator::ParseTemplate.new
|
51
|
+
frame.parse_setup_string elements[:text_area_to_use].text
|
52
|
+
frame.instance_eval(enumerate_elements_and_get_code) # give the buttons something to do when clicked :P
|
35
53
|
}
|
36
54
|
elements[:create_snippet].on_clicked {
|
37
|
-
|
38
|
-
frame.close
|
39
|
-
|
40
|
-
element_code = ""
|
41
|
-
frame.elements.each{|e|
|
42
|
-
if e[1].is_a? Java::JavaxSwing::JButton
|
43
|
-
element_code += " elements[:#{e[0]}].on_clicked { puts 'clicked #{e[0]}' }\n"
|
44
|
-
end
|
45
|
-
}
|
55
|
+
code = create_snippet_from_current
|
46
56
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
class MyWindow < ParseTemplate::JFramer
|
52
|
-
def initialize
|
53
|
-
super
|
54
|
-
parse_setup_filename 'my_window.template' # create this file first
|
55
|
-
|
56
|
-
#{element_code}
|
57
|
-
end
|
58
|
-
|
59
|
-
end
|
60
|
-
MyWindow.new
|
61
|
-
EOL
|
62
|
-
frame2 = ParseTemplate::JFramer.new.parse_setup_string <<-EOL
|
57
|
+
display_frame = SimpleGuiCreator::ParseTemplate.new
|
58
|
+
display_frame.parse_setup_string <<-EOL
|
59
|
+
--------Here's your snippet!--------------------
|
63
60
|
"Here's your snippet!"
|
64
61
|
[:code,width=500,height=400]
|
65
62
|
[ ]
|
66
63
|
[ ]
|
67
|
-
[Save Code Snippet:snippet_save]
|
68
64
|
"Here's your template:"
|
69
65
|
[:template_text,width=500,height=400,font=fixed_width]
|
70
66
|
[ ]
|
71
|
-
[Save
|
67
|
+
[Save Both files:save_all]
|
72
68
|
EOL
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
69
|
+
display_frame.elements[:code].text = code
|
70
|
+
template_text = elements[:text_area_to_use].text
|
71
|
+
display_frame.elements[:template_text].text = template_text
|
72
|
+
|
73
|
+
display_frame.elements[:save_all].on_clicked {
|
74
|
+
dir = SimpleGuiCreator.new_existing_dir_chooser_and_go "Pick directory to save both files to:"
|
75
|
+
template_file = dir + '/my_window.template'
|
76
|
+
if File.exist? template_file
|
77
|
+
if(SimpleGuiCreator.show_select_buttons_prompt("#{template_file} already exists, overwrite?", :yes => 'Overwrite!') != :yes)
|
78
|
+
raise 'abort this button!'
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
File.write(template_file, elements[:text_area_to_use].text)
|
83
|
+
rb_file = dir + '/my_window.rb'
|
84
|
+
File.write(rb_file, create_snippet_from_current)
|
85
|
+
puts 'wrote to ' + rb_file + ' and ' + template_file
|
86
|
+
SimpleGuiCreator.show_in_explorer rb_file
|
87
|
+
}
|
78
88
|
}
|
89
|
+
end
|
90
|
+
|
91
|
+
def create_snippet_from_current
|
92
|
+
# create a demo frame, so I can then pull elements from it
|
93
|
+
element_code = enumerate_elements_and_get_code
|
94
|
+
code=<<-END_CODE
|
95
|
+
# demo code to parse template file
|
96
|
+
require 'rubygems'
|
97
|
+
require 'simple_gui_creator'
|
98
|
+
|
99
|
+
class MyWindow < SimpleGuiCreator::ParseTemplate
|
100
|
+
def initialize
|
101
|
+
super
|
102
|
+
parse_setup_filename 'my_window.template' # layout/design template
|
103
|
+
#{element_code}
|
79
104
|
end
|
80
105
|
|
81
|
-
|
82
|
-
|
83
|
-
|
106
|
+
end
|
107
|
+
|
108
|
+
MyWindow.new # runs forever until closed
|
109
|
+
|
110
|
+
END_CODE
|
111
|
+
code
|
84
112
|
end
|
85
113
|
|
114
|
+
def enumerate_elements_and_get_code
|
115
|
+
fake_frame = SimpleGuiCreator::ParseTemplate.new.parse_setup_string elements[:text_area_to_use].text
|
116
|
+
fake_frame.close
|
117
|
+
|
118
|
+
element_code = ""
|
119
|
+
fake_frame.elements.each{|e|
|
120
|
+
if e[1].is_a? Java::JavaxSwing::JButton
|
121
|
+
element_code += " elements[:#{e[0]}].on_clicked { puts 'clicked #{e[0]}' }\n"
|
122
|
+
else
|
123
|
+
element_code += " #{e[0]}_current_text = elements[:#{e[0]}].text\n"
|
124
|
+
end
|
125
|
+
}
|
126
|
+
element_code
|
127
|
+
end
|
128
|
+
|
86
129
|
end
|
87
130
|
|
88
131
|
TestWindow.new
|
@@ -2,11 +2,13 @@ require 'rubygems'
|
|
2
2
|
require 'sane'
|
3
3
|
require __DIR__ + '/../lib/simple-ruby-gui-creator.rb'
|
4
4
|
|
5
|
-
a = ParseTemplate
|
5
|
+
a = SimpleGuiCreator::ParseTemplate.new
|
6
6
|
a.parse_setup_string <<EOL
|
7
7
|
|
8
|
+
|
8
9
|
| [a button:button_name,width=100,height=100,abs_x=50,abs_y=50] [a third button]
|
9
10
|
| [another button:button_name2] [another button:button_name4]|
|
10
11
|
| [another button:button_name3] |
|
11
12
|
|
13
|
+
|
12
14
|
EOL
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'java'
|
2
|
+
|
3
|
+
# helper/english friendlier methods for JFrame
|
4
|
+
|
5
|
+
class javax::swing::JFrame
|
6
|
+
|
7
|
+
java_import javax::swing::JFrame # so we can refer to it as JFrame, without polluting the global namespace
|
8
|
+
|
9
|
+
java_import java.awt.event.ActionListener
|
10
|
+
|
11
|
+
#class StateListener
|
12
|
+
# include java.awt.event.WindowListener
|
13
|
+
#end
|
14
|
+
|
15
|
+
class CloseListener < java.awt.event.WindowAdapter
|
16
|
+
def initialize parent, &block
|
17
|
+
super()
|
18
|
+
@parent = parent
|
19
|
+
@block = block
|
20
|
+
end
|
21
|
+
|
22
|
+
def windowClosed event # sometimes this, sometimes the other...
|
23
|
+
if @block
|
24
|
+
b = @block # force avoid calling it twice, since swing does seem to call this method twice, bizarrely
|
25
|
+
@block = nil
|
26
|
+
b.call
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def windowClosing event
|
31
|
+
#p 'windowClosing' # hitting the X goes *only* here, and twice? ok this is messed up
|
32
|
+
@parent.dispose
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize *args
|
37
|
+
super(*args) # we do always get here...
|
38
|
+
# because we do this, you should *not* have to call the unsafe:
|
39
|
+
# setDefaultCloseOperation(EXIT_ON_CLOSE)
|
40
|
+
# which basically does a System.exit(0) when the last jframe closes. Yikes jdk, yikes.
|
41
|
+
#addWindowListener(CloseListener.new(self))
|
42
|
+
dispose_on_close # don't keep running after being closed, and prevent the app from exiting! whoa!
|
43
|
+
end
|
44
|
+
|
45
|
+
def close
|
46
|
+
dispose # <sigh>
|
47
|
+
end
|
48
|
+
|
49
|
+
def dispose_on_close
|
50
|
+
setDefaultCloseOperation JFrame::DISPOSE_ON_CLOSE
|
51
|
+
end
|
52
|
+
|
53
|
+
def after_closed &block
|
54
|
+
addWindowListener(CloseListener.new(self) {
|
55
|
+
block.call
|
56
|
+
})
|
57
|
+
end
|
58
|
+
|
59
|
+
def after_minimized &block
|
60
|
+
addWindowStateListener {|e|
|
61
|
+
if e.new_state == java::awt::Frame::ICONIFIED
|
62
|
+
block.call
|
63
|
+
else
|
64
|
+
#puts 'non restore'
|
65
|
+
end
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
def after_restored_either_way &block
|
70
|
+
addWindowStateListener {|e|
|
71
|
+
if e.new_state == java::awt::Frame::NORMAL
|
72
|
+
block.call
|
73
|
+
else
|
74
|
+
#puts 'non restore'
|
75
|
+
end
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def bring_to_front # kludgey...but said to work for swing frames...
|
81
|
+
java.awt.EventQueue.invokeLater{
|
82
|
+
unminimize
|
83
|
+
toFront
|
84
|
+
repaint
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
def minimize
|
89
|
+
setState(java.awt.Frame::ICONIFIED)
|
90
|
+
end
|
91
|
+
|
92
|
+
def restore
|
93
|
+
setState(java.awt.Frame::NORMAL) # this line is probably enough, but do more just in case...
|
94
|
+
#setVisible(true)
|
95
|
+
end
|
96
|
+
|
97
|
+
alias unminimize restore
|
98
|
+
|
99
|
+
def maximize
|
100
|
+
setExtendedState(JFrame::MAXIMIZED_BOTH)
|
101
|
+
end
|
102
|
+
|
103
|
+
# avoid jdk6 always on top bug http://betterlogic.com/roger/2012/04/jframe-setalwaysontop-doesnt-work-after-using-joptionpane/
|
104
|
+
alias always_on_top_original always_on_top=
|
105
|
+
|
106
|
+
def always_on_top=bool
|
107
|
+
always_on_top_original false
|
108
|
+
always_on_top_original bool
|
109
|
+
end
|
110
|
+
|
111
|
+
def set_always_on_top bool
|
112
|
+
always_on_top=bool
|
113
|
+
end
|
114
|
+
|
115
|
+
def setAlwaysOnTop bool
|
116
|
+
always_on_top=bool
|
117
|
+
end
|
118
|
+
|
119
|
+
end # class JFrame
|
120
|
+
|
@@ -1,20 +1,14 @@
|
|
1
1
|
require 'java'
|
2
2
|
|
3
|
-
require File.dirname(__FILE__) + '/
|
3
|
+
require File.dirname(__FILE__) + '/swing_helpers.rb' # for JButton#on_clicked, etc.,
|
4
4
|
|
5
|
-
# for
|
6
|
-
module
|
7
|
-
|
8
|
-
def _dgb
|
9
|
-
require 'rubygems'
|
10
|
-
require 'ruby-debug'
|
11
|
-
debugger
|
12
|
-
end
|
5
|
+
# for documentation, see the README file
|
6
|
+
module SimpleGuiCreator
|
13
7
|
|
14
8
|
include_package 'javax.swing'; [JFrame, JPanel, JButton, JTextArea, JLabel, UIManager, JScrollPane]
|
15
9
|
java_import java.awt.Font
|
16
10
|
|
17
|
-
class
|
11
|
+
class ParseTemplate < JFrame
|
18
12
|
|
19
13
|
def initialize
|
20
14
|
super()
|
@@ -204,4 +198,11 @@ module ParseTemplate
|
|
204
198
|
|
205
199
|
end
|
206
200
|
|
201
|
+
private
|
202
|
+
def _dgb
|
203
|
+
require 'rubygems'
|
204
|
+
require 'ruby-debug'
|
205
|
+
debugger
|
206
|
+
end
|
207
|
+
|
207
208
|
end
|
@@ -15,271 +15,27 @@ This file is part of Sensible Cinema.
|
|
15
15
|
You should have received a copy of the GNU General Public License
|
16
16
|
along with Sensible Cinema. If not, see <http://www.gnu.org/licenses/>.
|
17
17
|
=end
|
18
|
-
require 'java'
|
19
|
-
require 'sane' # gem dependency
|
20
|
-
|
21
|
-
module SimpleGuiCreator
|
22
|
-
|
23
|
-
include_package 'javax.swing'
|
24
|
-
# will use these constants (http://jira.codehaus.org/browse/JRUBY-5107)
|
25
|
-
[JProgressBar, JButton, JFrame, JLabel, JPanel, JOptionPane,
|
26
|
-
JFileChooser, JComboBox, JDialog, SwingUtilities, JSlider, JPasswordField, UIManager]
|
27
|
-
|
28
|
-
include_package 'java.awt'
|
29
|
-
[FlowLayout, Font, BorderFactory, BorderLayout, FileDialog]
|
30
|
-
|
31
|
-
java_import java.awt.event.ActionListener
|
32
|
-
|
33
|
-
JFile = java.io.File # no import for this one...
|
34
18
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
# accepts :yes => "yes text", :no => "no text"
|
39
|
-
# returns :yes :no :cancel or :exited
|
40
|
-
# you must specify text for valid options.
|
41
|
-
# example, if you specify :cancel => 'cancel' then it won't raise if they cancel
|
42
|
-
# raises if they select cancel or exit, unless you pass in :exited => true as an option
|
43
|
-
def self.show_select_buttons_prompt message, names_hash = {}
|
44
|
-
names_hash[:yes] ||= 'Yes'
|
45
|
-
names_hash[:no] ||= 'No'
|
46
|
-
# ok ?
|
47
|
-
old = ['no', 'yes', 'ok'].map{|name| 'OptionPane.' + name + 'ButtonText'}.map{|name| [name, UIManager.get(name)]}
|
48
|
-
if names_hash[:yes]
|
49
|
-
UIManager.put("OptionPane.yesButtonText", names_hash[:yes])
|
50
|
-
end
|
51
|
-
if names_hash[:no]
|
52
|
-
UIManager.put("OptionPane.noButtonText", names_hash[:no])
|
53
|
-
end
|
54
|
-
# if names_hash[:ok] # ???
|
55
|
-
# UIManager.put("OptionPane.okButtonText", names_hash[:ok])
|
56
|
-
# end
|
57
|
-
if names_hash[:cancel]
|
58
|
-
UIManager.put("OptionPane.noButtonText", names_hash[:cancel])
|
59
|
-
end
|
60
|
-
title = message.split(' ')[0..5].join(' ')
|
61
|
-
returned = JOptionPane.showConfirmDialog SwingHelpers.get_always_on_top_frame, message, title, JOptionPane::YES_NO_CANCEL_OPTION
|
62
|
-
SwingHelpers.close_always_on_top_frame
|
63
|
-
old.each{|name, old_setting| UIManager.put(name, old_setting)}
|
64
|
-
out = JOptionReturnValuesTranslator[returned]
|
65
|
-
if !out || !names_hash.key?(out)
|
66
|
-
raise 'canceled or exited an option prompt:' + out.to_s + ' ' + message
|
67
|
-
end
|
68
|
-
out
|
69
|
-
end
|
70
|
-
|
71
|
-
end
|
72
|
-
|
73
|
-
class JButton
|
74
|
-
|
75
|
-
def initialize(*args)
|
76
|
-
super(*args)
|
77
|
-
set_font Font.new("Tahoma", Font::PLAIN, 11)
|
78
|
-
end
|
79
|
-
|
80
|
-
def on_clicked &block
|
81
|
-
raise unless block # sanity check
|
82
|
-
@block = block
|
83
|
-
add_action_listener do |e|
|
84
|
-
begin
|
85
|
-
block.call
|
86
|
-
rescue Exception => e
|
87
|
-
# e.backtrace[0] == "/Users/rogerdpack/sensible-cinema/lib/gui/create.rb:149:in `setup_create_buttons'"
|
88
|
-
bt_out = ""
|
89
|
-
for line in e.backtrace[0..1]
|
90
|
-
backtrace_pieces = line.split(':')
|
91
|
-
backtrace_pieces.shift if OS.doze? # ignore drive letter
|
92
|
-
filename = backtrace_pieces[0].split('/')[-1]
|
93
|
-
line_number = backtrace_pieces[1]
|
94
|
-
bt_out += " #{filename}:#{line_number}"
|
95
|
-
end
|
96
|
-
puts 'button cancelled somehow!' + e.to_s + ' ' + get_text[0..50] + bt_out
|
97
|
-
if $VERBOSE
|
98
|
-
puts "got fatal exception thrown in button [aborted] #{e} #{e.class} #{e.backtrace[0]}"
|
99
|
-
puts e.backtrace, e
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
self
|
104
|
-
end
|
105
|
-
|
106
|
-
def simulate_click
|
107
|
-
@block.call
|
108
|
-
end
|
109
|
-
|
110
|
-
def tool_tip= text
|
111
|
-
if text
|
112
|
-
text = "<html>" + text + "</html>"
|
113
|
-
text = text.gsub("\n", "<br/>")
|
114
|
-
end
|
115
|
-
self.set_tool_tip_text text
|
116
|
-
end
|
117
|
-
|
118
|
-
def enable
|
119
|
-
set_enabled true
|
120
|
-
end
|
121
|
-
|
122
|
-
def disable
|
123
|
-
set_enabled false
|
124
|
-
end
|
125
|
-
|
126
|
-
end
|
19
|
+
require 'java'
|
20
|
+
#require 'sane' # gem dependency
|
21
|
+
require File.dirname(__FILE__) + '/swing_helpers'
|
127
22
|
|
128
|
-
|
23
|
+
$simple_creator_show_console_prompts = true
|
129
24
|
|
130
|
-
|
131
|
-
|
132
|
-
#class StateListener
|
133
|
-
# include java.awt.event.WindowListener
|
134
|
-
#end
|
135
|
-
|
136
|
-
class CloseListener < java.awt.event.WindowAdapter
|
137
|
-
def initialize parent, &block
|
138
|
-
super()
|
139
|
-
@parent = parent
|
140
|
-
@block = block
|
141
|
-
end
|
142
|
-
|
143
|
-
def windowClosed event # sometimes this, sometimes the other...
|
144
|
-
if @block
|
145
|
-
b = @block # force avoid calling it twice, since swing does seem to call this method twice, bizarrely
|
146
|
-
@block = nil
|
147
|
-
b.call
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
def windowClosing event
|
152
|
-
#p 'windowClosing' # hitting the X goes *only* here, and twice? ok this is messed up
|
153
|
-
@parent.dispose
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
def initialize *args
|
158
|
-
super(*args) # we do always get here...
|
159
|
-
# because we do this, you should *not* have to call the unsafe:
|
160
|
-
# setDefaultCloseOperation(EXIT_ON_CLOSE)
|
161
|
-
# which basically does a System.exit(0) when the last jframe closes. Yikes jdk, yikes.
|
162
|
-
#addWindowListener(CloseListener.new(self))
|
163
|
-
dispose_on_close # don't keep running after being closed, and prevent the app from exiting! whoa!
|
164
|
-
end
|
165
|
-
|
166
|
-
def close
|
167
|
-
dispose # <sigh>
|
168
|
-
end
|
169
|
-
|
170
|
-
def dispose_on_close
|
171
|
-
setDefaultCloseOperation JFrame::DISPOSE_ON_CLOSE
|
172
|
-
end
|
173
|
-
|
174
|
-
def after_closed &block
|
175
|
-
addWindowListener(CloseListener.new(self) {
|
176
|
-
block.call
|
177
|
-
})
|
178
|
-
end
|
179
|
-
|
180
|
-
def after_minimized &block
|
181
|
-
addWindowStateListener {|e|
|
182
|
-
if e.new_state == java::awt::Frame::ICONIFIED
|
183
|
-
block.call
|
184
|
-
else
|
185
|
-
#puts 'non restore'
|
186
|
-
end
|
187
|
-
}
|
188
|
-
end
|
189
|
-
|
190
|
-
def after_restored_either_way &block
|
191
|
-
addWindowStateListener {|e|
|
192
|
-
if e.new_state == java::awt::Frame::NORMAL
|
193
|
-
block.call
|
194
|
-
else
|
195
|
-
#puts 'non restore'
|
196
|
-
end
|
197
|
-
}
|
198
|
-
end
|
199
|
-
|
200
|
-
|
201
|
-
def bring_to_front # kludgey...but said to work for swing frames...
|
202
|
-
java.awt.EventQueue.invokeLater{
|
203
|
-
unminimize
|
204
|
-
toFront
|
205
|
-
repaint
|
206
|
-
}
|
207
|
-
end
|
208
|
-
|
209
|
-
def minimize
|
210
|
-
setState(java.awt.Frame::ICONIFIED)
|
211
|
-
end
|
212
|
-
|
213
|
-
def restore
|
214
|
-
setState(java.awt.Frame::NORMAL) # this line is probably enough, but do more just in case...
|
215
|
-
#setVisible(true)
|
216
|
-
end
|
217
|
-
|
218
|
-
alias unminimize restore
|
219
|
-
|
220
|
-
def maximize
|
221
|
-
setExtendedState(JFrame::MAXIMIZED_BOTH)
|
222
|
-
end
|
223
|
-
|
224
|
-
# avoid jdk6 always on top bug http://betterlogic.com/roger/2012/04/jframe-setalwaysontop-doesnt-work-after-using-joptionpane/
|
225
|
-
alias always_on_top_original always_on_top=
|
226
|
-
|
227
|
-
def always_on_top=bool
|
228
|
-
always_on_top_original false
|
229
|
-
always_on_top_original bool
|
230
|
-
end
|
25
|
+
module SimpleGuiCreator
|
231
26
|
|
232
|
-
|
233
|
-
always_on_top=bool
|
234
|
-
end
|
27
|
+
JFile = java.io.File # no import for this one, so we don't lose access to Ruby's File class
|
235
28
|
|
236
|
-
|
237
|
-
always_on_top=bool
|
238
|
-
end
|
239
|
-
|
240
|
-
end # class JFrame
|
241
|
-
|
242
|
-
def self.open_url_to_view_it_non_blocking url
|
29
|
+
def self.open_url_to_view_it_non_blocking url
|
243
30
|
raise 'non http url?' unless url =~ /^http/i
|
244
31
|
if OS.windows?
|
245
32
|
system("start #{url.gsub('&', '^&')}") # LODO would launchy help/work here with the full url?
|
246
33
|
else
|
247
34
|
system "#{OS.open_file_command} \"#{url}\""
|
248
|
-
sleep 2 # disallow exiting immediately
|
35
|
+
sleep 2 # disallow any program exiting immediately...which can make the window *not* popup in certain circumstances...LODO fix [is it windows only?]
|
249
36
|
end
|
250
37
|
end
|
251
38
|
|
252
|
-
# wrapped in sensible-cinema-base
|
253
|
-
class JFileChooser
|
254
|
-
# also set_current_directory et al...
|
255
|
-
|
256
|
-
# raises on failure...
|
257
|
-
def go show_save_dialog_instead = false
|
258
|
-
if show_save_dialog_instead
|
259
|
-
success = show_save_dialog nil
|
260
|
-
else
|
261
|
-
success = show_open_dialog nil
|
262
|
-
end
|
263
|
-
unless success == Java::javax::swing::JFileChooser::APPROVE_OPTION
|
264
|
-
java.lang.System.exit 1 # kills background proc...but we shouldn't let them do stuff while a background proc is running, anyway
|
265
|
-
end
|
266
|
-
get_selected_file.get_absolute_path
|
267
|
-
end
|
268
|
-
|
269
|
-
# match FileDialog methods...
|
270
|
-
def set_title x
|
271
|
-
set_dialog_title x
|
272
|
-
end
|
273
|
-
|
274
|
-
def set_file f
|
275
|
-
set_selected_file JFile.new(f)
|
276
|
-
end
|
277
|
-
|
278
|
-
alias setFile set_file
|
279
|
-
|
280
|
-
end
|
281
|
-
|
282
|
-
|
283
39
|
# choose a file that may or may not exist yet...
|
284
40
|
def self.new_nonexisting_or_existing_filechooser_and_go title = nil, default_dir = nil, default_filename = nil # within JFileChooser class for now...
|
285
41
|
out = JFileChooser.new
|
@@ -291,6 +47,9 @@ module SimpleGuiCreator
|
|
291
47
|
out.set_file default_filename
|
292
48
|
end
|
293
49
|
got = out.go true
|
50
|
+
if !got
|
51
|
+
raise "did not select anything #{title} #{default_dir} #{default_filename}"
|
52
|
+
end
|
294
53
|
got
|
295
54
|
end
|
296
55
|
|
@@ -308,7 +67,7 @@ module SimpleGuiCreator
|
|
308
67
|
while(!found_non_exist)
|
309
68
|
got = out.go true
|
310
69
|
if(File.exist? got)
|
311
|
-
|
70
|
+
SimpleGuiCreator.show_blocking_message_dialog 'this file already exists, choose a new filename ' + got
|
312
71
|
else
|
313
72
|
found_non_exist = true
|
314
73
|
end
|
@@ -317,33 +76,20 @@ module SimpleGuiCreator
|
|
317
76
|
end
|
318
77
|
|
319
78
|
def self.new_existing_dir_chooser_and_go title=nil, default_dir = nil
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
else
|
330
|
-
raise "No dir selected " + title.to_s
|
331
|
-
end
|
332
|
-
end
|
333
|
-
|
334
|
-
# awt...the native looking one...
|
335
|
-
class FileDialog
|
336
|
-
def go
|
337
|
-
show
|
338
|
-
dispose # allow app to exit :P
|
339
|
-
if get_file
|
340
|
-
# they picked something...
|
341
|
-
File.expand_path(get_directory + '/' + get_file)
|
79
|
+
chooser = JFileChooser.new;
|
80
|
+
chooser.setCurrentDirectory(JFile.new default_dir) if default_dir
|
81
|
+
chooser.set_title title
|
82
|
+
chooser.setFileSelectionMode(JFileChooser::DIRECTORIES_ONLY)
|
83
|
+
chooser.setAcceptAllFileFilterUsed(false)
|
84
|
+
chooser.set_approve_button_text "Select This Directory"
|
85
|
+
|
86
|
+
if (chooser.showOpenDialog(nil) == JFileChooser::APPROVE_OPTION)
|
87
|
+
return chooser.getSelectedFile().get_absolute_path
|
342
88
|
else
|
343
|
-
|
89
|
+
raise "No dir selected " + title.to_s
|
344
90
|
end
|
345
91
|
end
|
346
|
-
|
92
|
+
|
347
93
|
|
348
94
|
# this doesn't have an "awesome" way to force existence, just loops
|
349
95
|
def self.new_previously_existing_file_selector_and_go title, use_this_dir = nil
|
@@ -372,51 +118,10 @@ module SimpleGuiCreator
|
|
372
118
|
got
|
373
119
|
end
|
374
120
|
|
375
|
-
class NonBlockingDialog < JDialog
|
376
|
-
def initialize title_and_display_text, close_button_text = 'Close'
|
377
|
-
super nil # so that set_title will work
|
378
|
-
lines = title_and_display_text.split("\n")
|
379
|
-
set_title lines[0]
|
380
|
-
get_content_pane.set_layout nil
|
381
|
-
lines.each_with_index{|line, idx|
|
382
|
-
jlabel = JLabel.new line
|
383
|
-
jlabel.set_bounds(10, 15*idx, 550, 24)
|
384
|
-
get_content_pane.add jlabel
|
385
|
-
}
|
386
|
-
close = JButton.new( close_button_text ).on_clicked {
|
387
|
-
self.dispose
|
388
|
-
}
|
389
|
-
number_of_lines = lines.length
|
390
|
-
close.set_bounds(125,30+15*number_of_lines, close_button_text.length * 15,25)
|
391
|
-
get_content_pane.add close
|
392
|
-
set_size 550, 100+(15*number_of_lines) # XXX variable width? or use swing build in better?
|
393
|
-
set_visible true
|
394
|
-
setDefaultCloseOperation JFrame::DISPOSE_ON_CLOSE
|
395
|
-
setLocationRelativeTo nil # center it on the screen
|
396
|
-
|
397
|
-
end
|
398
|
-
alias close dispose # yikes
|
399
|
-
end
|
400
|
-
|
401
|
-
def self.get_always_on_top_frame
|
402
|
-
fake_frame = JFrame.new
|
403
|
-
fake_frame.setUndecorated true # so we can have a teeny [invisible] window
|
404
|
-
fake_frame.set_size 1,1
|
405
|
-
fake_frame.set_location 300,300 # so that option pane's won't appear upper left
|
406
|
-
#fake_frame.always_on_top = true
|
407
|
-
fake_frame.show
|
408
|
-
@fake_frame = fake_frame
|
409
|
-
end
|
410
|
-
|
411
|
-
def self.close_always_on_top_frame
|
412
|
-
@fake_frame.close
|
413
|
-
end
|
414
|
-
|
415
121
|
# prompts for user input, raises if they cancel the prompt or if they enter nothing
|
416
122
|
def self.get_user_input(message, default = '', cancel_or_blank_ok = false)
|
417
123
|
p 'please enter the information in the prompt:' + message[0..50] + '...'
|
418
|
-
received = javax.swing.JOptionPane.showInputDialog(
|
419
|
-
close_always_on_top_frame
|
124
|
+
received = javax.swing.JOptionPane.showInputDialog(nil, message, default)
|
420
125
|
if !cancel_or_blank_ok
|
421
126
|
raise 'user cancelled input prompt ' + message unless received
|
422
127
|
raise 'did not enter anything?' + message unless received.present?
|
@@ -425,18 +130,30 @@ module SimpleGuiCreator
|
|
425
130
|
p 'received answer:' + received
|
426
131
|
received
|
427
132
|
end
|
133
|
+
|
134
|
+
def self.to_filename string
|
135
|
+
if File::ALT_SEPARATOR
|
136
|
+
File.expand_path(string).gsub('/', File::ALT_SEPARATOR)
|
137
|
+
else
|
138
|
+
File.expand_path(string)
|
139
|
+
end
|
140
|
+
end
|
428
141
|
|
429
142
|
def self.show_in_explorer filename_or_path
|
430
143
|
raise 'nonexistent file cannot reveal in explorer?' + filename_or_path unless File.exist?(filename_or_path)
|
144
|
+
filename_or_path = '"' + to_filename(filename_or_path.gsub('"', '\\"')) + '"' # quotify, escape it, FWIW untested
|
431
145
|
if OS.doze?
|
432
146
|
begin
|
433
|
-
c = "explorer /e,/select,#{filename_or_path
|
434
|
-
system c # command returns immediately...so system is ok
|
147
|
+
c = "explorer /e,/select,#{filename_or_path}"
|
148
|
+
system c # command returns immediately...so calling system on it is ok
|
435
149
|
rescue => why_does_this_happen_ignore_this_exception_it_probably_actually_succeeded
|
150
|
+
3 # for debugging so it can break here
|
436
151
|
end
|
437
152
|
elsif OS.mac?
|
438
|
-
c = "open -R " + "\"" + filename_or_path
|
439
|
-
|
153
|
+
c = "open -R " + "\"" + filename_or_path + "\""
|
154
|
+
system c # returns immediately
|
155
|
+
elsif OS.linux?
|
156
|
+
c = "nohup nautilus --no-desktop #{filename_or_path}"
|
440
157
|
system c
|
441
158
|
else
|
442
159
|
raise 'os reveal unsupported?'
|
@@ -444,10 +161,9 @@ module SimpleGuiCreator
|
|
444
161
|
end
|
445
162
|
|
446
163
|
def self.show_blocking_message_dialog message, title = message.split("\n")[0], style= JOptionPane::INFORMATION_MESSAGE
|
447
|
-
puts "please use GUI window popup... #{message} ..."
|
448
|
-
JOptionPane.showMessageDialog(
|
164
|
+
puts "please use GUI window popup... #{message} ..." if $simple_creator_show_console_prompts
|
165
|
+
JOptionPane.showMessageDialog(nil, message, title, style)
|
449
166
|
# the above has no return value <sigh> so just return true
|
450
|
-
close_always_on_top_frame
|
451
167
|
true
|
452
168
|
end
|
453
169
|
|
@@ -466,8 +182,7 @@ module SimpleGuiCreator
|
|
466
182
|
def self.get_password_input text
|
467
183
|
p 'please enter password at prompt'
|
468
184
|
pwd = JPasswordField.new(10)
|
469
|
-
got = JOptionPane.showConfirmDialog(
|
470
|
-
close_always_on_top_frame
|
185
|
+
got = JOptionPane.showConfirmDialog(nil, pwd, text, JOptionPane::OK_CANCEL_OPTION) < 0
|
471
186
|
if got
|
472
187
|
raise 'cancelled ' + text
|
473
188
|
else
|
@@ -480,63 +195,10 @@ module SimpleGuiCreator
|
|
480
195
|
end
|
481
196
|
end
|
482
197
|
|
483
|
-
class DropDownSelector < JDialog # JDialog is blocking...
|
484
|
-
|
485
|
-
def initialize parent, options_array, prompt_for_top_entry
|
486
|
-
super parent, true
|
487
|
-
set_title prompt_for_top_entry
|
488
|
-
@drop_down_elements = options_array
|
489
|
-
@selected_idx = nil
|
490
|
-
box = JComboBox.new
|
491
|
-
box.add_action_listener do |e|
|
492
|
-
idx = box.get_selected_index
|
493
|
-
if idx != 0
|
494
|
-
# don't count choosing the first as a real entry
|
495
|
-
@selected_idx = box.get_selected_index - 1
|
496
|
-
dispose
|
497
|
-
end
|
498
|
-
end
|
499
|
-
|
500
|
-
box.add_item @prompt = prompt_for_top_entry # put something in index 0
|
501
|
-
options_array.each{|drive|
|
502
|
-
box.add_item drive
|
503
|
-
}
|
504
|
-
add box
|
505
|
-
pack # how do you get this arbitrary size? what the...
|
506
|
-
|
507
|
-
end
|
508
|
-
|
509
|
-
# returns index from initial array that they selected, or raises if they hit the x on it
|
510
|
-
def go_selected_index
|
511
|
-
puts 'select from dropdown window'
|
512
|
-
show # blocks...
|
513
|
-
raise 'did not select, exited early ' + @prompt unless @selected_idx
|
514
|
-
@selected_idx
|
515
|
-
end
|
516
|
-
|
517
|
-
def go_selected_value
|
518
|
-
puts 'select from dropdown window ' + @drop_down_elements[-1] + ' ...'
|
519
|
-
show # blocks...
|
520
|
-
raise 'did not select, exited early ' + @prompt unless @selected_idx
|
521
|
-
@drop_down_elements[@selected_idx]
|
522
|
-
end
|
523
|
-
|
524
|
-
end
|
525
|
-
|
526
198
|
def self.hard_exit!; java::lang::System.exit 0; end
|
527
199
|
|
528
200
|
def self.invoke_in_gui_thread # sometimes I think I need this, but it never seems to help
|
529
201
|
SwingUtilities.invoke_later { yield }
|
530
202
|
end
|
531
203
|
|
532
|
-
end
|
533
|
-
|
534
|
-
class String
|
535
|
-
def to_filename
|
536
|
-
if File::ALT_SEPARATOR
|
537
|
-
File.expand_path(self).gsub('/', File::ALT_SEPARATOR)
|
538
|
-
else
|
539
|
-
File.expand_path(self)
|
540
|
-
end
|
541
|
-
end
|
542
|
-
end
|
204
|
+
end
|
@@ -0,0 +1,221 @@
|
|
1
|
+
require 'sane' # require_relative
|
2
|
+
require_relative 'jframe_helper_methods' # jframe stuff gets its own file, it's so much.
|
3
|
+
|
4
|
+
module SimpleGuiCreator
|
5
|
+
|
6
|
+
include_package 'javax.swing'
|
7
|
+
# and use these constants (bug: http://jira.codehaus.org/browse/JRUBY-5107)
|
8
|
+
[JProgressBar, JButton, JLabel, JPanel, JOptionPane,
|
9
|
+
JFileChooser, JComboBox, JDialog, SwingUtilities, JSlider, JPasswordField, UIManager]
|
10
|
+
|
11
|
+
include_package 'java.awt'; [Font, FileDialog]
|
12
|
+
|
13
|
+
class JOptionPane
|
14
|
+
JOptionReturnValuesTranslator = {0 => :yes, 1 => :no, 2 => :cancel, -1 => :exited}
|
15
|
+
|
16
|
+
# accepts :yes => "yes text", :no => "no text"
|
17
|
+
# returns :yes :no :cancel or :exited
|
18
|
+
# you must specify text for valid options.
|
19
|
+
# example, if you specify :cancel => 'cancel' then it won't raise if they cancel
|
20
|
+
# raises if they select cancel or exit, unless you pass in :exited => true as an option
|
21
|
+
def self.show_select_buttons_prompt message, names_hash = {}
|
22
|
+
names_hash[:yes] ||= 'Yes'
|
23
|
+
names_hash[:no] ||= 'No'
|
24
|
+
# ok ?
|
25
|
+
old = ['no', 'yes', 'ok'].map{|name| 'OptionPane.' + name + 'ButtonText'}.map{|name| [name, UIManager.get(name)]}
|
26
|
+
if names_hash[:yes]
|
27
|
+
UIManager.put("OptionPane.yesButtonText", names_hash[:yes])
|
28
|
+
end
|
29
|
+
if names_hash[:no]
|
30
|
+
UIManager.put("OptionPane.noButtonText", names_hash[:no])
|
31
|
+
end
|
32
|
+
# if names_hash[:ok] # ???
|
33
|
+
# UIManager.put("OptionPane.okButtonText", names_hash[:ok])
|
34
|
+
# end
|
35
|
+
if names_hash[:cancel]
|
36
|
+
UIManager.put("OptionPane.noButtonText", names_hash[:cancel])
|
37
|
+
end
|
38
|
+
title = message.split(' ')[0..5].join(' ')
|
39
|
+
returned = JOptionPane.showConfirmDialog nil, message, title, JOptionPane::YES_NO_CANCEL_OPTION
|
40
|
+
old.each{|name, old_setting| UIManager.put(name, old_setting)}
|
41
|
+
out = JOptionReturnValuesTranslator[returned]
|
42
|
+
if !out || !names_hash.key?(out)
|
43
|
+
raise 'canceled or exited an option prompt:' + out.to_s + ' ' + message
|
44
|
+
end
|
45
|
+
out
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
class JButton
|
51
|
+
|
52
|
+
def initialize(*args)
|
53
|
+
super(*args)
|
54
|
+
set_font Font.new("Tahoma", Font::PLAIN, 11)
|
55
|
+
end
|
56
|
+
|
57
|
+
def on_clicked &block
|
58
|
+
raise unless block # sanity check
|
59
|
+
@block = block
|
60
|
+
add_action_listener do |e|
|
61
|
+
begin
|
62
|
+
block.call
|
63
|
+
rescue Exception => e
|
64
|
+
# e.backtrace[0] == "/Users/rogerdpack/sensible-cinema/lib/gui/create.rb:149:in `setup_create_buttons'"
|
65
|
+
bt_out = ""
|
66
|
+
for line in e.backtrace[0..1]
|
67
|
+
backtrace_pieces = line.split(':')
|
68
|
+
backtrace_pieces.shift if OS.doze? && backtrace_pieces[1..1] == ':' # ignore drive letter colon split, which isn't always there oddly enough [1.8 mode I guess]
|
69
|
+
filename = backtrace_pieces[0].split('/')[-1]
|
70
|
+
line_number = backtrace_pieces[1]
|
71
|
+
bt_out += " #{filename}:#{line_number}"
|
72
|
+
end
|
73
|
+
puts 'button cancelled somehow!' + e.to_s + ' ' + get_text[0..50] + bt_out if $simple_creator_show_console_prompts
|
74
|
+
if $VERBOSE
|
75
|
+
puts "got fatal exception thrown in button [aborted] #{e} #{e.class} #{e.backtrace[0]}" if $simple_creator_show_console_prompts
|
76
|
+
puts e.backtrace, e if $simple_creator_show_console_prompts
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
self
|
81
|
+
end
|
82
|
+
|
83
|
+
def simulate_click
|
84
|
+
@block.call
|
85
|
+
end
|
86
|
+
|
87
|
+
def tool_tip= text
|
88
|
+
if text
|
89
|
+
text = "<html>" + text + "</html>"
|
90
|
+
text = text.gsub("\n", "<br/>")
|
91
|
+
end
|
92
|
+
self.set_tool_tip_text text
|
93
|
+
end
|
94
|
+
|
95
|
+
def enable
|
96
|
+
set_enabled true
|
97
|
+
end
|
98
|
+
|
99
|
+
def disable
|
100
|
+
set_enabled false
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
ToolTipManager.sharedInstance().setDismissDelay(10000) # these are way too fast normally
|
106
|
+
|
107
|
+
class JFileChooser
|
108
|
+
# also set_current_directory et al...
|
109
|
+
|
110
|
+
# raises on failure...
|
111
|
+
def go show_save_dialog_instead = false
|
112
|
+
if show_save_dialog_instead
|
113
|
+
success = show_save_dialog nil
|
114
|
+
else
|
115
|
+
success = show_open_dialog nil
|
116
|
+
end
|
117
|
+
unless success == Java::javax::swing::JFileChooser::APPROVE_OPTION
|
118
|
+
return nil
|
119
|
+
end
|
120
|
+
get_selected_file.get_absolute_path
|
121
|
+
end
|
122
|
+
|
123
|
+
# match FileDialog methods...
|
124
|
+
def set_title x
|
125
|
+
set_dialog_title x
|
126
|
+
end
|
127
|
+
|
128
|
+
def set_file f
|
129
|
+
set_selected_file JFile.new(f)
|
130
|
+
end
|
131
|
+
|
132
|
+
alias setFile set_file
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
# awt...the native looking one...
|
137
|
+
class FileDialog
|
138
|
+
def go
|
139
|
+
show
|
140
|
+
dispose # allow app to exit :P
|
141
|
+
if get_file
|
142
|
+
# they picked something...
|
143
|
+
File.expand_path(get_directory + '/' + get_file)
|
144
|
+
else
|
145
|
+
nil
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
|
151
|
+
class NonBlockingDialog < JDialog
|
152
|
+
def initialize title_and_display_text, close_button_text = 'Close'
|
153
|
+
super nil # so that set_title will work
|
154
|
+
lines = title_and_display_text.split("\n")
|
155
|
+
set_title lines[0]
|
156
|
+
get_content_pane.set_layout nil
|
157
|
+
lines.each_with_index{|line, idx|
|
158
|
+
jlabel = JLabel.new line
|
159
|
+
jlabel.set_bounds(10, 15*idx, 550, 24)
|
160
|
+
get_content_pane.add jlabel
|
161
|
+
}
|
162
|
+
close = JButton.new( close_button_text ).on_clicked {
|
163
|
+
self.dispose
|
164
|
+
}
|
165
|
+
number_of_lines = lines.length
|
166
|
+
close.set_bounds(125,30+15*number_of_lines, close_button_text.length * 15,25)
|
167
|
+
get_content_pane.add close
|
168
|
+
set_size 550, 100+(15*number_of_lines) # XXX variable width? or use swing build in better?
|
169
|
+
set_visible true
|
170
|
+
setDefaultCloseOperation JFrame::DISPOSE_ON_CLOSE
|
171
|
+
setLocationRelativeTo nil # center it on the screen
|
172
|
+
|
173
|
+
end
|
174
|
+
alias close dispose # yikes
|
175
|
+
end
|
176
|
+
|
177
|
+
|
178
|
+
class DropDownSelector < JDialog # JDialog is blocking...
|
179
|
+
|
180
|
+
def initialize parent, options_array, prompt_for_top_entry
|
181
|
+
super parent, true
|
182
|
+
set_title prompt_for_top_entry
|
183
|
+
@drop_down_elements = options_array
|
184
|
+
@selected_idx = nil
|
185
|
+
box = JComboBox.new
|
186
|
+
box.add_action_listener do |e|
|
187
|
+
idx = box.get_selected_index
|
188
|
+
if idx != 0
|
189
|
+
# don't count choosing the first as a real entry
|
190
|
+
@selected_idx = box.get_selected_index - 1
|
191
|
+
dispose
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
box.add_item @prompt = prompt_for_top_entry # put something in index 0
|
196
|
+
options_array.each{|drive|
|
197
|
+
box.add_item drive
|
198
|
+
}
|
199
|
+
add box
|
200
|
+
pack # how do you get this arbitrary size? what the...
|
201
|
+
|
202
|
+
end
|
203
|
+
|
204
|
+
# returns index from initial array that they selected, or raises if they hit the x on it
|
205
|
+
def go_selected_index
|
206
|
+
puts 'select from dropdown window' if $simple_creator_show_console_prompts
|
207
|
+
show # blocks...
|
208
|
+
raise 'did not select, exited early ' + @prompt unless @selected_idx
|
209
|
+
@selected_idx
|
210
|
+
end
|
211
|
+
|
212
|
+
def go_selected_value
|
213
|
+
puts 'select from dropdown window ' + @drop_down_elements[-1] + ' ...' if $simple_creator_show_console_prompts
|
214
|
+
show # blocks...
|
215
|
+
raise 'did not select, exited early ' + @prompt unless @selected_idx
|
216
|
+
@drop_down_elements[@selected_idx]
|
217
|
+
end
|
218
|
+
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
data/lib/simple_gui_creator.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
|
-
# just autoload everything always :)
|
2
1
|
|
3
|
-
module
|
2
|
+
module SimpleGuiCreator
|
4
3
|
def self.snake_case string
|
5
4
|
string = string.to_s.dup
|
6
5
|
string.gsub!(/::/, '/')
|
@@ -12,7 +11,14 @@ module SimpleGuiBootStrap
|
|
12
11
|
end
|
13
12
|
end
|
14
13
|
|
15
|
-
|
16
|
-
|
14
|
+
# some autoloads, in case they save any load time...
|
15
|
+
for clazz in [:DriveInfo, :MouseControl, :PlayAudio, :PlayMp3Audio, :RubyClip]
|
16
|
+
new_path = File.dirname(__FILE__) + '/simple_gui_creator/' + SimpleGuiCreator.snake_case(clazz) + '.rb'
|
17
17
|
autoload clazz, new_path
|
18
|
+
end
|
19
|
+
|
20
|
+
require File.dirname(__FILE__) + '/simple_gui_creator/simple_gui_creator.rb'
|
21
|
+
|
22
|
+
module SimpleGuiCreator
|
23
|
+
autoload :ParseTemplate, File.dirname(__FILE__) + '/simple_gui_creator/parse_template.rb'
|
18
24
|
end
|
data/spec/parse_template.spec.rb
CHANGED
data/spec/swing_helpers.spec.rb
CHANGED
@@ -18,7 +18,8 @@ This file is part of Sensible Cinema.
|
|
18
18
|
|
19
19
|
require File.expand_path(File.dirname(__FILE__) + '/common')
|
20
20
|
|
21
|
-
module
|
21
|
+
module SimpleGuiCreator
|
22
|
+
|
22
23
|
describe 'functionality' do
|
23
24
|
puts "most of these require user interaction, sadly"
|
24
25
|
|
@@ -34,34 +35,34 @@ module SwingHelpers
|
|
34
35
|
|
35
36
|
it "should be able to convert filenames well" do
|
36
37
|
if OS.windows?
|
37
|
-
"a/b/c".
|
38
|
+
SimpleGuiCreator.to_filename("a/b/c").should == File.expand_path("a\\b\\c").gsub('/', "\\")
|
38
39
|
else
|
39
|
-
"a/b/c".
|
40
|
+
SimpleGuiCreator.to_filename("a/b/c").should == File.expand_path("a/b/c")
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
43
44
|
it "should reveal a file" do
|
44
45
|
FileUtils.touch "a b"
|
45
|
-
|
46
|
+
SimpleGuiCreator.show_in_explorer "a b"
|
46
47
|
Dir.mkdir "a dir" unless File.exist?('a dir')
|
47
|
-
|
48
|
+
SimpleGuiCreator.show_in_explorer "a dir"
|
48
49
|
end
|
49
50
|
|
50
51
|
it "should reveal a url" do
|
51
|
-
|
52
|
+
SimpleGuiCreator.open_url_to_view_it_non_blocking "http://www.google.com"
|
52
53
|
end
|
53
54
|
|
54
55
|
it "should select folders" do
|
55
|
-
raise unless File.directory?(c =
|
56
|
+
raise unless File.directory?(c = SimpleGuiCreator.new_existing_dir_chooser_and_go('hello', '.'))
|
56
57
|
p c
|
57
|
-
raise unless File.directory?(c =
|
58
|
+
raise unless File.directory?(c = SimpleGuiCreator.new_existing_dir_chooser_and_go)
|
58
59
|
p c
|
59
60
|
end
|
60
61
|
|
61
62
|
it "should select nonexisting" do
|
62
63
|
name = JFileChooser.new_nonexisting_filechooser_and_go 'should force you to select nonexisting..'
|
63
64
|
raise if File.exist? name
|
64
|
-
name =
|
65
|
+
name = SimpleGuiCreator.new_previously_existing_file_selector_and_go 'should forc select existing file, try to select nonexist'
|
65
66
|
raise unless File.exist? name # it forced them to retry
|
66
67
|
end
|
67
68
|
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: simple_gui_creator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.1.
|
5
|
+
version: 0.1.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- rogerdpack
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-06-
|
13
|
+
date: 2012-06-22 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: sane
|
@@ -41,9 +41,11 @@ executables:
|
|
41
41
|
extensions: []
|
42
42
|
|
43
43
|
extra_rdoc_files:
|
44
|
+
- ChangeLog
|
44
45
|
- README
|
45
46
|
- TODO
|
46
47
|
files:
|
48
|
+
- ChangeLog
|
47
49
|
- README
|
48
50
|
- Rakefile
|
49
51
|
- TODO
|
@@ -53,6 +55,7 @@ files:
|
|
53
55
|
- ext/jl1.0.1.jar
|
54
56
|
- lib/simple_gui_creator.rb
|
55
57
|
- lib/simple_gui_creator/drive_info.rb
|
58
|
+
- lib/simple_gui_creator/jframe_helper_methods.rb
|
56
59
|
- lib/simple_gui_creator/mouse_control.rb
|
57
60
|
- lib/simple_gui_creator/parse_template.rb
|
58
61
|
- lib/simple_gui_creator/play_audio.rb
|
@@ -60,6 +63,7 @@ files:
|
|
60
63
|
- lib/simple_gui_creator/ruby_clip.rb
|
61
64
|
- lib/simple_gui_creator/simple_gui_creator.rb
|
62
65
|
- lib/simple_gui_creator/storage.rb
|
66
|
+
- lib/simple_gui_creator/swing_helpers.rb
|
63
67
|
- spec/common.rb
|
64
68
|
- spec/diesel.mp3
|
65
69
|
- spec/drive_info.spec.rb
|
@@ -102,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
102
106
|
requirements: []
|
103
107
|
|
104
108
|
rubyforge_project:
|
105
|
-
rubygems_version: 1.8.
|
109
|
+
rubygems_version: 1.8.24
|
106
110
|
signing_key:
|
107
111
|
specification_version: 3
|
108
112
|
summary: Framework to ease in creation of ruby GUI apps. Makes designing windows a snap.
|