simple_gui_creator 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|