{"id":16455290,"url":"https://github.com/cchantep/melasse","last_synced_at":"2025-03-23T10:32:33.578Z","repository":{"id":4424998,"uuid":"5562919","full_name":"cchantep/melasse","owner":"cchantep","description":"Melasse Java MVC glue API","archived":false,"fork":false,"pushed_at":"2024-03-19T15:16:58.000Z","size":217,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-03-19T16:36:58.434Z","etag":null,"topics":["gui","java","mvc","swing"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cchantep.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2012-08-26T19:16:54.000Z","updated_at":"2024-04-15T14:07:18.662Z","dependencies_parsed_at":"2023-07-05T18:01:28.488Z","dependency_job_id":"ad9f79e5-f232-40a1-9d88-e109e13c9d82","html_url":"https://github.com/cchantep/melasse","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cchantep%2Fmelasse","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cchantep%2Fmelasse/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cchantep%2Fmelasse/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cchantep%2Fmelasse/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cchantep","download_url":"https://codeload.github.com/cchantep/melasse/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245090840,"owners_count":20559296,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gui","java","mvc","swing"],"created_at":"2024-10-11T10:21:52.948Z","updated_at":"2025-03-23T10:32:33.258Z","avatar_url":"https://github.com/cchantep.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Melasse\n\nMelasse *glue* framework.\n\n[![CircleCI](https://circleci.com/gh/cchantep/melasse.svg?style=svg)](https://circleci.com/gh/cchantep/melasse)\n\n## Examples\n\nExample application shows how Melasse can be used to declare [UI data bindings](http://en.wikipedia.org/wiki/UI_data_binding).\n\n1. Download [application](https://github.com/cchantep/melasse/releases/download/v1.0/melasse-examples-1.0.jar),\n2. double-click to launch examples.\n\n## Overall\n\nMain usage class is `melasse.Binder`, which prepares UI bindings.\n\n```java\nBinder.bind(/* source, target, options */);\n```\n\n## Object path\n\nSource/observed element and as target/endpoint are specified to Melasse using object paths:\n\n```java\nimport melasse.Binder;\n\nBinder.bind(\"columnModel.columnCount\", aJTable, // observed\n            \"columnCount\", status, // target\n            optionMap);\n```\n\nIn previous example, starting from `aJTable` (not null instance of `JTable`) Melasse will observe change on `columnCount` property of `columnModel`, which is statically equivalent to:\n\n```java\naJTable.getColumnModel().getColumnCount();\n```\n\nUsing its own object path API allows Melasse to observe 'deep' property, which are not directly on the root (there `aJTable`), even if at some point element of the path is null when binding is set up.\n\nIn previous example, even if property `columnModel` of `aJTable` is null when binding is created, as soon as it will be set Melasse will start observing `columnCount` on this newly set property.\n\n### One-to-many\n\nFor some type, it's possible have a one-to-many binding, e.g. Enable action only if all related bindings are evaluated to true. \n\n```java\nimport melasse.Binder;\n\nBinder.bind(\"prop1\", sourceRoot,\n            \"enabled[]\", anAction,\n            optionMap);\n\nBinder.bind(\"prop2\", sourceRoot,\n            \"enabled[]\", anAction,\n            optionMap);\n\n// anAction is enabled only if both bindings are true\n```\n\n### Mediator\n\nMediator factory can be configured either on source or target path, in order to wrap referenced object so that property can be observed or set.\n\n```java\nBindingOptionMap opts = new BindingOptionMap().\n  add(BindingKey.INPUT_MEDIATOR_FACTORY, factoryToWrapSource).\n  add(BindingKey.OUTPUT_MEDIATOR_FACTORY, factoryToWrapTarget);\n```\n\n## Provided transformers\n\n- AppliedTransformer\n- IntegerToBooleanTransformer: Returns false if null or 0.\n- NegateBooleanTransformer\n- NotNullTransformer\n\n## Component\n\n```java\nimport melasse.Binder;\n\nBinder.bind(\"size\", anyAWTComponent, \n            \"targetProp\", target, \n            optionMap);\n```\n\n## Button/action\n\nUI properties transformed as boolean can be bound to activation of button or action using `enabled` property:\n\n```java\nimport melasse.Binder;\n\nBinder.bind(\"sourcePath\", sourceRoot,\n            \"enabled\", anAction,\n            optionMap);\n```\n\n## Text components\n\n```java\nimport melasse.Binder;\n\nBinder.bind(\"text\", textComponent,\n            \"targetPath\", targetRoot,\n            optionMap);\n```\n\n- If `TextBindingKey.CONTINUOUSLY_UPDATE_VALUE` is set: listens to each key event.\n- If `TextBindingKey.CONTINUOUSLY_UPDATE_VALUE` is not set: listens to action event and focus lost event.\n\n\u003e If text component is editable, programmatical call to `setText` [doesn't trigger binding](http://docs.oracle.com/javase/6/docs/api/javax/swing/text/JTextComponent.html#setText%28java.lang.String%29), only changes from UI do.\n\u003e If component is not editable property change will be bound.\n\nMost interesting transformers for text components are:\n\n- StringLengthToBooleanTransformer\n- StringToCharArrayTransformer\n\n### Bind button/action to provided value\n\nEnable button/action only if value is provided to a text component:\n\n```java\nimport melasse.StringLengthToBooleanTransformer;\nimport melasse.BindingOptionMap;\nimport melasse.TextBindingKey;\nimport melasse.Binder;\n\nBinder.bind(\"text\", textComponent,\n            \"enabled\", anAction,\n            new BindingOptionMap().\n            add(BindingKey.INPUT_TRANSFORMER,\n                StringLengthToBooleanTransformer.\n                getTrimmingInstance()).\n                add(TextBindingKey.CONTINUOUSLY_UPDATE_VALUE));\n```\n\n## Numbers\n\nNumeric properties can be bound, from model or from component, with specific options:\n\n```java\nimport melasse.NumericBindingKey;\nimport melasse.BindingOptionMap;\n\nBindingOptionMap opts1 = new BindingOptionMap().\n  add(NumericBindingKey.BIGINTEGER_TO_INTEGER);\n\nBindingOptionMap opts2 = new BindingOptionMap().\n  add(NumericBindingKey.INTEGER_TO_BIGINTEGER);\n```\n\nNumber can also be bound to string using a [format](http://docs.oracle.com/javase/7/docs/api/java/text/MessageFormat.html):\n\n```java\nimport melasse.NumberToStringTransformer;\n\nBinder.bind(\"numberProp\", source, \"text\", aLabel,\n            new BindingOptionMap().add(BindingKey.INPUT_TRANSFORMER,\n                NumberToStringTransformer.\n                getInstance(aJavaTextFormat)));\n```\n\n## Bind error display\n\nVisibility of error can be directly bound using `JLabel.visible` as endpoint.\n\n```java\nJLabel errorDisplay = new JLabel(\"Missing value\");\nJTextField field = new JTextField();\n\n// ... lay out comonents\n\nBinder.bind(\"visible\", errorDisplay, \"text\", field,\n                    new BindingOptionMap().\n                    add(BindingKey.INPUT_TRANSFORMER,\n                        StringLengthToBooleanTransformer.\n                        getTrimmingInstance().negate()).\n                        add(TextBindingKey.CONTINUOUSLY_UPDATE_VALUE));\n// |errorDisplay| will be visible when |field| is empty\n```\n\n## List selection model\n\nMelasse provide a specific support to bind following [list selection](http://docs.oracle.com/javase/7/docs/api/javax/swing/ListSelectionModel.html) properties: `selectionEmpty`, `minSelectionIndex` (first selected index, or -1) and `maxSelectionIndex`.\n\n```java\nimport melasse.NegateBooleanTransformer;\n\nBinder.bind(\"selectionEmpty\", aSelectionModel, \"enabled\", anAction,\n            new BindingOptionMap().add(BindingKey.INPUT_TRANSFORMER,\n              NegateBooleanTransformer.getInstance()));\n```\n\n## Enhanced property change support\n\nAs Melasse can be bound to property change on Java Bean, it also provided an enhanced utility to fire such changes.\n\nThis utility allow to declare dependencies between properties, so that if property B is depending on A, when A is changed there are 2 change events which are fired, first for A and second for B.\n\nThis is also useful to easily generate change event based on several properties. As dependent property can be a computed one, result of computation is fired as change event each time properties it depends on are changed. \n\n## Binding options\n\nWay bindings are set up can be configured providing options, as firth argument of the `bind` method.\n\n- targetModeOptions: When using a read-only property as binding source. Avoid warning such as `Target object does not support setting value for property X: myInstance@123456`.\n\n## Model classes\n\n- `melasse.swing.TableModel`: Change support for properties `rowCount`, `columnCount`, `dataVector`, using new method `.willChange()`.\n\n## AWT/Swing utility\n\n- melasse.QuietWrapAction\n\n## Usage\n\nMelasse can be used in Maven or SBT project using Applicius repository.\n\nFor Maven project:\n\n```xml\n\u003cproject\u003e\n  \u003c!-- ... --\u003e\n  \u003crepositories\u003e\n    \u003c!-- ... --\u003e\n\n    \u003crepository\u003e\n      \u003cid\u003eapplicius-releases\u003c/id\u003e\n      \u003cname\u003eApplicius Maven2 Releases Repository\u003c/name\u003e\n      \u003curl\u003ehttps://raw.github.com/applicius/mvn-repo/master/releases/\u003c/url\u003e\n    \u003c/repository\u003e\n  \u003c/repositories\u003e\n\n  \u003cdependencies\u003e\n    \u003cdependency\u003e\n      \u003cgroupId\u003emelasse\u003c/groupId\u003e\n      \u003cartifactId\u003emelasse-core\u003c/artifactId\u003e\n      \u003cversion\u003eVERSION\u003c/version\u003e\n    \u003c/dependency\u003e\n  \u003c/dependencies\u003e\n\n  \u003c!-- ... --\u003e\n\u003c/project\u003e\n```\n\nFor SBT project:\n\n```scala\nresolvers += \"Applicius Releases\" at \"https://raw.github.com/applicius/mvn-repo/master/releases/\"\n\nlibraryDependencies += \"melasse\" %% \"melasse-core\" % \"VERSION\"\n```\n\n## Build\n\nMelasse is built using Maven 3: \n\n```\n# git clone https://github.com/cchantep/melasse.git\n# cd melasse\n# mvn install\n```\n\nPre-requisites:\n\n- GIT client\n- Maven 3+\n- JDK 1.6+\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcchantep%2Fmelasse","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcchantep%2Fmelasse","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcchantep%2Fmelasse/lists"}