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
88 changes: 88 additions & 0 deletions LoopEditor/editorhost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,82 @@ QString EditorHost::previewStaleReason() const
return QString();
}

QString EditorHost::previewFidelityStateName() const
{
return pdfquick::tokens::classifyPreviewFidelityState(hasDocument(),
!previewStaleReason().isEmpty(),
pageFidelityIsAuthoritative(),
pageFidelityIsExact());
}

QVariantMap EditorHost::previewFidelityVisual() const
{
const pdfquick::tokens::LoopStateVisual visual =
pdfquick::tokens::resolvePreviewFidelityStateVisual(previewFidelityStateName());

QVariantMap result;
result.insert(QStringLiteral("kind"), pdfquick::tokens::stateKindName(visual.kind));
result.insert(QStringLiteral("colorRole"), pdfquick::tokens::colorRoleName(visual.colorRole));
result.insert(QStringLiteral("icon"), pdfquick::tokens::stateIconName(visual.icon));
result.insert(QStringLiteral("accessibleName"), visual.accessibleName);
return result;
}

QColor EditorHost::previewFidelityColor() const
{
const pdfquick::tokens::LoopStateVisual visual =
pdfquick::tokens::resolvePreviewFidelityStateVisual(previewFidelityStateName());
const pdfquick::tokens::LoopTheme theme =
highContrast() ? pdfquick::tokens::LoopTheme::HighContrast : pdfquick::tokens::LoopTheme::Dark;
return pdfquick::tokens::color(visual.colorRole, theme);
}

QString EditorHost::previewFidelityOriginName() const
{
return pdfquick::tokens::previewFidelityOriginName(previewFidelityStateName());
}

bool EditorHost::previewRequiresAuthoritative() const
{
return previewFidelityStateName() == QLatin1String("approximate");
}

QString EditorHost::previewFidelitySummary() const
{
const QString state = previewFidelityStateName();

if (state == QLatin1String("unavailable"))
{
return tr("No document is open, so there is no preview to describe.");
}
if (state == QLatin1String("stale"))
{
return tr("Not current evidence: %1").arg(previewStaleReason());
}
if (state == QLatin1String("authoritative") && !pageFidelityIsExact())
{
return tr("Fidelity authoritative but still approximate, origin output-preview: this page is "
"rendered with the overprint-accurate compositor, yet its diagnostics report an "
"approximation (%1). Do not read it as an exact render.")
.arg(pageFidelityReason());
}
if (state == QLatin1String("authoritative"))
{
return tr("Fidelity authoritative, origin output-preview: this page is rendered with the "
"overprint-accurate compositor. Read it with the plates and separations; it does "
"not by itself certify publication safety.");
}
if (state == QLatin1String("approximate"))
{
return tr("Fidelity approximate, origin fast-canvas: overprint is not simulated (%1). These "
"canvas pixels cannot stand as proof of print-safe output; switch this page to the "
"authoritative overprint render before any print claim.")
.arg(pageFidelityReason());
}
return tr("Fidelity exact, origin fast-canvas: this page reports no overprint-sensitive content. "
"The interactive preview still does not certify print-safe output.");
}

QString EditorHost::productionStateName() const
{
if (!hasDocument())
Expand Down Expand Up @@ -1338,6 +1414,18 @@ void EditorHost::toggleCurrentPageFidelity()
bumpPresentation();
}

bool EditorHost::ensureAuthoritativePreview()
{
if (!hasDocument() || !previewRequiresAuthoritative())
{
return false;
}

m_session->surfaces()->setPageAuthoritativeOverprint(currentPage(), true);
bumpPresentation();
return true;
}

