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
803 changes: 802 additions & 1 deletion LoopEditor/editorhost.cpp

Large diffs are not rendered by default.

86 changes: 86 additions & 0 deletions LoopEditor/editorhost.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include "pdfjobscheduler.h"
#include "pdfoperationhistory.h"
#include "pdfsignaturehandler.h"
#include "pdfauthoringedit.h"

#include <QColor>
#include <QImage>
Expand Down Expand Up @@ -169,6 +170,13 @@ class EditorHost final : public QObject
Q_PROPERTY(bool settingsResetPending READ settingsResetPending NOTIFY presentationChanged)
Q_PROPERTY(QVariantMap diagnosticsBundle READ diagnosticsBundle NOTIFY presentationChanged)

// ---- Direct authoring edits (ADR-014, issue #242) ------------------------------
// The last attachment extraction's outcome: `status` is `idle`, `written` or
// `refused`; `fileName` is the extracted name alone (never a path);
// `autoOpenRefused` says the extracted file must not be auto-opened because
// its type is executable; `typedError` is the stable refusal code.
Q_PROPERTY(QVariantMap attachmentExtraction READ attachmentExtraction NOTIFY presentationChanged)

// ---- Workspace surfaces (#586) -------------------------------------------------
// Every property below is a read-only projection of what Core, PdfTool or the
// shell's own run already decided. QML renders these; it derives no state and
Expand Down Expand Up @@ -355,6 +363,17 @@ class EditorHost final : public QObject
/// in C++.
Q_INVOKABLE bool collectDiagnosticsFileUrl(const QUrl& parentDirectory);

// ---- Direct authoring edits (ADR-014, issue #242) ------------------------------
/// The last attachment extraction's outcome. See the Q_PROPERTY above.
QVariantMap attachmentExtraction() const { return m_attachmentExtraction; }

/// Extracts one attachment into `directory` through the atomic writer, which
/// refuses to replace an existing file. The outcome is projected into
/// attachmentExtraction(); an extracted file whose type is executable is
/// reported with `autoOpenRefused`, and the shell must not hand it to the
/// operating system's opener. Reads the document; mutates nothing.
Q_INVOKABLE bool extractAttachmentFileUrl(const QUrl& directory, const QString& name);

/// Operator lifecycle of the governed-correction route (#586):
/// `idle`, `planned`, `preview-ready`, `approved`, `executing`, `succeeded`,
/// `stale`, `rejected`, `cancelled`, `failed`. It is a projection of the run the
Expand Down Expand Up @@ -617,6 +636,18 @@ class EditorHost final : public QObject
/// in-flight drag with ToolChanged (#141 AC3).
Q_INVOKABLE bool setActiveTool(const QString& toolId);

// ---- Bookmarks and hyperlinks (issue #233) -------------------------------------
/// Imports a bookmark interchange file and replaces the document outline
/// with its records. `revision` is the revision the operator saw when the
/// file dialog opened; an import that no longer matches it is refused with
/// a typed reason instead of landing on a revision the operator never saw.
Q_INVOKABLE bool importBookmarksFileUrl(const QUrl& url, const QString& revision);

/// Exports the document outline to the bookmark interchange file. The
/// exported bytes describe `revision`; a stale `revision` is refused rather
/// than exported as if it described the current document.
Q_INVOKABLE bool exportBookmarksFileUrl(const QUrl& url, const QString& revision);

// ---- Select, copy and capture (issue #232) -------------------------------------
/// Copies the canvas text selection to the clipboard. The clipboard is only
/// written when there is text to copy; a page with no text layer reports
Expand Down Expand Up @@ -693,12 +724,25 @@ class EditorHost final : public QObject
/// asks for one and answers with extractCurrentPageImagesFileUrl().
void imageExtractionRequested();

