Skip to content

Find paths to external programs automatically#101

Merged
AlanRockefeller merged 2 commits into
mainfrom
test
Jun 21, 2026
Merged

Find paths to external programs automatically#101
AlanRockefeller merged 2 commits into
mainfrom
test

Conversation

@AlanRockefeller

@AlanRockefeller AlanRockefeller commented Jun 20, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Added a Readme viewer from the Help menu.
    • Improved cross-platform auto-detection for external tools (including RawTherapee, Photoshop, and Helicon Focus).
  • Improvements

    • File/folder picker dialogs now start from the current path and better validate executable selections.
    • Batch membership is more consistently preserved and reflected during sorting/filtering and related actions.
    • Stack start/end markers can be toggled off by pressing the key again.
    • Close confirmation now references recycle bins (not batches).
  • UI Updates

    • Minor filter text field usability tweaks.

@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bcea6264-a254-4752-b793-f8c15aaa9b44

📥 Commits

Reviewing files that changed from the base of the PR and between 84124ae and 6a7d298.

📒 Files selected for processing (2)
  • faststack/app.py
  • faststack/config.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • faststack/config.py
  • faststack/app.py

Walkthrough

This PR refactors batch state management around sidecar-backed helpers and a centralized _finalize_batch_state that preserves batch membership through sort/filter operations. It adds cross-platform external tool auto-detection for Helicon Focus, Photoshop, and RawTherapee in config. It introduces a README viewer (Help menu), improves file/directory dialogs with current-path seeding and executable validation, replaces QuitBatchesDialog close gating with recycle-bin interception, and adds EntryMetadata.batch for UI display.

Changes

Batch State Management and Metadata Propagation

Layer / File(s) Summary
EntryMetadata.batch field and metadata propagation
faststack/models.py, faststack/app.py
EntryMetadata gains a batch: bool = False field; per-image metadata returned to the grid thumbnail model and get_current_metadata() is extended to include the batch boolean.
Sidecar persistence helpers and _finalize_batch_state
faststack/app.py
Adds range-normalization from arbitrary indices, sidecar-key abstraction, batch flag persistence/restoration from sidecar metadata, and a centralized _finalize_batch_state that normalizes, invalidates cache, optionally persists to sidecar, and fans out UI/model updates.
Batch preservation through sort and filter
faststack/app.py
set_sort_mode snapshots batch/stack paths for remapping after reorder; _apply_filter_to_cached_list preserves batch_start_index and restores runtime batches from sidecar flags for the new image_files order.
Batch mutation call sites migrated to _finalize_batch_state
faststack/app.py
end_current_batch, grid_add_selection_to_batch, add_favorites/uploaded/edited_to_batch, _auto_add_edited_to_batch_if_enabled, toggle_batch_membership, clear_all_batches, duplicate, and drag-completion now call _finalize_batch_state instead of manual normalize/invalidate/emit/sync sequences.
Delete/undo batch state restoration
faststack/app.py
_delete_indices, delete-undo rollback, optimistic batch-delete clearing, and pending-delete undo use _finalize_batch_state instead of direct cache invalidation.
Stack marker toggle-off support
faststack/app.py
begin_new_stack() and end_current_stack() cancel the pending marker when the same image is targeted a second time.

Cross-Platform External Tool Auto-Detection

Layer / File(s) Summary
External tool detection subsystem
faststack/config.py
Replaces Windows-only RawTherapee detection with OS-aware candidate-path generation, glob searching, version- and preference-based sorting, detect_external_tool_path(), per-tool wrappers, and a _TOOL_DETECTORS registry for Helicon/Photoshop/RawTherapee.
Config load integration with one-time detection flag
faststack/config.py
Adds core.external_tools_detected to DEFAULT_CONFIG; AppConfig.load() runs _detect_external_tool_paths() only on first run or when the flag is unset, never overwriting user-configured custom paths.

README Viewer, Dialog Improvements, and App Close Flow

