Document origin tracking and display #16

Closed
opened 2026-02-05 18:29:53 +00:00 by forbes · 1 comment
Owner

Overview

Track and display which origin each document belongs to. This provides visual feedback in the UI showing where documents came from and where they will be saved.

Parent Issue

Epic: #8 Unified File Origin System

Goals

  1. Track origin association for each open document
  2. Display origin indicator in document title/tab
  3. Persist origin association in document metadata
  4. Handle documents opened from different origins simultaneously

Detailed Design

Document-Origin Association

Each document tracks its origin:

// In OriginManager
class OriginManager {
    // ...
    
    // Document tracking
    FileOrigin* originForDocument(App::Document* doc) const;
    void setDocumentOrigin(App::Document* doc, FileOrigin* origin);
    
private:
    QMap<App::Document*, QString> m_documentOrigins;  // doc -> origin ID
};

Title Bar Display

Show origin in document title:

Standard format:
  "Part_001.FCStd [Work] - Kindred Create"
  "MyAssembly.FCStd [Local] - Kindred Create"
  "Untitled [Prod] * - Kindred Create"  (* = modified)

Implementation in MainWindow:

void MainWindow::updateWindowTitle() {
    App::Document* doc = App::GetApplication().getActiveDocument();
    if (!doc) {
        setWindowTitle(tr("Kindred Create"));
        return;
    }
    
    QString title = QString::fromUtf8(doc->Label.getValue());
    
    // Add origin suffix
    FileOrigin* origin = OriginManager::instance()->originForDocument(doc);
    if (origin) {
        title += QString(" [%1]").arg(origin->nickname());
    }
    
    // Add modified indicator
    if (doc->isTouched()) {
        title += " *";
    }
    
    title += " - " + tr("Kindred Create");
    setWindowTitle(title);
}

MDI Tab Display

Show origin in document tabs:

void MDIView::updateTabText() {
    App::Document* doc = getDocument();
    QString text = QString::fromUtf8(doc->Label.getValue());
    
    FileOrigin* origin = OriginManager::instance()->originForDocument(doc);
    if (origin && origin->type() != OriginType::Local) {
        // Only show for non-local origins to reduce clutter
        text += QString(" [%1]").arg(origin->nickname());
    }
    
    if (doc->isTouched()) {
        text += " *";
    }
    
    setWindowTitle(text);
}

Document Metadata Storage

Store origin info in document properties for persistence:

void OriginManager::setDocumentOrigin(App::Document* doc, FileOrigin* origin) {
    m_documentOrigins[doc] = origin->id();
    
    // Store in document for persistence
    if (!doc->getPropertyByName("OriginId")) {
        doc->addDynamicProperty("App::PropertyString", "OriginId", 
                                 "Origin", "File origin identifier");
    }
    doc->OriginId.setValue(origin->id().toUtf8().constData());
    
    Q_EMIT documentOriginChanged(doc, origin);
}

FileOrigin* OriginManager::originForDocument(App::Document* doc) const {
    // Check runtime cache first
    if (m_documentOrigins.contains(doc)) {
        return originById(m_documentOrigins[doc]);
    }
    
    // Check document property
    auto* prop = dynamic_cast<App::PropertyString*>(
        doc->getPropertyByName("OriginId"));
    if (prop) {
        QString originId = QString::fromUtf8(prop->getValue());
        if (FileOrigin* origin = originById(originId)) {
            m_documentOrigins[doc] = originId;
            return origin;
        }
    }
    
    // Default: check if it has a local file path
    if (!doc->FileName.isEmpty()) {
        return localOrigin();
    }
    
    return nullptr;
}

Tree View Display

Show origin icon overlay in model tree:

QIcon DocumentItem::icon() const {
    QIcon baseIcon = QIcon(":/icons/Document.svg");
    
    FileOrigin* origin = OriginManager::instance()->originForDocument(m_doc);
    if (origin && origin->type() == OriginType::Silo) {
        // Add small cloud overlay in corner
        return overlayIcon(baseIcon, ":/icons/origin-cloud-overlay.svg");
    }
    
    return baseIcon;
}

Status Bar

Show origin in status bar for active document:

void MainWindow::updateStatusBar() {
    App::Document* doc = App::GetApplication().getActiveDocument();
    if (!doc) {
        m_originStatusLabel->hide();
        return;
    }
    
    FileOrigin* origin = OriginManager::instance()->originForDocument(doc);
    if (origin) {
        m_originStatusLabel->setText(origin->name());
        m_originStatusLabel->setToolTip(
            tr("This document is stored in %1").arg(origin->name()));
        m_originStatusLabel->show();
    }
}

Document Lifecycle Handling

Track origin through document lifecycle:

void OriginManager::onDocumentCreated(App::Document* doc) {
    // New documents get current origin
    setDocumentOrigin(doc, currentOrigin());
}

void OriginManager::onDocumentOpened(App::Document* doc) {
    // Opened documents: restore from metadata or infer
    // (handled in originForDocument())
}

void OriginManager::onDocumentClosed(App::Document* doc) {
    m_documentOrigins.remove(doc);
}

Implementation Tasks

  • Add document-origin tracking to OriginManager
  • Store origin ID in document properties
  • Update window title with origin suffix
  • Update MDI tab text with origin
  • Add origin overlay to tree view icons
  • Add origin indicator to status bar
  • Handle document create/open/close events
  • Create overlay icons for tree view
  • Test with multiple documents from different origins

Files to Create/Modify

  • src/Gui/OriginManager.cpp (document tracking)
  • src/Gui/MainWindow.cpp (title bar, status bar)
  • src/Gui/MDIView.cpp (tab text)
  • src/Gui/Tree.cpp (tree view icons)
  • kindred-icons/origin-cloud-overlay.svg (new)

Acceptance Criteria

  • Document origin is tracked in memory
  • Origin persists in document file
  • Title bar shows origin nickname
  • Tabs show origin for Silo documents
  • Tree view shows origin indicator
  • Status bar shows origin info
  • New documents get current origin
  • Opened documents restore their origin
  • Multiple origins can be open simultaneously

Dependencies

  • #9 Origin abstraction layer
  • #10 Local filesystem origin
  • #11 Silo origin adapter

Blocking

  • #17 Mixed origin workflows
## Overview Track and display which origin each document belongs to. This provides visual feedback in the UI showing where documents came from and where they will be saved. ## Parent Issue Epic: #8 Unified File Origin System ## Goals 1. Track origin association for each open document 2. Display origin indicator in document title/tab 3. Persist origin association in document metadata 4. Handle documents opened from different origins simultaneously ## Detailed Design ### Document-Origin Association Each document tracks its origin: ```cpp // In OriginManager class OriginManager { // ... // Document tracking FileOrigin* originForDocument(App::Document* doc) const; void setDocumentOrigin(App::Document* doc, FileOrigin* origin); private: QMap<App::Document*, QString> m_documentOrigins; // doc -> origin ID }; ``` ### Title Bar Display Show origin in document title: ``` Standard format: "Part_001.FCStd [Work] - Kindred Create" "MyAssembly.FCStd [Local] - Kindred Create" "Untitled [Prod] * - Kindred Create" (* = modified) ``` Implementation in MainWindow: ```cpp void MainWindow::updateWindowTitle() { App::Document* doc = App::GetApplication().getActiveDocument(); if (!doc) { setWindowTitle(tr("Kindred Create")); return; } QString title = QString::fromUtf8(doc->Label.getValue()); // Add origin suffix FileOrigin* origin = OriginManager::instance()->originForDocument(doc); if (origin) { title += QString(" [%1]").arg(origin->nickname()); } // Add modified indicator if (doc->isTouched()) { title += " *"; } title += " - " + tr("Kindred Create"); setWindowTitle(title); } ``` ### MDI Tab Display Show origin in document tabs: ```cpp void MDIView::updateTabText() { App::Document* doc = getDocument(); QString text = QString::fromUtf8(doc->Label.getValue()); FileOrigin* origin = OriginManager::instance()->originForDocument(doc); if (origin && origin->type() != OriginType::Local) { // Only show for non-local origins to reduce clutter text += QString(" [%1]").arg(origin->nickname()); } if (doc->isTouched()) { text += " *"; } setWindowTitle(text); } ``` ### Document Metadata Storage Store origin info in document properties for persistence: ```cpp void OriginManager::setDocumentOrigin(App::Document* doc, FileOrigin* origin) { m_documentOrigins[doc] = origin->id(); // Store in document for persistence if (!doc->getPropertyByName("OriginId")) { doc->addDynamicProperty("App::PropertyString", "OriginId", "Origin", "File origin identifier"); } doc->OriginId.setValue(origin->id().toUtf8().constData()); Q_EMIT documentOriginChanged(doc, origin); } FileOrigin* OriginManager::originForDocument(App::Document* doc) const { // Check runtime cache first if (m_documentOrigins.contains(doc)) { return originById(m_documentOrigins[doc]); } // Check document property auto* prop = dynamic_cast<App::PropertyString*>( doc->getPropertyByName("OriginId")); if (prop) { QString originId = QString::fromUtf8(prop->getValue()); if (FileOrigin* origin = originById(originId)) { m_documentOrigins[doc] = originId; return origin; } } // Default: check if it has a local file path if (!doc->FileName.isEmpty()) { return localOrigin(); } return nullptr; } ``` ### Tree View Display Show origin icon overlay in model tree: ```cpp QIcon DocumentItem::icon() const { QIcon baseIcon = QIcon(":/icons/Document.svg"); FileOrigin* origin = OriginManager::instance()->originForDocument(m_doc); if (origin && origin->type() == OriginType::Silo) { // Add small cloud overlay in corner return overlayIcon(baseIcon, ":/icons/origin-cloud-overlay.svg"); } return baseIcon; } ``` ### Status Bar Show origin in status bar for active document: ```cpp void MainWindow::updateStatusBar() { App::Document* doc = App::GetApplication().getActiveDocument(); if (!doc) { m_originStatusLabel->hide(); return; } FileOrigin* origin = OriginManager::instance()->originForDocument(doc); if (origin) { m_originStatusLabel->setText(origin->name()); m_originStatusLabel->setToolTip( tr("This document is stored in %1").arg(origin->name())); m_originStatusLabel->show(); } } ``` ### Document Lifecycle Handling Track origin through document lifecycle: ```cpp void OriginManager::onDocumentCreated(App::Document* doc) { // New documents get current origin setDocumentOrigin(doc, currentOrigin()); } void OriginManager::onDocumentOpened(App::Document* doc) { // Opened documents: restore from metadata or infer // (handled in originForDocument()) } void OriginManager::onDocumentClosed(App::Document* doc) { m_documentOrigins.remove(doc); } ``` ## Implementation Tasks - [ ] Add document-origin tracking to OriginManager - [ ] Store origin ID in document properties - [ ] Update window title with origin suffix - [ ] Update MDI tab text with origin - [ ] Add origin overlay to tree view icons - [ ] Add origin indicator to status bar - [ ] Handle document create/open/close events - [ ] Create overlay icons for tree view - [ ] Test with multiple documents from different origins ## Files to Create/Modify - `src/Gui/OriginManager.cpp` (document tracking) - `src/Gui/MainWindow.cpp` (title bar, status bar) - `src/Gui/MDIView.cpp` (tab text) - `src/Gui/Tree.cpp` (tree view icons) - `kindred-icons/origin-cloud-overlay.svg` (new) ## Acceptance Criteria - [ ] Document origin is tracked in memory - [ ] Origin persists in document file - [ ] Title bar shows origin nickname - [ ] Tabs show origin for Silo documents - [ ] Tree view shows origin indicator - [ ] Status bar shows origin info - [ ] New documents get current origin - [ ] Opened documents restore their origin - [ ] Multiple origins can be open simultaneously ## Dependencies - #9 Origin abstraction layer - #10 Local filesystem origin - #11 Silo origin adapter ## Blocking - #17 Mixed origin workflows
Author
Owner

Complete. Closing with code references:

  • src/Gui/OriginManager.cpp_documentOrigins map tracking document-to-origin associations via setDocumentOrigin() / clearDocumentOrigin() / originForDocument() / findOwningOrigin()
  • src/Gui/FileOrigin.cpp:84 — Ownership detection via SiloItemId document property
  • src/Gui/MDIView.cpp:520-534 — Window title displays origin suffix (e.g. " [Work]") for non-local documents
Complete. Closing with code references: - `src/Gui/OriginManager.cpp` — `_documentOrigins` map tracking document-to-origin associations via `setDocumentOrigin()` / `clearDocumentOrigin()` / `originForDocument()` / `findOwningOrigin()` - `src/Gui/FileOrigin.cpp:84` — Ownership detection via `SiloItemId` document property - `src/Gui/MDIView.cpp:520-534` — Window title displays origin suffix (e.g. " [Work]") for non-local documents
forbes referenced this issue from a commit 2026-02-14 16:31:28 +00:00
forbes referenced this issue from a commit 2026-02-14 16:34:32 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: kindred/create#16