Progress Reporting
Introduction
The goal of this document is to create consistent, reliable, and maintainable messages to report progress using the Status bar.
Requirements:
- the system shall faciliate rich text formatting (bold, color, italic) per part of the message
- the system shall use a common mechanism to generate progress messages in a consistent manner
- the system shall assemble the message so that text is easy to translate and translations are easy to maintain.
STANDARD MESSAGE BUILDER
Class
StatusBarMessageBuilder
Message Template
QString template = "%1 | %2 | %3 | %4: %5 of %6 (%7%) | %8: %9 | %10";
Example:
%1 | %2 | %3 | %4: %5 of %6 (%7%)
CREATE | Completed | Catalog 1 of 1 | MyPhotos | Indexed: 2000 of 2000 (100%)
Component Breakdown
| Part | Field Name | All Possible Values | Notes |
|---|---|---|---|
| 1 | Operation | • "Create" (→ "CREATE") • "Search" (→ "SEARCH") • "Explore" (→ "EXPLORE") • "Update" (→ "UPDATE") | Translated as normal case, auto-converted to uppercase by builder |
| 2 | State | • "In Progress" • "Paused" • "Stopped" • "Cancelled" • "Completed" | Current state of operation |
| 3 | Device Context | • "Catalog X of Y | CatalogName" | Format: "Catalog 1 of 5 | MyPhotos" CatalogName displayed in HTML color (#39b2e5 blue) Shown for all catalog operations (even 1 of 1) |
| 4 | Process Title | Search Operations: • "File Types Updated" (populate file type) • "Loaded" (catalog index loading) • "Evaluated" (file criteria matching) Update Operations: • "Loaded" (only for Memory mode and catalogs that include Metadata) • "Counted" • "Indexed" (files scanned/updated in catalog) • "File Types Updated" • "Metadata Extracted" Create Operations: • "Counted" • "Indexed" (files added to new catalog) • "Metadata Extracted" Explore Operations: • "File Types Updated" • "Loaded" (catalog loading) | Process being executed, dynamically set by operation |
| 5 | Current Count | Any integer ≥ 0 | Items processed so far |
| 6 | Total Count | Any integer > 0, or 0 (unknown) | Total items (0 = unknown, shows only current) |
| 7 | Percent | 0-100 (integer) | Calculated from Part 5 / Part 6 |
| 8 | Result Title | • "Files found" • "Folders found" • "Found" (generic) | Files or folders being counted |
| 9 | Result Count | Any integer ≥ 0 | Result accumulator |
| 10 | Time to Completion | Duration string (e.g., "5m 23s", "1h 25m 20s") | Estimated time to completion Only used for Extract Metadata process Updates every batch (~100 files) |
| 11 | Current Item | File path string | Current file being processed Updates every ~50-100 files (batched) |
- DEV: consider spliting the DeviceContext (%3) in 2: DeviceList & DeviceName
- Note about Cancelled vs Stopped: "Cancelled" will be used for operations that would not have changed data when interrupted (ex: Create, Update), while "Stopped" is used when some data has been modified or generated (ex: "Search").
- DEV: make the hide delay a global parameter (5 seconds at the moment)
Examples for all possible Operations, states, & steps
//CREATE
CREATE | In Progress | Catalog 1 of 1 | MyPhotos | Counted: 500
CREATE | In Progress | Catalog 1 of 1 | MyPhotos | Indexed: 200 of 2000 (10%) | /home/stephane/Document/test.odt
CREATE | Cancelled | Catalog 1 of 1 | MyPhotos | Indexed: 500 of 2000 (25%)
CREATE | Completed | Catalog 1 of 1 | MyPhotos | Indexed: 2000 of 2000 (100%)
//SEARCH
SEARCH | In Progress | Catalog 1 of 5 | MyPhotos | Loaded: 100 of 1000 (10%)
SEARCH | In Progress | Catalog 1 of 5 | MyPhotos | Update file types: 200 of 2000 (10%)
SEARCH | In Progress | Catalog 3 of 5 | Documents | Evaluated: 10254 of 100000 (10%) | Found: 2025
SEARCH | Paused | Catalog 3 of 5 | Documents | Evaluated: 10254 of 100000 (10%) | Found: 2025
SEARCH | Stopped | Catalog 3 of 5 | Documents | Evaluated: 2500 of 10000 (25%) | Found: 125
SEARCH | Completed | Catalog 5 of 5 | Videos | Evaluated: 10000 of 10000 (100%) | Found: 250
//EXPLORE
EXPLORE | In Progress | Catalog 1 of 1 | MyPhotos | Loaded: 100 of 1000 (10%)
EXPLORE | In Progress | Catalog 1 of 1 | MyPhotos | Update file types: 200 of 2000 (10%)
(note: Pause or Stop is not available)
//UPDATE
UPDATE | In Progress | Catalog 1 of 5 | MyPhotos | Loaded: 100 of 1000 (10%)
UPDATE | In Progress | Catalog 1 of 1 | MyPhotos | Counted: 2000
UPDATE | In Progress | Catalog 1 of 5 | MyPhotos | Update file types: 200 of 2000 (10%)
UPDATE | In Progress | Catalog 1 of 5 | MyPhotos | Indexed: 200 of 2000 (10%) | /home/stephane/Document/test.odt
UPDATE | In Progress | Catalog 1 of 5 | MyPhotos | Indexed: 2000 of 2000 (100%)
UPDATE | In Progress | Catalog 1 of 5 | MyPhotos | Indexed: 2000 of 2000 (100%) | Saving
UPDATE | In Progress | Catalog 1 of 5 | MyPhotos | Extracted: 200 of 2000 (10%) | 1h 25m 10s | /home/stephane/Document/test.odt
(note: Pause is not available)
UPDATE | Cancelled | Catalog 1 of 1 | MyPhotos | Indexed: 2500 of 10000 (25%)
UPDATE | Completed | Catalog 1 of 1 | MyPhotos | Indexed: 1000 of 1000 (100%)
Other requirements
- Each phase of an Update operation shall refresh the status bar to display 100% when reaching this stage, so that if there is another phase or process starting just after, the waiting time is not perceived by the user as part of the previous phase
Ideas for UI improvements
- DEV: normalize the parts size with spaces (Operation, State)
- DEV: color code the opeartion states
Other Notes
- when triggering an update on a catalog from odler version (before 2.8), the step "File Types updated" is not the first step. It happens after the indexing step so that only remaining files are processed for file type update.
STATE MACHINE & ARCHITECTURE
Operation Phase State Machine
Catalog operations progress through explicit phases tracked by CatalogManager:
PHASE_IDLE
↓ (operation starts)
PHASE_COUNTING → (cancel) → emit catalogOperationCancelled() → PHASE_IDLE
↓ (counting completes)
PHASE_INDEXING → (cancel) → emit catalogOperationCancelled() → PHASE_IDLE
↓ (indexing completes, if needed)
PHASE_MIGRATING → (cancel) → emit catalogOperationCancelled() → PHASE_IDLE
↓ (all complete)
PHASE_COMPLETING
↓ (emit catalogOperationCompleted)
PHASE_IDLE
Phase Detection Rules:
PHASE_COUNTING: When currentPath starts with__COUNTING_STATE__|or ends with" files."PHASE_INDEXING: When totalFiles > 0 and currentPath contains real file pathsPHASE_MIGRATING: When currentPath starts with__FILETYPE_MIGRATION__|PHASE_COMPLETING: Set just before emitting catalogOperationCompleted
Phase Persistence:
m_currentPhase: Current phase during operationm_lastPhase: Preserved when operation ends (for cancelled messages)
Signal Flow & Responsibilities
CatalogJobStoppable
↓ (emits catalogProgress)
CatalogManager
├─ Updates: m_filesProcessed, m_totalFiles, m_currentPath
├─ Detects phase transitions → setOperationPhase()
├─ On completion: saves m_lastFilesProcessed, m_lastTotalFiles
└─ Emits: catalogOperationCompleted / catalogOperationCancelled
↓
CatalogProgressManager
├─ Listens to progress signals → calls updateFromCatalogManager()
├─ Builds IN-PROGRESS messages (only when operation running)
├─ Listens to completion/cancelled signals
└─ Builds FINAL messages using lastX values
Message Building Responsibility:
- In-Progress:
CatalogProgressManager::updateFromCatalogManager()- uses current values - Cancelled:
catalogOperationCancelledlambda - useslastPhase(),lastFilesProcessed(),lastTotalFiles() - Completed:
catalogOperationCompletedlambda - useslastFilesProcessed(),lastTotalFiles()
Critical Rule: updateFromCatalogManager() does NOTHING when operation not running to prevent message replacement.
State Preservation Pattern
The "last" value pattern ensures message data survives operation cleanup:
// During operation:
setFilesProcessed(100); // Updates both m_filesProcessed and m_lastFilesProcessed
// On completion (before cleanup):
m_lastFilesProcessed = results[1]; // Explicit save from job results
m_lastTotalFiles = results[1];
// After cleanup:
m_filesProcessed = 0; // Cleared
// But m_lastFilesProcessed = 100 // Preserved for completion message
// Signal handlers use:
m_catalogManager->lastFilesProcessed() // Always available
Multi-Catalog Context (TBD)
For operations processing multiple catalogs (Virtual/Storage devices):
- Catalog Index: Managed by DeviceUpdateManager (knows "processing 2 of 5")
- Catalog Name: Managed by CatalogManager (knows "MyPhotos")
- Message Building: CatalogProgressManager combines both
Architecture to be refined - see Issue #3 below.
## 3. Multi-Catalog Index Issue - Recommendation
**Current Problem:**
UPDATE | In Progress | Catalog 1 of 1 | MyPhotos | ... (processing catalog 1) UPDATE | In Progress | Catalog 1 of 1 | Videos | ... (processing catalog 2) ← WRONG UPDATE | In Progress | Catalog 1 of 1 | Docs | ... (processing catalog 3) ← WRONG
MESSAGE SOURCES TABLE
This section documents all status bar messages in Katalog, tracking their implementation status and MessageBuilder adoption.
Legend:
- ✅ = Uses StatusBarMessageBuilder
- ❌ = Direct setText() / legacy format
- ⚠️ = Partial / needs improvement
INITIALIZATION
| Message Type | Example | Timeout | Uses Builder | Location |
|---|---|---|---|---|
| Application ready | "Ready" | none | ❌ | MainWindow constructor timer |
Notes:
- Message shown after app initialization completes
- Currently uses direct setText
- Consider if this message is necessary (status bar could be empty initially)
- DEV: indeed, is this even displayed at any time? "Ready" is a default sate of conditions later (to be documented)
CATALOG OPERATIONS
CatalogProgressManager (⚠️ Partially Migrated)
| Message Type | Example | Timeout | Uses Builder | Status |
|---|---|---|---|---|
| In Progress (CREATE) | CREATE | In Progress | Catalog 1 of 1 | MyPhotos | Indexed: 200 of 2000 (10%) | none | ✅ | Working |
| In Progress (UPDATE) | UPDATE | In Progress | Catalog 1 of 1 | MyPhotos | Indexed: 200 of 2000 (10%) | none | ✅ | Working |
| Counting files | CREATE | In Progress | Catalog 1 of 1 | MyPhotos | Counting files: 1250 | none | ✅ | Working |
| Completed | CREATE | Completed | Catalog 1 of 1 | MyPhotos | Indexed: 2000 of 2000 (100%) | 5000ms | ⚠️ | ISSUE: Shows wrong operation/status |
| Stopped | UPDATE | Stopped | Catalog 1 of 1 | MyPhotos | 5000ms | ❌ | Legacy string "Operation cancelled" |
| Cancelled | "Operation cancelled" | 5000ms | ❌ | Direct setText |
Critical Issues:
- Completion branch (else): Needs to use MessageBuilder properly
- Operation type detection: May return wrong type after job cleanup
- Cancelled handler: Uses lambda with direct setText instead of MessageBuilder
Implementation Method: CatalogProgressManager::updateFromCatalogManager()
SEARCH OPERATIONS
SearchProgressManager (✅ Fully Migrated)
| Message Type | Example | Timeout | Uses Builder | Method |
|---|---|---|---|---|
| Search in progress | SEARCH | In Progress | Catalog 1 of 3 | Documents | Evaluated: 10254 of 100000 (10%) | Found: 2025 | none | ✅ | updateFromSearchManager() |
| Search completed | SEARCH | Completed | Found: 1250 | 5000ms | ✅ | updateFromSearchManager() |
| Search paused | Current message + " | PAUSED" | none | ✅ | updateFromSearchManager() |
Implementation: SearchProgressManager fully migrated to StatusBarMessageBuilder
MainWindow Search (✅ Fully Migrated)
| Message Type | Example | Timeout | Uses Builder | Method |
|---|---|---|---|---|
| Catalog loading | SEARCH | In Progress | Catalog 1 of 3 | MyPhotos | Loading: 100 of 1000 (10%) | none | ✅ | updateSearchProgress() |
| File type conversion | SEARCH | In Progress | Catalog 1 of 3 | MyPhotos | Update file types: 200 of 2000 (10%) | none | ✅ | updateSearchProgress() |
| Search stopped | SEARCH | Stopped | Files found: 125 | 5000ms | ✅ | updateSearchProgress() |
| Search ready | "Ready" | none | ❌ | updateStatusBarFromSearchManager() |
Notes:
- updateSearchProgress() fully uses MessageBuilder
- "Ready" state still uses direct setText
DEVICE UPDATE OPERATIONS
MainWindow Device Updates (❌ Not Migrated)
| Message Type | Example | Timeout | Uses Builder | Method |
|---|---|---|---|---|
| Update progress | "Scanning files: 500/1000 (50%) - MyDevice" | none | ❌ | onDeviceUpdateProgress() |
| Update error | "Operation cancelled" | 5000ms | ❌ | onDeviceUpdateError() |
| Update cancelled | "Operation cancelled" | 3000ms | ❌ | onDeviceUpdateCancelled() |
| UI state clear | (clears message) | - | N/A | setCatalogUpdateUIState(false) |
Notes:
- All methods use direct setText with simple string concatenation
- Should be migrated to use MessageBuilder for consistency
- onDeviceUpdateProgress() only called when CatalogProgressManager is NOT handling the operation
Target Format:
UPDATE | In Progress | MyDevice | Scanned: 500 of 1000 (50%)
EXPLORE TAB
Explore Operations (⚠️ Mixed)
| Message Type | Example | Timeout | Uses Builder | Method |
|---|---|---|---|---|
| File type conversion | EXPLORE | In Progress | MyPhotos | Update file types: 200 of 2000 (10%) | none | ✅ | Uses shared code path |
| Migration cancelled | "Migration cancelled" | 2000ms | ❌ | on_Explore_pushButton_OpenCatalog_clicked() |
| Catalog ready | "Catalog ready" | 2000ms | ❌ | on_Explore_pushButton_OpenCatalog_clicked() |
Notes:
- File type conversion uses same code as Search/Catalog operations
- Simple status messages still use direct setText
CREATE TAB
Create Operations (⚠️ Critical Issue)
| Message Type | Example | Timeout | Uses Builder | Status |
|---|---|---|---|---|
| In Progress | CREATE | In Progress | Catalog 1 of 1 | MyPhotos | Indexed: 200 of 2000 (10%) | none | ✅ | Working via CatalogProgressManager |
| Completed | CREATE | Completed | Catalog 1 of 1 | MyPhotos | Indexed: 2000 of 2000 (100%) | 5000ms | ⚠️ | GETS ERASED |
| Stopped/Error | "Operation cancelled" | 5000ms | ❌ | Direct setText |
Critical Issue:
setCreateCatalogUIState(false)callsstatusBarLabel->clear()- This ERASES the completion message immediately after CatalogProgressManager displays it
- Fix Required: Remove the clear() call, let CatalogProgressManager handle timeout
Location: src/mainwindow_tab_create.cpp line ~2157
MIGRATION PRIORITIES
High Priority (User-Visible Issues)
- 🔴 CatalogProgressManager completion - Shows wrong operation/status
- 🔴 CREATE statusBarLabel->clear() - Erases completion message
- 🔴 Cancelled operations - Legacy "Operation cancelled" string
Medium Priority (Consistency)
- 🟡 onDeviceUpdateProgress() - Should use MessageBuilder
- 🟡 onDeviceUpdateError() - Should use MessageBuilder
- 🟡 onDeviceUpdateCancelled() - Should use MessageBuilder
Low Priority (Simple Messages)
- 🟢 "Ready" states - Consider if needed at all
- 🟢 Explore tab simple messages - "Migration cancelled", "Catalog ready"