qml 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/README.md +82 -19
  4. data/changes.md +17 -0
  5. data/examples/fizzbuzz/capture.png +0 -0
  6. data/examples/todo_array/capture.png +0 -0
  7. data/examples/{todo → todo_array}/main.qml +1 -1
  8. data/examples/{todo/todo.rb → todo_array/todo_array.rb} +4 -7
  9. data/examples/todo_sequel/capture.png +0 -0
  10. data/examples/todo_sequel/main.qml +87 -0
  11. data/examples/todo_sequel/todo_sequel.rb +66 -0
  12. data/examples/twitter/capture.png +0 -0
  13. data/examples/twitter/main.qml +31 -19
  14. data/examples/twitter/twitter.rb +46 -23
  15. data/ext/qml/accessclass.cpp +1 -3
  16. data/ext/qml/ext_anywrapper.cpp +36 -0
  17. data/ext/qml/ext_anywrapper.h +26 -0
  18. data/ext/qml/ext_metaobject.cpp +3 -1
  19. data/ext/qml/init.cpp +3 -3
  20. data/ext/qml/listmodel.cpp +29 -4
  21. data/ext/qml/listmodel.h +2 -0
  22. data/ext/qml/util.cpp +7 -0
  23. data/ext/qml/util.h +1 -0
  24. data/ext/qml/weakvaluereference.cpp +34 -9
  25. data/ext/qml/weakvaluereference.h +7 -5
  26. data/lib/qml/class_builder.rb +1 -0
  27. data/lib/qml/data.rb +1 -0
  28. data/lib/qml/data/array_model.rb +23 -2
  29. data/lib/qml/data/list_model.rb +26 -26
  30. data/lib/qml/data/query_model.rb +60 -0
  31. data/lib/qml/version.rb +1 -1
  32. data/qml.gemspec +5 -1
  33. data/spec/qml/data/array_model_spec.rb +43 -56
  34. data/spec/qml/data/list_model_spec.rb +17 -0
  35. data/spec/qml/data/query_model_spec.rb +62 -0
  36. data/spec/shared_examples/qml/data/list_model.rb +33 -0
  37. data/spec/spec_helper.rb +7 -0
  38. metadata +70 -30
  39. data/ext/qml/ext_gcmarker.cpp +0 -39
  40. data/ext/qml/ext_gcmarker.h +0 -27
  41. data/spec/qml/.access_spec.rb.swp +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0dd71ef4746849334db1b91614801963b036e5f9
4
- data.tar.gz: 364c1f9e5d2fd15f937dd5ab009982160fdcd121
3
+ metadata.gz: 31d0f1bbab5b1fa3d4b602baa55fc7df071f65a4
4
+ data.tar.gz: 4ba0b8cecc4f63b26f2284e56f132d19bd176c2b
5
5
  SHA512:
6
- metadata.gz: 6843d7ff307be7803b1748943a7cd83ee0a84e29016e9714fbb4545ed4759e94b664c27ac9956deff501823ac9c1f24af768c977833ee91dd8d89b2ec419e58b
7
- data.tar.gz: 6eca2b5f9227c63241d1066053d922a9b5309b530476eeb780caa7a2e37be609a004fcb374ddbce3238846d4d03115f405cd1b9574487ea3803cc9e791b78979
6
+ metadata.gz: 29d4ae1d6ff4f3218cea47dd8d40b0b02441beb1a82f678138618c654dcc9ac0bf71f5cac6c11717ae13a6dc6d43cc1fab7fce3d061b01efe6761a308cba8c10
7
+ data.tar.gz: cb4a008e7083492d416a09d472668f67dc751db63ffd7d31d97d72726e9ec21610d4562e638c410548aaddedda3a1f2bc533bb2b0e7e021f4b9d77ec01e23ff1
data/Gemfile CHANGED
@@ -2,3 +2,5 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in qml.gemspec
4
4
  gemspec name: "qml"
