glimmer-dsl-swt 4.24.3.1 → 4.24.4.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/README.md +5 -5
- data/VERSION +1 -1
- data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +123 -15
- data/docs/reference/GLIMMER_SAMPLES.md +13 -0
- data/glimmer-dsl-swt.gemspec +0 -0
- data/lib/ext/glimmer.rb +5 -0
- data/lib/glimmer/data_binding/table_items_binding.rb +57 -22
- data/lib/glimmer/data_binding/widget_binding.rb +26 -4
- data/lib/glimmer/dsl/swt/custom_widget_expression.rb +1 -0
- data/lib/glimmer/swt/custom/code_text.rb +1 -1
- data/lib/glimmer/swt/custom/refined_table.rb +182 -0
- data/lib/glimmer/swt/table_proxy.rb +16 -1
- data/lib/glimmer/swt/widget_proxy.rb +6 -1
- data/lib/glimmer/ui/custom_widget.rb +8 -0
- data/samples/elaborate/contact_manager.rb +2 -2
- data/samples/elaborate/meta_sample/tutorials.yml +1 -0
- data/samples/elaborate/meta_sample.rb +11 -9
- data/samples/elaborate/tetris/view/high_score_dialog.rb +1 -1
- data/samples/hello/hello_custom_shell.rb +4 -4
- data/samples/hello/hello_refined_table.rb +159 -0
- data/samples/hello/hello_table.rb +9 -8
- metadata +15 -13
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: c0501a99ee5c020f5af90de5bef4b2de5649b71ecc72ef18c07cf7624e202cd2
         | 
| 4 | 
            +
              data.tar.gz: 17f1582e1692df7535ff337c9994f4db60ebf85c1ebc2a1e34057f29218e6dfd
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: c6653469f0356e6f8b26176cf1ed780b77a04288855c532c7f33cc0a6363e2674b79fb836cf9482cb7668d06002d8cfc097f73df7b9c1777b835ec231db37d76
         | 
| 7 | 
            +
              data.tar.gz: 87f7266996c85bb845495032c41f84132a86c935a516f6a38a96a3b57904855096c00e522c6065124b881f6fbaff865066f7978fe64e392a168d91e4a4aa7abc
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,5 +1,27 @@ | |
| 1 1 | 
             
            # Change Log
         | 
| 2 2 |  | 
| 3 | 
            +
            ## 4.24.4.1
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            - Optimize `table` data-binding performance (improving paging performance in `refined_table`) by making observer registrations run asynchronously in a separate thread
         | 
| 6 | 
            +
            - Fix cleaning of old `table` data-binding observers (it was retaining some old observers after table updates)
         | 
| 7 | 
            +
            - Fix issue with ActiveSupport overriding Facets String `underscore`/`snakecase`/`titlecase`/`camelcase` methods with different incompatible implementations when loaded by a project (now, that is repaired automatically)
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            ## 4.24.4.0
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            - Save `WidgetBinding` instances on `WidgetProxy` objects via `widget_bindings` attribute
         | 
| 12 | 
            +
            - Support specifying `@children_owner` in any custom widget for which adding children will not add them under the `body_root` (e.g. a composite wrapping a table will designate the table as the `@children_owner` for adding `table_column`s)
         | 
| 13 | 
            +
            - Add explicit `shell_proxy` method to `Glimmer::UI::CustomWidget` that delegates to `body_root` to avoid annoying false negative error every time that method is called
         | 
| 14 | 
            +
            - Optimize `table` data-binding performance for single-model update scenarios
         | 
| 15 | 
            +
            - Fix issue with data-binding a table as the body root of a custom widget when customizing column_attributes
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            ## 4.24.3.2
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            - Have `table` data-binding infer model attribute names from column names by convention (no need to specify `column_properties`)
         | 
| 20 | 
            +
            - Support `table` data-binding `column_properties` mapping of column names to model attribute names via a `Hash`
         | 
| 21 | 
            +
            - Support `table` data-binding alias of `column_attributes` in place of `column_properties` because the word 'attribute' is more Ruby-idiomatic than 'property' in the Ruby world
         | 
| 22 | 
            +
            - Handle boundary condition of font height reaching 0 on repeated zoom out of `code_text`
         | 
| 23 | 
            +
            - Battleship Video Tutorial in Glimmer Meta-Sample
         | 
| 24 | 
            +
             | 
| 3 25 | 
             
            ## 4.24.3.1
         | 
| 4 26 |  | 
| 5 27 | 
             
            - `code_text` default behavior support of zoom in (CMD+= on Mac, CTRL+= on Win/Linux), zoom out (CMD+- on Mac, CTRL+- on Win/Linux), and restore original font height (CMD+0 on Mac, CTRL+0 on Win/Linux).
         | 
    
        data/README.md
    CHANGED
    
    | @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for SWT 4.24. | 
| 1 | 
            +
            # [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for SWT 4.24.4.1
         | 
| 2 2 | 
             
            ## JRuby Desktop Development GUI Framework
         | 
