getting there
* stream view and page list working
This commit is contained in:
parent
7e71cb947b
commit
570d495faa
@ -59,6 +59,7 @@ pub struct PrimitiveModel {
|
||||
pub value: String,
|
||||
pub children: Vec<PrimitiveModel>,
|
||||
pub trace: Vec<PathTrace>,
|
||||
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<TreeViewNode>,
|
||||
children: Vec<TreeViewRequest>,
|
||||
}
|
||||
|
||||
impl TreeViewNode {
|
||||
impl TreeViewRequest {
|
||||
fn step(&self) -> Result<Step, String> {
|
||||
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<Mutex<Session>>,
|
||||
) -> Result<PrimitiveModel, String> {
|
||||
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<PrimitiveModel, String> {
|
||||
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<PathTrace>) {
|
||||
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(
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
||||
@ -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);
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -73,11 +71,15 @@
|
||||
{#if pagesShowing}
|
||||
<PageList {fState} h={height}></PageList>
|
||||
{:else if treeShowing}
|
||||
<TreeView
|
||||
bind:pathSelectedHandler
|
||||
file_id={fState.file.id}
|
||||
root={TreeViewNode.TRAILER}
|
||||
></TreeView>
|
||||
<div class="overflow-auto" style="height: {height}px">
|
||||
<TreeView
|
||||
{pathSelectedHandler}
|
||||
file_id={fState.file.id}
|
||||
root={TreeViewRequest.TRAILER}
|
||||
active={true}
|
||||
details={false}
|
||||
></TreeView>
|
||||
</div>
|
||||
{/if}
|
||||
</Pane>
|
||||
|
||||
|
||||
@ -1,48 +1,37 @@
|
||||
<script lang="ts">
|
||||
import type FileViewState from "../models/FileViewState.svelte";
|
||||
import PrimitiveIcon from "./PrimitiveIcon.svelte";
|
||||
import type PageModel from "../models/PageModel";
|
||||
import TreeView from "./TreeView.svelte";
|
||||
import TreeViewRequest from "../models/TreeViewRequest.svelte";
|
||||
import type { PathSelectedEvent } from "../events/PathSelectedEvent";
|
||||
|
||||
let { fState, h }: { fState: FileViewState; h: number } = $props();
|
||||
let selected: PageModel | undefined = $state(undefined);
|
||||
let selected_page_num: number | undefined = $state(undefined);
|
||||
let pages = $derived(fState.file.pages);
|
||||
|
||||
function handlePageSelect(page: PageModel) {
|
||||
selected = page;
|
||||
fState.selectPath(["Page" + page.page_num]);
|
||||
function pathSelectedHandler(event: PathSelectedEvent) {
|
||||
let path = event.detail.path;
|
||||
if (
|
||||
path.length > 0 &&
|
||||
path[0].startsWith("Page") &&
|
||||
!isNaN(+path[0].replace("Page", ""))
|
||||
) {
|
||||
selected_page_num = +path[0].replace("Page", "");
|
||||
}
|
||||
fState.selectPath(path);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td class="page-cell t-header border-forge-prim">Page</td>
|
||||
<td class="ref-cell t-header border-forge-sec">Ref</td>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
<div class="overflow-y-auto" style="height: {h - 25}px">
|
||||
<table>
|
||||
<tbody>
|
||||
{#each fState.file.pages as page}
|
||||
<tr
|
||||
class:selected={page === selected}
|
||||
class="hover:bg-forge-sec"
|
||||
ondblclick={() => handlePageSelect(page)}
|
||||
>
|
||||
<td class="page-cell t-data">
|
||||
<div class="key-field">
|
||||
<PrimitiveIcon ptype={"Reference"} />
|
||||
<p class="text-left">
|
||||
{page.key}
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
<td class="ref-cell t-data">{page.obj_num}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="overflow-y-auto" style="height: {h}px">
|
||||
{#each pages as page}
|
||||
<TreeView
|
||||
file_id={fState.file.id}
|
||||
root={new TreeViewRequest("Page" + page.page_num, [])}
|
||||
{pathSelectedHandler}
|
||||
active={selected_page_num === page.page_num}
|
||||
details={true}
|
||||
></TreeView>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -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 @@
|
||||
</thead>
|
||||
</table>
|
||||
<div class="overflow-y-auto" style="height: {bodyHeight}px">
|
||||
<table>
|
||||
<table bind:clientHeight={tableHeight}>
|
||||
<tbody>
|
||||
{#each prim.children as entry}
|
||||
<tr
|
||||
@ -63,6 +66,13 @@
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
{#if fState.prim?.ptype === "Stream"}
|
||||
<StreamEditor
|
||||
fileId={fState.file.id}
|
||||
path={fState.getMergedPath()}
|
||||
height={editorHeight}
|
||||
></StreamEditor>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
56
src/components/StreamEditor.svelte
Normal file
56
src/components/StreamEditor.svelte
Normal file
@ -0,0 +1,56 @@
|
||||
<script lang="ts">
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import type ContentModel from "../models/ContentModel.svelte";
|
||||
import { onMount } from "svelte";
|
||||
import * as monaco from "monaco-editor";
|
||||
|
||||
let {
|
||||
fileId,
|
||||
path,
|
||||
height,
|
||||
}: { fileId: string; path: string; height: number } = $props();
|
||||
|
||||
let contents: string | undefined = $state(undefined);
|
||||
let editorContainer: HTMLElement;
|
||||
let editor: monaco.editor.IStandaloneCodeEditor;
|
||||
onMount(() => {
|
||||
editor = monaco.editor.create(editorContainer, {
|
||||
value: "",
|
||||
language: "plaintext",
|
||||
theme: "vs-dark",
|
||||
minimap: { enabled: false },
|
||||
scrollBeyondLastLine: false,
|
||||
fontSize: 14,
|
||||
automaticLayout: true,
|
||||
});
|
||||
|
||||
return () => {
|
||||
editor.dispose();
|
||||
};
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
loadContents(path, fileId);
|
||||
});
|
||||
|
||||
$inspect(contents);
|
||||
function loadContents(path: string | undefined, id: string) {
|
||||
console.log("Loading contents for", path, id);
|
||||
if (!path || !id) return;
|
||||
path = path + "/Data";
|
||||
invoke<string>("get_stream_data", { id, path })
|
||||
.then((result) => {
|
||||
console.log("Contents loaded", result);
|
||||
contents = result;
|
||||
if (contents && editor) {
|
||||
editor.setValue(contents);
|
||||
}
|
||||
})
|
||||
.catch((err) => console.error(err));
|
||||
}
|
||||
</script>
|
||||
|
||||
<div bind:this={editorContainer} style="height: {height}px; width: 100%;"></div>
|
||||
|
||||
<style lang="postcss">
|
||||
</style>
|
||||
@ -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);
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if parent_view}
|
||||
<ul class="active">
|
||||
{#each parent_view.children as child}
|
||||
<li>
|
||||
<div class="item">
|
||||
{#if child.children.length > 0}
|
||||
<button
|
||||
onclick={() =>
|
||||
treeState.collapseTree(
|
||||
copyPathAndAppend(child.key),
|
||||
)}
|
||||
><span class="caret"><CaretDownOutline /></span
|
||||
></button
|
||||
{#each parent_view.children as child}
|
||||
<button
|
||||
class="row hover:bg-forge-sec w-full"
|
||||
onclick={() => selectItem(child)}
|
||||
>
|
||||
<div class="item" style="margin-left: {parent_path.length * 1}em">
|
||||
{#if child.isContainer()}
|
||||
<div>
|
||||
<span class="caret"
|
||||
>{#if child.expanded}<CaretDownOutline
|
||||
/>{:else}<CaretRightOutline />{/if}</span
|
||||
>
|
||||
{:else if child.isContainer()}
|
||||
<button
|
||||
onclick={() =>
|
||||
treeState.expandTree(
|
||||
copyPathAndAppend(child.key),
|
||||
)}
|
||||
><span class="caret"><CaretRightOutline /></span
|
||||
></button
|
||||
>
|
||||
{:else}
|
||||
<span class="no-caret"></span>
|
||||
{/if}
|
||||
<button
|
||||
class="select-button"
|
||||
ondblclick={() => selectItem(child)}
|
||||
>
|
||||
<div class="item">
|
||||
<PrimitiveIcon ptype={child.ptype} />
|
||||
<div class="row">
|
||||
<p>
|
||||
{child.key}
|
||||
</p>
|
||||
{#if child.sub_type}
|
||||
<p class="ml-1 text-forge-sec small">
|
||||
{child.sub_type}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
{#if child.children.length > 0}
|
||||
<svelte:self
|
||||
parent_view={child}
|
||||
parent_path={copyPathAndAppend(child.key)}
|
||||
{treeState}
|
||||
bind:pathSelectedHandler
|
||||
></svelte:self>
|
||||
</div>
|
||||
{:else}
|
||||
<span class="no-caret"></span>
|
||||
{/if}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
<div class="item">
|
||||
<PrimitiveIcon ptype={child.ptype} />
|
||||
<div class="row">
|
||||
<p>
|
||||
{child.key}
|
||||
</p>
|
||||
{#if details}
|
||||
<p class="hint">
|
||||
{" | " +
|
||||
child.ptype +
|
||||
" | " +
|
||||
child.sub_type +
|
||||
" | " +
|
||||
child.value}
|
||||
</p>
|
||||
{:else}
|
||||
<p class="ml-1 text-forge-sec small">
|
||||
{child.sub_type}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
{#if child.children.length > 0}
|
||||
<svelte:self
|
||||
{file_id}
|
||||
parent_view={child}
|
||||
parent_path={copyPathAndAppend(child.key)}
|
||||
{treeState}
|
||||
bind:pathSelectedHandler
|
||||
{details}
|
||||
></svelte:self>
|
||||
{/if}
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
<style lang="postcss">
|
||||
.hint {
|
||||
@apply ml-1 text-forge-text_hint text-xs whitespace-nowrap font-extralight;
|
||||
}
|
||||
|
||||
.select-button {
|
||||
@apply hover:bg-forge-sec pr-3;
|
||||
cursor: pointer;
|
||||
@ -144,17 +150,14 @@
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* Style the caret/arrow */
|
||||
.caret {
|
||||
@apply text-forge-sec;
|
||||
cursor: pointer;
|
||||
user-select: none; /* Prevent text selection */
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* Create the caret/arrow with a unicode, and style it */
|
||||
.caret::before {
|
||||
display: inline-block;
|
||||
margin-right: 6px;
|
||||
.caret-active {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
/* Show the nested list when the user clicks on the caret/arrow (with JavaScript) */
|
||||
|
||||
@ -2,47 +2,79 @@
|
||||
import TreeNode from "./TreeNode.svelte";
|
||||
import PrimitiveIcon from "./PrimitiveIcon.svelte";
|
||||
import TreeViewState from "../models/TreeViewState.svelte";
|
||||
import type TreeViewNode from "../models/TreeViewNode.svelte";
|
||||
import type TreeViewRequest from "../models/TreeViewRequest.svelte";
|
||||
import { PathSelectedEvent } from "../events/PathSelectedEvent";
|
||||
import { CaretDownOutline, CaretRightOutline } from "flowbite-svelte-icons";
|
||||
|
||||
let {
|
||||
file_id,
|
||||
root,
|
||||
pathSelectedHandler = $bindable(),
|
||||
active = true,
|
||||
pathSelectedHandler,
|
||||
active,
|
||||
details,
|
||||
}: {
|
||||
file_id: string;
|
||||
root: TreeViewNode;
|
||||
root: TreeViewRequest;
|
||||
pathSelectedHandler: any;
|
||||
active: boolean;
|
||||
details: boolean;
|
||||
} = $props();
|
||||
|
||||
let h = $state(100);
|
||||
let treeState = $state(new TreeViewState(file_id, root));
|
||||
let states: TreeViewState[] = $state([]);
|
||||
let treeState: TreeViewState | undefined = $derived(
|
||||
states.find((state) => state.file_id === file_id),
|
||||
);
|
||||
|
||||
if (active) {
|
||||
loadTreeView();
|
||||
}
|
||||
|
||||
function loadTreeView() {
|
||||
if (!treeState) {
|
||||
let newState = new TreeViewState(file_id, root);
|
||||
newState.loadTreeView();
|
||||
states.push(newState);
|
||||
}
|
||||
}
|
||||
|
||||
function select() {
|
||||
loadTreeView();
|
||||
pathSelectedHandler(new PathSelectedEvent(file_id, [root.key]));
|
||||
}
|
||||
</script>
|
||||
|
||||
<div bind:clientHeight={h} class="full-container">
|
||||
<div class="overflow-auto" style="height: {h}px">
|
||||
<ul id="myUL">
|
||||
{#if treeState.view}
|
||||
<li>
|
||||
<div class="item">
|
||||
<PrimitiveIcon ptype={"Dictionary"} />
|
||||
{"Trailer "}
|
||||
</div>
|
||||
{#if active}
|
||||
<TreeNode
|
||||
bind:pathSelectedHandler
|
||||
parent_view={treeState.view}
|
||||
parent_path={treeState.view.getPath()}
|
||||
{treeState}
|
||||
></TreeNode>
|
||||
{/if}
|
||||
</li>
|
||||
<ul id="myUL">
|
||||
{#if root}
|
||||
<li>
|
||||
<button
|
||||
class="item hover:bg-forge-sec w-full"
|
||||
onmouseenter={() => loadTreeView()}
|
||||
onclick={() => select()}
|
||||
>
|
||||
{#if active && treeState?.view}
|
||||
<span class="caret"><CaretDownOutline /></span>
|
||||
{:else}
|
||||
<span class="caret"><CaretRightOutline /></span>
|
||||
{/if}
|
||||
<div class="item">
|
||||
<PrimitiveIcon ptype={"Dictionary"} />
|
||||
{root.key}
|
||||
</div>
|
||||
</button>
|
||||
{#if active && treeState?.view}
|
||||
<TreeNode
|
||||
{file_id}
|
||||
bind:pathSelectedHandler
|
||||
parent_view={treeState.view}
|
||||
parent_path={treeState.view.getPath()}
|
||||
{treeState}
|
||||
{details}
|
||||
></TreeNode>
|
||||
{/if}
|
||||
</ul>
|
||||
</div>
|
||||
getTrace
|
||||
</div>
|
||||
getPath
|
||||
</li>
|
||||
{/if}
|
||||
</ul>
|
||||
|
||||
<style lang="postcss">
|
||||
.item {
|
||||
@ -55,4 +87,10 @@ getPath
|
||||
#myUL {
|
||||
list-style-type: none;
|
||||
}
|
||||
/* Style the caret/arrow */
|
||||
.caret {
|
||||
@apply text-forge-sec;
|
||||
cursor: pointer;
|
||||
user-select: none; /* Prevent text selection */
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -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
|
||||
});
|
||||
}
|
||||
|
||||
@ -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("/");
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
45
src/models/TreeViewRequest.svelte.ts
Normal file
45
src/models/TreeViewRequest.svelte.ts
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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<Primitive>("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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user