qtext 0.5.0 → 0.6.0
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/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
|