5
+
6
+ gem 'coveralls', require: false
data/README.md CHANGED
@@ -1,14 +1,25 @@
1
1
  # ruby-qml
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/qml.svg)](http://badge.fury.io/rb/qml)
3
4
  [![Build Status](https://travis-ci.org/seanchas116/ruby-qml.svg?branch=master)](https://travis-ci.org/seanchas116/ruby-qml)
4
-
5
- **NOTE: ruby-qml is not yet released as a gem.**
5
+ [![Coverage Status](https://coveralls.io/repos/seanchas116/ruby-qml/badge.png?branch=master)](https://coveralls.io/r/seanchas116/ruby-qml?branch=master)
6
6
 
7
7
  ruby-qml is a QML / Qt Quick wrapper for Ruby.
8
8
  It provides bindings between QML and Ruby and enables you to use Qt Quick-based GUI from Ruby.
9
9
 
10
+ * [Documentation](http://rubydoc.info/github/seanchas116/ruby-qml/master/frames)
11
+ * [Examples](https://github.com/seanchas116/ruby-qml/tree/master/examples)
12
+
13
+ ## Gallery
14
+
15
+ [![Screenshot](https://raw.github.com/seanchas116/ruby-qml/master/examples/todo_sequel/capture.png)](https://github.com/seanchas116/ruby-qml/tree/master/examples/todo_sequel)
16
+
17
+ [![Screenshot](https://raw.github.com/seanchas116/ruby-qml/master/examples/twitter/capture.png)](https://github.com/seanchas116/ruby-qml/tree/master/examples/twitter)
18
+
10
19
  ## Installation
11
20
 
21
+ ruby-qml currently requires **Ruby 2.0 or later**.
22
+
12
23
  ### OS X with Homebrew
13
24
 
14
25
  Run the following commands to install ruby-qml on OS X with Homebrew:
@@ -59,9 +70,8 @@ QML.application do |app|
59
70
  end
60
71
  ```
61
72
 
62
- #### main.qml
63
-
64
73
  ```qml
74
+ // main.qml
65
75
  import QtQuick 2.2
66
76
  import QtQuick.Controls 1.1
67
77
 
@@ -82,7 +92,10 @@ By including `QML::Access`, you can also define **properties and signals** in Ru
82
92
  Properties are used to bind data between QML and Ruby.
83
93
  Signals are used to provide the observer pattern-like notification from Ruby to QML.
84
94
 
95
+ ![Screenshot](https://raw.github.com/seanchas116/ruby-qml/master/examples/fizzbuzz/capture.png)
96
+
85
97
  ```ruby
98
+ # Ruby
86
99
  class FizzBuzz
87
100
  include QML::Access
88
101
  register_to_qml under: "Example", version: "1.0"
@@ -114,8 +127,7 @@ end
114
127
  ```
115
128
 
116
129
  ```qml
117
- // main.qml
118
-
130
+ // QML - main.qml
119
131
  import QtQuick 2.2
120
132
  import QtQuick.Controls 1.1
121
133
  import QtQuick.Layouts 1.1
@@ -196,25 +208,30 @@ To bind list data between QML ListView and Ruby, you can use ListModels.
196
208
 
197
209
  * `QML::Data::ArrayModel` - provides a simple list model implementation using Array.
198
210
 
211
+ * `QML::Data::QueryModel` - for databases (like ActiveRecord, Sequel or something)
212
+
199
213
  This example uses `ArrayModel` to provide list data for a QML ListView.
200
214
  When the content of the ArrayModel is changed, the list view is also automatically updated.
201
215
 
202
- ```ruby
203
- class TodoModel < QML::Data::ArrayModel
204
- column :title, :description, :due_date
205
- end
216
+ #### Examples
206
217
 
218
+ * [Todo example](https://github.com/seanchas116/ruby-qml/tree/master/examples/todo_sequel)
219
+
220
+ ```ruby
221
+ # Ruby
207
222
  class TodoController
208
223
  include QML::Access
209
224
  register_to_qml under: "Example", version: "1.0"
210
225
 
211
- property :model, TodoModel.new
226
+ property :model, QML::Data::ArrayModel.new(:title, :description, :due_date)
212
227
 
213
228
  def add(title, description, due_date)
214
- item = OpenStruct.new(
229
+ # Items of list models must be "Hash-like" (have #[] method to get columns)
230
+ item = {
215
231
  title: title,
216
232
  description: description,
217
- due_date: due_date)
233
+ due_date: due_date
234
+ }
218
235
  p item
219
236
  model << item
220
237
  end
@@ -222,6 +239,7 @@ end
222
239
  ```
223
240
 
224
241
  ```qml
242
+ // QML
225
243
  ListView {
226
244
  model: todo.model
227
245
  delegate: Text {
@@ -233,6 +251,54 @@ TodoController {
233
251
  }
234
252
  ```
235
253
 
254
+ ### Combile asynchronous operations
255
+
256
+ In QML, all UI-related operations are done synchronously in the event loop.
257
+ To set result of asynchronous operations to the UI, use `QML.later` or `QML::Dispatchable#later`.
258
+
259
+ #### Examples
260
+
261
+ * [Twitter Example](https://github.com/seanchas116/ruby-qml/tree/master/examples/twitter)
262
+
263
+ ```ruby
264
+ # Ruby
265
+ class HeavyTaskController
266
+ # QML::Access includes QML::Dispathable
267
+ include QML::Access
268
+ register_to_qml under: "Example", version: "1.0"
269
+
270
+ property :result, ''
271
+
272
+ def set_result(result)
273
+ self.result = result
274
+ end
275
+
276
+ def start_heavy_task
277
+ Thread.new do
278
+ self.later.set_result do_heavy_task() # #set_result is called in the main thread in the next event loop
279
+ # or
280
+ QML.later do
281
+ set_result do_heavy_task()
282
+ end
283
+ end
284
+ end
285
+ end
286
+ ```
287
+
288
+ ```qml
289
+ // QML
290
+ Text {
291
+ text: controller.result
292
+ }
293
+ Button {
294
+ text: "Start!!"
295
+ onClicked: controller.start_heavy_task()
296
+ }
297
+ HeavyTaskController {
298
+ id: controller
299
+ }
300
+ ```
301
+
236
302
  ### Use Qt objects in Ruby
237
303
 
238
304
  In ruby-qml, Qt objects (QObject-derived C++ objects and QML objects) can be accessed from Ruby via the meta-object system of Qt.
@@ -292,7 +358,7 @@ It enables you to use your Qt C++ codes from Ruby easily.
292
358
 
293
359
 
294
360
  ```c++
295
- // plugin example
361
+ // C++ - plugin example
296
362
  class MyPlugin : public QObject
297
363
  {
298
364
  Q_OBJECT
@@ -305,6 +371,7 @@ public slots:
305
371
  ```
306
372
 
307
373
  ```ruby
374
+ # Ruby
308
375
  plugin = QML::PluginLoader.new(directory, "myplugin").instance
309
376
  plugin.foo
310
377
  ```
@@ -322,7 +389,7 @@ All objects created inside QML and objects returned from C++ methods will be *ma
322
389
  #### Unmanaged objects
323
390
 
324
391
  *Unmanaged* objects are not managed and never garbage collected.
325
- Objects that have parents and that obtained from properties of other Qt objects will be *unmanaged* by default.
392
+ Objects that have parents or that obtained from properties of other Qt objects will be *unmanaged* by default.
326
393
 
327
394
  #### Specify management status explicitly
328
395
 
@@ -336,10 +403,6 @@ obj = plugin.create_object
336
403
  obj.prefer_managed false
337
404
  ```
338
405
 
339
- ## Examples
340
-
341
- See the `/example` directory.
342
-
343
406
  ## Contributing
344
407
 
345
408
  Contributions are welcome. When you are contributing to ruby-qml:
@@ -0,0 +1,17 @@
1
+ # 0.0.2 (2014-07-21)
2
+
3
+ * Improve list models
4
+
5
+ * Add ArrayModel#replace
6
+ * Add QueryModel for ORMs
7
+ * Specify column names in ListModel#initialize
8
+
9
+ * Add To-do example with [Sequel](http://sequel.jeremyevans.net/)
10
+
11
+ * Bug fixes
12
+
13
+ * Improve README
14
+
15
+ # 0.0.1 (2014-07-19)
16
+
17
+ * Initial release
@@ -55,7 +55,7 @@ ApplicationWindow {
55
55
  text: "\uf073"
56
56
  }
57
57
  Text {
58
- text: due_date
58
+ text: Qt.formatDateTime(due_date)
59
59
  }
60
60
  }
61
61
  }
@@ -6,10 +6,6 @@ module Examples
6
6
  module Todo
7
7
  VERSION = '0.1'
8
8
 
9
- class TodoModel < QML::Data::ArrayModel
10
- column :title, :description, :due_date
11
- end
12
-
13
9
  class TodoController
14
10
  include QML::Access
15
11
  register_to_qml
@@ -17,13 +13,14 @@ module Examples
17
13
  property :title, ''
18
14
  property :description, ''
19
15
  property :due_date, ''
20
- property :model, TodoModel.new
16
+ property :model, QML::Data::ArrayModel.new(:title, :description, :due_date)
21
17
 
22
18
  def add
23
- item = OpenStruct.new(
19
+ item = {
24
20
  title: title,
25
21
  description: description,
26
- due_date: due_date)
22
+ due_date: due_date
23
+ }
27
24
  p item
28
25
  model << item
29
26
  end
@@ -0,0 +1,87 @@
1
+ import QtQuick 2.3
2
+ import QtQuick.Controls 1.2
3
+ import QtQuick.Layouts 1.1
4
+ import Examples.Todo 0.1
5
+
6
+ ApplicationWindow {
7
+ visible: true
8
+ title: "Todo with Sequel"
9
+
10
+ FontLoader {
11
+ source: "../assets/fonts/fontawesome-webfont.ttf"
12
+ }
13
+ id: window
14
+ property int margin: 10
15
+ width: layout.implicitWidth + 2 * margin
16
+ height: layout.implicitHeight + 2 * margin
17
+
18
+ RowLayout {
19
+ id: layout
20
+ anchors.fill: parent
21
+ anchors.margins: window.margin
22
+ ColumnLayout {
23
+ TextField {
24
+ placeholderText: "Title"
25
+ id: titleField
26
+ }
27
+ TextField {
28
+ placeholderText: "Description"
29
+ id: descriptionField
30
+ }
31
+ Calendar {
32
+ id: calendar
33
+ }
34
+ Button {
35
+ text: "Add"
36
+ onClicked: todo.add()
37
+ }
38
+ }
39
+ ColumnLayout {
40
+ RowLayout {
41
+ Label { text: "Sort by" }
42
+ ComboBox {
43
+ id: orderComboBox
44
+ model: ListModel {
45
+ ListElement { text: "Title"; column: "title" }
46
+ ListElement { text: "Description"; column: "description" }
47
+ ListElement { text: "Due Date"; column: "due_date" }
48
+ }
49
+ property string currentColumn: model.get(currentIndex).column
50
+ }
51
+ }
52
+ ListView {
53
+ model: todo.model
54
+ spacing: 10
55
+ Layout.fillWidth: true
56
+ Layout.fillHeight: true
57
+ Layout.alignment: Qt.AlignTop
58
+ Layout.minimumWidth: 300
59
+ delegate: ColumnLayout {
60
+ Text {
61
+ font.bold: true
62
+ text: title
63
+ }
64
+ Text {
65
+ text: description
66
+ }
67
+ RowLayout {
68
+ Text {
69
+ font.family: "FontAwesome"
70
+ text: "\uf073"
71
+ }
72
+ Text {
73
+ text: Qt.formatDate(due_date)
74
+ }
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ TodoController {
81
+ id: todo
82
+ title: titleField.text
83
+ description: descriptionField.text
84
+ due_date: calendar.selectedDate
85
+ order_by: orderComboBox.currentColumn
86
+ }
87
+ }
@@ -0,0 +1,66 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../../lib', __FILE__)
2
+ require 'qml'
3
+ require 'sequel'
4
+
5
+ module Examples
6
+ module Todo
7
+ VERSION = '0.1'
8
+
9
+ DB = Sequel.sqlite
10
+
11
+ DB.create_table :todos do
12
+ primary_key :id
13
+ String :title
14
+ String :description
15
+ Date :due_date
16
+ end
17
+
18
+ class SequelModel < QML::Data::QueryModel
19
+ attr_accessor :dataset
20
+
21
+ def initialize(dataset)
22
+ @dataset = dataset
23
+ super(*dataset.columns)
24
+ end
25
+
26
+ def query_count
27
+ @dataset.count
28
+ end
29
+
30
+ def query(offset, count)
31
+ @dataset.offset(offset).limit(count).all
32
+ end
33
+ end
34
+
35
+ class TodoController
36
+ include QML::Access
37
+ register_to_qml
38
+
39
+ def initialize
40
+ super
41
+ @todo_dataset = DB[:todos]
42
+ self.model = SequelModel.new(@todo_dataset)
43
+ end
44
+
45
+ property :title, ''
46
+ property :description, ''
47
+ property :due_date, ''
48
+ property :order_by, ''
49
+ property :model
50
+
51
+ def add
52
+ @todo_dataset.insert(title: title, description: description, due_date: due_date)
53
+ model.update
54
+ end
55
+
56
+ on_changed :order_by do
57
+ model.dataset = @todo_dataset.order(order_by.to_sym)
58
+ model.update
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ QML.application do |app|
65
+ app.load_path Pathname(__FILE__) + '../main.qml'
66
+ end
@@ -5,32 +5,44 @@ import Examples.Twitter 0.1
5
5
 
6
6
  ApplicationWindow {
7
7
  visible: true
8
- width: 200
9
- height: 100
10
- title: "Twitter Test"
8
+ width: 300
9
+ height: 500
10
+ title: "Twitter Search Test - " + controller.word
11
11
 
12
- ListView {
12
+ ColumnLayout {
13
13
  anchors.fill: parent
14
- model: controller.model
15
- delegate: RowLayout {
16
- Image {
17
- width: 100
18
- height: 100
19
- source: user_icon
20
- }
21
- ColumnLayout {
22
- Text {
23
- font.bold: true
24
- text: user_name
25
- }
26
- Text {
27
- text: tweet_text
14
+ anchors.margins: 10
15
+ TextField {
16
+ id: wordField
17
+ placeholderText: 'Search...'
18
+ onEditingFinished: controller.fetch_tweets()
19
+ }
20
+ ScrollView {
21
+ Layout.fillHeight: true
22
+ Layout.fillWidth: true
23
+ ListView {
24
+ model: controller.model
25
+ delegate: RowLayout {
26
+ Image {
27
+ width: 100
28
+ height: 100
29
+ source: user_icon
30
+ }
31
+ ColumnLayout {
32
+ Text {
33
+ font.bold: true
34
+ text: user_name
35
+ }
36
+ Text {
37
+ text: tweet_text
38
+ }
39
+ }
28
40
  }
29
41
  }
30
42
  }
31
43
  }
32
-
33
44
  TwitterController {
34
45
  id: controller
46
+ word: wordField.text
35
47
  }
36
48
  }