sweet 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|