| 3 3 | 
             
            [](http://badge.fury.io/rb/glimmer-dsl-swt)
         | 
| 4 4 | 
             
            [](https://travis-ci.com/github/AndyObtiva/glimmer-dsl-swt)
         | 
| @@ -21,7 +21,7 @@ Featured in JRuby Cookbook](http://shop.oreilly.com/product/9780596519650.do) an | |
| 21 21 |  | 
| 22 22 | 
             
            
         | 
| 23 23 |  | 
| 24 | 
            -
            [Glimmer DSL for SWT](https://rubygems.org/gems/glimmer-dsl-swt) 4.24. | 
| 24 | 
            +
            [Glimmer DSL for SWT](https://rubygems.org/gems/glimmer-dsl-swt) 4.24.4.1 includes [SWT 4.24](https://download.eclipse.org/eclipse/downloads/drops4/R-4.24-202206070700/), which was released on June 7, 2022. Gem version numbers are in sync with the SWT library versions. The first two digits represent the SWT version number. The last two digits represent the minor and patch versions of Glimmer DSL for SWT.
         | 
| 25 25 |  | 
| 26 26 | 
             
            **Starting in version 4.20.0.0, [Glimmer DSL for SWT](https://rubygems.org/gems/glimmer-dsl-swt) comes with the new [***Shine***](/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#shine) syntax** for highly intuitive and visually expressive View/Model Attribute Mapping, relying on `<=>` for bidirectional (two-way) data-binding and `<=` for unidirectional (one-way) data-binding, providing an alternative to the `bind` keyword. That was [originally conceived back in 2007](https://andymaleh.blogspot.com/2007/12/data-shining-in-glimmer.html).
         | 
| 27 27 |  | 
| @@ -338,7 +338,7 @@ jgem install glimmer-dsl-swt | |
| 338 338 |  | 
| 339 339 | 
             
            Or this command if you want a specific version:
         | 
| 340 340 | 
             
            ```
         | 
| 341 | 
            -
            jgem install glimmer-dsl-swt -v 4.24. | 
| 341 | 
            +
            jgem install glimmer-dsl-swt -v 4.24.4.1
         | 
| 342 342 | 
             
            ```
         | 
| 343 343 |  | 
| 344 344 | 
             
            `jgem` is JRuby's version of `gem` command.
         | 
| @@ -366,7 +366,7 @@ Note: if you're using activerecord or activesupport, keep in mind that Glimmer u | |
| 366 366 |  | 
| 367 367 | 
             
            Add the following to `Gemfile`:
         | 
| 368 368 | 
             
            ```
         | 
| 369 | 
            -
            gem 'glimmer-dsl-swt', '~> 4.24. | 
| 369 | 
            +
            gem 'glimmer-dsl-swt', '~> 4.24.4.1'
         | 
| 370 370 | 
             
            ```
         | 
| 371 371 |  | 
| 372 372 | 
             
            And, then run:
         | 
| @@ -389,7 +389,7 @@ glimmer | |
| 389 389 | 
             
            ```
         | 
| 390 390 |  | 
| 391 391 | 
             
            ```
         | 
| 392 | 
            -
            Glimmer (JRuby Desktop Development GUI Framework) - JRuby Gem: glimmer-dsl-swt v4.24. | 
| 392 | 
            +
            Glimmer (JRuby Desktop Development GUI Framework) - JRuby Gem: glimmer-dsl-swt v4.24.4.1
         | 
| 393 393 |  | 
| 394 394 | 
             
            Usage: glimmer [--bundler] [--pd] [--quiet] [--debug] [--log-level=VALUE] [[ENV_VAR=VALUE]...] [[-jruby-option]...] (application.rb or task[task_args]) [[application2.rb]...]
         | 
| 395 395 |  | 
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            4.24. | 
| 1 | 
            +
            4.24.4.1
         | 
| @@ -54,9 +54,11 @@ This guide should help you get started with Glimmer DSL for SWT. For more advanc | |
| 54 54 | 
             
                - [Combo](#combo)
         | 
| 55 55 | 
             
                - [List](#list)
         | 
| 56 56 | 
             
                - [Table](#table)
         | 
| 57 | 
            +
                  - [Table Item Properties](#table-item-properties)
         | 
| 57 58 | 
             
                  - [Table Selection](#table-selection)
         | 
| 58 59 | 
             
                  - [Table Editing](#table-editing)
         | 
| 59 60 | 
             
                  - [Table Sorting](#table-sorting)
         | 
| 61 | 
            +
                  - [Refined Table](#refined-table)
         | 
| 60 62 | 
             
                - [Tree](#tree)
         | 
| 61 63 | 
             
                - [DateTime](#datetime)
         | 
| 62 64 | 
             
              - [Observer](#observer)
         | 
| @@ -3996,13 +3998,13 @@ You may learn more about Glimmer's data-binding syntax by reading the code under | |
| 3996 3998 |  | 
| 3997 3999 | 
             
            The SWT Tree widget renders a multi-column data table, such as a contact listing or a sales report.
         | 
| 3998 4000 |  | 
| 3999 | 
            -
            To data-bind a Table, you need the main model | 
| 4001 | 
            +
            To data-bind a Table, you need the main model and the collection property. The text for each row cell will be inferred from column names as underscored model attributes. For example, for a column named "Full Name", it is assumed by convention that the model has a `full_name` attribute.
         | 
| 4000 4002 |  | 
| 4001 | 
            -
             | 
| 4003 | 
            +
            Data-binding involves using the `<=` operator (one-way data-binding) or `<=>` operator (two-way data-binding), and an optional `column_attributes` kwarg (alias: `column_properties`) that takes an array that maps table columns to model attributes or a hash that maps column name strings to model attributes.
         | 
| 4002 4004 |  | 
| 4003 4005 | 
             
            It assumes you have already defined table columns via the `table_column` `table`-nested widget.
         | 
| 4004 4006 |  | 
| 4005 | 
            -
            Example:
         | 
| 4007 | 
            +
            Example (automatically inferring table items' [rows'] model attributes by convention from column names):
         | 
| 4006 4008 |  | 
| 4007 4009 | 
             
            ```ruby
         | 
| 4008 4010 | 
             
            shell {
         | 
| @@ -4019,8 +4021,10 @@ shell { | |
| 4019 4021 | 
             
                  text "Adult"
         | 
| 4020 4022 | 
             
                  width 120
         | 
| 4021 4023 | 
             
                }
         | 
| 4022 | 
            -
                 | 
| 4024 | 
            +
                
         | 
| 4025 | 
            +
                items <=> [group, :people]
         | 
| 4023 4026 | 
             
                selection <=> [group, :selected_person]
         | 
| 4027 | 
            +
                
         | 
| 4024 4028 | 
             
                on_mouse_up do |event|
         | 
| 4025 4029 | 
             
                  @table.edit_table_item(event.table_item, event.column_index)
         | 
| 4026 4030 | 
             
                end
         | 
| @@ -4028,15 +4032,71 @@ shell { | |
| 4028 4032 | 
             
            }
         | 
| 4029 4033 | 
             
            ```
         | 
| 4030 4034 |  | 
| 4031 | 
            -
            The code above includes two data-bindings:
         | 
| 4032 | 
            -
            - Table `items`, which first data-binds to the model collection property (group.people), and then maps each column  | 
| 4035 | 
            +
            The code above includes two data-bindings and a listener:
         | 
| 4036 | 
            +
            - Table `items`, which first data-binds to the model collection property (group.people), and then maps each column to a model attribute (name, age, adult) for displaying each table item column.
         | 
| 4033 4037 | 
             
            - Table `selection`, which data-binds the single table item (row) selected by the user to the model attribute denoted by `<=>` (or data-binds multiple table items to a model attribute array value for a table with `:multi` SWT style)
         | 
| 4034 4038 | 
             
            - The `on_mouse_up` event handler invokes `@table.edit_table_item(event.table_item, event.column_index)` to start edit mode on the clicked table item cell, and then saves or cancel depending on whether the user hits ENTER or ESC once done editing (or focus-out after either making a change or not making any changes.)
         | 
| 4035 4039 |  | 
| 4040 | 
            +
            Example (specifying `column_attributes` explicitly because some diverge from column names):
         | 
| 4041 | 
            +
             | 
| 4042 | 
            +
            ```ruby
         | 
| 4043 | 
            +
            shell {
         | 
| 4044 | 
            +
              @table = table {
         | 
| 4045 | 
            +
                table_column {
         | 
| 4046 | 
            +
                  text "Full Name"
         | 
| 4047 | 
            +
                  width 120
         | 
| 4048 | 
            +
                }
         | 
| 4049 | 
            +
                table_column {
         | 
| 4050 | 
            +
                  text "Age in Years"
         | 
| 4051 | 
            +
                  width 120
         | 
| 4052 | 
            +
                }
         | 
| 4053 | 
            +
                table_column {
         | 
| 4054 | 
            +
                  text "Adult"
         | 
| 4055 | 
            +
                  width 120
         | 
| 4056 | 
            +
                }
         | 
| 4057 | 
            +
                
         | 
| 4058 | 
            +
                items <=> [group, :people, column_attributes: {'Full Name' => :name, 'Age in Years' => :age}]
         | 
| 4059 | 
            +
                selection <=> [group, :selected_person]
         | 
| 4060 | 
            +
                
         | 
| 4061 | 
            +
                on_mouse_up do |event|
         | 
| 4062 | 
            +
                  @table.edit_table_item(event.table_item, event.column_index)
         | 
| 4063 | 
            +
                end
         | 
| 4064 | 
            +
              }
         | 
| 4065 | 
            +
            }
         | 
| 4066 | 
            +
            ```
         | 
| 4067 | 
            +
             | 
| 4068 | 
            +
            Example (specifying `column_attributes` explicitly because all diverge from column names):
         | 
| 4069 | 
            +
             | 
| 4070 | 
            +
            ```ruby
         | 
| 4071 | 
            +
            shell {
         | 
| 4072 | 
            +
              @table = table {
         | 
| 4073 | 
            +
                table_column {
         | 
| 4074 | 
            +
                  text "Full Name"
         | 
| 4075 | 
            +
                  width 120
         | 
| 4076 | 
            +
                }
         | 
| 4077 | 
            +
                table_column {
         | 
| 4078 | 
            +
                  text "Age in Years"
         | 
| 4079 | 
            +
                  width 120
         | 
| 4080 | 
            +
                }
         | 
| 4081 | 
            +
                table_column {
         | 
| 4082 | 
            +
                  text "Is Adult"
         | 
| 4083 | 
            +
                  width 120
         | 
| 4084 | 
            +
                }
         | 
| 4085 | 
            +
                
         | 
| 4086 | 
            +
                items <=> [group, :people, column_attributes: [:name, :age, :adult]]
         | 
| 4087 | 
            +
                selection <=> [group, :selected_person]
         | 
| 4088 | 
            +
                
         | 
| 4089 | 
            +
                on_mouse_up do |event|
         | 
| 4090 | 
            +
                  @table.edit_table_item(event.table_item, event.column_index)
         | 
| 4091 | 
            +
                end
         | 
| 4092 | 
            +
              }
         | 
| 4093 | 
            +
            }
         | 
| 4094 | 
            +
            ```
         | 
| 4095 | 
            +
             | 
| 4036 4096 | 
             
            Additionally, Table `items` data-binding automatically stores each row model in the [SWT `TableItem`](https://help.eclipse.org/latest/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/widgets/TableItem.html) object representing it, by using the `set_data` method. This enables things like searchability.
         | 
| 4037 4097 |  | 
| 4038 | 
            -
            The table widget in Glimmer is represented by a subclass of `WidgetProxy` called `TableProxy`.
         | 
| 4039 | 
            -
            TableProxy includes a `search` method that takes a block to look for a table item.
         | 
| 4098 | 
            +
            The table widget in Glimmer is represented by a subclass of `Glimmer::SWT::WidgetProxy` called `Glimmer::SWT::TableProxy`.
         | 
| 4099 | 
            +
            `Glimmer::SWT::TableProxy` includes a `search` method that takes a block to look for a table item.
         | 
| 4040 4100 |  | 
| 4041 4101 | 
             
            Example:
         | 
| 4042 4102 |  | 
| @@ -4051,11 +4111,14 @@ This automatically leverages the SWT TableEditor custom class behind the scenes, | |
| 4051 4111 | 
             
            passed table item text into something else.
         | 
| 4052 4112 | 
             
            It automatically persists the change to `items` data-bound model on ENTER/FOCUS-OUT or cancels on ESC/NO-CHANGE.
         | 
| 4053 4113 |  | 
| 4114 | 
            +
            Note that `table` is useful with a maximum of about 100 rows only, not more than that, or otherwise it will not offer a user-friendly experience due to requiring users to scroll through a lot of data.
         | 
| 4115 | 
            +
            If you need to display a table with more than 100 rows, then you need to employ pagination. That is already supported in the [Refined Table (`refined_table`)](#refined-table) custom widget documented below.
         | 
| 4116 | 
            +
             | 
| 4054 4117 | 
             
            ##### Table Item Properties
         | 
| 4055 4118 |  | 
| 4056 4119 | 
             
            When data-binding a `table`'s `items`, extra [`TableItem` properties](https://help.eclipse.org/latest/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/widgets/TableItem.html) are data-bound automatically by convention for `background` color, `foreground` color, `font`, and `image` if corresponding properties (attributes) are available on the model.
         | 
| 4057 4120 |  | 
| 4058 | 
            -
            That means that if ` | 
| 4121 | 
            +
            That means that if `column_attributes` were `[:name, :age, :adult]`, then the following [`TableItem` properties](https://help.eclipse.org/latest/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/widgets/TableItem.html) are also data-bound by convention:
         | 
| 4059 4122 | 
             
            - `background` to `:name_background, :age_background, :adult_background` model attributes
         | 
| 4060 4123 | 
             
            - `foreground` to `:name_foreground, :age_foreground, :adult_foreground` model attributes
         | 
| 4061 4124 | 
             
            - `font` to `:name_font, :age_font, :adult_font` model attributes
         | 
| @@ -4104,7 +4167,7 @@ shell { | |
| 4104 4167 | 
             
                  text "Adult"
         | 
| 4105 4168 | 
             
                  width 120
         | 
| 4106 4169 | 
             
                }
         | 
| 4107 | 
            -
                items  | 
| 4170 | 
            +
                items <=> [group, :people]
         | 
| 4108 4171 | 
             
                selection bind(group, :selected_person)
         | 
| 4109 4172 | 
             
              }
         | 
| 4110 4173 | 
             
            }
         | 
| @@ -4131,7 +4194,7 @@ shell { | |
| 4131 4194 | 
             
                  width 120
         | 
| 4132 4195 | 
             
                  editor :checkbox
         | 
| 4133 4196 | 
             
                }
         | 
| 4134 | 
            -
                items  | 
| 4197 | 
            +
                items <=> [group, :people]
         | 
| 4135 4198 | 
             
                selection bind(group, :selected_person)
         | 
| 4136 4199 | 
             
              }
         | 
| 4137 4200 | 
             
            }
         | 
| @@ -4170,7 +4233,7 @@ shell { | |
| 4170 4233 | 
             
                  # assume there is a `Person#industry_options` property method on the model to provide items to the `combo`
         | 
| 4171 4234 | 
             
                  editor :combo, :read_only # passes :ready_only SWT style to `combo` widget
         | 
| 4172 4235 | 
             
                }
         | 
| 4173 | 
            -
                items  | 
| 4236 | 
            +
                items <=> [group, :people, column_attributes: {'Date of Birth' => :formatted_date}]
         | 
| 4174 4237 | 
             
                selection bind(group, :selected_person)
         | 
| 4175 4238 | 
             
              }
         | 
| 4176 4239 | 
             
            }
         | 
| @@ -4178,7 +4241,7 @@ shell { | |
| 4178 4241 |  | 
| 4179 4242 | 
             
            Check out [Hello, Table!](/docs/reference/GLIMMER_SAMPLES.md#hello-table) for an actual example including table editors.
         | 
| 4180 4243 |  | 
| 4181 | 
            -
            [Are We There Yet?](#are-we-there-yet) is an actual production Glimmer application that takes full advantage of table capabilities, storing model data in a database via ActiveRecord. As such, it's an excellent demonstration of how to use Glimmer DSL for SWT with a database.
         | 
| 4244 | 
            +
            [Are We There Yet?](#are-we-there-yet) is an actual production Glimmer application that takes full advantage of table capabilities, storing model data in a database via ActiveRecord and SQLite DB. As such, it's an excellent demonstration of how to use Glimmer DSL for SWT with a database. [Contact Manager](https://github.com/AndyObtiva/contact_manager) is an external sample application that also utilizes a table with ActiveRecord and SQLite DB. It comes with a [blog post](https://andymaleh.blogspot.com/2022/06/using-activerecord-with-sqlite-db-in.html?m=0) that provides a step by step guide on how to build such an application.
         | 
| 4182 4245 |  | 
| 4183 4246 | 
             
            ##### Table Sorting
         | 
| 4184 4247 |  | 
| @@ -4229,7 +4292,7 @@ Example: | |
| 4229 4292 | 
             
                  sort { |d1, d2| d1.to_date <=> d2.to_date }
         | 
| 4230 4293 | 
             
                }
         | 
| 4231 4294 | 
             
                additional_sort_properties :project_name, :duration_in_hours, :name
         | 
| 4232 | 
            -
                items  | 
| 4295 | 
            +
                items <=> [Task, :list, column_attributes: [:name, :project_name, :duration, :priority, :start_date]]
         | 
| 4233 4296 | 
             
                # ...
         | 
| 4234 4297 | 
             
              }
         | 
| 4235 4298 | 
             
            # ...
         | 
| @@ -4242,7 +4305,52 @@ Here is an explanation of the example above: | |
| 4242 4305 | 
             
            - Task Start Date table column has a custom sort comparator block
         | 
| 4243 4306 | 
             
            - Additional (secondary) sort properties are applied when sorting by Task, Project, or Duration in the order specified
         | 
| 4244 4307 |  | 
| 4245 | 
            -
             | 
| 4308 | 
            +
            `<= [model, :property, read_only_sort: true]` could be used with items to make sorting not propagate sorting changes to model.
         | 
| 4309 | 
            +
             | 
| 4310 | 
            +
            ##### Refined Table
         | 
| 4311 | 
            +
             | 
| 4312 | 
            +
            **(ALPHA FEATURE)**
         | 
| 4313 | 
            +
             | 
| 4314 | 
            +
            `refined_table` is a custom widget that can handle very large amounts of data by applying pagination.
         | 
| 4315 | 
            +
             | 
| 4316 | 
            +
            Just use like a standard `table`, but data-bind models to the `model_array` property instead of `items`. `refined_table` will take care of the rest.
         | 
| 4317 | 
            +
             | 
| 4318 | 
            +
            Options:
         | 
| 4319 | 
            +
            - `per_page` (default: `10`): specifies how many rows to display per page
         | 
| 4320 | 
            +
            - `page` (default: `1` if table is filled and `0` otherwise): specifies initial page
         | 
| 4321 | 
            +
             | 
| 4322 | 
            +
            Note that currently `refined_table` only supports displaying a **read-only** table (meaning it can read updates from the model, but it cannot write back to the model through `TableEditor` cells).
         | 
| 4323 | 
            +
             | 
| 4324 | 
            +
            Example taken from [Hello, Refined Table!](/docs/reference/GLIMMER_SAMPLES.md#hello-refined-table):
         | 
| 4325 | 
            +
             | 
| 4326 | 
            +
            
         | 
| 4327 | 
            +
             | 
| 4328 | 
            +
            ```ruby
         | 
| 4329 | 
            +
                  #... more code precedes
         | 
| 4330 | 
            +
                  
         | 
| 4331 | 
            +
                  refined_table(per_page: 20) {
         | 
| 4332 | 
            +
                    table_column {
         | 
| 4333 | 
            +
                      width 100
         | 
| 4334 | 
            +
                      text 'Date'
         | 
| 4335 | 
            +
                    }
         | 
| 4336 | 
            +
                    table_column {
         | 
| 4337 | 
            +
                      width 200
         | 
| 4338 | 
            +
                      text 'Ballpark'
         | 
| 4339 | 
            +
                    }
         | 
| 4340 | 
            +
                    table_column {
         | 
| 4341 | 
            +
                      width 150
         | 
| 4342 | 
            +
                      text 'Home Team'
         | 
| 4343 | 
            +
                    }
         | 
| 4344 | 
            +
                    table_column {
         | 
| 4345 | 
            +
                      width 150
         | 
| 4346 | 
            +
                      text 'Away Team'
         | 
| 4347 | 
            +
                    }
         | 
| 4348 | 
            +
                    
         | 
| 4349 | 
            +
                    model_array <= [@baseball_season, :games, column_attributes: {'Home Team' => :home_team_name, 'Away Team' => :away_team_name}]
         | 
| 4350 | 
            +
                  }
         | 
| 4351 | 
            +
                  
         | 
| 4352 | 
            +
                  #...more code follows
         | 
| 4353 | 
            +
            ```
         | 
| 4246 4354 |  | 
| 4247 4355 | 
             
            #### Tree
         | 
| 4248 4356 |  | 
| @@ -41,6 +41,7 @@ | |
| 41 41 | 
             
                - [Hello, Slider!](#hello-slider)
         | 
| 42 42 | 
             
                - [Hello, Spinner!](#hello-spinner)
         | 
| 43 43 | 
             
                - [Hello, Table!](#hello-table)
         | 
| 44 | 
            +
                - [Hello, Refined Table!](#hello-refined-table)
         | 
| 44 45 | 
             
                - [Hello, Link!](#hello-link)
         | 
| 45 46 | 
             
                - [Hello, Dialog!](#hello-dialog)
         | 
| 46 47 | 
             
                - [Hello, Code Text!](#hello-code-text)
         | 
| @@ -780,6 +781,18 @@ Hello, Table! Game Booked Rows | |
| 780 781 |  | 
| 781 782 | 
             
            
         | 
| 782 783 |  | 
| 784 | 
            +
            #### Hello, Refined Table!
         | 
| 785 | 
            +
             | 
| 786 | 
            +
            This sample demonstrates the use of the [`refined_table` widget](/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md#refined-table), which provides a paginated `table` that can handle very large amounts of data.
         | 
| 787 | 
            +
             | 
| 788 | 
            +
            Code:
         | 
| 789 | 
            +
             | 
| 790 | 
            +
            [samples/hello/hello_refined_table.rb](/samples/hello/hello_refined_table.rb)
         | 
| 791 | 
            +
             | 
| 792 | 
            +
            Hello, Refined Table!
         | 
| 793 | 
            +
             | 
| 794 | 
            +
            
         | 
| 795 | 
            +
             | 
| 783 796 | 
             
            #### Hello, Link!
         | 
| 784 797 |  | 
| 785 798 | 
             
            This sample demonstrates the use of the `link` widget in Glimmer, including identifying which link was clicked and performing an action (displaying help) based on its location.
         | 
    
        data/glimmer-dsl-swt.gemspec
    CHANGED
    
    | Binary file | 
    
        data/lib/ext/glimmer.rb
    CHANGED
    
    | @@ -27,6 +27,11 @@ module Glimmer | |
| 27 27 | 
             
                  if Object.const_defined?(:ActiveSupport) && ActiveSupport.const_defined?(:Dependencies)
         | 
| 28 28 | 
             
                    begin
         | 
| 29 29 | 
             
                      ActiveSupport::Dependencies.unhook!
         | 
| 30 | 
            +
                      # override activesupport string method implementations if already loaded
         | 
| 31 | 
            +
                      gem 'facets'
         | 
| 32 | 
            +
                      load 'facets/string/snakecase.rb'
         | 
| 33 | 
            +
                      load 'facets/string/titlecase.rb'
         | 
| 34 | 
            +
                      load 'facets/string/camelcase.rb'
         | 
| 30 35 | 
             
                    rescue => e
         | 
| 31 36 | 
             
                      # noop TODO support logging unimportant details below debug level
         | 
| 32 37 | 
             
                    end
         | 
| @@ -37,18 +37,17 @@ module Glimmer | |
| 37 37 | 
             
                  include_package 'org.eclipse.swt.widgets'
         | 
| 38 38 |  | 
| 39 39 | 
             
                  TABLE_ITEM_PROPERTIES = %w[background foreground font image]
         | 
| 40 | 
            +
                  
         | 
| 41 | 
            +
                  attr_reader :data_binding_done
         | 
| 40 42 |  | 
| 41 43 | 
             
                  def initialize(parent, model_binding, column_properties = nil)
         | 
| 42 | 
            -
                    @table = parent
         | 
| 44 | 
            +
                    @table = parent.is_a?(Glimmer::SWT::TableProxy) ? parent : parent.body_root # assume custom widget in latter case
         | 
| 45 | 
            +
                    @table.table_items_binding = self
         | 
| 43 46 | 
             
                    @model_binding = model_binding
         | 
| 44 47 | 
             
                    @read_only_sort = @model_binding.binding_options[:read_only_sort]
         | 
| 45 | 
            -
                    @column_properties = @model_binding.binding_options[:column_properties] || @model_binding.binding_options[:column_attributes] || column_properties
         | 
| 46 48 | 
             
                    @table.editable = false if @model_binding.binding_options[:read_only]
         | 
| 47 | 
            -
                     | 
| 48 | 
            -
             | 
| 49 | 
            -
                    else # assume custom widget
         | 
| 50 | 
            -
                      @table.body_root.column_properties = @column_properties
         | 
| 51 | 
            -
                    end
         | 
| 49 | 
            +
                    @table.column_properties = @model_binding.binding_options[:column_properties] || @model_binding.binding_options[:column_attributes] || column_properties
         | 
| 50 | 
            +
                    @column_properties = @table.column_properties # normalized column properties
         | 
| 52 51 | 
             
                    Glimmer::SWT::DisplayProxy.instance.auto_exec(override_sync_exec: @model_binding.binding_options[:sync_exec], override_async_exec: @model_binding.binding_options[:async_exec]) do
         | 
| 53 52 | 
             
                      @table.swt_widget.data = @model_binding
         | 
| 54 53 | 
             
                      @table.swt_widget.set_data('table_items_binding', self)
         | 
| @@ -67,6 +66,7 @@ module Glimmer | |
| 67 66 | 
             
                    Glimmer::SWT::DisplayProxy.instance.auto_exec(override_sync_exec: @model_binding.binding_options[:sync_exec], override_async_exec: @model_binding.binding_options[:async_exec]) do
         | 
| 68 67 | 
             
                      new_model_collection = model_binding_evaluated_property = @model_binding.evaluate_property unless internal_sort # this ensures applying converters (e.g. :on_read)
         | 
| 69 68 | 
             
                      return if same_table_data?(new_model_collection)
         | 
| 69 | 
            +
                      
         | 
| 70 70 | 
             
                      if same_model_collection?(new_model_collection)
         | 
| 71 71 | 
             
                        new_model_collection_attribute_values = model_collection_attribute_values(new_model_collection)
         | 
| 72 72 | 
             
                        @table.swt_widget.items.each_with_index do |table_item, row_index|
         | 
| @@ -83,24 +83,42 @@ module Glimmer | |
| 83 83 | 
             
                        @last_model_collection_attribute_values = new_model_collection_attribute_values
         | 
| 84 84 | 
             
                      else
         | 
| 85 85 | 
             
                        if new_model_collection and new_model_collection.is_a?(Array)
         | 
| 86 | 
            -
                           | 
| 87 | 
            -
                          @ | 
| 88 | 
            -
                           | 
| 89 | 
            -
                           | 
| 90 | 
            -
             | 
| 91 | 
            -
             | 
| 92 | 
            -
             | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
             | 
| 86 | 
            +
                          @model_observer_registrations ||= {}
         | 
| 87 | 
            +
                          @table_item_property_observation_mutex ||= Mutex.new
         | 
| 88 | 
            +
                          
         | 
| 89 | 
            +
                          Thread.new do
         | 
| 90 | 
            +
                            @data_binding_done = false
         | 
| 91 | 
            +
                            @table_item_property_observation_mutex.synchronize do
         | 
| 92 | 
            +
                              deregister_model_observer_registrations
         | 
| 93 | 
            +
                            
         | 
| 94 | 
            +
                              new_model_collection.each_with_index do |model, model_index|
         | 
| 95 | 
            +
                                @model_observer_registrations[model_index] ||= {}
         | 
| 96 | 
            +
                                @column_properties.each do |column_property|
         | 
| 97 | 
            +
                                  model_observer_registration = observe(model, column_property)
         | 
| 98 | 
            +
                                  @model_observer_registrations[model_index][column_property] = model_observer_registration
         | 
| 99 | 
            +
                                  add_dependent(@table_observer_registration => model_observer_registration)
         | 
| 100 | 
            +
                                end
         | 
| 101 | 
            +
                              end
         | 
| 102 | 
            +
                
         | 
| 103 | 
            +
                              if !same_model_collection_with_different_sort?(new_model_collection)
         | 
| 104 | 
            +
                                new_model_collection.each_with_index do |model, model_index|
         | 
| 105 | 
            +
                                  TABLE_ITEM_PROPERTIES.each do |table_item_property|
         | 
| 106 | 
            +
                                    @column_properties.each do |column_property|
         | 
| 107 | 
            +
                                      column_property = "#{column_property}_#{table_item_property}"
         | 
| 108 | 
            +
                                      model_observer_registration = observe(model, column_property)
         | 
| 109 | 
            +
                                      @model_observer_registrations[model_index][column_property] = model_observer_registration
         | 
| 110 | 
            +
                                      add_dependent(@table_observer_registration => model_observer_registration)
         | 
| 111 | 
            +
                                    end
         | 
| 112 | 
            +
                                  end
         | 
| 113 | 
            +
                                end
         | 
| 114 | 
            +
                              end
         | 
| 115 | 
            +
                              @data_binding_done = true
         | 
| 100 116 | 
             
                            end
         | 
| 101 117 | 
             
                          end
         | 
| 118 | 
            +
                          
         | 
| 102 119 | 
             
                          @model_collection = new_model_collection
         | 
| 103 120 | 
             
                        end
         | 
| 121 | 
            +
                        
         | 
| 104 122 | 
             
                        populate_table(@model_collection, @table, @column_properties, internal_sort: internal_sort)
         | 
| 105 123 | 
             
                      end
         | 
| 106 124 | 
             
                    end
         | 
| @@ -200,7 +218,24 @@ module Glimmer | |
| 200 218 | 
             
                  end
         | 
| 201 219 |  | 
| 202 220 | 
             
                  def table_item_model_collection
         | 
| 203 | 
            -
                     | 
| 221 | 
            +
                    Glimmer::SWT::DisplayProxy.instance.auto_exec do
         | 
| 222 | 
            +
                      if @table.disposed?
         | 
| 223 | 
            +
                        []
         | 
| 224 | 
            +
                      else
         | 
| 225 | 
            +
                        @table.swt_widget.items.map(&:get_data)
         | 
| 226 | 
            +
                      end
         | 
| 227 | 
            +
                    end
         | 
| 228 | 
            +
                  end
         | 
| 229 | 
            +
                  
         | 
| 230 | 
            +
                  def deregister_model_observer_registrations
         | 
| 231 | 
            +
                    @model_observer_registrations&.dup&.each do |model_index, model_column_properties|
         | 
| 232 | 
            +
                      model_column_properties.dup.each do |column_property, model_observer_registration|
         | 
| 233 | 
            +
                        remove_dependent(@table_observer_registration => model_observer_registration) if model_observer_registration
         | 
| 234 | 
            +
                        model_observer_registration&.unobserve
         | 
| 235 | 
            +
                        model_column_properties.delete(column_property)
         | 
| 236 | 
            +
                      end
         | 
| 237 | 
            +
                      @model_observer_registrations.delete(model_index)
         | 
| 238 | 
            +
                    end
         | 
| 204 239 | 
             
                  end
         | 
| 205 240 |  | 
| 206 241 | 
             
                  def model_collection_attribute_values(model_collection)
         | 
| @@ -31,7 +31,8 @@ module Glimmer | |
| 31 31 | 
             
                  include Observable
         | 
| 32 32 | 
             
                  include Observer
         | 
| 33 33 |  | 
| 34 | 
            -
                  attr_reader :widget, :property
         | 
| 34 | 
            +
                  attr_reader :widget, :property, :model_binding
         | 
| 35 | 
            +
                  
         | 
| 35 36 | 
             
                  def initialize(widget, property, sync_exec: nil, async_exec: nil)
         | 
| 36 37 | 
             
                    @widget = widget
         | 
| 37 38 | 
             
                    @property = property
         | 
| @@ -40,17 +41,35 @@ module Glimmer | |
| 40 41 | 
             
                    SWT::DisplayProxy.instance.auto_exec(override_sync_exec: @sync_exec, override_async_exec: @async_exec) do
         | 
| 41 42 | 
             
                      if @widget.is_a?(Glimmer::SWT::WidgetProxy) && @widget.respond_to?(:on_widget_disposed)
         | 
| 42 43 | 
             
                        @widget.on_widget_disposed do |dispose_event|
         | 
| 43 | 
            -
                           | 
| 44 | 
            +
                          unless @widget.shell_proxy.last_shell_closing?
         | 
| 45 | 
            +
                            @widget_proxy.widget_bindings.delete(self)
         | 
| 46 | 
            +
                            deregister_all_observables
         | 
| 47 | 
            +
                          end
         | 
| 44 48 | 
             
                        end
         | 
| 45 49 | 
             
                      end
         | 
| 46 50 | 
             
                      # TODO look into hooking on_shape_disposed without slowing down shapes in samples like Tetris
         | 
| 47 51 | 
             
                    end
         | 
| 52 | 
            +
                    # TODO try to come up with a more comprehensive and cleaner solution to miscallenous objects like MessageBoxProxy with regards to @widget_proxy
         | 
| 53 | 
            +
                    @widget_proxy = widget.is_a?(Glimmer::SWT::WidgetProxy) ? widget : (widget.respond_to?(:body_root) ? widget.body_root : widget)
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
                  
         | 
| 56 | 
            +
                  def observe(*args)
         | 
| 57 | 
            +
                    if @widget_proxy.respond_to?(:widget_bindings)
         | 
| 58 | 
            +
                      # TODO try to come up with a more comprehensive and cleaner solution to miscallenous objects like MessageBoxProxy with regards to the following code
         | 
| 59 | 
            +
                      # assumes only one observation
         | 
| 60 | 
            +
                      @model_binding = args.first if args.size == 1
         | 
| 61 | 
            +
                      @widget_proxy.widget_bindings << self
         | 
| 62 | 
            +
                    end
         | 
| 63 | 
            +
                    super
         | 
| 48 64 | 
             
                  end
         | 
| 49 65 |  | 
| 50 66 | 
             
                  def call(value)
         | 
| 51 67 | 
             
                    SWT::DisplayProxy.instance.auto_exec(override_sync_exec: @sync_exec, override_async_exec: @async_exec) do
         | 
| 52 68 | 
             
                      if @widget.respond_to?(:disposed?) && @widget.disposed?
         | 
| 53 | 
            -
                         | 
| 69 | 
            +
                        unless @widget.shell_proxy.last_shell_closing?
         | 
| 70 | 
            +
                          @widget_proxy.widget_bindings.delete(self)
         | 
| 71 | 
            +
                          deregister_all_observables
         | 
| 72 | 
            +
                        end
         | 
| 54 73 | 
             
                        return
         | 
| 55 74 | 
             
                      end
         | 
| 56 75 | 
             
                      # need the rescue false for a scenario with tree items not being equal to model objects raising an exception
         | 
| @@ -62,7 +81,10 @@ module Glimmer | |
| 62 81 |  | 
| 63 82 | 
             
                  def evaluate_property
         | 
| 64 83 | 
             
                    if @widget.respond_to?(:disposed?) && @widget.disposed?
         | 
| 65 | 
            -
                       | 
| 84 | 
            +
                      unless @widget.shell_proxy.last_shell_closing?
         | 
| 85 | 
            +
                        @widget_proxy.widget_bindings.delete(self)
         | 
| 86 | 
            +
                        deregister_all_observables
         | 
| 87 | 
            +
                      end
         | 
| 66 88 | 
             
                      return
         | 
| 67 89 | 
             
                    end
         | 
| 68 90 | 
             
                    @widget.get_attribute(@property)
         | 
| @@ -26,6 +26,7 @@ require 'glimmer/dsl/top_level_expression' | |
| 26 26 | 
             
            require 'glimmer/ui/custom_widget'
         | 
| 27 27 | 
             
            require 'glimmer/ui/custom_shell'
         | 
| 28 28 | 
             
            require 'glimmer/swt/custom/code_text'
         | 
| 29 | 
            +
            require 'glimmer/swt/custom/refined_table'
         | 
| 29 30 | 
             
            require 'glimmer/swt/custom/radio_group'
         | 
| 30 31 | 
             
            require 'glimmer/swt/custom/checkbox_group'
         | 
| 31 32 |  | 
| @@ -349,7 +349,7 @@ module Glimmer | |
| 349 349 |  | 
| 350 350 | 
             
                    def bump_font_height_down
         | 
| 351 351 | 
             
                      @original_font_height ||= font_datum.height
         | 
| 352 | 
            -
                      new_font_height = font_datum.height - 1
         | 
| 352 | 
            +
                      new_font_height = (font_datum.height - 1) == 0 ? font_datum.height : (font_datum.height - 1)
         | 
| 353 353 | 
             
                      update_font_height(new_font_height)
         | 
| 354 354 | 
             
                    end
         | 
| 355 355 |  | 
| @@ -0,0 +1,182 @@ | |
| 1 | 
            +
            # Copyright (c) 2007-2022 Andy Maleh
         | 
| 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.
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            require 'glimmer/ui/custom_widget'
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            module Glimmer
         | 
| 25 | 
            +
              module SWT
         | 
| 26 | 
            +
                module Custom
         | 
| 27 | 
            +
                  # RefinedTable is a customization of Table with support for Filtering/Pagination
         | 
| 28 | 
            +
                  class RefinedTable
         | 
| 29 | 
            +
                    include Glimmer::UI::CustomWidget
         | 
| 30 | 
            +
                    
         | 
| 31 | 
            +
                    option :per_page, default: 10
         | 
| 32 | 
            +
                    option :page, default: 0
         | 
| 33 | 
            +
                    option :model_array
         | 
| 34 | 
            +
                    
         | 
| 35 | 
            +
                    attr_accessor :refined_model_array
         | 
| 36 | 
            +
                    attr_reader :table_proxy, :page_text_proxy
         | 
| 37 | 
            +
                    
         | 
| 38 | 
            +
                    before_body do
         | 
| 39 | 
            +
                      self.model_array ||= []
         | 
| 40 | 
            +
                      self.refined_model_array = []
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
                    
         | 
| 43 | 
            +
                    after_body do
         | 
| 44 | 
            +
                      Glimmer::DataBinding::Observer.proc do |new_widget_bindings|
         | 
| 45 | 
            +
                        new_widget_bindings.each do |new_widget_binding|
         | 
| 46 | 
            +
                          if new_widget_binding.property.to_s == 'model_array' && !@data_bound
         | 
| 47 | 
            +
                            @data_bound = true
         | 
| 48 | 
            +
                            model_binding = new_widget_binding.model_binding
         | 
| 49 | 
            +
                            observe(self, :model_array) do
         | 
| 50 | 
            +
                              paginate
         | 
| 51 | 
            +
                            end
         | 
| 52 | 
            +
                            @table_proxy.content {
         | 
| 53 | 
            +
                              items(dsl: true) <=> [self, :refined_model_array, model_binding.binding_options.merge(read_only: true)]
         | 
| 54 | 
            +
                            }
         | 
| 55 | 
            +
                            paginate
         | 
| 56 | 
            +
                          end
         | 
| 57 | 
            +
                        end
         | 
| 58 | 
            +
                      end.observe(body_root.widget_bindings)
         | 
| 59 | 
            +
                    end
         | 
| 60 | 
            +
                    
         | 
| 61 | 
            +
                    body {
         | 
| 62 | 
            +
                      composite {
         | 
| 63 | 
            +
                        composite {
         | 
| 64 | 
            +
                          layout_data(:fill, :center, true, false)
         | 
| 65 | 
            +
                          
         | 
| 66 | 
            +
                          fill_layout(:horizontal)
         | 
| 67 | 
            +
                          
         | 
| 68 | 
            +
                          button {
         | 
| 69 | 
            +
                            text '<<'
         | 
| 70 | 
            +
                            
         | 
| 71 | 
            +
                            on_widget_selected do
         | 
| 72 | 
            +
                              self.page = first_page
         | 
| 73 | 
            +
                              paginate
         | 
| 74 | 
            +
                            end
         | 
| 75 | 
            +
                          }
         | 
| 76 | 
            +
                          
         | 
| 77 | 
            +
                          button {
         | 
| 78 | 
            +
                            text '<'
         | 
| 79 | 
            +
                            
         | 
| 80 | 
            +
                            on_widget_selected do
         | 
| 81 | 
            +
                              self.page -= 1
         | 
| 82 | 
            +
                              paginate
         | 
| 83 | 
            +
                            end
         | 
| 84 | 
            +
                          }
         | 
| 85 | 
            +
                          
         | 
| 86 | 
            +
                          @page_text_proxy = text(:border, :center) {
         | 
| 87 | 
            +
                            text <= [self, :page, on_read: ->(value) { "#{value} of #{page_count}" }]
         | 
| 88 | 
            +
                            
         | 
| 89 | 
            +
                            on_focus_gained do
         | 
| 90 | 
            +
                              @page_text_proxy.select_all
         | 
| 91 | 
            +
                            end
         | 
| 92 | 
            +
                            
         | 
| 93 | 
            +
                            on_focus_lost do
         | 
| 94 | 
            +
                              self.page = @page_text_proxy.text.to_i
         | 
| 95 | 
            +
                              paginate
         | 
| 96 | 
            +
                            end
         | 
| 97 | 
            +
                            
         | 
| 98 | 
            +
                            on_key_pressed do |key_event|
         | 
| 99 | 
            +
                              if key_event.keyCode == swt(:cr)
         | 
| 100 | 
            +
                                self.page = @page_text_proxy.text.to_i
         | 
| 101 | 
            +
                                paginate
         | 
| 102 | 
            +
                              end
         | 
| 103 | 
            +
                            end
         | 
| 104 | 
            +
                          }
         | 
| 105 | 
            +
                          
         | 
| 106 | 
            +
                          button {
         | 
| 107 | 
            +
                            text '>'
         | 
| 108 | 
            +
                            
         | 
| 109 | 
            +
                            on_widget_selected do
         | 
| 110 | 
            +
                              self.page += 1
         | 
| 111 | 
            +
                              paginate
         | 
| 112 | 
            +
                            end
         | 
| 113 | 
            +
                          }
         | 
| 114 | 
            +
                          
         | 
| 115 | 
            +
                          button {
         | 
| 116 | 
            +
                            text '>>'
         | 
| 117 | 
            +
                            
         | 
| 118 | 
            +
                            on_widget_selected do
         | 
| 119 | 
            +
                              self.page = last_page
         | 
| 120 | 
            +
                              paginate
         | 
| 121 | 
            +
                            end
         | 
| 122 | 
            +
                          }
         | 
| 123 | 
            +
                        }
         | 
| 124 | 
            +
                        
         | 
| 125 | 
            +
                        @children_owner = @table_proxy = table(swt_style)
         | 
| 126 | 
            +
                      }
         | 
| 127 | 
            +
                    }
         | 
| 128 | 
            +
                    
         | 
| 129 | 
            +
                    def table_block=(block)
         | 
| 130 | 
            +
                      @table_proxy.content(&block)
         | 
| 131 | 
            +
                    end
         | 
| 132 | 
            +
                    
         | 
| 133 | 
            +
                    def method_missing(method_name, *args, &block)
         | 
| 134 | 
            +
                      dsl_mode = @dsl_mode || args.last.is_a?(Hash) && args.last[:dsl]
         | 
| 135 | 
            +
                      if dsl_mode
         | 
| 136 | 
            +
                        args.pop if args.last.is_a?(Hash) && args.last[:dsl]
         | 
| 137 | 
            +
                        super(method_name, *args, &block)
         | 
| 138 | 
            +
                      elsif @table_proxy&.respond_to?(method_name, *args, &block)
         | 
| 139 | 
            +
                        @table_proxy&.send(method_name, *args, &block)
         | 
| 140 | 
            +
                      else
         | 
| 141 | 
            +
                        super
         | 
| 142 | 
            +
                      end
         | 
| 143 | 
            +
                    end
         | 
| 144 | 
            +
                    
         | 
| 145 | 
            +
                    def respond_to?(method_name, *args, &block)
         | 
| 146 | 
            +
                      dsl_mode = @dsl_mode || args.last.is_a?(Hash) && args.last[:dsl]
         | 
| 147 | 
            +
                      if dsl_mode
         | 
| 148 | 
            +
                        args = args[0...-1] if args.last.is_a?(Hash) && args.last[:dsl]
         | 
| 149 | 
            +
                        super(method_name, *args, &block)
         | 
| 150 | 
            +
                      else
         | 
| 151 | 
            +
                        super || @table_proxy&.respond_to?(method_name, *args, &block)
         | 
| 152 | 
            +
                      end
         | 
| 153 | 
            +
                    end
         | 
| 154 | 
            +
                    
         | 
| 155 | 
            +
                    def page_count
         | 
| 156 | 
            +
                      (model_array && (model_array.count / per_page.to_f).ceil) || 0
         | 
| 157 | 
            +
                    end
         | 
| 158 | 
            +
                    
         | 
| 159 | 
            +
                    def corrected_page(initial_page_value = nil)
         | 
| 160 | 
            +
                      correct_page = initial_page_value || page
         | 
| 161 | 
            +
                      correct_page = [correct_page, page_count].min
         | 
| 162 | 
            +
                      correct_page = [correct_page, 1].max
         | 
| 163 | 
            +
                      correct_page = (model_array&.count.to_i > 0) ? (correct_page > 0 ? correct_page : 1) : 0
         | 
| 164 | 
            +
                      correct_page
         | 
| 165 | 
            +
                    end
         | 
| 166 | 
            +
                    
         | 
| 167 | 
            +
                    def first_page
         | 
| 168 | 
            +
                      (model_array&.count.to_i > 0) ? 1 : 0
         | 
| 169 | 
            +
                    end
         | 
| 170 | 
            +
                    
         | 
| 171 | 
            +
                    def last_page
         | 
| 172 | 
            +
                      page_count
         | 
| 173 | 
            +
                    end
         | 
| 174 | 
            +
                    
         | 
| 175 | 
            +
                    def paginate
         | 
| 176 | 
            +
                      self.page = corrected_page(page)
         | 
| 177 | 
            +
                      self.refined_model_array = model_array[(page - 1) * per_page, per_page]
         | 
| 178 | 
            +
                    end
         | 
| 179 | 
            +
                  end
         | 
| 180 | 
            +
                end
         | 
| 181 | 
            +
              end
         | 
| 182 | 
            +
            end
         | 
| @@ -246,7 +246,9 @@ module Glimmer | |
| 246 246 | 
             
                  end
         | 
| 247 247 |  | 
| 248 248 | 
             
                  attr_reader :table_editor, :table_editor_widget_proxy, :sort_property, :sort_direction, :sort_block, :sort_type, :sort_by_block, :additional_sort_properties, :editor, :editable
         | 
| 249 | 
            -
                   | 
| 249 | 
            +
                  attr_writer :column_properties
         | 
| 250 | 
            +
                  attr_accessor :table_items_binding
         | 
| 251 | 
            +
                  alias column_attributes= column_properties=
         | 
| 250 252 | 
             
                  alias editable? editable
         | 
| 251 253 |  | 
| 252 254 | 
             
                  def initialize(underscored_widget_name, parent, args)
         | 
| @@ -258,6 +260,19 @@ module Glimmer | |
| 258 260 | 
             
                    @table_editor.minimumHeight = 20
         | 
| 259 261 | 
             
                    self.editable = editable_style
         | 
| 260 262 | 
             
                  end
         | 
| 263 | 
            +
                  
         | 
| 264 | 
            +
                  def column_properties
         | 
| 265 | 
            +
                    if @column_properties.nil?
         | 
| 266 | 
            +
                      swt_widget.columns.to_a.map(&:text).map(&:underscore)
         | 
| 267 | 
            +
                    elsif @column_properties.is_a?(Hash)
         | 
| 268 | 
            +
                      @column_properties = swt_widget.columns.to_a.map(&:text).map do |column_name|
         | 
| 269 | 
            +
                        @column_properties[column_name] || column_name.underscore
         | 
| 270 | 
            +
                      end
         | 
| 271 | 
            +
                    else
         | 
| 272 | 
            +
                      @column_properties
         | 
| 273 | 
            +
                    end
         | 
| 274 | 
            +
                  end
         | 
| 275 | 
            +
                  alias column_attributes column_properties
         | 
| 261 276 |  | 
| 262 277 | 
             
                  def items
         | 
| 263 278 | 
             
                    auto_exec do
         | 
| @@ -159,7 +159,8 @@ module Glimmer | |
| 159 159 | 
             
                        @parent_proxy = parent
         | 
| 160 160 | 
             
                        styles, extra_options = extract_args(underscored_widget_name, args)
         | 
| 161 161 | 
             
                        swt_widget_class = self.class.swt_widget_class_for(underscored_widget_name)
         | 
| 162 | 
            -
                         | 
| 162 | 
            +
                        swt_widget_producer = @parent_proxy.respond_to?(:children_owner) ? @parent_proxy.children_owner : @parent_proxy
         | 
| 163 | 
            +
                        @swt_widget = swt_widget_class.new(swt_widget_producer.swt_widget, style(underscored_widget_name, styles), *extra_options)
         | 
| 163 164 | 
             
                      else
         | 
| 164 165 | 
             
                        @swt_widget = swt_widget
         | 
| 165 166 | 
             
                        underscored_widget_name = self.class.underscored_widget_name(@swt_widget)
         | 
| @@ -769,6 +770,10 @@ module Glimmer | |
| 769 770 | 
             
                      end
         | 
| 770 771 | 
             
                    end
         | 
| 771 772 | 
             
                  end
         | 
| 773 | 
            +
                  
         | 
| 774 | 
            +
                  def widget_bindings
         | 
| 775 | 
            +
                    @widget_bindings ||= []
         | 
| 776 | 
            +
                  end
         | 
| 772 777 |  | 
| 773 778 | 
             
                  def content(&block)
         | 
| 774 779 | 
             
                    auto_exec do
         | 
| @@ -122,7 +122,7 @@ class ContactManager | |
| 122 122 | 
             
                      }
         | 
| 123 123 | 
             
                    }
         | 
| 124 124 |  | 
| 125 | 
            -
                    table(:editable, : | 
| 125 | 
            +
                    table(:editable, :border) { |table_proxy|
         | 
| 126 126 | 
             
                      layout_data {
         | 
| 127 127 | 
             
                        horizontal_alignment :fill
         | 
| 128 128 | 
             
                        vertical_alignment :fill
         | 
| @@ -144,7 +144,7 @@ class ContactManager | |
| 144 144 | 
             
                        width 200
         | 
| 145 145 | 
             
                      }
         | 
| 146 146 |  | 
| 147 | 
            -
                      items <=> [@contact_manager_presenter, :results | 
| 147 | 
            +
                      items <=> [@contact_manager_presenter, :results]
         | 
| 148 148 |  | 
| 149 149 | 
             
                      on_mouse_up do |event|
         | 
| 150 150 | 
             
                        table_proxy.edit_table_item(event.table_item, event.column_index)
         | 
| @@ -41,9 +41,11 @@ class Sample | |
| 41 41 |  | 
| 42 42 | 
             
                def ensure_user_glimmer_directory
         | 
| 43 43 | 
             
                  unless @ensured_glimmer_directory
         | 
| 44 | 
            -
                     | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 44 | 
            +
                    Thread.new do
         | 
| 45 | 
            +
                      FileUtils.rm_rf(user_glimmer_directory)
         | 
| 46 | 
            +
                      FileUtils.cp_r(glimmer_directory, user_glimmer_directory)
         | 
| 47 | 
            +
                      @ensured_glimmer_directory = true
         | 
| 48 | 
            +
                    end
         | 
| 47 49 | 
             
                  end
         | 
| 48 50 | 
             
                end
         | 
| 49 51 |  | 
| @@ -123,11 +125,11 @@ class Sample | |
| 123 125 | 
             
              end
         | 
| 124 126 |  | 
| 125 127 | 
             
              def file_relative_path
         | 
| 126 | 
            -
                file.sub( | 
| 128 | 
            +
                file.sub(Sample.glimmer_directory, '')
         | 
| 127 129 | 
             
              end
         | 
| 128 130 |  | 
| 129 131 | 
             
              def user_file
         | 
| 130 | 
            -
                File.join( | 
| 132 | 
            +
                File.join(Sample.user_glimmer_directory, file_relative_path)
         | 
| 131 133 | 
             
              end
         | 
| 132 134 |  | 
| 133 135 | 
             
              def user_file_parent_directory
         | 
| @@ -209,10 +211,10 @@ class SampleDirectory | |
| 209 211 | 
             
                  @samples.each do |sample|
         | 
| 210 212 | 
             
                    observe(sample, :selected) do |new_selected_value|
         | 
| 211 213 | 
             
                      if new_selected_value
         | 
| 212 | 
            -
                         | 
| 214 | 
            +
                        SampleDirectory.all_samples.reject {|a_sample| a_sample.name == sample.name}.each do |other_sample|
         | 
| 213 215 | 
             
                          other_sample.selected = false
         | 
| 214 216 | 
             
                        end
         | 
| 215 | 
            -
                         | 
| 217 | 
            +
                        SampleDirectory.selected_sample = sample
         | 
| 216 218 | 
             
                      end
         | 
| 217 219 | 
             
                    end
         | 
| 218 220 | 
             
                  end
         | 
| @@ -227,8 +229,8 @@ class SampleDirectory | |
| 227 229 | 
             
              def selected_sample_name=(selected_name)
         | 
| 228 230 | 
             
                @selected_sample_name = selected_name
         | 
| 229 231 | 
             
                unless selected_name.nil?
         | 
| 230 | 
            -
                  ( | 
| 231 | 
            -
                   | 
| 232 | 
            +
                  (SampleDirectory.sample_directories - [self]).each { |sample_dir| sample_dir.selected_sample_name = nil }
         | 
| 233 | 
            +
                  SampleDirectory.selected_sample = samples.detect { |sample| sample.name == @selected_sample_name }
         | 
| 232 234 | 
             
                end
         | 
| 233 235 | 
             
              end
         | 
| 234 236 |  | 
| @@ -157,19 +157,19 @@ class HelloCustomShell | |
| 157 157 | 
             
                    layout_data :fill, :fill, true, true
         | 
| 158 158 |  | 
| 159 159 | 
             
                    table_column {
         | 
| 160 | 
            -
                      text 'Date | 
| 160 | 
            +
                      text 'Date'
         | 
| 161 161 | 
             
                      width 180
         | 
| 162 162 | 
             
                    }
         | 
| 163 163 | 
             
                    table_column {
         | 
| 164 | 
            -
                      text 'Subject | 
| 164 | 
            +
                      text 'Subject'
         | 
| 165 165 | 
             
                      width 180
         | 
| 166 166 | 
             
                    }
         | 
| 167 167 | 
             
                    table_column {
         | 
| 168 | 
            -
                      text 'From | 
| 168 | 
            +
                      text 'From'
         | 
| 169 169 | 
             
                      width 360
         | 
| 170 170 | 
             
                    }
         | 
| 171 171 |  | 
| 172 | 
            -
                    items <=> [@email_system, :emails | 
| 172 | 
            +
                    items <=> [@email_system, :emails]
         | 
| 173 173 | 
             
                    selection <=> [@email_system, :selected_email]
         | 
| 174 174 |  | 
| 175 175 | 
             
                    on_mouse_up do |event|
         | 
| @@ -0,0 +1,159 @@ | |
| 1 | 
            +
            # Copyright (c) 2007-2022 Andy Maleh
         | 
| 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.
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            require 'glimmer-dsl-swt'
         | 
| 23 | 
            +
            require 'date'
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            class HelloRefinedTable
         | 
| 26 | 
            +
              BaseballTeam = Struct.new(:name, :town, :ballpark, keyword_init: true) do
         | 
| 27 | 
            +
                class << self
         | 
| 28 | 
            +
                  def all
         | 
| 29 | 
            +
                    @all ||= [
         | 
| 30 | 
            +
                      {town: 'Chicago', name: 'White Sox', ballpark: 'Guaranteed Rate Field'},
         | 
| 31 | 
            +
                      {town: 'Cleveland', name: 'Indians', ballpark: 'Progressive Field'},
         | 
| 32 | 
            +
                      {town: 'Detroit', name: 'Tigers', ballpark: 'Comerica Park'},
         | 
| 33 | 
            +
                      {town: 'Kansas City', name: 'Royals', ballpark: 'Kauffman Stadium'},
         | 
| 34 | 
            +
                      {town: 'Minnesota', name: 'Twins', ballpark: 'Target Field'},
         | 
| 35 | 
            +
                      {town: 'Baltimore', name: 'Orioles', ballpark: 'Oriole Park at Camden Yards'},
         | 
| 36 | 
            +
                      {town: 'Boston', name: 'Red Sox', ballpark: 'Fenway Park'},
         | 
| 37 | 
            +
                      {town: 'New York', name: 'Yankees', ballpark: 'Comerica Park'},
         | 
| 38 | 
            +
                      {town: 'Tampa Bay', name: 'Rays', ballpark: 'Tropicana Field'},
         | 
| 39 | 
            +
                      {town: 'Toronto', name: 'Blue Jays', ballpark: 'Rogers Centre'},
         | 
| 40 | 
            +
                      {town: 'Houston', name: 'Astros', ballpark: 'Minute Maid Park'},
         | 
| 41 | 
            +
                      {town: 'Los Angeles', name: 'Angels', ballpark: 'Angel Stadium'},
         | 
| 42 | 
            +
                      {town: 'Oakland', name: 'Athletics', ballpark: 'RingCentral Coliseum'},
         | 
| 43 | 
            +
                      {town: 'Seattle', name: 'Mariners', ballpark: 'T-Mobile Park'},
         | 
| 44 | 
            +
                      {town: 'Texas', name: 'Rangers', ballpark: 'Globe Life Field'},
         | 
| 45 | 
            +
                      {town: 'Chicago', name: 'Cubs', ballpark: 'Wrigley Field'},
         | 
| 46 | 
            +
                      {town: 'Cincinnati', name: 'Reds', ballpark: 'Great American Ball Park'},
         | 
| 47 | 
            +
                      {town: 'Milwaukee', name: 'Brewers', ballpark: 'American Family Field'},
         | 
| 48 | 
            +
                      {town: 'Pittsburgh', name: 'Pirates', ballpark: 'PNC Park'},
         | 
| 49 | 
            +
                      {town: 'St. Louis', name: 'Cardinals', ballpark: 'Busch Stadium'},
         | 
| 50 | 
            +
                      {town: 'Atlanta', name: 'Braves', ballpark: 'Truist Park'},
         | 
| 51 | 
            +
                      {town: 'Miami', name: 'Marlins', ballpark: 'LoanDepot Park'},
         | 
| 52 | 
            +
                      {town: 'New York', name: 'Mets', ballpark: 'Citi Field'},
         | 
| 53 | 
            +
                      {town: 'Philadelphia', name: 'Phillies', ballpark: 'Citizens Bank Park'},
         | 
| 54 | 
            +
                      {town: 'Washington', name: 'Nationals', ballpark: 'Nationals Park'},
         | 
| 55 | 
            +
                      {town: 'Arizona', name: 'Diamondbacks', ballpark: 'Chase Field'},
         | 
| 56 | 
            +
                      {town: 'Colorado', name: 'Rockies', ballpark: 'Coors Field'},
         | 
| 57 | 
            +
                      {town: 'Los Angeles', name: 'Dodgers', ballpark: 'Dodger Stadium'},
         | 
| 58 | 
            +
                      {town: 'San Diego', name: 'Padres', ballpark: 'Petco Park'},
         | 
| 59 | 
            +
                      {town: 'San Francisco', name: 'Giants', ballpark: 'Oracle Park'},
         | 
| 60 | 
            +
                    ].map {|team_kwargs| new(team_kwargs)}
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
                
         | 
| 64 | 
            +
                def complete_name
         | 
| 65 | 
            +
                  "#{town} #{name}"
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
              end
         | 
| 68 | 
            +
                
         | 
| 69 | 
            +
              BaseballGame = Struct.new(:date, :home_team, :away_team, keyword_init: true) do
         | 
| 70 | 
            +
                def home_team_name
         | 
| 71 | 
            +
                  home_team.complete_name
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
                
         | 
| 74 | 
            +
                def away_team_name
         | 
| 75 | 
            +
                  away_team.complete_name
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
                
         | 
| 78 | 
            +
                def ballpark
         | 
| 79 | 
            +
                  home_team.ballpark
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
              
         | 
| 83 | 
            +
              BaseballSeason = Struct.new(:year) do
         | 
| 84 | 
            +
                def games
         | 
| 85 | 
            +
                  if @games.nil?
         | 
| 86 | 
            +
                    @games = []
         | 
| 87 | 
            +
                    baseball_team_combinations = BaseballTeam.all.combination(2).to_a
         | 
| 88 | 
            +
                    current_day = first_day
         | 
| 89 | 
            +
                    day_offset = 0
         | 
| 90 | 
            +
                    begin
         | 
| 91 | 
            +
                      if (day_offset % 7 != 6)
         | 
| 92 | 
            +
                        day_games = []
         | 
| 93 | 
            +
                        half_teams_count = BaseballTeam.all.count / 2
         | 
| 94 | 
            +
                        while day_games.uniq.count < half_teams_count
         | 
| 95 | 
            +
                          baseball_team_pair = baseball_team_combinations.sample
         | 
| 96 | 
            +
                          teams_played_so_far = day_games.map {|game| [game.home_team, game.away_team]}.flatten
         | 
| 97 | 
            +
                          unless teams_played_so_far.include?(baseball_team_pair.first) || teams_played_so_far.include?(baseball_team_pair.last)
         | 
| 98 | 
            +
                            baseball_game = BaseballGame.new(
         | 
| 99 | 
            +
                              date: current_day,
         | 
| 100 | 
            +
                              home_team: baseball_team_pair.first,
         | 
| 101 | 
            +
                              away_team: baseball_team_pair.last,
         | 
| 102 | 
            +
                            )
         | 
| 103 | 
            +
                            day_games << baseball_game
         | 
| 104 | 
            +
                            @games << baseball_game
         | 
| 105 | 
            +
                          end
         | 
| 106 | 
            +
                        end
         | 
| 107 | 
            +
                      end
         | 
| 108 | 
            +
                      day_offset += 1
         | 
| 109 | 
            +
                      current_day += 1
         | 
| 110 | 
            +
                    end while current_day != first_day_of_playoffs
         | 
| 111 | 
            +
                  end
         | 
| 112 | 
            +
                  @games
         | 
| 113 | 
            +
                end
         | 
| 114 | 
            +
                
         | 
| 115 | 
            +
                def first_day
         | 
| 116 | 
            +
                  @first_day ||= Date.new(year, 04, 01)
         | 
| 117 | 
            +
                end
         | 
| 118 | 
            +
                
         | 
| 119 | 
            +
                def first_day_of_playoffs
         | 
| 120 | 
            +
                  @last_day ||= Date.new(year, 10, 01)
         | 
| 121 | 
            +
                end
         | 
| 122 | 
            +
              end
         | 
| 123 | 
            +
              
         | 
| 124 | 
            +
              include Glimmer::UI::Application
         | 
| 125 | 
            +
              
         | 
| 126 | 
            +
              before_body do
         | 
| 127 | 
            +
                @baseball_season = BaseballSeason.new(Time.now.year)
         | 
| 128 | 
            +
              end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
              body {
         | 
| 131 | 
            +
                shell {
         | 
| 132 | 
            +
                  text 'Hello, Refined Table!'
         | 
| 133 | 
            +
                
         | 
| 134 | 
            +
                  refined_table(per_page: 20) { # also `page: 1` by default
         | 
| 135 | 
            +
                    table_column {
         | 
| 136 | 
            +
                      width 100
         | 
| 137 | 
            +
                      text 'Date'
         | 
| 138 | 
            +
                    }
         | 
| 139 | 
            +
                    table_column {
         | 
| 140 | 
            +
                      width 200
         | 
| 141 | 
            +
                      text 'Ballpark'
         | 
| 142 | 
            +
                    }
         | 
| 143 | 
            +
                    table_column {
         | 
| 144 | 
            +
                      width 150
         | 
| 145 | 
            +
                      text 'Home Team'
         | 
| 146 | 
            +
                    }
         | 
| 147 | 
            +
                    table_column {
         | 
| 148 | 
            +
                      width 150
         | 
| 149 | 
            +
                      text 'Away Team'
         | 
| 150 | 
            +
                    }
         | 
| 151 | 
            +
                    
         | 
| 152 | 
            +
                    model_array <= [@baseball_season, :games, column_attributes: {'Home Team' => :home_team_name, 'Away Team' => :away_team_name}]
         | 
| 153 | 
            +
                  }
         | 
| 154 | 
            +
                }
         | 
| 155 | 
            +
              }
         | 
| 156 | 
            +
             | 
| 157 | 
            +
            end
         | 
| 158 | 
            +
             | 
| 159 | 
            +
            HelloRefinedTable.launch
         | 
| @@ -302,15 +302,16 @@ class HelloTable | |
| 302 302 | 
             
                    }
         | 
| 303 303 |  | 
| 304 304 | 
             
                    # Data-bind table items (rows) to a model collection (BaseballGame.schedule),
         | 
| 305 | 
            -
                    #  | 
| 306 | 
            -
                    #  | 
| 307 | 
            -
                    # | 
| 308 | 
            -
                    #  | 
| 305 | 
            +
                    # automatically inferring model attributes from column names by convention
         | 
| 306 | 
            +
                    # (e.g. 'Home Team' column assumes a `home_team` attribute on models)
         | 
| 307 | 
            +
                    #
         | 
| 308 | 
            +
                    # By convention, every inferred model attribute can be accompanied by extra
         | 
| 309 | 
            +
                    # model attributes to set extra table properties with the following suffixes:
         | 
| 310 | 
            +
                    # `_background`, `_foreground`, `_font`, and `_image`
         | 
| 311 | 
            +
                    #
         | 
| 312 | 
            +
                    # For example, for :game_date, model could also implement these related properties:
         | 
| 309 313 | 
             
                    # `game_date_background`, `game_date_foreground`, `game_date_font`, `game_date_image`
         | 
| 310 | 
            -
                     | 
| 311 | 
            -
                    items <=> [BaseballGame, :schedule,
         | 
| 312 | 
            -
                                column_properties: [:game_date, :game_time, :ballpark, :home_team, :away_team, :promotion]
         | 
| 313 | 
            -
                              ]
         | 
| 314 | 
            +
                    items <=> [BaseballGame, :schedule]
         | 
| 314 315 |  | 
| 315 316 | 
             
                    # Data-bind table selection
         | 
| 316 317 | 
             
                    selection <=> [BaseballGame, :selected_game]
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: glimmer-dsl-swt
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 4.24. | 
| 4 | 
            +
              version: 4.24.4.1
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Andy Maleh
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2022-08 | 
| 11 | 
            +
            date: 2022-09-08 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -344,17 +344,17 @@ dependencies: | |
| 344 344 | 
             
                    version: 0.14.1.cr2
         | 
| 345 345 | 
             
            description: Glimmer DSL for SWT (JRuby Desktop Development GUI Framework) is a native-GUI
         | 
| 346 346 | 
             
              cross-platform desktop development library written in JRuby, an OS-threaded faster
         | 
| 347 | 
            -
              JVM version of Ruby. It includes SWT 4. | 
| 348 | 
            -
               | 
| 349 | 
            -
               | 
| 350 | 
            -
               | 
| 351 | 
            -
               | 
| 352 | 
            -
               | 
| 353 | 
            -
               | 
| 354 | 
            -
               | 
| 355 | 
            -
               | 
| 356 | 
            -
               | 
| 357 | 
            -
               | 
| 347 | 
            +
              JVM version of Ruby. It includes SWT 4.24 (released June 7, 2022). Glimmer's main
         | 
| 348 | 
            +
              innovation is a declarative Ruby DSL that enables productive and efficient authoring
         | 
| 349 | 
            +
              of desktop application user-interfaces by relying on the robust Eclipse SWT library.
         | 
| 350 | 
            +
              Glimmer additionally innovates by having built-in data-binding support, which greatly
         | 
| 351 | 
            +
              facilitates synchronizing the GUI with domain models, thus achieving true decoupling
         | 
| 352 | 
            +
              of object oriented components and enabling developers to solve business problems
         | 
| 353 | 
            +
              (test-first) without worrying about GUI concerns, or alternatively drive development
         | 
| 354 | 
            +
              GUI-first, and then write clean business models (test-first) afterwards. Not only
         | 
| 355 | 
            +
              does Glimmer provide a large set of GUI widgets, but it also supports drawing Canvas
         | 
| 356 | 
            +
              Graphics like Shapes and Animations. To get started quickly, Glimmer offers scaffolding
         | 
| 357 | 
            +
              options for Apps, Gems, and Custom Widgets. Glimmer also includes native-executable
         | 
| 358 358 | 
             
              packaging support, sorely lacking in other libraries, thus enabling the delivery
         | 
| 359 359 | 
             
              of desktop apps written in Ruby as truly native DMG/PKG/APP files on the Mac, MSI/EXE
         | 
| 360 360 | 
             
              files on Windows, and DEB/RPM files on Linux. Glimmer was the first Ruby gem to
         | 
| @@ -472,6 +472,7 @@ files: | |
| 472 472 | 
             
            - lib/glimmer/swt/custom/code_text.rb
         | 
| 473 473 | 
             
            - lib/glimmer/swt/custom/drawable.rb
         | 
| 474 474 | 
             
            - lib/glimmer/swt/custom/radio_group.rb
         | 
| 475 | 
            +
            - lib/glimmer/swt/custom/refined_table.rb
         | 
| 475 476 | 
             
            - lib/glimmer/swt/custom/shape.rb
         | 
| 476 477 | 
             
            - lib/glimmer/swt/custom/shape/arc.rb
         | 
| 477 478 | 
             
            - lib/glimmer/swt/custom/shape/cubic.rb
         | 
| @@ -670,6 +671,7 @@ files: | |
| 670 671 | 
             
            - samples/hello/hello_progress_bar.rb
         | 
| 671 672 | 
             
            - samples/hello/hello_radio.rb
         | 
| 672 673 | 
             
            - samples/hello/hello_radio_group.rb
         | 
| 674 | 
            +
            - samples/hello/hello_refined_table.rb
         | 
| 673 675 | 
             
            - samples/hello/hello_sash_form.rb
         | 
| 674 676 | 
             
            - samples/hello/hello_scale.rb
         | 
| 675 677 | 
             
            - samples/hello/hello_scrolled_composite.rb
         |