/// Send by e-mail hands the current published revision to the shell's mail
/// client. `path` is the published artifact and `revision` is the identity it
/// was published as, so the receiving side can refuse a mismatch. Emitted
/// only for an open document with no unsaved changes: an unsaved or stale
/// revision is refused instead, never mailed as if it were the file.
void documentMailRequested(const QString& path, const QString& revision);

/// The shell-side surfaces (#239). The commands emit these; QML owns the
/// dialogs and opens them.
void settingsPanelRequested();
void settingsResetRequested();
void diagnosticsCollectionRequested();

/// The bookmark import/export commands need a file, so the shell asks for
/// one and answers with importBookmarksFileUrl()/exportBookmarksFileUrl().
/// The commands themselves write nothing.
void bookmarkImportRequested();
void bookmarkExportRequested();

private:
void connectFacade();
void connectViewport();
Expand All @@ -709,7 +753,45 @@ class EditorHost final : public QObject
void registerFeatureHandlers();
void refreshFeatureAvailability();
bool commandPermissionAllowed(const QString& commandId) const;
/// Applies one document-family direct-edit command through the facade's
/// direct-edit gateway (ADR-014). The command's declared scalars become the
/// request's payload; for an attachment the host reads the source file, so
/// the gateway itself never touches the filesystem. The facade's typed
/// refusal is returned as it stands.
pdfinteraction::DirectEditOutcome submitDocumentDirectEdit(pdfinteraction::DirectEditKind kind,
const QVariantMap& parameters);
/// Hands the current published revision to the shell's mail client. Refuses
/// when there is no open document, when its source is not a file, or when it
/// has unsaved changes: the bytes on disk would then be a different revision
/// than the one on screen. Never writes and never opens anything itself.
bool handOffPublishedRevisionToMail(QString* typedError);
bool requestMoveSelection(const QVariantMap& parameters);

// ---- Bookmarks and hyperlinks (issue #233) -------------------------------------
/// Runs one authoring command: submits the built edit through the facade
/// gateway and finishes the invocation with the outcome, announcing what
/// happened. `buildError` is the command's typed refusal when no edit could
/// be built.
void runAuthoringEdit(pdfinteraction::CommandInvocationId invocation,
const std::optional<pdf::PDFAuthoringEdit>& edit,
const QString& buildError,
const QVariantMap& parameters);
/// The fence and the facade call behind every authoring command. `typedError`
/// is set on refusal.
pdfinteraction::DirectEditOutcome submitAuthoringEdit(const pdf::PDFAuthoringEdit& edit,
const QVariantMap& parameters,
QString& typedError);
/// The link rectangle and page a hyperlink command addresses: explicit
/// scalars when the surface supplied them, otherwise the current text
/// selection, which is the Quick shell's own "this region" gesture.
bool authoringLinkGeometry(const QVariantMap& parameters, int* pageIndex, QRectF* rectangle,
QString& typedError) const;
/// Moves to the next (1) or previous (-1) bookmark page in outline order,
/// wrapping at the ends like the shell's historical bookmark cursor.
bool goToAdjacentBookmark(int direction, QString& typedError);
/// The operator-facing sentence for one applied edit.
QString authoringEditAnnouncement(const pdf::PDFAuthoringEdit& edit,
const pdfinteraction::DirectEditOutcome& outcome) const;
void moveSearch(int direction);
bool moveFindingSelection(int direction);
void refreshHitTestSources();
Expand Down Expand Up @@ -835,6 +917,10 @@ class EditorHost final : public QObject
};
DiagnosticsBundleState m_diagnosticsBundle;

/// The last attachment extraction's outcome (ADR-014, issue #242). A
/// projection of the Core writer's own result: file name only, never a path.
QVariantMap m_attachmentExtraction;