Layer / File(s) Summary
README resource helpers and get_readme_text slot
faststack/resources.py, faststack/app.py, packaging/faststack.spec
Adds faststack_readme_path() and readme_from_metadata() for README discovery; adds get_readme_text() slot with file/metadata fallback; bundles README.md in the PyInstaller spec for frozen builds.
File/directory dialog current_path and executable validation
faststack/app.py, faststack/ui/provider.py
Adds _dialog_start_directory(); open_file_dialog accepts current_path with platform-specific executable filters; check_executable_path replaces check_path_exists; open_directory_dialog accepts current_path; UIState slots updated to match and expose get_readme_text.
SettingsDialog updated to new dialog slots and executable check
faststack/qml/SettingsDialog.qml
openFileDialog(currentPath) and openDirectoryDialog(currentPath) seed dialogs at the current path; pathIsExecutable() replaces pathExists() for Helicon, Photoshop, RawTherapee, and Default Image Directory Browse buttons.
QML README dialog and Help menu action
faststack/qml/Main.qml
Adds openReadmeDialog(), a scrollable markdown-capable readmeDialog with external link support, and a Help > View Readme menu action.
App close flow: recycle-bin gating replaces QuitBatchesDialog
faststack/qml/Main.qml, faststack/qml/QuitBatchesDialog.qml
Removes allowCloseWithBatches and the QuitBatchesDialog block; onClosing now gates on recycle-bin items via allowCloseWithRecycleBins; cleanup dialog cancel/close handlers simplified.
FilterDialog text field clip and font tweak
faststack/qml/FilterDialog.qml
FilterDialog TextField gains clip: true and a reduced font.pixelSize.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • AlanRockefeller/faststack#3: Both PRs touch file/directory picker plumbing—adding/changing open_file_dialog and executable-path validation; PR #3 introduces the original slots while this PR renames and threads current_path through them.
  • AlanRockefeller/faststack#15: This PR's batch refactoring directly extends PR #15's batch selection system, adding EntryMetadata.batch and _finalize_batch_state for sidecar persistence and normalized batch membership.
  • AlanRockefeller/faststack#31: Both PRs modify faststack/app.py's deletion/undo flow with batch state restoration and dialog/close gating around those operations.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 48.15% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main objective of the PR, which is to add automatic detection for external program paths across Helicon Focus, Photoshop, and RawTherapee.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@AlanRockefeller

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 84124ae5b0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread faststack/app.py Outdated
Comment on lines +1758 to +1759
active_keys = self._current_batch_metadata_keys()
images_to_update = list(self._all_images or self.image_files)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve hidden batch flags while persisting filtered changes

When a filter is active, _restore_batches_from_sidecar_flags() rebuilds self.batches only from the visible self.image_files, so active_keys contains only visible batch members. Persisting across self._all_images then sets batch=false for every hidden image whose key is not in active_keys, so adding/toggling a visible batch item while filtered silently removes previously batched hidden images from the sidecar selection.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
faststack/config.py (1)

384-386: 💤 Low value

Potential KeyError if called with unknown tool name.

If detect_external_tool_path is called with a tool_name not in _TOOL_LABELS, line 385 will raise a KeyError, bypassing the intended warning. The function already returns ([], []) for unknown tools at line 303, so this is unlikely in practice, but defensive handling would be cleaner.

Suggested improvement
     except (OSError, RuntimeError) as e:
-        log.warning("Error detecting %s path: %s", _TOOL_LABELS[tool_name], e)
+        log.warning("Error detecting %s path: %s", _TOOL_LABELS.get(tool_name, tool_name), e)
         return None
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@faststack/config.py` around lines 384 - 386, The exception handler on line
385 accesses _TOOL_LABELS[tool_name] directly without checking if tool_name
exists in the dictionary, which could raise a KeyError. Replace the direct
dictionary access with the .get() method using a fallback value like "unknown
tool" or the tool_name itself to ensure the warning logs properly even if an
unexpected tool_name reaches this exception handler.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@faststack/app.py`:
- Around line 1756-1782: The images_to_update selection in the
_persist_batch_flags method uses _all_images or self.image_files, but
active_keys only contains keys from the currently filtered image_files, causing
the method to write batch=False to hidden images when edits occur during
filtering. Change the images_to_update assignment to only iterate over the
filtered self.image_files instead of _all_images to ensure batch flag
persistence only affects visible images, preserving the batch membership of
hidden images when filters are cleared.
- Around line 8204-8205: The _finalize_batch_state() method calls with
batch_changed condition are persisting batch flag changes while delete
operations are still undoable, causing the persisted flags to be cleared before
undo can restore them. Modify the _finalize_batch_state() calls (at the
identified location and also at lines 8433-8435) to pass persist=False parameter
while the delete operation is still undoable. After the worker completes and the
delete is no longer undoable, you can persist the batch state changes by either
deferring the persist call or making a separate call to _finalize_batch_state()
with persist=True once the delete operation has been finalized.

---

Nitpick comments:
In `@faststack/config.py`:
- Around line 384-386: The exception handler on line 385 accesses
_TOOL_LABELS[tool_name] directly without checking if tool_name exists in the
dictionary, which could raise a KeyError. Replace the direct dictionary access
with the .get() method using a fallback value like "unknown tool" or the
tool_name itself to ensure the warning logs properly even if an unexpected
tool_name reaches this exception handler.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1c1d7faa-d7f5-445d-81f0-49f141fe49bc

📥 Commits

Reviewing files that changed from the base of the PR and between ee24f7b and 84124ae.

📒 Files selected for processing (10)
  • faststack/app.py
  • faststack/config.py
  • faststack/models.py
  • faststack/qml/FilterDialog.qml
  • faststack/qml/Main.qml
  • faststack/qml/QuitBatchesDialog.qml
  • faststack/qml/SettingsDialog.qml
  • faststack/resources.py
  • faststack/ui/provider.py
  • packaging/faststack.spec
💤 Files with no reviewable changes (1)
  • faststack/qml/QuitBatchesDialog.qml

Comment thread faststack/app.py
Comment thread faststack/app.py
@AlanRockefeller AlanRockefeller merged commit f5af459 into main Jun 21, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant