diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 440efac..2997d15 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -59,6 +59,7 @@ pub struct PrimitiveModel { pub value: String, pub children: Vec, pub trace: Vec, + pub expanded: bool, } #[derive(Serialize, Debug, Clone)] @@ -79,12 +80,12 @@ pub struct PageModel { page_num: u64, } #[derive(Deserialize, Serialize, Debug, Clone)] -pub struct TreeViewNode { +pub struct TreeViewRequest { key: String, - children: Vec, + children: Vec, } -impl TreeViewNode { +impl TreeViewRequest { fn step(&self) -> Result { Step::parse_step(&self.key) } @@ -303,7 +304,7 @@ fn resolve_parent(step: Step, file: &CosFile) -> Result<(Primitive, PathTrace), #[tauri::command] fn get_prim_tree_by_path( id: &str, - path: TreeViewNode, + path: TreeViewRequest, session: State>, ) -> Result { let session_guard = session @@ -315,7 +316,7 @@ fn get_prim_tree_by_path( } fn get_prim_tree_by_path_with_file( - node: TreeViewNode, + node: TreeViewRequest, file: &CosFile, ) -> Result { let step = node.step()?; @@ -332,7 +333,7 @@ fn get_prim_tree_by_path_with_file( } fn expand( - node: &TreeViewNode, + node: &TreeViewRequest, parent_model: &mut PrimitiveModel, parent: &Primitive, file: &CosFile, @@ -357,7 +358,7 @@ fn expand( } fn expand_children( - node: &TreeViewNode, + node: &TreeViewRequest, file: &CosFile, prim: &Primitive, mut expanded: &mut PrimitiveModel, @@ -562,6 +563,7 @@ impl PrimitiveModel { value: value, children: Vec::new(), trace: path, + expanded: false, } } @@ -604,6 +606,7 @@ impl PrimitiveModel { } fn add_children(&mut self, primitive: &Primitive, path: Vec) { + self.expanded = true; match primitive { Primitive::Dictionary(dict) => dict.iter().for_each(|(name, value)| { self.add_child( @@ -623,6 +626,7 @@ impl PrimitiveModel { value: "".to_string(), children: vec![], trace: append_path("Data".to_string(), &path), + expanded: false, }); stream.info.iter().for_each(|(name, value)| { self.add_child( diff --git a/src-tauri/src/tests.rs b/src-tauri/src/tests.rs index 2dfde76..01c80e9 100644 --- a/src-tauri/src/tests.rs +++ b/src-tauri/src/tests.rs @@ -6,7 +6,7 @@ mod tests { use crate::{ get_prim_by_path_with_file, get_prim_model_by_path_with_file, get_prim_tree_by_path_with_file, get_stream_data_by_path_with_file, - get_xref_table_model_with_file, to_pdf_file, PathTrace, PrimitiveModel, TreeViewNode, + get_xref_table_model_with_file, to_pdf_file, PathTrace, PrimitiveModel, TreeViewRequest, }; use pdf::content::{display_ops, serialize_ops, Op}; @@ -61,25 +61,25 @@ mod tests { "Loading file" ); let mut path = Vec::new(); - path.push(TreeViewNode { + path.push(TreeViewRequest { key: "Index".to_string(), - children: vec![TreeViewNode { + children: vec![TreeViewRequest { key: "1".to_string(), children: vec![], }], }); - path.push(TreeViewNode { + path.push(TreeViewRequest { key: "Info".to_string(), children: vec![], }); - path.push(TreeViewNode { + path.push(TreeViewRequest { key: "Root".to_string(), - children: vec![TreeViewNode { + children: vec![TreeViewRequest { key: "Pages".to_string(), children: vec![], }], }); - let root = TreeViewNode { + let root = TreeViewRequest { key: "/".to_string(), children: path, }; diff --git a/src/components/FileView.svelte b/src/components/FileView.svelte index 6ca5397..cf2f6e0 100644 --- a/src/components/FileView.svelte +++ b/src/components/FileView.svelte @@ -7,10 +7,10 @@ import { createEventDispatcher, onMount } from "svelte"; import PageList from "./PageList.svelte"; import ContentsView from "./ContentsView.svelte"; - import TreeViewNode from "../models/TreeViewNode.svelte"; + import TreeViewRequest from "../models/TreeViewRequest.svelte"; import TreeViewState from "../models/TreeViewState.svelte"; import type { PathSelectedEvent } from "../events/PathSelectedEvent"; - + TreeViewRequest; let { treeShowing, xrefTableShowing, @@ -52,10 +52,8 @@ window.removeEventListener("mousedown", handleMouseButton); }; }); - function pathSelectedHandler(event: PathSelectedEvent) { - console.log("Path selected", event.detail.path); - fState.selectPath(event.detail.path); + fState.selectPathHandler(event); } @@ -73,11 +71,15 @@ {#if pagesShowing} {:else if treeShowing} - +
+ +
{/if} diff --git a/src/components/PageList.svelte b/src/components/PageList.svelte index 29ccc84..95eb2da 100644 --- a/src/components/PageList.svelte +++ b/src/components/PageList.svelte @@ -1,48 +1,37 @@
- - - - - - - -
PageRef
-
- - - {#each fState.file.pages as page} - handlePageSelect(page)} - > - - - - {/each} - -
-
- -

- {page.key} -

-
-
{page.obj_num}
+
+ {#each pages as page} + + {/each}
diff --git a/src/components/PrimitiveView.svelte b/src/components/PrimitiveView.svelte index 744e90b..613d4c3 100644 --- a/src/components/PrimitiveView.svelte +++ b/src/components/PrimitiveView.svelte @@ -3,12 +3,15 @@ import type Primitive from "../models/Primitive.svelte"; import ContentsView from "./ContentsView.svelte"; import PrimitiveIcon from "./PrimitiveIcon.svelte"; + import StreamEditor from "./StreamEditor.svelte"; let { fState, height }: { fState: FileViewState; height: number } = $props(); let bodyHeight = $derived(height - 24); let prim = $derived(fState.prim); let showContents = $state(false); + let tableHeight = $state(0); + let editorHeight = $derived(Math.max(800, bodyHeight - tableHeight)); $inspect(fState.highlightedPrim); function handlePrimSelect(prim: Primitive) { if (prim.isContainer()) { @@ -39,7 +42,7 @@
- +
{#each prim.children as entry}
+ {#if fState.prim?.ptype === "Stream"} + + {/if}
diff --git a/src/components/StreamEditor.svelte b/src/components/StreamEditor.svelte new file mode 100644 index 0000000..683f0c1 --- /dev/null +++ b/src/components/StreamEditor.svelte @@ -0,0 +1,56 @@ + + +
+ + diff --git a/src/components/TreeNode.svelte b/src/components/TreeNode.svelte index 3f0bc79..c29a45c 100644 --- a/src/components/TreeNode.svelte +++ b/src/components/TreeNode.svelte @@ -7,15 +7,19 @@ import { createEventDispatcher } from "svelte"; let { + file_id, parent_view, parent_path, treeState, pathSelectedHandler = $bindable(), + details, }: { - parent_view: Primitive; + file_id: string; + parent_view: Primitive | undefined; parent_path: string[]; - treeState: TreeViewState; + treeState: TreeViewState | undefined; pathSelectedHandler: any; + details: boolean; } = $props(); function copyPathAndAppend(key: string): string[] { @@ -35,73 +39,75 @@ function selectItem(child: Primitive) { let _path = copyPathAndAppend(child.key); - console.log("Selecting from tree", _path); - treeState.expandTree(_path); - - const event = new PathSelectedEvent(_path); + if (child.expanded) { + treeState?.collapseTree(_path); + } else { + treeState?.expandTree(_path); + } + const event = new PathSelectedEvent(file_id, _path); pathSelectedHandler(event); } {#if parent_view} -
    - {#each parent_view.children as child} -
  • -
    - {#if child.children.length > 0} - selectItem(child)} + > +
    + {#if child.isContainer()} +
    + {#if child.expanded}{:else}{/if} - {:else if child.isContainer()} - - {:else} - - {/if} - -
    - {#if child.children.length > 0} - +
    + {:else} + {/if} -
  • - {/each} -
+
+ +
+

+ {child.key} +

+ {#if details} +

+ {" | " + + child.ptype + + " | " + + child.sub_type + + " | " + + child.value} +

+ {:else} +

+ {child.sub_type} +

+ {/if} +
+
+ + + {#if child.children.length > 0} + + {/if} + {/each} {/if} diff --git a/src/events/PathSelectedEvent.ts b/src/events/PathSelectedEvent.ts index 8a4bf95..530430d 100644 --- a/src/events/PathSelectedEvent.ts +++ b/src/events/PathSelectedEvent.ts @@ -1,9 +1,9 @@ -export class PathSelectedEvent extends CustomEvent<{ path: string[] }> { +export class PathSelectedEvent extends CustomEvent<{ file_id: string, path: string[] }> { static readonly eventName = 'pathselected'; - constructor(path: string[]) { + constructor(file_id: string, path: string[]) { super(PathSelectedEvent.eventName, { - detail: { path }, + detail: { file_id, path }, bubbles: true }); } diff --git a/src/models/FileViewState.svelte.ts b/src/models/FileViewState.svelte.ts index 37701c8..7dfcfaf 100644 --- a/src/models/FileViewState.svelte.ts +++ b/src/models/FileViewState.svelte.ts @@ -2,8 +2,10 @@ import type PdfFile from "./PdfFile"; import type XRefEntry from "./XRefEntry"; import Primitive from "./Primitive.svelte"; import { invoke } from "@tauri-apps/api/core"; -import TreeViewNode from "./TreeViewNode.svelte"; +import TreeViewRequest from "./TreeViewRequest.svelte"; import type XRefTable from "./XRefTable"; +import TreeViewState from "./TreeViewState.svelte"; +import type { PathSelectedEvent } from "../events/PathSelectedEvent"; export default class FileViewState { @@ -13,7 +15,6 @@ export default class FileViewState { public highlightedPrim: Primitive | undefined = $state(); public xref_entries: XRefEntry[] = $state([]); - constructor(file: PdfFile) { this.file = file; @@ -53,13 +54,14 @@ export default class FileViewState { .catch(err => console.error(err)); } - - - public getTreeRoot() { - return this.treeState; + public selectPathHandler(event: PathSelectedEvent) { + console.log("Selecting path", event.detail); + if (event.detail.file_id !== this.file.id) { + return; + } + this.selectPath(event.detail.path); } - public getMergedPath() { return this.mergePaths(this.path); } @@ -96,7 +98,7 @@ export default class FileViewState { return "/"; } if (paths[0] === "/") { - return "/" + paths.slice(1, paths.length).join("/") + return "Trailer/" + paths.slice(1, paths.length).join("/") } return paths.join("/"); } diff --git a/src/models/Primitive.svelte.ts b/src/models/Primitive.svelte.ts index ab8f6db..57f5a41 100644 --- a/src/models/Primitive.svelte.ts +++ b/src/models/Primitive.svelte.ts @@ -5,6 +5,7 @@ export default class Primitive { public value: string; public children: Primitive[]; public trace: Trace[] = $state([]); + public expanded: boolean = $state(false); constructor( p: Primitive @@ -18,6 +19,7 @@ export default class Primitive { this.children.push(new Primitive(child)); } this.trace = []; + this.expanded = p.expanded; for (let path of p.trace) { this.trace.push(path); } @@ -54,6 +56,14 @@ export default class Primitive { if (path.startsWith("Page")) { return path }; return +path; } + + public withoutChildren(): Primitive { + return new Primitive({ + ...this, + children: [], + expanded: false, + }); + } } export interface Trace { diff --git a/src/models/TreeViewNode.svelte.ts b/src/models/TreeViewNode.svelte.ts deleted file mode 100644 index a280fc0..0000000 --- a/src/models/TreeViewNode.svelte.ts +++ /dev/null @@ -1,33 +0,0 @@ -export default class TreeViewNode { - - public key: string; - public children: TreeViewNode[]; - constructor( - key: string, - children: TreeViewNode[] - ) { - this.key = key; - this.children = children; - } - - static TRAILER = new TreeViewNode("Trailer", [new TreeViewNode("Root", [])]); - - - public getChild(key: string) { - return this.children.find(child => child.key === key); - } - - public addChild(key: string) { - let child = new TreeViewNode(key, []) - this.children.push(child); - return child; - } - - public clearChildren() { - this.children = []; - } - - public removeChild(key: string) { - this.children = this.children.filter(child => child.key !== key); - } -} \ No newline at end of file diff --git a/src/models/TreeViewRequest.svelte.ts b/src/models/TreeViewRequest.svelte.ts new file mode 100644 index 0000000..a2718c0 --- /dev/null +++ b/src/models/TreeViewRequest.svelte.ts @@ -0,0 +1,45 @@ +export default class TreeViewRequest { + + public key: string; + public children: TreeViewRequest[]; + public displayName: string; + public active: boolean; + + constructor( + key: string, + children: TreeViewRequest[] + ) { + if (key.startsWith("Page")) { + this.displayName = "Page " + key.slice(4); + } else { + this.displayName = key; + } + this.key = key; + this.children = children; + this.active = true; + } + + static TRAILER = new TreeViewRequest("Trailer", [new TreeViewRequest("Root", [])]); + + public clone(): TreeViewRequest { + return new TreeViewRequest(this.key, this.children.map(child => child.clone())); + } + + public getChild(key: string) { + return this.children.find(child => child.key === key); + } + + public addChild(key: string) { + let child = new TreeViewRequest(key, []) + this.children.push(child); + return child; + } + + public clearChildren() { + this.children = []; + } + + public removeChild(key: string) { + this.children = this.children.filter(child => child.key !== key); + } +} \ No newline at end of file diff --git a/src/models/TreeViewState.svelte.ts b/src/models/TreeViewState.svelte.ts index 66a29f0..a055603 100644 --- a/src/models/TreeViewState.svelte.ts +++ b/src/models/TreeViewState.svelte.ts @@ -1,28 +1,39 @@ import { invoke } from "@tauri-apps/api/core"; import Primitive from "./Primitive.svelte"; -import TreeViewNode from "./TreeViewNode.svelte"; -import type FileViewState from "./FileViewState.svelte"; +import TreeViewRequest from "./TreeViewRequest.svelte"; +import type { PathSelectedEvent } from "../events/PathSelectedEvent"; export default class TreeViewState { - public root: TreeViewNode = $state(new TreeViewNode("Trailer", [new TreeViewNode("Root", [])])); + + private root: TreeViewRequest = $state(new TreeViewRequest("Trailer", [new TreeViewRequest("Root", [])])); public view: Primitive | undefined = $state(); + active: boolean = $state(false); + file_id: string; - constructor(file_id: string, root: TreeViewNode) { + constructor(file_id: string, root: TreeViewRequest) { console.log("Creating tree view state", file_id, root); this.file_id = file_id; this.root = root; - this.loadTreeView(); } public loadTreeView() { - console.log("Loading tree view", this.root); + this.setTreeViewRequest(this.getRoot()); + } + + public getRoot(): TreeViewRequest { + return this.root.clone(); + } + + public setTreeViewRequest(treeViewRequest: TreeViewRequest) { + console.log("Loading tree view", treeViewRequest); invoke("get_prim_tree_by_path", { id: this.file_id, - path: this.root, + path: treeViewRequest, }) .then((result) => { this.view = new Primitive(result); + this.root = treeViewRequest; }) .catch((err) => console.error(err)); } @@ -32,16 +43,18 @@ export default class TreeViewState { console.error("Empty path"); return; } - let node = this.root; + console.log("Expanding tree", this.getRoot(), path); + let root = this.getRoot(); + let node = root; for (let key of path.slice(1, path.length)) { - let _node: TreeViewNode | undefined = node.getChild(key); + let _node: TreeViewRequest | undefined = node.getChild(key); if (_node) { node = _node; } else { node = node.addChild(key); } } - this.loadTreeView(); + this.setTreeViewRequest(root); } public collapseTree(path: string[]) { @@ -50,16 +63,17 @@ export default class TreeViewState { return; } if (path.length == 1) { - this.root.clearChildren(); + this.view = this.view?.withoutChildren(); return; } - let node: TreeViewNode | undefined = this.root; + let root: TreeViewRequest = this.root; + let node: TreeViewRequest | undefined = root; for (let key of path.slice(1, path.length - 1)) { node = node?.getChild(key); } if (node) { node.removeChild(path[path.length - 1]); + this.setTreeViewRequest(root); } - this.loadTreeView(); } -} \ No newline at end of file +} diff --git a/tailwind.config.ts b/tailwind.config.ts index a9ba797..b4244d4 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -27,7 +27,8 @@ export default { active: 'rgb(44, 71, 73)', bound: 'rgba(0, 0, 0, 0.29)', text: '#dadada', - text_sec: '#6c6c6c', + text_sec: '#838686', + text_hint: '#5adada', } } }