QPointer<pdfquick::LoopCanvasItem> m_canvas;
QHash<QString, pdf::PDFJobKind> m_activeAsyncJobs;
QString m_outputJobId;
Expand Down
4 changes: 4 additions & 0 deletions LoopEditor/qml/MenuModel.qml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ QtObject {
}
switch (entry.id) {
case "actionAbout": return qsTr("About")
case "actionAddAttachment": return qsTr("Add Attachment")
case "actionAutomaticDocumentRefresh": return qsTr("Automatic Document Refresh")
case "actionBecomeASponsor": return qsTr("Become ASponsor")
case "actionBleedFixup": return qsTr("Bleed Fixup")
Expand Down Expand Up @@ -124,6 +125,7 @@ QtObject {
case "actionCreateTextStrikeout": return qsTr("Create Text Strikeout")
case "actionCreateTextUnderline": return qsTr("Create Text Underline")
case "actionDeselectText": return qsTr("Deselect Text")
case "actionEditDocumentMetadata": return qsTr("Edit Document Metadata")
case "actionEncryption": return qsTr("Encryption")
case "actionExtractImage": return qsTr("Extract Image")
case "actionFind": return qsTr("Find")
Expand Down Expand Up @@ -161,6 +163,7 @@ QtObject {
case "actionQuit": return qsTr("Quit")
case "actionRedo": return qsTr("Redo")
case "actionRemoveExternalLinks": return qsTr("Remove External Links")
case "actionRemoveAttachment": return qsTr("Remove Attachment")
case "actionRender_to_Images": return qsTr("Render to Images")
case "actionRendering_Errors": return qsTr("Rendering Errors")
case "actionRenderOptionAntialiasing": return qsTr("Render Option Antialiasing")
Expand All @@ -180,6 +183,7 @@ QtObject {
case "actionSelectText": return qsTr("Select Text")
case "actionSelectTextAll": return qsTr("Select Text All")
case "actionSend_by_E_Mail": return qsTr("Send by E Mail")
case "actionSetFormFieldValue": return qsTr("Set Form Field Value")
case "actionShow_Text_Blocks": return qsTr("Show Text Blocks")
case "actionShow_Text_Lines": return qsTr("Show Text Lines")
case "actionStickyNoteComment": return qsTr("Sticky Note Comment")
Expand Down
8 changes: 8 additions & 0 deletions LoopLibCore/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ add_library(LoopLibCore SHARED
sources/pdfalgorithmlcs.h
sources/pdfannotation.cpp
sources/pdfannotation.h
sources/pdfannotationauthoring.cpp
sources/pdfannotationauthoring.h
sources/pdfblendfunction.cpp
sources/pdfblendfunction.h
sources/pdfccittfaxdecoder.cpp
Expand Down Expand Up @@ -136,6 +138,8 @@ add_library(LoopLibCore SHARED
sources/pdfdocumenttextfloweditormodel.h
sources/pdfdocumentwriter.cpp
sources/pdfdocumentwriter.h
sources/pdfdirectedit.cpp
sources/pdfdirectedit.h
sources/pdfwriteobjectvisitor.cpp
sources/pdfwriteobjectvisitor_p.h
sources/pdfexecutionpolicy.cpp
Expand Down Expand Up @@ -166,6 +170,8 @@ add_library(LoopLibCore SHARED
sources/pdfoptimizer.h
sources/pdfoptionalcontent.cpp
sources/pdfoptionalcontent.h
sources/pdfauthoringedit.cpp
sources/pdfauthoringedit.h
sources/pdfoutline.cpp
sources/pdfoutline.h
sources/pdfpagenavigation.cpp
Expand Down Expand Up @@ -286,6 +292,8 @@ add_library(LoopLibCore SHARED
sources/pdfartifactidentity.cpp
sources/pdfartifactstore.h
sources/pdfartifactstore.cpp
sources/pdfauthoringhistory.h
sources/pdfauthoringhistory.cpp
sources/pdfoperationhistory.h
sources/pdfoperationhistory.cpp
sources/pdfoperationhistorystore.h
Expand Down
Loading
Loading