sweet 0.0.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/COPYING +18 -0
- data/README.rdoc +41 -0
- data/Rakefile +50 -0
- data/bin/sweet +16 -0
- data/examples/hello_world.rb +11 -0
- data/examples/snippet108.rb +46 -0
- data/examples/snippet128.rb +159 -0
- data/examples/snippet169.rb +47 -0
- data/examples/snippet82.rb +57 -0
- data/lib/sweet/base.rb +223 -0
- data/lib/sweet/composite.rb +14 -0
- data/lib/sweet/dialog.rb +9 -0
- data/lib/sweet/downloader.rb +63 -0
- data/lib/sweet/hacks.rb +43 -0
- data/lib/sweet/shell.rb +53 -0
- data/lib/sweet/widget.rb +151 -0
- data/lib/sweet.rb +1 -0
- data/spec/downloader_spec.rb +36 -0
- metadata +100 -0
data/COPYING
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright (c) 2010 Michael Klaus
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to
|
5
|
+
deal in the Software without restriction, including without limitation the
|
6
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
7
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
16
|
+
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
== Sweet: The SWT wrapper for JRuby
|
2
|
+
|
3
|
+
Sweet is designed to provide the most readable and straight-forward DSL for the
|
4
|
+
SWT toolkit while maintaining all of its flexibility. If you find any limits to
|
5
|
+
this claim, please open a bug report or fix it on a fork if you feel
|
6
|
+
adventurous.
|
7
|
+
|
8
|
+
=== Install
|
9
|
+
|
10
|
+
Sweet is available as a gem:
|
11
|
+
|
12
|
+
sudo gem install sweet
|
13
|
+
|
14
|
+
To install the necessary SWT for your platform libraries, run:
|
15
|
+
|
16
|
+
sudo sweet install
|
17
|
+
|
18
|
+
|
19
|
+
=== Example
|
20
|
+
|
21
|
+
Sweet.app 'My first Application', :layout => :fill do
|
22
|
+
label 'Your name:'
|
23
|
+
@name = edit_line
|
24
|
+
|
25
|
+
button 'Push me' do
|
26
|
+
puts "Hello, #{@name.text}!"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
You can then start your application via:
|
31
|
+
|
32
|
+
sweet my_app.rb
|
33
|
+
|
34
|
+
Or put the following lines into the head of your file:
|
35
|
+
|
36
|
+
require 'rubygems'
|
37
|
+
require 'sweet'
|
38
|
+
|
39
|
+
Also, take a look at the files in the example folder to get a head start.
|
40
|
+
|
41
|
+
Have fun!
|
data/Rakefile
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#
|
2
|
+
# To change this template, choose Tools | Templates
|
3
|
+
# and open the template in the editor.
|
4
|
+
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'rake'
|
8
|
+
require 'rake/clean'
|
9
|
+
require 'rake/gempackagetask'
|
10
|
+
require 'rake/rdoctask'
|
11
|
+
require 'rake/testtask'
|
12
|
+
require 'spec/rake/spectask'
|
13
|
+
|
14
|
+
spec = Gem::Specification.new do |s|
|
15
|
+
s.name = 'Sweet'
|
16
|
+
s.version = '0.0.1'
|
17
|
+
s.has_rdoc = true
|
18
|
+
s.extra_rdoc_files = ['README', 'LICENSE']
|
19
|
+
s.summary = 'Your summary here'
|
20
|
+
s.description = s.summary
|
21
|
+
s.author = ''
|
22
|
+
s.email = ''
|
23
|
+
# s.executables = ['your_executable_here']
|
24
|
+
s.files = %w(LICENSE README Rakefile) + Dir.glob("{bin,lib,spec}/**/*")
|
25
|
+
s.require_path = "lib"
|
26
|
+
s.bindir = "bin"
|
27
|
+
end
|
28
|
+
|
29
|
+
Rake::GemPackageTask.new(spec) do |p|
|
30
|
+
p.gem_spec = spec
|
31
|
+
p.need_tar = true
|
32
|
+
p.need_zip = true
|
33
|
+
end
|
34
|
+
|
35
|
+
Rake::RDocTask.new do |rdoc|
|
36
|
+
files =['README', 'LICENSE', 'lib/**/*.rb']
|
37
|
+
rdoc.rdoc_files.add(files)
|
38
|
+
rdoc.main = "README" # page to start on
|
39
|
+
rdoc.title = "Sweet Docs"
|
40
|
+
rdoc.rdoc_dir = 'doc/rdoc' # rdoc output folder
|
41
|
+
rdoc.options << '--line-numbers'
|
42
|
+
end
|
43
|
+
|
44
|
+
Rake::TestTask.new do |t|
|
45
|
+
t.test_files = FileList['test/**/*.rb']
|
46
|
+
end
|
47
|
+
|
48
|
+
Spec::Rake::SpecTask.new do |t|
|
49
|
+
t.spec_files = FileList['spec/**/*.rb']
|
50
|
+
end
|
data/bin/sweet
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env jruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'sweet/downloader'
|
5
|
+
|
6
|
+
cmd = ARGV[0]
|
7
|
+
|
8
|
+
if cmd == 'install'
|
9
|
+
tk = ARGV[1]
|
10
|
+
opts = tk ? {:tk => tk} : {}
|
11
|
+
Sweet::Downloader.download_swt opts
|
12
|
+
else
|
13
|
+
require 'sweet'
|
14
|
+
load cmd
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
$: << File.join(__FILE__, '../lib')
|
2
|
+
require 'sweet'
|
3
|
+
|
4
|
+
# Display display = new Display ();
|
5
|
+
# Shell shell = new Shell (display);
|
6
|
+
# shell.setLayout (new RowLayout ());
|
7
|
+
Sweet.app :layout => :row do
|
8
|
+
|
9
|
+
# Label label = new Label (shell, SWT.NONE);
|
10
|
+
# label.setText ("Enter your name:");
|
11
|
+
label 'Enter your name:'
|
12
|
+
|
13
|
+
# Text text = new Text (shell, SWT.BORDER);
|
14
|
+
# text.setLayoutData (new RowData (100, SWT.DEFAULT));
|
15
|
+
edit_line :style => swt::BORDER, :row_data => 100
|
16
|
+
|
17
|
+
# Button ok = new Button (shell, SWT.PUSH);
|
18
|
+
# ok.setText ("OK");
|
19
|
+
# ok.addSelectionListener(new SelectionAdapter() {
|
20
|
+
# public void widgetSelected(SelectionEvent e) {
|
21
|
+
# System.out.println("OK");
|
22
|
+
# }
|
23
|
+
# });
|
24
|
+
button 'OK' do
|
25
|
+
puts 'OK'
|
26
|
+
end
|
27
|
+
|
28
|
+
# Button cancel = new Button (shell, SWT.PUSH);
|
29
|
+
# cancel.setText ("Cancel");
|
30
|
+
# cancel.addSelectionListener(new SelectionAdapter() {
|
31
|
+
# public void widgetSelected(SelectionEvent e) {
|
32
|
+
# System.out.println("Cancel");
|
33
|
+
# }
|
34
|
+
# });
|
35
|
+
# shell.setDefaultButton (cancel);
|
36
|
+
self.default_button = button 'Cancel' do
|
37
|
+
puts 'Cancel'
|
38
|
+
end
|
39
|
+
|
40
|
+
# shell.pack ();
|
41
|
+
# shell.open ();
|
42
|
+
# while (!shell.isDisposed ()) {
|
43
|
+
# if (!display.readAndDispatch ()) display.sleep ();
|
44
|
+
# }
|
45
|
+
# display.dispose ();
|
46
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
$: << File.join(__FILE__, '../lib')
|
2
|
+
require 'sweet'
|
3
|
+
|
4
|
+
# Display display = new Display();
|
5
|
+
# final Shell shell = new Shell(display);
|
6
|
+
# GridLayout gridLayout = new GridLayout();
|
7
|
+
# gridLayout.numColumns = 3;
|
8
|
+
# shell.setLayout(gridLayout);
|
9
|
+
Sweet.app :layout => :grid.conf(:numColumns => 3) do
|
10
|
+
|
11
|
+
# ToolBar toolbar = new ToolBar(shell, SWT.NONE);
|
12
|
+
# GridData data = new GridData();
|
13
|
+
# data.horizontalSpan = 3;
|
14
|
+
# toolbar.setLayoutData(data);
|
15
|
+
tool_bar :grid_data => {:span => 3} do
|
16
|
+
|
17
|
+
# ToolItem itemBack = new ToolItem(toolbar, SWT.PUSH);
|
18
|
+
# itemBack.setText("Back");
|
19
|
+
# ToolItem itemForward = new ToolItem(toolbar, SWT.PUSH);
|
20
|
+
# itemForward.setText("Forward");
|
21
|
+
# ToolItem itemStop = new ToolItem(toolbar, SWT.PUSH);
|
22
|
+
# itemStop.setText("Stop");
|
23
|
+
# ToolItem itemRefresh = new ToolItem(toolbar, SWT.PUSH);
|
24
|
+
# itemRefresh.setText("Refresh");
|
25
|
+
# ToolItem itemGo = new ToolItem(toolbar, SWT.PUSH);
|
26
|
+
# itemGo.setText("Go");
|
27
|
+
# /* event handling */
|
28
|
+
# Listener listener = new Listener() {
|
29
|
+
# public void handleEvent(Event event) {
|
30
|
+
# ToolItem item = (ToolItem)event.widget;
|
31
|
+
# String string = item.getText();
|
32
|
+
# if (string.equals("Back")) browser.back();
|
33
|
+
# else if (string.equals("Forward")) browser.forward();
|
34
|
+
# else if (string.equals("Stop")) browser.stop();
|
35
|
+
# else if (string.equals("Refresh")) browser.refresh();
|
36
|
+
# else if (string.equals("Go")) browser.setUrl(location.getText());
|
37
|
+
# }
|
38
|
+
# };
|
39
|
+
%w{Back Forward Stop Refresh}.each do |caption|
|
40
|
+
tool_item(caption) { @browser.send(caption.downcase) }
|
41
|
+
end
|
42
|
+
tool_item('Go') { @browser.setUrl @location.text }
|
43
|
+
end
|
44
|
+
|
45
|
+
# Label labelAddress = new Label(shell, SWT.NONE);
|
46
|
+
# labelAddress.setText("Address");
|
47
|
+
label 'Address'
|
48
|
+
|
49
|
+
# final Text location = new Text(shell, SWT.BORDER);
|
50
|
+
# data = new GridData();
|
51
|
+
# data.horizontalAlignment = GridData.FILL;
|
52
|
+
# data.horizontalSpan = 2;
|
53
|
+
# data.grabExcessHorizontalSpace = true;
|
54
|
+
# location.setLayoutData(data);
|
55
|
+
# location.addListener(SWT.DefaultSelection, new Listener() {
|
56
|
+
# public void handleEvent(Event e) {
|
57
|
+
# browser.setUrl(location.getText());
|
58
|
+
# }
|
59
|
+
# });
|
60
|
+
@location = edit_line :grid_data => {:align => :fill, :span => 2, :grab => true} do
|
61
|
+
@browser.setUrl @location.text
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
# final Browser browser;
|
66
|
+
# try {
|
67
|
+
# browser = new Browser(shell, SWT.NONE);
|
68
|
+
# } catch (SWTError e) {
|
69
|
+
# System.out.println("Could not instantiate Browser: " + e.getMessage());
|
70
|
+
# display.dispose();
|
71
|
+
# return;
|
72
|
+
# }
|
73
|
+
begin
|
74
|
+
# data = new GridData();
|
75
|
+
# data.horizontalAlignment = GridData.FILL;
|
76
|
+
# data.verticalAlignment = GridData.FILL;
|
77
|
+
# data.horizontalSpan = 3;
|
78
|
+
# data.grabExcessHorizontalSpace = true;
|
79
|
+
# data.grabExcessVerticalSpace = true;
|
80
|
+
# browser.setLayoutData(data);
|
81
|
+
@browser = browser :grid_data => {
|
82
|
+
:align => [:fill, :fill],
|
83
|
+
:span => 3,
|
84
|
+
:grab => [true, true]
|
85
|
+
}
|
86
|
+
rescue org.eclipse.swt.SWTError => e
|
87
|
+
SYSERR.puts "Could not instantiate Browser: #{e.message}"
|
88
|
+
exit
|
89
|
+
end
|
90
|
+
|
91
|
+
# final Label status = new Label(shell, SWT.NONE);
|
92
|
+
# data = new GridData(GridData.FILL_HORIZONTAL);
|
93
|
+
# data.horizontalSpan = 2;
|
94
|
+
# status.setLayoutData(data);
|
95
|
+
@status = label :grid_data => {:span => 2, :align => :fill}
|
96
|
+
|
97
|
+
# final ProgressBar progressBar = new ProgressBar(shell, SWT.NONE);
|
98
|
+
# data = new GridData();
|
99
|
+
# data.horizontalAlignment = GridData.END;
|
100
|
+
# progressBar.setLayoutData(data);
|
101
|
+
@progress_bar = progress :grid_data => {:align => :end}
|
102
|
+
|
103
|
+
#
|
104
|
+
# browser.addProgressListener(new ProgressListener() {
|
105
|
+
# public void changed(ProgressEvent event) {
|
106
|
+
# if (event.total == 0) return;
|
107
|
+
# int ratio = event.current * 100 / event.total;
|
108
|
+
# progressBar.setSelection(ratio);
|
109
|
+
# }
|
110
|
+
# public void completed(ProgressEvent event) {
|
111
|
+
# progressBar.setSelection(0);
|
112
|
+
# }
|
113
|
+
# });
|
114
|
+
@browser.on_progress_changed do |event|
|
115
|
+
if event.total != 0
|
116
|
+
@progress_bar.fraction = event.current.to_f / event.total
|
117
|
+
end
|
118
|
+
end
|
119
|
+
@browser.on_progress_completed do
|
120
|
+
@progress_bar.selection = 0
|
121
|
+
end
|
122
|
+
|
123
|
+
# browser.addStatusTextListener(new StatusTextListener() {
|
124
|
+
# public void changed(StatusTextEvent event) {
|
125
|
+
# status.setText(event.text);
|
126
|
+
# }
|
127
|
+
# });
|
128
|
+
@browser.on_status_text do |event|
|
129
|
+
@status.text = event.text
|
130
|
+
end
|
131
|
+
|
132
|
+
# browser.addLocationListener(new LocationListener() {
|
133
|
+
# public void changed(LocationEvent event) {
|
134
|
+
# if (event.top) location.setText(event.location);
|
135
|
+
# }
|
136
|
+
# public void changing(LocationEvent event) {
|
137
|
+
# }
|
138
|
+
# });
|
139
|
+
@browser.on_location_changed do |event|
|
140
|
+
@location.text = event.location if event.top
|
141
|
+
end
|
142
|
+
|
143
|
+
# itemBack.addListener(SWT.Selection, listener);
|
144
|
+
# itemForward.addListener(SWT.Selection, listener);
|
145
|
+
# itemStop.addListener(SWT.Selection, listener);
|
146
|
+
# itemRefresh.addListener(SWT.Selection, listener);
|
147
|
+
# itemGo.addListener(SWT.Selection, listener);
|
148
|
+
#
|
149
|
+
# shell.open();
|
150
|
+
# browser.setUrl("http://eclipse.org");
|
151
|
+
@browser.setUrl "http://eclipse.org"
|
152
|
+
|
153
|
+
#
|
154
|
+
# while (!shell.isDisposed()) {
|
155
|
+
# if (!display.readAndDispatch())
|
156
|
+
# display.sleep();
|
157
|
+
# }
|
158
|
+
# display.dispose();
|
159
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
$: << File.join(__FILE__, '../lib')
|
2
|
+
require 'sweet'
|
3
|
+
|
4
|
+
# Display display = new Display ();
|
5
|
+
# final Shell shell = new Shell (display);
|
6
|
+
# shell.setLayout (new FillLayout ());
|
7
|
+
Sweet.app :layout => :fill do
|
8
|
+
|
9
|
+
# Listener listener = new Listener () {
|
10
|
+
# public void handleEvent (Event e) {
|
11
|
+
# Control [] children = shell.getChildren ();
|
12
|
+
# for (int i=0; i<children.length; i++) {
|
13
|
+
# Control child = children [i];
|
14
|
+
# if (e.widget != child && child instanceof Button && (child.getStyle () & SWT.TOGGLE) != 0) {
|
15
|
+
# ((Button) child).setSelection (false);
|
16
|
+
# }
|
17
|
+
# }
|
18
|
+
# ((Button) e.widget).setSelection (true);
|
19
|
+
# }
|
20
|
+
# };
|
21
|
+
@listener = proc do |e|
|
22
|
+
shell.children.each do |child|
|
23
|
+
if e.widget != child && child.is_a?(widgets::Button) && (child.style & swt::TOGGLE)
|
24
|
+
child.selection = false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
e.widget.selection = true
|
28
|
+
end
|
29
|
+
|
30
|
+
# for (int i=0; i<20; i++) {
|
31
|
+
# Button button = new Button (shell, SWT.TOGGLE);
|
32
|
+
# button.setText ("B" + i);
|
33
|
+
# button.addListener (SWT.Selection, listener);
|
34
|
+
# if (i == 0) button.setSelection (true);
|
35
|
+
# }
|
36
|
+
|
37
|
+
20.times do |i|
|
38
|
+
button "B#{i}", :style => swt::TOGGLE, :selection => i == 0, &@listener
|
39
|
+
end
|
40
|
+
|
41
|
+
# shell.pack ();
|
42
|
+
# shell.open ();
|
43
|
+
# while (!shell.isDisposed ()) {
|
44
|
+
# if (!display.readAndDispatch ()) display.sleep ();
|
45
|
+
# }
|
46
|
+
# display.dispose ();
|
47
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
$: << File.join(__FILE__, '../lib')
|
2
|
+
require 'sweet'
|
3
|
+
|
4
|
+
#Display display = new Display();
|
5
|
+
# Shell shell = new Shell(display);
|
6
|
+
# shell.setLayout(new FillLayout());
|
7
|
+
Sweet.app :layout => :fill do
|
8
|
+
|
9
|
+
# CTabFolder folder = new CTabFolder(shell, SWT.BORDER);
|
10
|
+
@folder = tab_folder do
|
11
|
+
# for (int i = 0; i < 4; i++) {
|
12
|
+
# CTabItem item = new CTabItem(folder, SWT.CLOSE);
|
13
|
+
# item.setText("Item "+i);
|
14
|
+
# Text text = new Text(folder, SWT.MULTI);
|
15
|
+
# text.setText("Content for Item "+i);
|
16
|
+
# item.setControl(text);
|
17
|
+
# }
|
18
|
+
4.times do |i|
|
19
|
+
tab_item "Item #{i}", :control => edit_area("Content for Item #{i}")
|
20
|
+
end
|
21
|
+
|
22
|
+
# final CTabItem specialItem = new CTabItem(folder, SWT.CLOSE);
|
23
|
+
# specialItem.setText("Don't Close Me");
|
24
|
+
# Text text = new Text(folder, SWT.MULTI);
|
25
|
+
# text.setText("This tab can never be closed");
|
26
|
+
# specialItem.setControl(text);
|
27
|
+
@special_item = tab_item("Don't Close Me") do
|
28
|
+
edit_area("This tab can never be closed")
|
29
|
+
end
|
30
|
+
|
31
|
+
# final CTabItem noCloseItem = new CTabItem(folder, SWT.NONE);
|
32
|
+
# noCloseItem.setText("No Close Button");
|
33
|
+
# Text text2 = new Text(folder, SWT.MULTI);
|
34
|
+
# text2.setText("This tab does not have a close button");
|
35
|
+
# noCloseItem.setControl(text2);
|
36
|
+
tab_item "No Close Button", edit_area("This tab does not have a close button"), :style => :none
|
37
|
+
end
|
38
|
+
|
39
|
+
# folder.addCTabFolder2Listener(new CTabFolder2Adapter() {
|
40
|
+
# public void close(CTabFolderEvent event) {
|
41
|
+
# if (event.item.equals(specialItem)) {
|
42
|
+
# event.doit = false;
|
43
|
+
# }
|
44
|
+
# }
|
45
|
+
# });
|
46
|
+
@folder.on_close do |event|
|
47
|
+
event.doit = event.item != @special_item
|
48
|
+
end
|
49
|
+
|
50
|
+
# shell.pack();
|
51
|
+
# shell.open();
|
52
|
+
# while (!shell.isDisposed()) {
|
53
|
+
# if (!display.readAndDispatch())
|
54
|
+
# display.sleep();
|
55
|
+
# }
|
56
|
+
# display.dispose();
|
57
|
+
end
|
data/lib/sweet/base.rb
ADDED
@@ -0,0 +1,223 @@
|
|
1
|
+
require 'sweet/downloader'
|
2
|
+
|
3
|
+
begin
|
4
|
+
load Sweet::SWT_JAR
|
5
|
+
rescue LoadError => e
|
6
|
+
STDERR.puts "No swt.jar found. Run:"
|
7
|
+
STDERR.puts " sweet install [toolkit]"
|
8
|
+
exit
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'java'
|
12
|
+
%w{hacks widget composite shell dialog}.each{|file| require "sweet/#{file}"}
|
13
|
+
|
14
|
+
# TODO create gemspec
|
15
|
+
# TODO evaluate integration of jface
|
16
|
+
# TODO enable additive and replacing :style on widget creation
|
17
|
+
module Sweet
|
18
|
+
|
19
|
+
import 'org.eclipse.swt'
|
20
|
+
import 'org.eclipse.swt.widgets'
|
21
|
+
import 'org.eclipse.swt.custom'
|
22
|
+
import 'org.eclipse.swt.browser'
|
23
|
+
|
24
|
+
# TODO integrate all standard widgets
|
25
|
+
WIDGET_HACKS = {
|
26
|
+
ProgressBar => {:custom_code => proc {
|
27
|
+
def fraction=(value)
|
28
|
+
setSelection value.to_f * maximum
|
29
|
+
end
|
30
|
+
def fraction
|
31
|
+
selection / maximum
|
32
|
+
end
|
33
|
+
}},
|
34
|
+
Text => {:custom_code => proc{
|
35
|
+
def password=(value)
|
36
|
+
self.echo_char = ?* if value
|
37
|
+
end
|
38
|
+
def password
|
39
|
+
! echo_char.nil?
|
40
|
+
end
|
41
|
+
}},
|
42
|
+
CTabFolder => {:default_listener => 'CTabFolder2'}
|
43
|
+
}
|
44
|
+
|
45
|
+
DEFAULT = {:init_args => :text, :block_handler => SWT::Selection}
|
46
|
+
WIDGET_OPTIONS = {
|
47
|
+
# Text components
|
48
|
+
:label => {:style => SWT::WRAP, :init_args => :text},
|
49
|
+
:edit_line => {:class => Text, :style => SWT::SINGLE | SWT::BORDER, :init_args => :text, :block_handler => :on_widget_default_selected},
|
50
|
+
:edit_area => {:class => Text, :style => SWT::MULTI | SWT::BORDER, :init_args => :text, :block_handler => :on_widget_default_selected},
|
51
|
+
|
52
|
+
# Buttons
|
53
|
+
:button => DEFAULT.merge(:style => SWT::PUSH),
|
54
|
+
:toggle_button => DEFAULT.merge(:class => Button, :style => SWT::TOGGLE),
|
55
|
+
:radio_button => DEFAULT.merge(:class => Button, :style => SWT::RADIO),
|
56
|
+
:check_button => DEFAULT.merge(:class => Button, :style => SWT::CHECK),
|
57
|
+
:arrow_button => DEFAULT.merge(:class => Button, :style => SWT::ARROW),
|
58
|
+
|
59
|
+
# Menus
|
60
|
+
:menubar => {:class => Menu, :style => SWT::BAR},
|
61
|
+
:popup => {:class => Menu, :style => SWT::POP_UP},
|
62
|
+
:item => {:class => MenuItem, :style => SWT::PUSH, :init_args => :text, :block_handler => :on_widget_selected},
|
63
|
+
:separator => {:class => MenuItem, :style => SWT::SEPARATOR},
|
64
|
+
:submenu => {:class => MenuItem, :style => SWT::CASCADE, :init_args => :text, :block_handler => proc{|c, opts, block|
|
65
|
+
sub = Menu.new(c.app, SWT::DROP_DOWN)
|
66
|
+
sub.sweeten(c.app, opts, &block)
|
67
|
+
c.menu = sub
|
68
|
+
}
|
69
|
+
},
|
70
|
+
|
71
|
+
# Toolbars
|
72
|
+
:tool_item => DEFAULT.merge(:style => SWT::PUSH),
|
73
|
+
# TODO make CoolBar work
|
74
|
+
# :cool_item => {:init_args => :control, :block_handler => proc{ |c, opts, proc|
|
75
|
+
# c.control = proc.call
|
76
|
+
# }},
|
77
|
+
|
78
|
+
# Tabs
|
79
|
+
:tab_folder => {:class => CTabFolder, :style => SWT::BORDER},
|
80
|
+
:tab_item => {:class => CTabItem, :style => SWT::CLOSE, :init_args => [:text, :control], :block_handler => proc{|c, opts, proc|
|
81
|
+
c.control = proc.call
|
82
|
+
}},
|
83
|
+
|
84
|
+
# Other components
|
85
|
+
:tree => {:style => SWT::VIRTUAL, :block_handler => SWT::Selection},
|
86
|
+
:progress => {:class => ProgressBar, :style => SWT::SMOOTH},
|
87
|
+
:group => {:init_args => :text},
|
88
|
+
|
89
|
+
# Dialogs
|
90
|
+
:color_dialog => {:style => SWT::APPLICATION_MODAL, :init_args => :text}
|
91
|
+
}.unify
|
92
|
+
|
93
|
+
WIDGETS = {}
|
94
|
+
|
95
|
+
def self.app(*args, &block)
|
96
|
+
# prepare the arguments
|
97
|
+
count = args.length
|
98
|
+
name = args.first.is_a?(String) ? args.shift : 'SWEET Application'
|
99
|
+
raise ArgumentError.new(count, 2) if args.size > 1
|
100
|
+
opts = args.first || {}
|
101
|
+
|
102
|
+
# build the UI
|
103
|
+
Display.setAppName(name)
|
104
|
+
display = Display.new
|
105
|
+
|
106
|
+
# TODO allow multiple shells
|
107
|
+
shell = Shell.new(display)
|
108
|
+
shell.sweeten(display, name, opts, &block)
|
109
|
+
shell.open
|
110
|
+
|
111
|
+
# dispatch loop
|
112
|
+
while (!shell.isDisposed) do
|
113
|
+
display.sleep unless display.readAndDispatch
|
114
|
+
end
|
115
|
+
|
116
|
+
display.dispose
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.create_widget(parent, name, *args, &block)
|
120
|
+
init = WIDGET_OPTIONS[name] || {}
|
121
|
+
|
122
|
+
unless cls = WIDGETS[name]
|
123
|
+
# puts "Loading widget #{name}"
|
124
|
+
# filename = File.join('sweet/widget', name.to_s)
|
125
|
+
# begin
|
126
|
+
# require filename
|
127
|
+
# rescue LoadError
|
128
|
+
cls = create_widget_class(name, init)
|
129
|
+
# end
|
130
|
+
end
|
131
|
+
|
132
|
+
opts = args.last.is_a?(Hash) ? args.pop.dup : {}
|
133
|
+
|
134
|
+
style = opts.delete(:style) || init[:style] || SWT::NONE
|
135
|
+
style = Array(style).inject(0) do |result, value|
|
136
|
+
value = value.swt_const if value.is_a? Symbol
|
137
|
+
result | value
|
138
|
+
end
|
139
|
+
|
140
|
+
Sweet.debug "Creating #{cls.java_class.simple_name}(#{parent}, #{style})"
|
141
|
+
result = cls.new(parent, style)
|
142
|
+
result.instance_variable_set(:@block_handler, init[:block_handler])
|
143
|
+
|
144
|
+
if init_args = init[:init_args]
|
145
|
+
Hash[Array(init_args).zip(args)].each do |k, v|
|
146
|
+
opts.merge! k => v if v
|
147
|
+
end
|
148
|
+
end
|
149
|
+
result.sweeten(parent.app, opts, &block)
|
150
|
+
|
151
|
+
result
|
152
|
+
end
|
153
|
+
|
154
|
+
def self.create_widget_class(name, init)
|
155
|
+
# build widget with default accessors
|
156
|
+
class_name = init[:class] || name
|
157
|
+
class_name = class_name.to_s.camelize(:upper) if class_name.is_a?(Symbol)
|
158
|
+
cls = class_name.is_a?(Class) ? class_name : const_get(class_name)
|
159
|
+
|
160
|
+
unless WIDGETS.values.member? cls
|
161
|
+
delegate_events(cls)
|
162
|
+
if hacks = WIDGET_HACKS[cls]
|
163
|
+
if custom_code = hacks[:custom_code]
|
164
|
+
cls.class_eval &custom_code
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
cls
|
170
|
+
end
|
171
|
+
|
172
|
+
def self.delegate_events(cls)
|
173
|
+
hacks = WIDGET_HACKS[cls]
|
174
|
+
default_listener = (hacks[:default_listener] || '').underscore if hacks
|
175
|
+
|
176
|
+
methods = cls.java_class.java_instance_methods
|
177
|
+
methods.each do |m|
|
178
|
+
next unless m.name =~ /(add(.*)Listener)/
|
179
|
+
j = $1
|
180
|
+
n = $2.underscore
|
181
|
+
p = m.parameter_types[0]
|
182
|
+
evts = p.declared_instance_methods
|
183
|
+
|
184
|
+
if evts.size == 1
|
185
|
+
s = "on_#{n}"
|
186
|
+
cls.send(:alias_method, s, j) unless cls.respond_to?(s)
|
187
|
+
else
|
188
|
+
evts.each do |evt|
|
189
|
+
s = evt.name.underscore
|
190
|
+
if s.split(/_/).size == 1 && n != default_listener
|
191
|
+
s = n + "_" + s
|
192
|
+
end
|
193
|
+
# TODO provide addListener SWT::Xxx option
|
194
|
+
unused_events = evts.select{ |e| e.name != evt.name }.map{ |e| "def #{e.name.underscore}(e)\nend" }.join("\n")
|
195
|
+
cls.class_eval <<-EOF
|
196
|
+
def on_#{s}(&block)
|
197
|
+
l = Class.new do
|
198
|
+
include Java.#{p}
|
199
|
+
def initialize(&block)
|
200
|
+
@block = block
|
201
|
+
end
|
202
|
+
def #{evt.name}(e)
|
203
|
+
@block.call e
|
204
|
+
end
|
205
|
+
#{unused_events}
|
206
|
+
end
|
207
|
+
#{j} l.new(&block)
|
208
|
+
end
|
209
|
+
EOF
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def self.set_debug
|
216
|
+
@debug = true
|
217
|
+
end
|
218
|
+
def self.debug(text)
|
219
|
+
# TODO add a decent logging mechanism
|
220
|
+
puts text if @debug
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Java::OrgEclipseSwtWidgets::Composite
|
2
|
+
|
3
|
+
def layout=(name, options = {})
|
4
|
+
class_name = "#{name.to_s.capitalize}Layout"
|
5
|
+
l = instance_eval "org.eclipse.swt.layout.#{class_name}.new"
|
6
|
+
|
7
|
+
options.each_pair do |k,v|
|
8
|
+
l.send("#{k}=", v)
|
9
|
+
end
|
10
|
+
|
11
|
+
setLayout l
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
data/lib/sweet/dialog.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
module Sweet
|
2
|
+
SWT_JAR = File.join(File.dirname(__FILE__), '../../swt/swt.jar')
|
3
|
+
|
4
|
+
module Downloader
|
5
|
+
def self.download_swt(opts = {})
|
6
|
+
require 'rubygems'
|
7
|
+
require 'open-uri'
|
8
|
+
require 'zippy'
|
9
|
+
require 'fileutils'
|
10
|
+
|
11
|
+
platform = system_qualifier(opts)
|
12
|
+
puts "Downloading SWT #{platform}"
|
13
|
+
|
14
|
+
# TODO support other SWT versions
|
15
|
+
open("http://mirrors.ibiblio.org/pub/mirrors/eclipse/eclipse/downloads/drops/R-3.5.2-201002111343/swt-3.5.2-#{platform}.zip") do |remote|
|
16
|
+
Zippy.open(remote.path) do |zip|
|
17
|
+
FileUtils.mkdir_p File.dirname(Sweet::SWT_JAR)
|
18
|
+
File.open(Sweet::SWT_JAR, 'wb') do |f|
|
19
|
+
f.write zip['swt.jar']
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# TODO integrate user input to all feasible platforms
|
26
|
+
def self.system_qualifier(opts = {})
|
27
|
+
props = Java.java.lang.System.properties
|
28
|
+
os = (opts[:os] || props['os.name']).downcase
|
29
|
+
|
30
|
+
arch = (opts[:arch] || props['os.arch']).downcase
|
31
|
+
arch = 'x86' if arch =~ /..86$/
|
32
|
+
|
33
|
+
wish_tk = opts[:tk]
|
34
|
+
tk = case os
|
35
|
+
when *%w{linux solaris sunos}
|
36
|
+
os = 'solaris' if os == 'sunos'
|
37
|
+
%w{gtk motif}.member?(wish_tk) ? wish_tk : 'gtk'
|
38
|
+
when 'mac os x'
|
39
|
+
os = 'macosx'
|
40
|
+
arch = nil if arch != 'x86_64'
|
41
|
+
%w{carbon cocoa}.member?(wish_tk) ? wish_tk : 'cocoa'
|
42
|
+
when 'qnx'
|
43
|
+
arch = 'x86'
|
44
|
+
'photon'
|
45
|
+
when 'aix'
|
46
|
+
arch = 'ppc'
|
47
|
+
'motif'
|
48
|
+
when 'hp-ux'
|
49
|
+
os = 'hpux'
|
50
|
+
arch = 'ia64_32'
|
51
|
+
'motif'
|
52
|
+
when 'windows vista'
|
53
|
+
os = 'win32'
|
54
|
+
arch = 'x86' if wish_tk == 'wpf'
|
55
|
+
%w{wpf win32}.member?(wish_tk) ? wish_tk : 'win32'
|
56
|
+
when /windows/
|
57
|
+
os = 'win32' # returns win32 as tk also
|
58
|
+
end
|
59
|
+
|
60
|
+
[tk, os, arch].compact.join('-')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/sweet/hacks.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
class Hash
|
2
|
+
def unify
|
3
|
+
each_pair do |k, v|
|
4
|
+
if k.is_a? Array
|
5
|
+
k.each do |key|
|
6
|
+
self[key.to_sym] = v
|
7
|
+
end
|
8
|
+
self.delete k
|
9
|
+
elsif ! k.is_a?(Symbol)
|
10
|
+
self[k.to_sym] = v
|
11
|
+
self.delete k
|
12
|
+
end
|
13
|
+
end
|
14
|
+
self
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Symbol
|
19
|
+
# For configuring layouts
|
20
|
+
def conf(opts = {})
|
21
|
+
[self, opts]
|
22
|
+
end
|
23
|
+
def swt_const
|
24
|
+
org.eclipse.swt.SWT.const_get(self.to_s.upcase)
|
25
|
+
end
|
26
|
+
def swt_event
|
27
|
+
org.eclipse.swt.SWT.const_get(self.to_s.camelize(:upper))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# TODO find those things in JRuby
|
32
|
+
class String
|
33
|
+
def camelize(first_letter_in_uppercase = :upper)
|
34
|
+
s = gsub(/\/(.?)/){|x| "::#{x[-1..-1].upcase unless x == '/'}"}.gsub(/(^|_)(.)/){|x| x[-1..-1].upcase}
|
35
|
+
s[0...1] = s[0...1].downcase unless first_letter_in_uppercase == :upper
|
36
|
+
s
|
37
|
+
end
|
38
|
+
def underscore
|
39
|
+
gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
40
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').tr("-", "_").downcase
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
data/lib/sweet/shell.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# TODO pack into WIDGETS
|
2
|
+
class Java::OrgEclipseSwtWidgets::Shell
|
3
|
+
attr_reader :display
|
4
|
+
alias_property :title => :text
|
5
|
+
|
6
|
+
def sweeten(display, name, opts = {}, &block)
|
7
|
+
@display = display
|
8
|
+
|
9
|
+
self.text = opts.delete(:title) || name
|
10
|
+
w, h = opts.delete(:width), opts.delete(:height)
|
11
|
+
|
12
|
+
super(self, opts, &block)
|
13
|
+
|
14
|
+
pack
|
15
|
+
size = (w || width), (h || height)
|
16
|
+
end
|
17
|
+
|
18
|
+
def sweet_containers
|
19
|
+
@sweet_containers ||= [self]
|
20
|
+
end
|
21
|
+
|
22
|
+
def perform(&block)
|
23
|
+
display.syncExec block
|
24
|
+
end
|
25
|
+
|
26
|
+
def busy(&block)
|
27
|
+
Thread.new do
|
28
|
+
perform do
|
29
|
+
custom::BusyIndicator.showWhile(display) do
|
30
|
+
block.call
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def menubar(&block)
|
37
|
+
self.menu_bar = make_menu(:menubar, &block)
|
38
|
+
end
|
39
|
+
|
40
|
+
def popup(&block)
|
41
|
+
self.menu = make_menu(:popup, &block)
|
42
|
+
end
|
43
|
+
|
44
|
+
def method_missing(name, *args, &block)
|
45
|
+
Sweet.create_widget(sweet_containers.last, name, *args, &block) || super
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
def make_menu(type, &block)
|
50
|
+
Sweet.create_widget(sweet_containers.last, type, &block)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
data/lib/sweet/widget.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
class Java::OrgEclipseSwtWidgets::Widget
|
4
|
+
extend Forwardable
|
5
|
+
attr_reader :app
|
6
|
+
|
7
|
+
def sweeten(app, opts, &block)
|
8
|
+
@app = app
|
9
|
+
self.options = opts
|
10
|
+
|
11
|
+
if block
|
12
|
+
case handler = @block_handler
|
13
|
+
when nil
|
14
|
+
handle_container &block
|
15
|
+
when Symbol
|
16
|
+
send handler, &block
|
17
|
+
when Numeric
|
18
|
+
addListener handler, &block
|
19
|
+
when Proc
|
20
|
+
instance_eval do
|
21
|
+
handler.call self, opts, block
|
22
|
+
end
|
23
|
+
else
|
24
|
+
raise "Invalid :block_handler ",handler
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
puts "Unknown properties for class #{self.class}: #{opts.keys.inspect}" unless opts.empty?
|
29
|
+
end
|
30
|
+
|
31
|
+
def app(&block)
|
32
|
+
block ? @app.instance_eval(&block) : @app
|
33
|
+
end
|
34
|
+
|
35
|
+
def append(&block)
|
36
|
+
raise "Append called without block" unless block
|
37
|
+
handle_container &block
|
38
|
+
end
|
39
|
+
|
40
|
+
def meta(&block)
|
41
|
+
@meta ||= class << self
|
42
|
+
self
|
43
|
+
end
|
44
|
+
block ? @meta.class_eval(&block) : @meta
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.alias_property(aliases = {})
|
48
|
+
aliases.each do |from, to|
|
49
|
+
alias_method from, to unless "to"
|
50
|
+
alias_method "#{from}=", "#{to}=" unless "#{to}="
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def options=(opts)
|
55
|
+
# TODO reader method
|
56
|
+
opts.each_pair do |k, v|
|
57
|
+
case k
|
58
|
+
when :hidden
|
59
|
+
setVisible !v
|
60
|
+
else
|
61
|
+
name = k.to_s + "="
|
62
|
+
if respond_to?(name)
|
63
|
+
if v
|
64
|
+
Sweet.debug "#{self.java_class.simple_name}.#{k} = #{v.inspect}"
|
65
|
+
send name, *v
|
66
|
+
end
|
67
|
+
opts.delete(k)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
# TODO unify this layout mess somehow
|
75
|
+
# TODO hierarchical hash for nicer client code
|
76
|
+
def grid_data=(*opts)
|
77
|
+
opts = Hash[opts]
|
78
|
+
ax, ay = opts[:align]
|
79
|
+
gx, gy = opts[:grab]
|
80
|
+
sx, sy = opts[:span]
|
81
|
+
args = [ax || swt::BEGINNING, ay || swt::CENTER,
|
82
|
+
gx || false, gy || false, sx || 1, sy || 1]
|
83
|
+
args.map!{|v| v.is_a?(Symbol) ? v.swt_const : v}
|
84
|
+
Sweet.debug args.inspect
|
85
|
+
l = layouts::GridData.new(*args)
|
86
|
+
self.layout_data = l
|
87
|
+
end
|
88
|
+
def row_data=(x, y = nil)
|
89
|
+
self.layout_data = layouts::RowData.new(x || swt::DEFAULT, y || swt::DEFAULT)
|
90
|
+
end
|
91
|
+
|
92
|
+
def perform(&block)
|
93
|
+
app.perform &block
|
94
|
+
end
|
95
|
+
|
96
|
+
def hide
|
97
|
+
self.visible = false
|
98
|
+
end
|
99
|
+
def show
|
100
|
+
self.visible = true
|
101
|
+
end
|
102
|
+
|
103
|
+
def width
|
104
|
+
size.x
|
105
|
+
end
|
106
|
+
def width=(value)
|
107
|
+
self.size = value, nil
|
108
|
+
end
|
109
|
+
|
110
|
+
def height
|
111
|
+
size.y
|
112
|
+
end
|
113
|
+
def height=(value)
|
114
|
+
self.size = nil, value
|
115
|
+
end
|
116
|
+
|
117
|
+
def size=(*s)
|
118
|
+
nw, nh = s.flatten
|
119
|
+
nw ||= width
|
120
|
+
nh ||= height
|
121
|
+
setSize(nw, nh)
|
122
|
+
end
|
123
|
+
|
124
|
+
# TODO replace via import?
|
125
|
+
def swt
|
126
|
+
org.eclipse.swt.SWT
|
127
|
+
end
|
128
|
+
def widgets
|
129
|
+
org.eclipse.swt.widgets
|
130
|
+
end
|
131
|
+
def layouts
|
132
|
+
org.eclipse.swt.layout
|
133
|
+
end
|
134
|
+
def custom
|
135
|
+
org.eclipse.swt.custom
|
136
|
+
end
|
137
|
+
|
138
|
+
def method_missing(name, *args, &block)
|
139
|
+
handle_container(&block) rescue super
|
140
|
+
end
|
141
|
+
|
142
|
+
private
|
143
|
+
def handle_container(&block)
|
144
|
+
app.sweet_containers.push self
|
145
|
+
app &block
|
146
|
+
ensure
|
147
|
+
app.sweet_containers.pop
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
|
data/lib/sweet.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'sweet/base'
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'sweet/downloader'
|
2
|
+
|
3
|
+
describe Sweet::Downloader, '#system_qualifier' do
|
4
|
+
before :each do
|
5
|
+
@d = Sweet::Downloader
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'returns gtk-linux-x86 for Linux i686' do
|
9
|
+
@d.system_qualifier(:os => 'Linux', :arch => 'i686').should == 'gtk-linux-x86'
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'returns gtk-linux-x86 for Linux x86_64' do
|
13
|
+
@d.system_qualifier(:os => 'Linux', :arch => 'x86_64').should == 'gtk-linux-x86_64'
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'returns motif-linux-x86 for Linux i686 and :tk => "motif"' do
|
17
|
+
@d.system_qualifier(:os => 'Linux', :arch => 'i686', :tk => 'motif').should == 'motif-linux-x86'
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'returns cocoa-macos for Mac OS X i686' do
|
21
|
+
@d.system_qualifier(:os => 'Mac OS X', :arch => 'i686').should == 'cocoa-macosx'
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'returns cocoa-macos-x86_64 for Mac OS X x86_64' do
|
25
|
+
@d.system_qualifier(:os => 'Mac OS X', :arch => 'x86_64').should == 'cocoa-macosx-x86_64'
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'returns win32-win32-x86 for Windows XP' do
|
29
|
+
@d.system_qualifier(:os => 'Windows XP', :arch => 'i686').should == 'win32-win32-x86'
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'returns win32-win32-x86_64 for Windows Vista on x86_64' do
|
33
|
+
@d.system_qualifier(:os => 'Windows Vista', :arch => 'x86_64').should == 'win32-win32-x86_64'
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sweet
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Michael Klaus
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-05-17 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: zippy
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
33
|
+
description: The SWT wrapper for JRuby
|
34
|
+
email: Michael.Klaus@gmx.net
|
35
|
+
executables:
|
36
|
+
- sweet
|
37
|
+
extensions: []
|
38
|
+
|
39
|
+
extra_rdoc_files:
|
40
|
+
- README.rdoc
|
41
|
+
- COPYING
|
42
|
+
files:
|
43
|
+
- COPYING
|
44
|
+
- README.rdoc
|
45
|
+
- Rakefile
|
46
|
+
- bin/sweet
|
47
|
+
- spec/downloader_spec.rb
|
48
|
+
- lib/sweet.rb
|
49
|
+
- lib/sweet/shell.rb
|
50
|
+
- lib/sweet/widget.rb
|
51
|
+
- lib/sweet/hacks.rb
|
52
|
+
- lib/sweet/downloader.rb
|
53
|
+
- lib/sweet/composite.rb
|
54
|
+
- lib/sweet/base.rb
|
55
|
+
- lib/sweet/dialog.rb
|
56
|
+
- examples/snippet128.rb
|
57
|
+
- examples/snippet169.rb
|
58
|
+
- examples/snippet108.rb
|
59
|
+
- examples/snippet82.rb
|
60
|
+
- examples/hello_world.rb
|
61
|
+
has_rdoc: true
|
62
|
+
homepage: http://github.org/QaDeS/sweet
|
63
|
+
licenses: []
|
64
|
+
|
65
|
+
post_install_message:
|
66
|
+
rdoc_options:
|
67
|
+
- --quiet
|
68
|
+
- --line-numbers
|
69
|
+
- --inline-source
|
70
|
+
- --title
|
71
|
+
- "Sweet: The SWT wrapper for JRuby"
|
72
|
+
- --main
|
73
|
+
- README.rdoc
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
segments:
|
82
|
+
- 0
|
83
|
+
version: "0"
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
segments:
|
90
|
+
- 0
|
91
|
+
version: "0"
|
92
|
+
requirements: []
|
93
|
+
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 1.3.7
|
96
|
+
signing_key:
|
97
|
+
specification_version: 3
|
98
|
+
summary: The SWT wrapper for JRuby
|
99
|
+
test_files: []
|
100
|
+
|