fix: resolve PPD media type and tray option discovery and selection (#1, #2) #3

Merged
gronod merged 1 commits from fix/ppd-media-type-and-tray-options into development 2026-09-07 22:48:18 +01:00
Owner

Summary

This PR resolves both open issues:

  • Issue #1: Media type selection box displays numeric PPD choice codes instead of human-readable driver names
  • Issue #2: Tray selection picklist is empty due to empty-array coalescing bug and missing vendor PPD keywords (Epson/Canon)

Changes

  1. Core Models & PPD Parsing (CUPSManager.swift):

    • Added struct PPDChoice: Equatable, Hashable storing both internal name (e.g. "13") and human-readable title (e.g. "Epson Premium Glossy").
    • Implemented decodePPDString(_:) for PPD hex character escape decoding (CD<2F>DVD -> CD/DVD, <2E> -> ., etc.).
    • Added optionDetails(in:keyword:) to parse choice names and localized display titles, stripping quotes and decoding escapes.
    • Added dynamic keyword & choice discovery:
      • Media types: checks MediaType, CNIJMediaType (Canon), and scans *OpenUI for /Media Type.
      • Paper sources: checks InputSlot, EPIJ_FdSo (Epson), CNIJMediaSupply (Canon), and scans *OpenUI for /Paper Source, /Media Source, etc.
    • Updated PrinterQueue and PPDOptions to expose structured choices and discovered keywords.
  2. Inspector UI (InspectorView.swift):

    • Fixed the Swift nil-coalescing empty array bug: (q?.trayChoices.isEmpty == false) ? q!.trayChoices : [PPDChoice(name: "Auto", title: "Auto")] and (q?.mediaTypeChoices.isEmpty == false) ? q!.mediaTypeChoices : [PPDChoice(name: "Plain", title: "Plain")].
    • Added refillChoices and selectChoice to populate dropdowns with display titles while setting NSMenuItem.representedObject to the computer-readable choice code.
    • Updated push(into engine:) to retrieve representedObject so underlying choice codes are passed into PrintEngine.
  3. Print Engine (PrintEngine.swift):

    • Updated applyOptionalPPDKeys(to:queue:) to use the queue's discovered vendor keywords (mediaTypeKeyword and trayKeyword).
    • Added dual-identity resolution so jobs specifying either display titles or internal choice codes correctly resolve to the expected PPD choice code.
  4. Testing (Tests/, TargetPrint.xcodeproj):

    • Added Tests/PPDOptionsTests.swift covering hex decoding, Epson/Canon/Standard PPD parsing, fallback behaviors, and PrintEngine resolution.
    • Added Tests/TestRunnerMain.swift and Scripts/test_runner.sh for complete automated testing under Command Line Tools.
    • Registered PPDOptionsTests.swift in TargetPrint.xcodeproj/project.pbxproj.

Closes #1
Closes #2

### Summary This PR resolves both open issues: - **Issue #1**: Media type selection box displays numeric PPD choice codes instead of human-readable driver names - **Issue #2**: Tray selection picklist is empty due to empty-array coalescing bug and missing vendor PPD keywords (Epson/Canon) ### Changes 1. **Core Models & PPD Parsing (`CUPSManager.swift`)**: - Added `struct PPDChoice: Equatable, Hashable` storing both internal `name` (e.g. `"13"`) and human-readable `title` (e.g. `"Epson Premium Glossy"`). - Implemented `decodePPDString(_:)` for PPD hex character escape decoding (`CD<2F>DVD` -> `CD/DVD`, `<2E>` -> `.`, etc.). - Added `optionDetails(in:keyword:)` to parse choice names and localized display titles, stripping quotes and decoding escapes. - Added dynamic keyword & choice discovery: - Media types: checks `MediaType`, `CNIJMediaType` (Canon), and scans `*OpenUI` for `/Media Type`. - Paper sources: checks `InputSlot`, `EPIJ_FdSo` (Epson), `CNIJMediaSupply` (Canon), and scans `*OpenUI` for `/Paper Source`, `/Media Source`, etc. - Updated `PrinterQueue` and `PPDOptions` to expose structured choices and discovered keywords. 2. **Inspector UI (`InspectorView.swift`)**: - Fixed the Swift nil-coalescing empty array bug: `(q?.trayChoices.isEmpty == false) ? q!.trayChoices : [PPDChoice(name: "Auto", title: "Auto")]` and `(q?.mediaTypeChoices.isEmpty == false) ? q!.mediaTypeChoices : [PPDChoice(name: "Plain", title: "Plain")]`. - Added `refillChoices` and `selectChoice` to populate dropdowns with display titles while setting `NSMenuItem.representedObject` to the computer-readable choice code. - Updated `push(into engine:)` to retrieve `representedObject` so underlying choice codes are passed into `PrintEngine`. 3. **Print Engine (`PrintEngine.swift`)**: - Updated `applyOptionalPPDKeys(to:queue:)` to use the queue's discovered vendor keywords (`mediaTypeKeyword` and `trayKeyword`). - Added dual-identity resolution so jobs specifying either display titles or internal choice codes correctly resolve to the expected PPD choice code. 4. **Testing (`Tests/`, `TargetPrint.xcodeproj`)**: - Added `Tests/PPDOptionsTests.swift` covering hex decoding, Epson/Canon/Standard PPD parsing, fallback behaviors, and `PrintEngine` resolution. - Added `Tests/TestRunnerMain.swift` and `Scripts/test_runner.sh` for complete automated testing under Command Line Tools. - Registered `PPDOptionsTests.swift` in `TargetPrint.xcodeproj/project.pbxproj`. Closes #1 Closes #2
gronod added 1 commit 2026-09-07 22:45:10 +01:00
fix: resolve PPD media type and tray option discovery and selection
Build macOS Packages / Build macOS (Intel) (pull_request) Successful in 39s
Build macOS Packages / Build macOS (Apple Silicon) (pull_request) Successful in 40s
Build macOS Packages / Build macOS (Universal) (pull_request) Failing after 10s
e319e5b106
- Parse PPD translation strings and decode hex escapes (e.g. CD<2F>DVD -> CD/DVD)
- Populate InspectorView media type and tray dropdowns with human-readable titles while preserving computer-readable choice codes
- Fix empty-array nil coalescing bug in InspectorView preventing empty tray and media type popups
- Support OEM vendor PPD keywords (Canon CNIJMediaType/CNIJMediaSupply, Epson EPIJ_FdSo)
- Add dual-identity lookup in PrintEngine and InspectorView for robust choice code vs title resolution
- Add comprehensive PPDOptionsTests and CLI test runner

Closes #1, Closes #2
gronod merged commit 8eb4bd408d into development 2026-09-07 22:48:18 +01:00
Sign in to join this conversation.