Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ GuiInteraction enables standalone Groovy applications to have the same user inte

```groovy
dependencies {
implementation 'se.alipsa.gi:gi-swing:0.4.0' // or gi-fx, gi-console
implementation 'se.alipsa.gi:gi-swing:0.4.1' // or gi-fx, gi-console
}
```

Expand All @@ -40,14 +40,14 @@ dependencies {
<dependency>
<groupId>se.alipsa.gi</groupId>
<artifactId>gi-swing</artifactId>
<version>0.4.0</version>
<version>0.4.1</version>
</dependency>
```

### Groovy Script with Grape

```groovy
@Grab(group:'se.alipsa.gi', module:'gi-swing', version:'0.4.0')
@Grab('se.alipsa.gi:gi-swing:0.4.1')
import se.alipsa.gi.swing.InOut

def io = new InOut()
Expand All @@ -57,14 +57,17 @@ println("File chosen was $file")

## Gade Compatibility

Scripts can run both in Gade and standalone by checking for the `io` variable:
Scripts can run both in Gade and standalone by checking for the `io` variable.
The dependency is loaded only when Gade has not already supplied `io`:

```groovy
import static groovy.grape.Grape.grab

// This makes the code run equally in Gade and in a standalone Groovy script
if (!binding.hasVariable('io')) {
@Grab(group:'se.alipsa.gi', module:'gi-swing', version:'0.4.0')
import se.alipsa.gi.swing.InOut
binding.setVariable('io', new InOut())
grab(group: 'se.alipsa.gi', module: 'gi-swing', version: '0.4.1')
def inOutClass = this.class.classLoader.loadClass('se.alipsa.gi.swing.InOut')
binding.setVariable('io', inOutClass.newInstance())
}

def file = io.chooseFile("Choose a file", ".", "Pick a file please!")
Expand All @@ -81,6 +84,9 @@ println("File chosen was $file")

## Building from Source

Install a JDK 21 toolchain before building. Gradle uses that toolchain even if
the Gradle daemon runs on a newer JDK.

```bash
./gradlew build
```
Expand Down Expand Up @@ -109,7 +115,7 @@ refresh needs an API key and can be rate limited; it is not a PR gate. Run

## Requirements

- JDK 21 or later
- Java 21 or later to use the published libraries; JDK 21 to build from source
- For gi-fx: JDK with JavaFX support (e.g., BellSoft Liberica Full JDK)

## License
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ plugins {
}

group = 'se.alipsa.gi'
version = '0.4.1-SNAPSHOT'
version = '0.4.1'
description = 'Allows Gade Gui Interactive capabilities from a standalone app'

java {
Expand Down
15 changes: 9 additions & 6 deletions docs/API-Guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ This guide provides usage examples for the GuiInteraction library.

```groovy
// Using Grape for dependency resolution
@Grab(group:'se.alipsa.gi', module:'gi-swing', version:'0.4.0')
@Grab('se.alipsa.gi:gi-swing:0.4.1')
import se.alipsa.gi.swing.InOut

def io = new InOut()
Expand All @@ -26,7 +26,7 @@ Or in your `build.gradle`:

```groovy
dependencies {
implementation 'se.alipsa.gi:gi-swing:0.4.0'
implementation 'se.alipsa.gi:gi-swing:0.4.1'
}
```

Expand Down Expand Up @@ -326,14 +326,17 @@ assert FileUtils.baseName("/tmp/report#2.pdf") == "report#2.pdf"

## Gade Compatibility

The library is designed to be compatible with [Gade](https://github.com/Alipsa/gade). Scripts can detect the environment:
The library is designed to be compatible with [Gade](https://github.com/Alipsa/gade).
Scripts can detect the environment and load gi-swing only when `io` is absent:

```groovy
import static groovy.grape.Grape.grab

// Check if running in Gade or standalone
if (!binding.hasVariable('io')) {
@Grab(group:'se.alipsa.gi', module:'gi-swing', version:'0.4.0')
import se.alipsa.gi.swing.InOut
binding.setVariable('io', new InOut())
grab(group: 'se.alipsa.gi', module: 'gi-swing', version: '0.4.1')
def inOutClass = this.class.classLoader.loadClass('se.alipsa.gi.swing.InOut')
binding.setVariable('io', inOutClass.newInstance())
}

// Now 'io' works the same in both Gade and standalone
Expand Down
16 changes: 9 additions & 7 deletions docs/DEPENDENCIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ The core module includes these key dependencies:
### gi-fx, gi-swing, gi-console

UI modules add minimal additional dependencies:
- **gi-fx**: JavaFX (provided by JVM), YearMonthPicker
- **gi-swing**: Batik (SVG), LGoodDatePicker, Swing YearMonthPicker
- **gi-fx**: JavaFX (supplied by the JDK or consumer), fx-yearmonth-picker
- **gi-swing**: swing-widgets (date and year-month pickers); SVG rendering uses Matrix Charts from `gi-common`
- **gi-console**: JSoup (HTML parsing)

## Apache Tika Dependency Impact
Expand Down Expand Up @@ -49,9 +49,9 @@ PDFs or Office documents), add the full parser package:

```groovy
dependencies {
implementation 'se.alipsa.gi:gi-common:0.4.0'
implementation 'se.alipsa.gi:gi-common:0.4.1'
// Add full Tika parsers for document content extraction
implementation 'org.apache.tika:tika-parsers-standard-package:3.2.3'
implementation 'org.apache.tika:tika-parsers-standard-package:3.3.2'
}
```

Expand All @@ -64,11 +64,13 @@ This adds support for:

### Fat JAR for Standalone Scripts

The fat JARs (`gi-swing-fatjar`, `gi-fx-fatjar`, etc.) include all dependencies
and are designed for standalone Groovy scripts:
The fat JAR artifacts bundle runtime dependencies but exclude Groovy, which the
consuming application must supply. `gi-fx` also needs JavaFX at runtime, either
from the JDK or as separate dependencies. The artifact classifier is `fatjar`;
disable transitive resolution to avoid loading separate copies of bundled dependencies:

```groovy
@Grab(group:'se.alipsa.gi', module:'gi-swing', version:'0.4.0', classifier:'fatjar')
@Grab(group='se.alipsa.gi', module='gi-swing', version='0.4.1', classifier='fatjar', transitive=false)
import se.alipsa.gi.swing.InOut
```

Expand Down
5 changes: 4 additions & 1 deletion docs/PUBLISHING.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ After releasing:
- [ ] Push tag: `git push origin vX.Y.Z`
- [ ] Create GitHub release: https://github.com/Alipsa/GuiInteraction/releases/new
- [ ] Verify on Maven Central (may take 10-30 minutes): https://central.sonatype.com/search?q=se.alipsa.gi
- [ ] Bump version to next SNAPSHOT for development
- [ ] Immediately bump version to the next SNAPSHOT for development before other changes land on main

## Troubleshooting

Expand Down Expand Up @@ -285,6 +285,9 @@ script generates notes from commit subjects. Both paths are idempotent for a
version already in the changelog, so `--skip` retries do not duplicate notes.
If a retry finds additional curated notes under `## Unreleased`, the script
warns that they are not included in the already-recorded version.
If `release.md` already has a dated heading for the version, the script leaves
that date unchanged. Check it against the actual publication date and re-date
the heading before running a delayed release.

Commit curated notes before running `release.sh`: every release path requires
`release.md` to be clean. SNAPSHOT and `--bump` releases also require clean
Expand Down
2 changes: 1 addition & 1 deletion gi-common/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ See the [API Guide](../docs/API-Guide.md) for detailed usage examples.
<dependency>
<groupId>se.alipsa.gi</groupId>
<artifactId>gi-common</artifactId>
<version>0.4.0</version>
<version>0.4.1</version>
</dependency>
```

Expand Down
12 changes: 6 additions & 6 deletions gi-console/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ This module provides console-based (text mode) interaction capabilities. It's de

```groovy
dependencies {
implementation 'se.alipsa.gi:gi-console:0.4.0'
implementation 'se.alipsa.gi:gi-console:0.4.1'
}
```

Expand All @@ -36,14 +36,14 @@ dependencies {
<dependency>
<groupId>se.alipsa.gi</groupId>
<artifactId>gi-console</artifactId>
<version>0.4.0</version>
<version>0.4.1</version>
</dependency>
```

### Grape (Groovy Script)

```groovy
@Grab(group:'se.alipsa.gi', module:'gi-console', version:'0.4.0')
@Grab('se.alipsa.gi:gi-console:0.4.1')
import se.alipsa.gi.console.InOut

def io = new InOut()
Expand Down Expand Up @@ -76,19 +76,19 @@ io.view("<h1>Hello</h1><p>Welcome!</p>", "Greeting")

## Fat JAR

A fat JAR (with all dependencies bundled) is available:
A fat JAR bundles runtime dependencies; the consuming application supplies Groovy:

```groovy
dependencies {
implementation 'se.alipsa.gi:gi-console:0.4.0:fatjar'
implementation 'se.alipsa.gi:gi-console:0.4.1:fatjar'
}
```

## Limitations

- **Clipboard**: Clipboard access is unavailable in headless environments; clipboard methods log the issue and return `null` or no-op.
- **Password Input**: Uses masked input through `System.console()` when available. In IDEs and some CI environments, it falls back to visible stdin input and logs a warning.
- **Charts/Images**: `display(Chart)` and `display(File)` for images print a message instead of showing graphics
- **Charts/Images**: chart display prints a message instead of showing graphics; `display(File)` asks the desktop application to open an existing file when the platform supports it
- **Swing Components**: `display(JComponent)` is not supported
- **File Choosers**: User manually types file paths instead of browsing

Expand Down
12 changes: 6 additions & 6 deletions gi-fx/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ This module provides JavaFX-based dialogs and viewers for user interaction. It o

## Features

- Native JavaFX dialogs for file/directory selection
- JavaFX dialogs for file/directory selection
- Rich date and year-month pickers with calendar UI
- WebView-based HTML rendering
- Markdown viewing with full formatting support
Expand All @@ -26,7 +26,7 @@ This module provides JavaFX-based dialogs and viewers for user interaction. It o

```groovy
dependencies {
implementation 'se.alipsa.gi:gi-fx:0.4.0'
implementation 'se.alipsa.gi:gi-fx:0.4.1'
}
```

Expand All @@ -36,14 +36,14 @@ dependencies {
<dependency>
<groupId>se.alipsa.gi</groupId>
<artifactId>gi-fx</artifactId>
<version>0.4.0</version>
<version>0.4.1</version>
</dependency>
```

### Grape (Groovy Script)

```groovy
@Grab(group:'se.alipsa.gi', module:'gi-fx', version:'0.4.0')
@Grab('se.alipsa.gi:gi-fx:0.4.1')
import se.alipsa.gi.fx.InOut

def io = new InOut()
Expand Down Expand Up @@ -71,11 +71,11 @@ io.viewMarkdown("# Title\n\nSome **bold** text", "Document")

## Fat JAR

A fat JAR (with all dependencies bundled) is available:
A fat JAR bundles runtime dependencies; the consuming application supplies Groovy and JavaFX:

```groovy
dependencies {
implementation 'se.alipsa.gi:gi-fx:0.4.0:fatjar'
implementation 'se.alipsa.gi:gi-fx:0.4.1:fatjar'
}
```

Expand Down
15 changes: 7 additions & 8 deletions gi-swing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ This module provides Swing-based dialogs and viewers for user interaction. It wo
## Features

- Standard Swing file and directory choosers
- Date and year-month pickers (via LGoodDatePicker)
- Date and year-month pickers via `se.alipsa:swing-widgets`
- HTML viewing via JEditorPane
- Table display with JTable
- Clipboard operations
Expand All @@ -26,7 +26,7 @@ This module provides Swing-based dialogs and viewers for user interaction. It wo

```groovy
dependencies {
implementation 'se.alipsa.gi:gi-swing:0.4.0'
implementation 'se.alipsa.gi:gi-swing:0.4.1'
}
```

Expand All @@ -36,14 +36,14 @@ dependencies {
<dependency>
<groupId>se.alipsa.gi</groupId>
<artifactId>gi-swing</artifactId>
<version>0.4.0</version>
<version>0.4.1</version>
</dependency>
```

### Grape (Groovy Script)

```groovy
@Grab(group:'se.alipsa.gi', module:'gi-swing', version:'0.4.0')
@Grab('se.alipsa.gi:gi-swing:0.4.1')
import se.alipsa.gi.swing.InOut

def io = new InOut()
Expand Down Expand Up @@ -75,11 +75,11 @@ io.view([

## Fat JAR

A fat JAR (with all dependencies bundled) is available:
A fat JAR bundles runtime dependencies; the consuming application supplies Groovy:

```groovy
dependencies {
implementation 'se.alipsa.gi:gi-swing:0.4.0:fatjar'
implementation 'se.alipsa.gi:gi-swing:0.4.1:fatjar'
Comment thread
perNyfelt marked this conversation as resolved.
}
```

Expand All @@ -89,8 +89,7 @@ dependencies {

## Dependencies

- [LGoodDatePicker](https://github.com/LGoodDatePicker/LGoodDatePicker) - Date picker component
- [swing-yearmonth-picker](https://github.com/Alipsa/swing-yearmonth-picker) - Year-month picker
- `se.alipsa:swing-widgets` - Date and year-month picker components

## API Documentation

Expand Down
4 changes: 2 additions & 2 deletions gi-swing/test.gsh
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import static groovy.grape.Grape.grab

if (! binding.hasVariable('io')) {
grab(group:"se.alipsa.gi", module: "gi-swing", version:"0.4.0")
binding.setVariable('io', this.class.classLoader.loadClass("se.alipsa.gi.swing.InOut").getDeclaredConstructor().newInstance())
binding.setVariable('io', this.class.classLoader.loadClass("se.alipsa.gi.swing.InOut").newInstance())
}

def file = io.chooseFile("Choose a file", ".", "Pick a file please!" )
println("File chosen was $file")
println("File chosen was $file")
15 changes: 10 additions & 5 deletions release.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
# Gui Interaction Release Notes

## Unreleased

## 0.4.1 - 2026-09-27
- Fixed (build): pin Java 21 toolchains in all modules; run Spotless and SpotBugs in default builds; scan all modules with `dependencyCheckAggregate`.
- Fixed (build): select JavaFX natives for the Gradle JVM's OS and architecture; unsupported combinations fail when JavaFX dependencies resolve, leaving unrelated tasks available.
- Fixed: console null file names and password EOF no longer throw; null matrix views are guarded and unnamed JavaFX tables use `Table` as their title.
- Fixed (build): select JavaFX natives for the host OS and Java 21 toolchain architecture; unsupported combinations fail when JavaFX dependencies resolve, leaving unrelated tasks available.
- Fixed: console null file names and password EOF no longer throw; null matrix views are guarded and unnamed Swing and JavaFX tables use `Table` as their title.
- Fixed: JavaFX copy shortcut detection uses locale-independent casing, and the redundant `rowsForViewer` helper was removed.
- Fixed (packaging): merge duplicate licence, notice, and dependency metadata in fat JARs.
- Fixed (release): promote curated Unreleased notes, preserve backslashes in commit subjects, handle release retries, and validate version shapes before mutating files.
- Added: debug diagnostics for `urlExists` failures and Windows shell branch coverage with a CI smoke job.
- Build: upgraded Groovy to 5.1.3, Matrix BOM to 2.6.0, CommonMark to 0.30.0, jsoup to 1.23.2, JUnit to 6.1.3, Gradle Versions to 0.64.0, Spotless to 8.10.2, and SpotBugs (plugin/engine) to 6.5.11/4.10.4.
- Added: `urlExists` warnings for unsupported schemes and broken redirects, with debug diagnostics for connection and HTTP failures. Logged URLs redact credentials, including malformed URL paths.
- Added (test): Windows shell execution integration coverage.
- Build: upgraded Groovy to 5.1.3, Matrix BOM to 2.6.0, CommonMark to 0.30.0, jsoup to 1.23.2, JUnit to 6.1.3, Gradle Versions to 0.64.0, Spotless to 8.10.3, and SpotBugs (plugin/engine) to 6.5.12/4.10.4.
- Common: added `sh` and `shell` methods for executing platform shell commands. `sh` returns captured standard output and can stream output while the command runs; `shell` returns a `ShellResult` containing standard output, standard error, exit code, and success status. Both support optional timeouts. These methods execute arbitrary commands and should not receive untrusted input.
- Breaking (packaging): fat JARs are now built with GradleUp Shadow via the `shadowJar` task instead of a hand-rolled `fatJar` task. The published artifact name is unchanged (`<module>-<version>-fatjar.jar`), but the Gradle task is now `shadowJar`.
- Fixed: fat JARs dropped all but the first copy of each `META-INF/services` entry, disabling most ph-css/gsvg service registrations and part of Tika's. Service files are now merged.
Expand All @@ -25,10 +28,12 @@
- Fixed: console `display(File)` called `Desktop.open` without checking that the OPEN action is supported, and threw on a null file. Both are now reported on stdout.
- Fixed: console input now honors `stdin.encoding` (JDK 25+) or the platform console's charset (JDK 17+) instead of always using the JVM default.
- Fixed: `saveToClipboard(File)` wrote `Lost ownership` to stdout when clipboard ownership changed.
- Build: CI now runs `./gradlew check --no-configuration-cache`, which is the only invocation under which Spotless and SpotBugs are applied. The scheduled dependency-check job is reachable again.
- Build: CI builds and tests all modules on Linux and Windows, including Spotless and SpotBugs. The dependency-check job runs on a schedule or by manual dispatch.
- Build: `release.sh` verifies the version was actually written to `build.gradle`, names the modules already published when a release fails partway, validates/explicitly confirms `--skip <module,...>` before resuming without re-publishing them, and rejects `--skip` with `--bump`.
- Fixed: publishing `gi-console`, `gi-fx`, or `gi-swing` failed with "multiple artifacts with the identical extension and classifier" because the Shadow migration both declared the fat-jar artifact explicitly and let Shadow's own publication variant add it. The explicit declaration is removed; Shadow's variant is sufficient.
- Fixed: fat jars now also merge `META-INF/groovy/org.codehaus.groovy.runtime.ExtensionModule`, so bundling multiple Groovy extension-module jars (e.g. `matrix-core` and `matrix-groovy-ext`) no longer silently hides one's extension methods behind the other's.
- Fixed (release): choose the newest installed JavaFX-capable SDKMAN JDK 21 when several versions are available.
- Fixed (test): load the Swing HTML page test from a stable fixture so Windows can complete it without a temporary-file deletion race.

## 0.4.0 - 2026-08-03
- Breaking: `FileUtils.getResourceUrl` returns `null` for paths that do not exist; use `File` for output targets that will be created later.
Expand Down
Loading