void EditorHost::selectFinding(const QString& findingId)
{
if (!m_session->revisionSource() || findingId.isEmpty())
Expand Down
29 changes: 29 additions & 0 deletions LoopEditor/editorhost.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ class EditorHost final : public QObject
Q_PROPERTY(QString fixRollbackSummary READ fixRollbackSummary NOTIFY presentationChanged)
Q_PROPERTY(QVariantMap previewIdentity READ previewIdentity NOTIFY presentationChanged)
Q_PROPERTY(QString previewStaleReason READ previewStaleReason NOTIFY presentationChanged)
Q_PROPERTY(QString previewFidelityStateName READ previewFidelityStateName NOTIFY presentationChanged)
Q_PROPERTY(QVariantMap previewFidelityVisual READ previewFidelityVisual NOTIFY presentationChanged)
Q_PROPERTY(QColor previewFidelityColor READ previewFidelityColor NOTIFY presentationChanged)
Q_PROPERTY(QString previewFidelityOriginName READ previewFidelityOriginName NOTIFY presentationChanged)
Q_PROPERTY(QString previewFidelitySummary READ previewFidelitySummary NOTIFY presentationChanged)
Q_PROPERTY(bool previewRequiresAuthoritative READ previewRequiresAuthoritative NOTIFY presentationChanged)

public:
enum LoopWorkspace
Expand Down Expand Up @@ -293,6 +299,22 @@ class EditorHost final : public QObject
QVariantMap previewIdentity() const;
QString previewStaleReason() const;

/// Render fidelity and origin of the interactive preview (#28), the same fact on the
/// ordinary canvas and in the Production Preview. `previewFidelityStateName` is one of
/// `unavailable`, `stale`, `exact`, `approximate` or `authoritative`, derived by
/// `pdfquick::tokens::classifyPreviewFidelityState()` from the preview state and the
/// current page's render diagnostics; `previewFidelityOriginName` names the render path
/// (`none`, `fast-canvas`, `output-preview`). `previewRequiresAuthoritative` is true for
/// the overprint-sensitive fast render (`approximate`), whose pixels are not proof of
/// print-safe output. The interactive preview never certifies publication safety: only
/// `authoritative` names the output-preview origin, and no state reaches a pass.
QString previewFidelityStateName() const;
QVariantMap previewFidelityVisual() const;
QColor previewFidelityColor() const;
QString previewFidelityOriginName() const;
QString previewFidelitySummary() const;
bool previewRequiresAuthoritative() const;

/// Overprint render fidelity for the currently displayed page (issue #49).
/// True (and pageFidelityReason empty) when the page has no overprint
/// content, or none is known yet. Separate from the document-wide
Expand Down Expand Up @@ -364,6 +386,13 @@ class EditorHost final : public QObject
/// authoritative overprint-accurate one. Re-renders only that page;
/// the document stays open.
Q_INVOKABLE void toggleCurrentPageFidelity();

/// The explicit switch the preview surfaces call before a page is presented as proof:
/// when the current page is the overprint-sensitive fast render, it moves that page to
/// the authoritative output-preview render and returns true. A page that is already
/// authoritative, is exact, or has no document returns false and is left alone.
Q_INVOKABLE bool ensureAuthoritativePreview();

Q_INVOKABLE void goToPage(int pageIndex);
Q_INVOKABLE void goToOutlinePage(int pageIndex);
Q_INVOKABLE void setWorkspace(LoopWorkspace workspace);
Expand Down
32 changes: 13 additions & 19 deletions LoopEditor/qml/CanvasPane.qml
Original file line number Diff line number Diff line change
Expand Up @@ -53,23 +53,28 @@ Item {
Accessible.description: qsTr("The selected finding's registered evidence mode.")
}

// Persistent, non-modal render-fidelity indicator (issue #49). Unlike a
// toast, this stays up for as long as the current page is approximated so
// an operator cannot miss overprinted artwork that will drop out on
// press. Mirrors Main.qml's stateBanner: a Pane + Label status bar, shown
// only when there is something to say.
// Persistent, non-modal render-fidelity indicator (issue #49, #28). Unlike a
// toast, this stays up for as long as the page is not an exact fast render so an operator
// cannot miss overprinted artwork that will drop out on press. It names
// both the fidelity and the render origin (fast canvas path vs the
// authoritative output-preview path) via EditorHost's projection, and lets
// the operator escalate the current page. The words come from
// previewFidelitySummary; QML derives nothing. Mirrors Main.qml's
// stateBanner: a Pane + Label status bar.
Pane {
id: fidelityBanner
objectName: "renderFidelityBanner"
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
padding: 8
visible: root.host && root.host.hasDocument
&& (!root.host.pageFidelityIsExact || root.host.pageFidelityIsAuthoritative)
visible: root.host && root.host.hasDocument && root.host.previewFidelityStateName !== "exact"

Accessible.role: Accessible.StatusBar
Accessible.name: qsTr("Render fidelity status")
Accessible.description: root.host && root.host.previewFidelityOriginName === "output-preview"
? qsTr("Authoritative output-preview render")
: qsTr("Fast canvas render")

RowLayout {
anchors.fill: parent
Expand All @@ -79,18 +84,7 @@ Item {
id: fidelityLabel
Layout.fillWidth: true
wrapMode: Text.WordWrap
text: {
if (!root.host) {
return ""
}
if (root.host.pageFidelityIsAuthoritative && root.host.pageFidelityIsExact) {
return qsTr("Accurate render")
}
const reason = root.host.pageFidelityReason
return reason.length > 0
? qsTr("Approximate render: %1").arg(reason)
: qsTr("Approximate render")
}
text: root.host ? root.host.previewFidelitySummary : ""
Accessible.name: qsTr("Render fidelity message")
}

Expand Down
38 changes: 32 additions & 6 deletions LoopEditor/qml/ProductionPreviewPane.qml
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,22 @@ Pane {
wrapMode: Text.WordWrap
text: !root.host
? ""
: (root.host.pageFidelityIsExact
? qsTr("This page is rendered with exact overprint fidelity.")
: qsTr("This page is approximate: %1").arg(root.host.pageFidelityReason))
Accessible.name: qsTr("Page render fidelity")
: qsTr("Fidelity %1, origin %2.")
.arg(root.host.previewFidelityStateName)
.arg(root.host.previewFidelityOriginName)
Accessible.name: qsTr("Page render fidelity and origin")
}

// The same fidelity-and-origin fact the ordinary canvas banner shows, on the
// surface where a production/print claim is read. An approximate overprint
// render states that its pixels are not proof of print-safe output.
StateBadge {
objectName: "productionPreviewFidelityBadge"
Layout.fillWidth: true
visual: root.host ? root.host.previewFidelityVisual : null
stateColor: root.host ? root.host.previewFidelityColor : "transparent"
labelText: root.host ? root.host.previewFidelitySummary : ""
badgePrefix: "productionPreviewFidelityBadge"
}

Label {
Expand All @@ -107,12 +119,26 @@ Pane {
RowLayout {
Layout.fillWidth: true

// The explicit switch to the authoritative render the acceptance requires
// before a print claim. Enabled only while the page is still the
// overprint-sensitive fast render.
Button {
objectName: "productionPreviewProveButton"
text: qsTr("Proof this page (authoritative render)")
enabled: root.host && root.host.previewRequiresAuthoritative
onClicked: if (root.host) root.host.ensureAuthoritativePreview()
Accessible.name: qsTr("Switch this page to the authoritative overprint render")
Accessible.description: qsTr("Moves the current page to the output-preview render before any print claim. The document stays open.")
}

Button {
objectName: "productionPreviewFidelityToggle"
text: qsTr("Use exact overprint render")
text: root.host && root.host.pageFidelityIsAuthoritative
? qsTr("Return to the fast preview")
: qsTr("Use exact overprint render")
enabled: root.host && root.host.hasDocument
onClicked: if (root.host) root.host.toggleCurrentPageFidelity()
Accessible.name: qsTr("Switch this page to the exact overprint render")
Accessible.name: qsTr("Change this page's render fidelity")
Accessible.description: qsTr("Re-renders the current page only; the document stays open.")
}
}
Expand Down
72 changes: 72 additions & 0 deletions LoopLibQuick/sources/loopstatevisual.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,4 +267,76 @@ LoopStateVisual resolveFixLifecycleStateVisual(const QString& stateName)
QStringLiteral("No correction planned") };
}

QString classifyPreviewFidelityState(bool hasDocument, bool stale, bool authoritative, bool exact)
{
// The host owns these four facts; this orders them and names the result. An open
// document whose preview belongs to an earlier revision is stale before it is
// anything else, and an authoritative render is authoritative before it is judged
// on its (ascertained later) diagnostics.
if (!hasDocument)
{
return QStringLiteral("unavailable");
}
if (stale)
{
return QStringLiteral("stale");
}
if (authoritative)
{
return QStringLiteral("authoritative");
}
if (!exact)
{
// The fast canvas path on overprint-sensitive content: overprint is not simulated.
return QStringLiteral("approximate");
}
return QStringLiteral("exact");
}

QString previewFidelityOriginName(const QString& stateName)
{
const QString normalized = stateName.trimmed().toLower();

if (normalized == QLatin1String("authoritative"))
{
return QStringLiteral("output-preview");
}
if (normalized == QLatin1String("approximate") || normalized == QLatin1String("exact"))
{
return QStringLiteral("fast-canvas");
}
return QStringLiteral("none");
}

LoopStateVisual resolvePreviewFidelityStateVisual(const QString& stateName)
{
const QString normalized = stateName.trimmed().toLower();

if (normalized == QLatin1String("authoritative"))
{
return { StateKind::Info, ColorRole::SeverityInfo, StateIcon::BadgeOverlay,
QStringLiteral("Authoritative output-preview render") };
}
if (normalized == QLatin1String("approximate"))
{
// The overprint-sensitive fast render: never a pass, never a proof of print-safe output.
return { StateKind::Warning, ColorRole::SeverityWarning, StateIcon::Cross,
QStringLiteral("Approximate render, overprint is not simulated") };
}
if (normalized == QLatin1String("exact"))
{
return { StateKind::Info, ColorRole::SeverityInfo, StateIcon::FilledSquare,
QStringLiteral("Fast preview path, no overprint-sensitive content") };
}
if (normalized == QLatin1String("stale"))
{
return { StateKind::Incomplete, ColorRole::StateIncomplete, StateIcon::Hatched,
QStringLiteral("Preview is stale for the current revision") };
}

// "unavailable", an empty string and anything unrecognised: no preview to trust.
return { StateKind::NotChecked, ColorRole::StateNotChecked, StateIcon::Outline,
QStringLiteral("Preview fidelity unavailable") };
}

} // namespace pdfquick::tokens
21 changes: 21 additions & 0 deletions LoopLibQuick/sources/loopstatevisual.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,27 @@ LOOPLIBQUICK_EXPORT LoopStateVisual resolvePreflightStateVisual(const QString& s
/// every state carries a shape no other state uses, so the state survives without colour.
LOOPLIBQUICK_EXPORT LoopStateVisual resolveFixLifecycleStateVisual(const QString& stateName);

/// Render fidelity and origin of the interactive preview (#28). The state name is derived
/// from four facts the host already holds: whether a document is open, whether the preview
/// is stale for the open revision, whether the current page is showing the authoritative
/// output-preview render, and whether that page's render is diagnostic-exact.
///
/// `approximate` is the overprint-sensitive page on the fast canvas path: overprint is not
/// simulated there, so those pixels are never proof of print-safe output. `authoritative`
/// is the only state that names the output-preview origin. No preview state reaches a pass
/// treatment: the interactive preview proves a page's render path, never publication safety.
LOOPLIBQUICK_EXPORT QString classifyPreviewFidelityState(bool hasDocument, bool stale, bool authoritative, bool exact);

/// Which render path produced the preview's pixels, for a state name above: `none`,
/// `fast-canvas` or `output-preview`. Rendering only, no analysis.
LOOPLIBQUICK_EXPORT QString previewFidelityOriginName(const QString& stateName);

/// Canonical treatment for a preview fidelity state name. Each state takes a shape no other
/// preview state uses, and `approximate` (the fast canvas path on overprint-sensitive
/// content) can never be read as proof of print-safe output: no preview state carries a pass
/// colour or a check.
LOOPLIBQUICK_EXPORT LoopStateVisual resolvePreviewFidelityStateVisual(const QString& stateName);

} // namespace pdfquick::tokens

#endif // LOOPSTATEVISUAL_H
Loading
Loading