qtext 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +10 -0
- data/License.txt +20 -0
- data/Manifest.txt +24 -0
- data/README.txt +17 -10
- data/Rakefile +4 -0
- data/config/hoe.rb +73 -0
- data/config/requirements.rb +15 -0
- data/env.sh +1 -0
- data/lib/qtext/action_builder.rb +94 -51
- data/lib/qtext/extensions.rb +70 -36
- data/lib/qtext/object_table_model.rb +53 -19
- data/lib/qtext/version.rb +1 -1
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +82 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/website.rake +17 -0
- data/test/test_helper.rb +46 -0
- data/test/test_object_table.rb +61 -14
- data/test/test_widget.rb +106 -0
- metadata +26 -13
- data/test/test_qtext.rb +0 -11
data/History.txt
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
== 0.6.0
|
2
|
+
* add Qt::Widget.signal class method which adds some signal emitting and
|
3
|
+
handling methods.
|
4
|
+
* remove Qt::Widget.construct and construct_exec because they're already part
|
5
|
+
of Qt::Widget.new
|
6
|
+
* Documentation
|
7
|
+
* Some testing
|
8
|
+
|
9
|
+
== 0.5.0
|
10
|
+
* Add ActionBuilder to create menus and other sets of Qt::Action objects
|
data/License.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 FIXME full name
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest.txt
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
History.txt
|
2
|
+
License.txt
|
3
|
+
Manifest.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
6
|
+
config/hoe.rb
|
7
|
+
config/requirements.rb
|
8
|
+
env.sh
|
9
|
+
lib/qtext.rb
|
10
|
+
lib/qtext/action_builder.rb
|
11
|
+
lib/qtext/extensions.rb
|
12
|
+
lib/qtext/flags.rb
|
13
|
+
lib/qtext/object_table_model.rb
|
14
|
+
lib/qtext/version.rb
|
15
|
+
script/console
|
16
|
+
script/destroy
|
17
|
+
script/generate
|
18
|
+
script/txt2html
|
19
|
+
tasks/deployment.rake
|
20
|
+
tasks/environment.rake
|
21
|
+
tasks/website.rake
|
22
|
+
test/test_helper.rb
|
23
|
+
test/test_object_table.rb
|
24
|
+
test/test_widget.rb
|
data/README.txt
CHANGED
@@ -1,32 +1,39 @@
|
|
1
1
|
= qtext
|
2
2
|
|
3
|
-
|
3
|
+
http://rubyforge.org/projects/qtext
|
4
4
|
|
5
5
|
== DESCRIPTION:
|
6
6
|
|
7
|
-
Some extensions to qt4-qtruby to make it more rubyish
|
7
|
+
Some extensions to qt4-qtruby to make it more rubyish.
|
8
8
|
|
9
|
-
== FEATURES
|
10
|
-
|
11
|
-
|
9
|
+
== FEATURES
|
10
|
+
- ActionBuilder module to simplify creating Action objects for inclusion into menus.
|
11
|
+
- ObjectTableModel so that you can easily display a collection of objects in a table
|
12
|
+
- signal and construct_signal for Qt::Widget to reduce the need for c++ signatures
|
13
|
+
- to_variant method for Object. Specific overrides for some objects.
|
14
|
+
- invalid method for Qt::ModelIndex to cache creation of an empty index
|
15
|
+
- invalid method for Qt::Variant to cache creation of an empty variant
|
16
|
+
- KeyEvent instances will respond to things like delete? (the delete key) for most keys
|
17
|
+
- value method for some widgets (RadioButton, CheckBox), returning the value of the widget
|
12
18
|
|
13
19
|
== SYNOPSIS:
|
14
20
|
|
15
|
-
|
21
|
+
require 'qtext'
|
16
22
|
|
17
23
|
== REQUIREMENTS:
|
18
24
|
|
19
|
-
|
20
|
-
|
25
|
+
- qtruby4
|
26
|
+
- Shoulda if you want to run tests
|
27
|
+
- ActiveSupport. Only needed in Header for humanize.
|
21
28
|
== INSTALL:
|
22
29
|
|
23
|
-
|
30
|
+
sudo gem install qtext
|
24
31
|
|
25
32
|
== LICENSE:
|
26
33
|
|
27
34
|
(The MIT License)
|
28
35
|
|
29
|
-
Copyright (c) 2008
|
36
|
+
Copyright (c) 2008 John Anderson
|
30
37
|
|
31
38
|
Permission is hereby granted, free of charge, to any person obtaining
|
32
39
|
a copy of this software and associated documentation files (the
|
data/Rakefile
ADDED
data/config/hoe.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'qtext/version'
|
2
|
+
|
3
|
+
AUTHOR = 'FIXME full name' # can also be an array of Authors
|
4
|
+
EMAIL = "panic@semiosix.com"
|
5
|
+
DESCRIPTION = "description of gem"
|
6
|
+
GEM_NAME = 'qtext' # what ppl will type to install your gem
|
7
|
+
RUBYFORGE_PROJECT = 'qtext' # The unix name for your project
|
8
|
+
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
9
|
+
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
10
|
+
EXTRA_DEPENDENCIES = [
|
11
|
+
# ['activesupport', '>= 1.3.1']
|
12
|
+
] # An array of rubygem dependencies [name, version]
|
13
|
+
|
14
|
+
@config_file = "~/.rubyforge/user-config.yml"
|
15
|
+
@config = nil
|
16
|
+
RUBYFORGE_USERNAME = "unknown"
|
17
|
+
def rubyforge_username
|
18
|
+
unless @config
|
19
|
+
begin
|
20
|
+
@config = YAML.load(File.read(File.expand_path(@config_file)))
|
21
|
+
rescue
|
22
|
+
puts <<-EOS
|
23
|
+
ERROR: No rubyforge config file found: #{@config_file}
|
24
|
+
Run 'rubyforge setup' to prepare your env for access to Rubyforge
|
25
|
+
- See http://newgem.rubyforge.org/rubyforge.html for more details
|
26
|
+
EOS
|
27
|
+
exit
|
28
|
+
end
|
29
|
+
end
|
30
|
+
RUBYFORGE_USERNAME.replace @config["username"]
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
REV = nil
|
35
|
+
# UNCOMMENT IF REQUIRED:
|
36
|
+
# REV = YAML.load(`svn info`)['Revision']
|
37
|
+
VERS = Qtext::VERSION::STRING + (REV ? ".#{REV}" : "")
|
38
|
+
RDOC_OPTS = ['--quiet', '--title', 'qtext documentation',
|
39
|
+
"--opname", "index.html",
|
40
|
+
"--line-numbers",
|
41
|
+
"--main", "README",
|
42
|
+
"--inline-source"]
|
43
|
+
|
44
|
+
class Hoe
|
45
|
+
def extra_deps
|
46
|
+
@extra_deps.reject! { |x| Array(x).first == 'hoe' }
|
47
|
+
@extra_deps
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Generate all the Rake tasks
|
52
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
53
|
+
$hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
54
|
+
p.developer(AUTHOR, EMAIL)
|
55
|
+
p.description = DESCRIPTION
|
56
|
+
p.summary = DESCRIPTION
|
57
|
+
p.url = HOMEPATH
|
58
|
+
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
59
|
+
p.test_globs = ["test/**/test_*.rb"]
|
60
|
+
p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
|
61
|
+
|
62
|
+
# == Optional
|
63
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
64
|
+
#p.extra_deps = EXTRA_DEPENDENCIES
|
65
|
+
|
66
|
+
#p.spec_extras = {} # A hash of extra values to set in the gemspec.
|
67
|
+
end
|
68
|
+
|
69
|
+
CHANGES = $hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
|
70
|
+
PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
|
71
|
+
$hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), '')
|
72
|
+
$hoe.rsync_args = '-av --delete --ignore-errors'
|
73
|
+
$hoe.spec.post_install_message = File.open(File.dirname(__FILE__) + "/../PostInstall.txt").read rescue ""
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
include FileUtils
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
%w[rake hoe newgem rubigen].each do |req_gem|
|
6
|
+
begin
|
7
|
+
require req_gem
|
8
|
+
rescue LoadError
|
9
|
+
puts "This Rakefile requires the '#{req_gem}' RubyGem."
|
10
|
+
puts "Installation: gem install #{req_gem} -y"
|
11
|
+
exit
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
|
data/env.sh
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
export RUBYLIB=$RUBYLIB:`pwd`/lib
|
data/lib/qtext/action_builder.rb
CHANGED
@@ -1,66 +1,95 @@
|
|
1
1
|
require 'Qt4'
|
2
2
|
require 'qtext/extensions.rb'
|
3
3
|
|
4
|
+
# The declaration of module Find in the require breaks
|
5
|
+
# the constant in Qt::KeySequence. It's a bug in the Qt bindings.
|
6
|
+
begin
|
7
|
+
$old_qt_key_sequence_find_value = Qt::KeySequence::Find
|
8
|
+
require 'find'
|
9
|
+
if Qt::KeySequence::Find == Find
|
10
|
+
module Qt
|
11
|
+
class KeySequence
|
12
|
+
Find = $old_qt_key_sequence_find_value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
4
19
|
=begin rdoc
|
5
|
-
This module can be used
|
6
|
-
|
20
|
+
This module can be used in an object that has
|
21
|
+
an add_action method (usually a subclass of Qt::Widget) to make the construction of
|
22
|
+
collections of actions more rubyish.
|
23
|
+
Menus are generally made up of a collection of actions.
|
7
24
|
|
8
|
-
Once included, it's intended to be called as follows
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
Once included, it's intended to be called as follows:
|
26
|
+
def some_setup_method_or_other
|
27
|
+
build_actions do
|
28
|
+
list :edit do
|
29
|
+
#~ new_action :action_cut, 'Cu&t', :shortcut => Qt::KeySequence::Cut
|
30
|
+
action :action_copy, '&Copy', :shortcut => Qt::KeySequence::Copy, :method => :copy_current_selection
|
31
|
+
action :action_paste, '&Paste', :shortcut => Qt::KeySequence::Paste, :method => :paste
|
32
|
+
separator
|
33
|
+
action :action_ditto, '&Ditto', :shortcut => 'Ctrl+\'', :method => :ditto, :tool_tip => 'Copy same field from previous record'
|
34
|
+
action :action_ditto_right, 'Ditto R&ight', :shortcut => 'Ctrl+]', :method => :ditto_right, :tool_tip => 'Copy field one to right from previous record'
|
35
|
+
action :action_ditto_left, '&Ditto L&eft', :shortcut => 'Ctrl+[', :method => :ditto_left, :tool_tip => 'Copy field one to left from previous record'
|
36
|
+
action :action_insert_date, 'Insert Date', :shortcut => 'Ctrl+;', :method => :insert_current_date
|
37
|
+
action :action_open_editor, '&Open Editor', :shortcut => 'F4', :method => :open_editor
|
38
|
+
separator
|
39
|
+
action :action_row, 'New Ro&w', :shortcut => 'Ctrl+N', :method => :row
|
40
|
+
action :action_refresh, '&Refresh', :shortcut => 'Ctrl+R', :method => :refresh
|
41
|
+
action :action_delete_rows, 'Delete Rows', :shortcut => 'Ctrl+Delete', :method => :delete_rows
|
42
|
+
|
43
|
+
if $options[:debug]
|
44
|
+
action :action_dump, 'D&ump', :shortcut => 'Ctrl+Shift+D' do
|
45
|
+
puts model.collection[current_index.row].inspect
|
46
|
+
end
|
28
47
|
end
|
29
48
|
end
|
49
|
+
|
50
|
+
separator
|
30
51
|
end
|
31
|
-
|
32
|
-
separator
|
33
52
|
end
|
34
|
-
|
35
|
-
You can also do something like this:
|
36
|
-
|
53
|
+
Or you can pass a parameter to the block if you need access to surrounding variables:
|
37
54
|
build_actions do |ab|
|
38
|
-
ab.list
|
55
|
+
ab.list :edit do
|
39
56
|
#~ new_action :action_cut, 'Cu&t', :shortcut => Qt::KeySequence::Cut
|
40
57
|
ab.action :action_copy, '&Copy', :shortcut => Qt::KeySequence::Copy, :method => :copy_current_selection
|
41
58
|
end
|
42
59
|
end
|
43
|
-
|
44
60
|
If the including class defines a method called action_triggered( &block ),
|
45
61
|
it can be used to wrap the code triggered by actions. That way, the
|
46
62
|
including class
|
47
|
-
can catch exceptions and things like that.
|
48
|
-
|
63
|
+
can catch exceptions and things like that.
|
64
|
+
def action_triggered( &block )
|
65
|
+
catch :something_happened do
|
66
|
+
yield
|
67
|
+
end
|
68
|
+
end
|
69
|
+
If this method is not defined, it will be created in the including class as an empty wrapper.
|
49
70
|
=end
|
50
71
|
module ActionBuilder
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
72
|
+
# raise a RuntimeError if the including class/module does not define add_action
|
73
|
+
def self.included( including_module )
|
74
|
+
shortlist = including_module.instance_methods.grep /action/i
|
75
|
+
# add_action is actually an method_missing lookup for addAction, so
|
76
|
+
# search for both.
|
77
|
+
unless shortlist.any? {|x| %w{add_action addAction}.include?( x )}
|
78
|
+
raise NotImplementedError( "#{including_module.class.name} must have an add_action method" )
|
79
|
+
end
|
57
80
|
end
|
58
81
|
|
59
|
-
|
60
|
-
|
82
|
+
# Outer block for the build process.
|
83
|
+
def build_actions( &block )
|
84
|
+
raise 'a block must be present' if block.nil?
|
85
|
+
if block.arity == -1
|
86
|
+
instance_eval &block
|
87
|
+
else
|
88
|
+
yield self
|
89
|
+
end
|
61
90
|
end
|
62
91
|
|
63
|
-
#
|
92
|
+
# Create a new separator and add a new separator.
|
64
93
|
def separator
|
65
94
|
Qt::Action.construct( parent ) do |action|
|
66
95
|
action.separator = true
|
@@ -69,27 +98,29 @@ module ActionBuilder
|
|
69
98
|
end
|
70
99
|
end
|
71
100
|
|
72
|
-
#
|
73
|
-
# as strongly as with Qt::ActionGroup
|
74
|
-
#
|
75
|
-
# set of Qt::Action instances created in the block
|
101
|
+
# Create and return a list of actions. The actions are grouped together, but not
|
102
|
+
# as strongly as with Qt::ActionGroup.
|
103
|
+
# A method called "#{group_name}_actions" will be added to self, which will return the
|
104
|
+
# set of Qt::Action instances created in the block.
|
76
105
|
def list( group_name, &block )
|
77
106
|
unless respond_to?( "#{group_name.to_s}_actions" )
|
78
107
|
self.class.send( :define_method, "#{group_name.to_s}_actions" ) do
|
79
108
|
eval "@#{group_name.to_s}_actions"
|
80
109
|
end
|
81
110
|
end
|
82
|
-
self.collect_actions
|
111
|
+
self.collect_actions.clear
|
83
112
|
yield( self )
|
84
113
|
# copy actions to the right instance variable
|
85
114
|
eval "@#{group_name.to_s}_actions = collect_actions"
|
86
115
|
end
|
87
116
|
|
88
|
-
# Create
|
89
|
-
#
|
117
|
+
# Create a new Qt::Action and
|
118
|
+
# 1. pass it to Qt::Widget::add_action
|
119
|
+
# 1. add it to the collect_actions collection.
|
120
|
+
# The block takes predence over options[:method], which is a method
|
90
121
|
# on self to be called.
|
91
|
-
#
|
92
|
-
#
|
122
|
+
# Option keys can be any method in Qt::Action, ie :tool_tip, :shortcut, :status_tip etc.
|
123
|
+
# A value for :shortcut is automatically passed to Qt::KeySequence.new.
|
93
124
|
def action( name_or_action, text = nil, options = {}, &block )
|
94
125
|
if name_or_action.class == Qt::Action
|
95
126
|
add_action( name_or_action )
|
@@ -114,15 +145,27 @@ module ActionBuilder
|
|
114
145
|
# add action for Qt
|
115
146
|
add_action action
|
116
147
|
|
117
|
-
# add actions for list. Yes, it's a side-effect.
|
148
|
+
# add actions for list. Yes, it's a side-effect.
|
149
|
+
# TODO is there a better way to do this?
|
118
150
|
collect_actions << action
|
119
151
|
|
120
152
|
action_method_or_block( action, options, &block )
|
121
153
|
end
|
122
154
|
end
|
123
155
|
end
|
156
|
+
|
157
|
+
protected
|
158
|
+
|
159
|
+
# the set of actions created so far in a particular list.
|
160
|
+
def collect_actions
|
161
|
+
@collect_actions ||= []
|
162
|
+
end
|
163
|
+
|
164
|
+
def collect_actions=( arr )
|
165
|
+
@collect_actions = arr
|
166
|
+
end
|
124
167
|
|
125
|
-
#
|
168
|
+
# If parent doesn't define this, add it so that
|
126
169
|
# our action_method_or_block will work.
|
127
170
|
unless instance_methods.include?( :action_triggered )
|
128
171
|
def action_triggered( &someblock )
|
data/lib/qtext/extensions.rb
CHANGED
@@ -17,28 +17,6 @@ class Object
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
class Class
|
21
|
-
# TODO Qt bindings will accept a block for new, which
|
22
|
-
# makes this somewhat irrelevant. Unless it's really
|
23
|
-
# necessary to pass args in
|
24
|
-
def construct_exec( *args, &block )
|
25
|
-
raise "block is nil" if block.nil?
|
26
|
-
inst = self.new( *args )
|
27
|
-
# using the Rails implementation, included in Qt
|
28
|
-
block.bind( inst )[*args]
|
29
|
-
# return the newly configured instance
|
30
|
-
inst
|
31
|
-
end
|
32
|
-
|
33
|
-
# see self.construct
|
34
|
-
def construct( *args, &block )
|
35
|
-
raise "block is nil" if block.nil?
|
36
|
-
inst = self.new( *args )
|
37
|
-
yield( inst )
|
38
|
-
inst
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
20
|
class NilClass
|
43
21
|
def to_variant
|
44
22
|
Qt::Variant.invalid
|
@@ -103,6 +81,7 @@ module Qt
|
|
103
81
|
class ItemSelection
|
104
82
|
include Enumerable
|
105
83
|
|
84
|
+
# Iterate through SelectionRange instances in this selection
|
106
85
|
def each( &block )
|
107
86
|
index = 0
|
108
87
|
max = self.count
|
@@ -122,9 +101,6 @@ module Qt
|
|
122
101
|
end
|
123
102
|
end
|
124
103
|
|
125
|
-
# This provides a bunch of methods to get easy access to the entity
|
126
|
-
# and it's values directly from the index without having to keep
|
127
|
-
# asking the model and jumping through other unncessary hoops
|
128
104
|
class ModelIndex
|
129
105
|
# Because using Qt::ModelIndex.new the whole time is wasteful
|
130
106
|
def self.invalid
|
@@ -133,7 +109,8 @@ module Qt
|
|
133
109
|
|
134
110
|
alias_method :old_inspect, :inspect
|
135
111
|
def inspect
|
136
|
-
|
112
|
+
# need the self here otherwise Qt bindings get confused.
|
113
|
+
if self.valid?
|
137
114
|
#<Qt::ModelIndex:0xb6004e8c>
|
138
115
|
# fetch address from superclass inspect
|
139
116
|
super =~ /ModelIndex:(.*)>/
|
@@ -157,7 +134,8 @@ module Qt
|
|
157
134
|
|
158
135
|
end
|
159
136
|
|
160
|
-
#
|
137
|
+
# Make keystrokes events easier to work with. For <tt>Qt::Key_Whatever</tt>
|
138
|
+
# events, KeyEvent instances will now respond to <tt>whatever?</tt>
|
161
139
|
class KeyEvent
|
162
140
|
# override otherwise the new method_missing fails
|
163
141
|
# to call the old_method_missing
|
@@ -184,8 +162,7 @@ module Qt
|
|
184
162
|
|
185
163
|
alias_method :old_method_missing, :method_missing
|
186
164
|
|
187
|
-
# shortcut for the Qt::Key_Whatever constants
|
188
|
-
# just say event.whatever?
|
165
|
+
# Provide a shortcut for the Qt::Key_Whatever constants. Just say event.whatever?
|
189
166
|
def method_missing( sym, *args )
|
190
167
|
begin
|
191
168
|
if sym.to_s[-1] == "?"[0]
|
@@ -218,10 +195,10 @@ module Qt
|
|
218
195
|
end
|
219
196
|
|
220
197
|
class TableView
|
221
|
-
#
|
222
|
-
def model=(
|
223
|
-
@model =
|
224
|
-
super(
|
198
|
+
# store the model in a data member, otherwise it gets garbage-collected.
|
199
|
+
def model=( model )
|
200
|
+
@model = model
|
201
|
+
super( model )
|
225
202
|
end
|
226
203
|
end
|
227
204
|
|
@@ -266,9 +243,11 @@ module Qt
|
|
266
243
|
|
267
244
|
class Widget
|
268
245
|
# add a signal with the given signature, and create
|
269
|
-
# a method called method_name which will
|
246
|
+
# a method called method_name which will emit the signal,
|
247
|
+
# a method called method_name_signal which will return the signal
|
270
248
|
# ready to be used in a connect. If method_name is not provided
|
271
|
-
# the method will be named as the name part of signature
|
249
|
+
# the method will be named as the name part of signature.
|
250
|
+
# Also create a handler on_method_name {|*args| }
|
272
251
|
def self.construct_signal( signature, method_name = nil )
|
273
252
|
# add the signal
|
274
253
|
q_signal( signature )
|
@@ -286,7 +265,62 @@ module Qt
|
|
286
265
|
SIGNAL( signature )
|
287
266
|
end
|
288
267
|
|
289
|
-
#
|
268
|
+
# create the connection method
|
269
|
+
line, st = __LINE__, <<-EOF
|
270
|
+
def on_#{base_method_name}( &block )
|
271
|
+
connect( #{method_name} ) do |*args|
|
272
|
+
yield( *args )
|
273
|
+
end
|
274
|
+
end
|
275
|
+
EOF
|
276
|
+
class_eval st, __FILE__, line + 1
|
277
|
+
end
|
278
|
+
|
279
|
+
# specify a signal symbol, and add the other methods, namely
|
280
|
+
# - <tt>symbol</tt> which emits the signal
|
281
|
+
# - <tt>symbol_signal</tt> which is the method added by q_signal, ie the actual Qt emitter
|
282
|
+
# - <tt>on_symbol {|*args| }</tt> which is the handler
|
283
|
+
def self.signal( symbol )
|
284
|
+
# add the signal emitter
|
285
|
+
signature = "#{symbol.to_s}_signal( QVariant & )"
|
286
|
+
q_signal( signature )
|
287
|
+
|
288
|
+
# add an emitter
|
289
|
+
line_number, st = __LINE__, <<-EOF
|
290
|
+
def #{symbol.to_s}( *args )
|
291
|
+
#~ puts "ingoing args: \#\{args.inspect\}"
|
292
|
+
# convert args to variant(s)
|
293
|
+
variant =
|
294
|
+
case args.size
|
295
|
+
when 0; Qt::Variant.new
|
296
|
+
when 1; args[0].to_variant
|
297
|
+
else; Qt::Variant.new( args )
|
298
|
+
end
|
299
|
+
#~ puts "ingoing variant: \#\{variant.inspect\}"
|
300
|
+
emit #{symbol.to_s}_signal( variant )
|
301
|
+
end
|
302
|
+
EOF
|
303
|
+
class_eval st, __FILE__, line_number + 1
|
304
|
+
|
305
|
+
# create the connection method
|
306
|
+
line_number, st = __LINE__, <<-EOF
|
307
|
+
def on_#{symbol.to_s}( &block )
|
308
|
+
Kernel.raise "on_#{symbol.to_s} must have a block" if block.nil?
|
309
|
+
connect( SIGNAL( '#{signature}' ) ) do |variant|
|
310
|
+
#~ puts "outcoming variant: \#\{variant.inspect\}"
|
311
|
+
# convert variants to Ruby objects
|
312
|
+
args =
|
313
|
+
case variant.typeName
|
314
|
+
when nil; nil
|
315
|
+
when 'QVariantList'; variant.value.map{|x| x.value}
|
316
|
+
else variant.value
|
317
|
+
end
|
318
|
+
#~ puts "outcoming args: \#\{args.inspect\}"
|
319
|
+
yield( *args )
|
320
|
+
end
|
321
|
+
end
|
322
|
+
EOF
|
323
|
+
class_eval st, __FILE__, line_number + 1
|
290
324
|
end
|
291
325
|
end
|
292
326
|
|
@@ -1,9 +1,17 @@
|
|
1
1
|
require 'active_support'
|
2
2
|
require 'qtext/flags.rb'
|
3
3
|
|
4
|
+
=begin rdoc
|
5
|
+
A header for ObjectTableModel.
|
6
|
+
=end
|
4
7
|
class Header
|
5
8
|
attr_reader :attribute, :title, :alignment
|
6
|
-
|
9
|
+
|
10
|
+
# args is a hash that can contain the following:
|
11
|
+
# - :attribute (required) is the name of the attribute on objects in the table's collection,
|
12
|
+
# the values for which will be displayed in this column.
|
13
|
+
# - :title is the column header. Defaults to attribute.humanize
|
14
|
+
# - :alignment is one of the Qt::Align constants. Defaults to Qt::AlignLeft | Qt::AlignVCenter.
|
7
15
|
def initialize( args = {} )
|
8
16
|
raise "there must be an attribute" unless args.has_key?( :attribute )
|
9
17
|
@attribute = args[:attribute]
|
@@ -13,23 +21,46 @@ class Header
|
|
13
21
|
end
|
14
22
|
|
15
23
|
=begin rdoc
|
16
|
-
A Qt
|
17
|
-
of headers, which are methods to call on the objects to populate columns
|
24
|
+
A specialisation of Qt::TableModel that is given a collection of objects, and a collection
|
25
|
+
of headers, which are methods to call on the objects to populate columns.
|
26
|
+
|
27
|
+
Given
|
28
|
+
Thing = Struct.new( :name, :value, :location, :price, :other, :ignored )
|
29
|
+
and
|
30
|
+
@data = method_to_create_lots_of_things
|
31
|
+
The following will display the four named attributes in 4 columns
|
32
|
+
ObjectTableModel.new :data => @data, :headers => [ :name, :value, :location, :price ]
|
33
|
+
and this will right-align the price column:
|
34
|
+
ObjectTableModel.new :data => @data, :headers => [ :name, :value, :location, Header.new( :attribute => :price, :alignment => Qt::AlignRight ) ]
|
18
35
|
=end
|
19
36
|
class ObjectTableModel < Qt::AbstractTableModel
|
20
37
|
include QtFlags
|
21
38
|
attr_reader :collection, :headers
|
22
39
|
|
23
|
-
#
|
24
|
-
|
40
|
+
# Rubyish method for rowCount
|
41
|
+
def row_count( parent_index = Qt::ModelIndex.invalid )
|
42
|
+
rowCount( parent_index )
|
43
|
+
end
|
44
|
+
|
45
|
+
# Rubyish method for columnCount
|
46
|
+
def column_count( parent_index = Qt::ModelIndex.invalid )
|
47
|
+
columnCount( parent_index )
|
48
|
+
end
|
49
|
+
|
50
|
+
# args can contain the following:
|
51
|
+
# - :parent => the Qt::Object that is the parent of this class.
|
52
|
+
# - :headers => array of either symbols representing the attribute on the
|
53
|
+
# elements of the data collection, or Header instances.
|
54
|
+
# - :data => array of objects, with attributes corresponding to the headers
|
55
|
+
# - :collection is an alias for :data
|
25
56
|
def initialize( args = {} )
|
26
|
-
super()
|
57
|
+
super( args[:parent] )
|
27
58
|
@collection = args[:data] || args[:collection] || []
|
28
59
|
set_headers( args[:headers] )
|
29
60
|
end
|
30
61
|
|
31
62
|
# implementation of Qt:AbstractItemModel method
|
32
|
-
def rowCount( parent_model_index )
|
63
|
+
def rowCount( parent_model_index = Qt::ModelIndex.invalid )
|
33
64
|
if parent_model_index.valid?
|
34
65
|
0
|
35
66
|
else
|
@@ -45,16 +76,6 @@ class ObjectTableModel < Qt::AbstractTableModel
|
|
45
76
|
end
|
46
77
|
end
|
47
78
|
|
48
|
-
def attribute_for_index( column )
|
49
|
-
headers[column]
|
50
|
-
end
|
51
|
-
|
52
|
-
def field_value_at( index )
|
53
|
-
obj = collection[index.row]
|
54
|
-
att = attribute_for_index( index.column ).attribute
|
55
|
-
obj.send( att ) unless obj.nil? or att.nil?
|
56
|
-
end
|
57
|
-
|
58
79
|
# implementation of Qt:AbstractItemModel method
|
59
80
|
def headerData( section, orientation, role )
|
60
81
|
value =
|
@@ -152,7 +173,7 @@ class ObjectTableModel < Qt::AbstractTableModel
|
|
152
173
|
end
|
153
174
|
|
154
175
|
# implementation of Qt:AbstractItemModel method
|
155
|
-
|
176
|
+
#-- TODO make this editable
|
156
177
|
def flags( index )
|
157
178
|
return 0 unless index.valid?
|
158
179
|
super
|
@@ -162,6 +183,7 @@ class ObjectTableModel < Qt::AbstractTableModel
|
|
162
183
|
collection[index]
|
163
184
|
end
|
164
185
|
|
186
|
+
# Set the value at the index, and make sure the view is updated.
|
165
187
|
def []=( index, value )
|
166
188
|
if index >= collection.size
|
167
189
|
beginInsertRows( Qt::ModelIndex.invalid, collection.size, collection.size + ( index - collection.size ) )
|
@@ -173,6 +195,7 @@ class ObjectTableModel < Qt::AbstractTableModel
|
|
173
195
|
end
|
174
196
|
end
|
175
197
|
|
198
|
+
# Insert a new object into the collection, and make sure the view is updated.
|
176
199
|
def <<( obj )
|
177
200
|
beginInsertRows( Qt::ModelIndex.invalid, collection.size, collection.size )
|
178
201
|
collection << obj
|
@@ -198,7 +221,7 @@ class ObjectTableModel < Qt::AbstractTableModel
|
|
198
221
|
reset
|
199
222
|
end
|
200
223
|
|
201
|
-
# a collection of
|
224
|
+
# a collection of Header instances
|
202
225
|
def headers=( arr )
|
203
226
|
set_headers( arr )
|
204
227
|
reset
|
@@ -215,4 +238,15 @@ protected
|
|
215
238
|
end
|
216
239
|
end
|
217
240
|
end
|
241
|
+
|
242
|
+
def attribute_for_index( column )
|
243
|
+
headers[column]
|
244
|
+
end
|
245
|
+
|
246
|
+
def field_value_at( index )
|
247
|
+
obj = collection[index.row]
|
248
|
+
att = attribute_for_index( index.column ).attribute
|
249
|
+
obj.send( att ) unless obj.nil? or att.nil?
|
250
|
+
end
|
251
|
+
|
218
252
|
end
|
data/lib/qtext/version.rb
CHANGED
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/qtext.rb'}"
|
9
|
+
puts "Loading qtext gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
data/script/txt2html
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
GEM_NAME = 'qtext' # what ppl will type to install your gem
|
4
|
+
RUBYFORGE_PROJECT = 'qtext'
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
begin
|
8
|
+
require 'newgem'
|
9
|
+
require 'rubyforge'
|
10
|
+
rescue LoadError
|
11
|
+
puts "\n\nGenerating the website requires the newgem RubyGem"
|
12
|
+
puts "Install: gem install newgem\n\n"
|
13
|
+
exit(1)
|
14
|
+
end
|
15
|
+
require 'redcloth'
|
16
|
+
require 'syntax/convertors/html'
|
17
|
+
require 'erb'
|
18
|
+
require File.dirname(__FILE__) + "/../lib/#{GEM_NAME}/version.rb"
|
19
|
+
|
20
|
+
version = Qtext::VERSION::STRING
|
21
|
+
download = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
22
|
+
|
23
|
+
def rubyforge_project_id
|
24
|
+
RubyForge.new.autoconfig["group_ids"][RUBYFORGE_PROJECT]
|
25
|
+
end
|
26
|
+
|
27
|
+
class Fixnum
|
28
|
+
def ordinal
|
29
|
+
# teens
|
30
|
+
return 'th' if (10..19).include?(self % 100)
|
31
|
+
# others
|
32
|
+
case self % 10
|
33
|
+
when 1: return 'st'
|
34
|
+
when 2: return 'nd'
|
35
|
+
when 3: return 'rd'
|
36
|
+
else return 'th'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Time
|
42
|
+
def pretty
|
43
|
+
return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def convert_syntax(syntax, source)
|
48
|
+
return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
|
49
|
+
end
|
50
|
+
|
51
|
+
if ARGV.length >= 1
|
52
|
+
src, template = ARGV
|
53
|
+
template ||= File.join(File.dirname(__FILE__), '/../website/template.html.erb')
|
54
|
+
else
|
55
|
+
puts("Usage: #{File.split($0).last} source.txt [template.html.erb] > output.html")
|
56
|
+
exit!
|
57
|
+
end
|
58
|
+
|
59
|
+
template = ERB.new(File.open(template).read)
|
60
|
+
|
61
|
+
title = nil
|
62
|
+
body = nil
|
63
|
+
File.open(src) do |fsrc|
|
64
|
+
title_text = fsrc.readline
|
65
|
+
body_text_template = fsrc.read
|
66
|
+
body_text = ERB.new(body_text_template).result(binding)
|
67
|
+
syntax_items = []
|
68
|
+
body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)</\1>!m){
|
69
|
+
ident = syntax_items.length
|
70
|
+
element, syntax, source = $1, $2, $3
|
71
|
+
syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}</#{element}>"
|
72
|
+
"syntax-temp-#{ident}"
|
73
|
+
}
|
74
|
+
title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
|
75
|
+
body = RedCloth.new(body_text).to_html
|
76
|
+
body.gsub!(%r!(?:<pre><code>)?syntax-temp-(\d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }
|
77
|
+
end
|
78
|
+
stat = File.stat(src)
|
79
|
+
created = stat.ctime
|
80
|
+
modified = stat.mtime
|
81
|
+
|
82
|
+
$stdout << template.result(binding)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
desc 'Release the website and new gem version'
|
2
|
+
task :deploy => [:check_version, :website, :release] do
|
3
|
+
puts "Remember to create SVN tag:"
|
4
|
+
puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " +
|
5
|
+
"svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
|
6
|
+
puts "Suggested comment:"
|
7
|
+
puts "Tagging release #{CHANGES}"
|
8
|
+
end
|
9
|
+
|
10
|
+
desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
|
11
|
+
task :local_deploy => [:website_generate, :install_gem]
|
12
|
+
|
13
|
+
task :check_version do
|
14
|
+
unless ENV['VERSION']
|
15
|
+
puts 'Must pass a VERSION=x.y.z release version'
|
16
|
+
exit
|
17
|
+
end
|
18
|
+
unless ENV['VERSION'] == VERS
|
19
|
+
puts "Please update your version.rb to match the release version, currently #{VERS}"
|
20
|
+
exit
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'Install the package as a gem, without generating documentation(ri/rdoc)'
|
25
|
+
task :install_gem_no_doc => [:clean, :package] do
|
26
|
+
sh "#{'sudo ' unless Hoe::WINDOZE }gem install pkg/*.gem --no-rdoc --no-ri"
|
27
|
+
end
|
28
|
+
|
29
|
+
namespace :manifest do
|
30
|
+
desc 'Recreate Manifest.txt to include ALL files'
|
31
|
+
task :refresh do
|
32
|
+
`rake check_manifest | patch -p0 > Manifest.txt`
|
33
|
+
end
|
34
|
+
end
|
data/tasks/website.rake
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
desc 'Generate website files'
|
2
|
+
task :website_generate => :ruby_env do
|
3
|
+
(Dir['website/**/*.txt'] - Dir['website/version*.txt']).each do |txt|
|
4
|
+
sh %{ #{RUBY_APP} script/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} }
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
desc 'Upload website files to rubyforge'
|
9
|
+
task :website_upload do
|
10
|
+
host = "#{rubyforge_username}@rubyforge.org"
|
11
|
+
remote_dir = "/var/www/gforge-projects/#{PATH}/"
|
12
|
+
local_dir = 'website'
|
13
|
+
sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}}
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Generate and upload website files'
|
17
|
+
task :website => [:website_generate, :website_upload, :publish_docs]
|
data/test/test_helper.rb
CHANGED
@@ -1,2 +1,48 @@
|
|
1
1
|
require 'test/unit'
|
2
2
|
require File.dirname(__FILE__) + '/../lib/qtext'
|
3
|
+
require 'shoulda'
|
4
|
+
|
5
|
+
# Allow running of setup and teardown things before
|
6
|
+
# an entire suite, instead of just one per test
|
7
|
+
class SuiteWrapper < Test::Unit::TestSuite
|
8
|
+
attr_accessor :tests
|
9
|
+
|
10
|
+
def initialize( name, test_case )
|
11
|
+
super( name )
|
12
|
+
@test_case = test_case
|
13
|
+
end
|
14
|
+
|
15
|
+
def startup
|
16
|
+
end
|
17
|
+
|
18
|
+
def shutdown
|
19
|
+
end
|
20
|
+
|
21
|
+
def run( *args )
|
22
|
+
startup
|
23
|
+
@test_case.startup if @test_case.respond_to? :startup
|
24
|
+
retval = super
|
25
|
+
@test_case.shutdown if @test_case.respond_to? :shutdown
|
26
|
+
shutdown
|
27
|
+
retval
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module Test
|
32
|
+
module Unit
|
33
|
+
class TestCase
|
34
|
+
unless respond_to? :old_suite
|
35
|
+
class << self
|
36
|
+
alias_method :old_suite, :suite
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.suite
|
40
|
+
os = old_suite
|
41
|
+
sw = SuiteWrapper.new( os.name, self )
|
42
|
+
sw.tests = os.tests
|
43
|
+
sw
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/test/test_object_table.rb
CHANGED
@@ -3,25 +3,72 @@ require 'qtext/object_table_model.rb'
|
|
3
3
|
require 'Qt4'
|
4
4
|
|
5
5
|
class TestObjectTableModel < Test::Unit::TestCase
|
6
|
-
Thing = Struct.new( :name, :value, :location, :price )
|
6
|
+
Thing = Struct.new( :name, :value, :location, :price, :ignored )
|
7
|
+
|
8
|
+
def self.startup
|
9
|
+
$app ||= Qt::Application.new( [] )
|
10
|
+
end
|
11
|
+
|
7
12
|
def setup
|
8
13
|
@data = [
|
9
|
-
Thing.new( "Screwdriver", 'high', 'toolbox', 10.96 ),
|
10
|
-
Thing.new( "Thermometer", '15 degrees', 'bathroom', 0.01 ),
|
14
|
+
Thing.new( "Screwdriver", 'high', 'toolbox', 10.96, 'not' ),
|
15
|
+
Thing.new( "Thermometer", '15 degrees', 'bathroom', 0.01, 'here' ),
|
11
16
|
Thing.new( "Bed", 'large', 'bedroom' ),
|
12
|
-
Thing.new( "Approximation", 'useful', 'maths', 'none' )
|
17
|
+
Thing.new( "Approximation", 'useful', 'maths', 'none', 'all' )
|
13
18
|
]
|
19
|
+
@model = ObjectTableModel.new( :data => @data, :headers => [ :name, :value, :location, Header.new( :attribute => :price, :alignment => Qt::AlignRight ) ] )
|
20
|
+
@main_window = Qt::MainWindow.new
|
21
|
+
@view = Qt::TableView.new( @main_window ) { |tv| tv.model = @model }
|
22
|
+
@main_window.central_widget = @view
|
23
|
+
end
|
24
|
+
|
25
|
+
should 'have a 4 x 4 size' do
|
26
|
+
assert_equal 4, @model.rowCount
|
27
|
+
assert_equal 4, @model.row_count
|
28
|
+
assert_equal 4, @model.columnCount
|
29
|
+
assert_equal 4, @model.column_count
|
30
|
+
end
|
31
|
+
|
32
|
+
should 'have 0x0 size for children models at a given index' do
|
33
|
+
index = @model.create_index(1,1)
|
34
|
+
assert_equal 0, @model.row_count( index )
|
35
|
+
assert_equal 0, @model.column_count( index )
|
36
|
+
end
|
37
|
+
|
38
|
+
should 'return correct data' do
|
39
|
+
@data.each_with_index do |item,i|
|
40
|
+
Thing.members.each_with_index do |member,j|
|
41
|
+
next if j >= 4
|
42
|
+
model_index = @model.create_index(i,j)
|
43
|
+
assert_equal item[member], @model.data( model_index ).value
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
should 'return nil for invalid index' do
|
49
|
+
assert_equal Qt::Variant.invalid, @model.data( Qt::ModelIndex.invalid )
|
50
|
+
end
|
51
|
+
|
52
|
+
should 'have price aligned right' do
|
53
|
+
assert_equal Qt::AlignLeft.to_i, @model.data( @model.create_index(0,0), Qt::TextAlignmentRole ).to_i & Qt::AlignLeft.to_i
|
54
|
+
assert_equal Qt::AlignLeft.to_i, @model.data( @model.create_index(0,1), Qt::TextAlignmentRole ).to_i & Qt::AlignLeft.to_i
|
55
|
+
assert_equal Qt::AlignRight.to_i, @model.data( @model.create_index(0,3), Qt::TextAlignmentRole ).to_i & Qt::AlignRight.to_i
|
56
|
+
end
|
57
|
+
|
58
|
+
should_eventually 'display the window' do
|
59
|
+
#~ should 'display the window' do
|
60
|
+
@main_window.window_title = 'Test ObjectTableModel'
|
61
|
+
@main_window.move( 150, 0 )
|
62
|
+
@main_window.show
|
63
|
+
$app.exec
|
64
|
+
end
|
65
|
+
|
66
|
+
should 'have a nil parent' do
|
67
|
+
assert_nil @model.parent
|
14
68
|
end
|
15
69
|
|
16
|
-
|
17
|
-
model = ObjectTableModel.new( :data => @data, :headers => [ :name, :value, :location, :price ] )
|
18
|
-
|
19
|
-
main_window = Qt::MainWindow.new
|
20
|
-
main_window.central_widget = Qt::TableView.construct( main_window ) { |tv| tv.model = model }
|
21
|
-
|
22
|
-
main_window.window_title = 'Test ObjectTableModel'
|
23
|
-
main_window.move( 150, 0 )
|
24
|
-
main_window.show
|
25
|
-
app.exec
|
70
|
+
should 'have parent == @model' do
|
71
|
+
model = ObjectTableModel.new( :parent => @model, :data => @data, :headers => [ :name, :value, :location, Header.new( :attribute => :price, :alignment => Qt::AlignRight ) ] )
|
72
|
+
assert_equal @model, model.parent
|
26
73
|
end
|
27
74
|
end
|
data/test/test_widget.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
$app = Qt::Application.new []
|
4
|
+
|
5
|
+
class Thok < Qt::Widget
|
6
|
+
signal :whatever
|
7
|
+
end
|
8
|
+
|
9
|
+
class TestWidget < Test::Unit::TestCase
|
10
|
+
|
11
|
+
def setup
|
12
|
+
@thok = Thok.new
|
13
|
+
end
|
14
|
+
|
15
|
+
should 'have a whatever_signal method' do
|
16
|
+
assert_equal 1, @thok.methods.grep( /^whatever_signal$/ ).size
|
17
|
+
assert_raise ArgumentError do
|
18
|
+
@thok.whatever_signal( 'hello' )
|
19
|
+
end
|
20
|
+
|
21
|
+
assert_nothing_raised do
|
22
|
+
@thok.whatever_signal( 'hello'.to_variant )
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
should 'have a whatever emitter' do
|
27
|
+
assert_equal 1, @thok.methods.grep( /^whatever$/ ).size
|
28
|
+
assert_nothing_raised { @thok.whatever }
|
29
|
+
assert_nothing_raised { @thok.whatever 1 }
|
30
|
+
assert_nothing_raised { @thok.whatever 1,2,3 }
|
31
|
+
assert_nothing_raised { @thok.whatever [4,5,6] }
|
32
|
+
end
|
33
|
+
|
34
|
+
should 'have an on_whatever handler' do
|
35
|
+
assert_equal 1, @thok.methods.grep( /^on_whatever$/ ).size
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'on_whatever handler' do
|
39
|
+
should 'handle nil args' do
|
40
|
+
@thok.on_whatever do |arg|
|
41
|
+
assert_nil arg
|
42
|
+
end
|
43
|
+
@thok.whatever
|
44
|
+
@thok.whatever( nil )
|
45
|
+
end
|
46
|
+
|
47
|
+
should 'handle single args' do
|
48
|
+
@thok.on_whatever do |arg|
|
49
|
+
assert_not_nil arg
|
50
|
+
assert_not_equal Array, arg.class
|
51
|
+
end
|
52
|
+
@thok.whatever 1
|
53
|
+
@thok.whatever 'hello'
|
54
|
+
end
|
55
|
+
|
56
|
+
should_eventually 'handle objects' do
|
57
|
+
NVP = Struct.new :name, :value
|
58
|
+
nvp = NVP.new
|
59
|
+
nvp.name = 'how'
|
60
|
+
nvp.value = 'that'
|
61
|
+
@thok.on_whatever do |arg|
|
62
|
+
assert_not_nil arg
|
63
|
+
assert_equal NVP, arg.class
|
64
|
+
end
|
65
|
+
@thok.whatever nvp
|
66
|
+
end
|
67
|
+
|
68
|
+
should 'handle arg lists' do
|
69
|
+
@thok.on_whatever do |arg1,arg2|
|
70
|
+
assert_not_nil arg1
|
71
|
+
assert_not_nil arg2
|
72
|
+
assert_not_equal Array, arg1.class
|
73
|
+
assert_not_equal Array, arg2.class
|
74
|
+
end
|
75
|
+
@thok.whatever 1,2
|
76
|
+
@thok.whatever 'hello','there'
|
77
|
+
end
|
78
|
+
|
79
|
+
should 'handle a single array' do
|
80
|
+
@thok.on_whatever do |ary|
|
81
|
+
assert_not_nil ary
|
82
|
+
assert_equal Array, ary.class
|
83
|
+
assert_equal 3, ary.size
|
84
|
+
assert_equal [4,5,6], ary
|
85
|
+
end
|
86
|
+
@thok.whatever [4,5,6]
|
87
|
+
end
|
88
|
+
|
89
|
+
should_eventually 'handle multiple arrays' do
|
90
|
+
@thok.on_whatever do |ary1,ary2|
|
91
|
+
assert_not_nil ary1
|
92
|
+
assert_not_nil ary2
|
93
|
+
assert_equal Array, ary1.class
|
94
|
+
assert_equal Array, ary2.class
|
95
|
+
assert_equal 3, ary1.size
|
96
|
+
assert_equal 3, ary2.size
|
97
|
+
# fails here because ary1 is an array of variants
|
98
|
+
puts "ary1: #{ary1.inspect}"
|
99
|
+
assert_equal [4,5,6], ary1
|
100
|
+
assert_equal [7,8,9], ary2
|
101
|
+
end
|
102
|
+
@thok.whatever( [4,5,6], [7,8,9] )
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qtext
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- FIXME full name
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-10-09 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -30,25 +30,38 @@ executables: []
|
|
30
30
|
extensions: []
|
31
31
|
|
32
32
|
extra_rdoc_files:
|
33
|
+
- History.txt
|
34
|
+
- License.txt
|
35
|
+
- Manifest.txt
|
33
36
|
- README.txt
|
34
37
|
files:
|
38
|
+
- History.txt
|
39
|
+
- License.txt
|
40
|
+
- Manifest.txt
|
35
41
|
- README.txt
|
42
|
+
- Rakefile
|
43
|
+
- config/hoe.rb
|
44
|
+
- config/requirements.rb
|
45
|
+
- env.sh
|
36
46
|
- lib/qtext.rb
|
37
47
|
- lib/qtext/action_builder.rb
|
38
|
-
- lib/qtext/version.rb
|
39
|
-
- lib/qtext/flags.rb
|
40
48
|
- lib/qtext/extensions.rb
|
49
|
+
- lib/qtext/flags.rb
|
41
50
|
- lib/qtext/object_table_model.rb
|
51
|
+
- lib/qtext/version.rb
|
52
|
+
- script/console
|
53
|
+
- script/destroy
|
54
|
+
- script/generate
|
55
|
+
- script/txt2html
|
56
|
+
- tasks/deployment.rake
|
57
|
+
- tasks/environment.rake
|
58
|
+
- tasks/website.rake
|
59
|
+
- test/test_helper.rb
|
60
|
+
- test/test_object_table.rb
|
61
|
+
- test/test_widget.rb
|
42
62
|
has_rdoc: true
|
43
63
|
homepage: http://qtext.rubyforge.org
|
44
|
-
post_install_message:
|
45
|
-
|
46
|
-
For more information on qtext, see http://qtext.rubyforge.org
|
47
|
-
|
48
|
-
NOTE: Change this information in PostInstall.txt
|
49
|
-
You can also delete it if you don't want it.
|
50
|
-
|
51
|
-
|
64
|
+
post_install_message: ""
|
52
65
|
rdoc_options:
|
53
66
|
- --main
|
54
67
|
- README.txt
|
@@ -75,5 +88,5 @@ specification_version: 2
|
|
75
88
|
summary: description of gem
|
76
89
|
test_files:
|
77
90
|
- test/test_object_table.rb
|
78
|
-
- test/
|
91
|
+
- test/test_widget.rb
|
79
92
|
- test/test_helper.rb
|