mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 08:46:55 +08:00
feat(编辑能力): 完善跨文档复制、样式与选取
This commit is contained in:
1 parent
20374f52f1
commit
88adea348b
6 files changed
+605
-98
No files matched your search
+94
-29
@@ -112,63 +112,107 @@ func (e *Editor) ImportObjects(source *Editor, sourcePage int, ids []string, pag
|
||||
// 入参: ctx 取消上下文, source 来源编辑器, sourcePage 来源页, ids 对象标识, page 目标页, options 迁移选项
|
||||
// 返回: []string 新对象标识, error 校验、迁移或取消错误
|
||||
func (e *Editor) ImportObjectsContext(ctx context.Context, source *Editor, sourcePage int, ids []string, page int, options ObjectImportOptions) ([]string, error) {
|
||||
objects, _, err := e.importSelection(ctx, source, sourcePage, ids, nil, page, options, true)
|
||||
return objects, err
|
||||
}
|
||||
|
||||
// ImportSelection 导入独立单页选区包,重映射对象和资源标识,一次撤销恢复全部
|
||||
// 入参: ctx 取消上下文, source 单页选区阅读器, page 目标页, options 位移及导入配置
|
||||
// 返回: []string 正文标识, []string 注解标识, error 校验或迁移错误
|
||||
func (e *Editor) ImportSelection(ctx context.Context, source *Reader, page int, options ObjectImportOptions) ([]string, []string, error) {
|
||||
doc, err := source.DocContext(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if len(doc.Pages.Page) != 1 {
|
||||
return nil, nil, fmt.Errorf("selection requires exactly one page")
|
||||
}
|
||||
origin, err := source.EditorContext(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
content, err := origin.page(0)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var objects, annotations []string
|
||||
for _, layer := range content.Content.Layer {
|
||||
for _, object := range layer.Objects {
|
||||
objects = append(objects, editorObjectID(object))
|
||||
}
|
||||
}
|
||||
notes, err := origin.Annotations(0)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
for _, note := range notes {
|
||||
annotations = append(annotations, note.ID)
|
||||
}
|
||||
return e.importSelection(ctx, origin, 0, objects, annotations, page, options, true)
|
||||
}
|
||||
|
||||
// importSelection 迁移正文与注解,共用资源映射并保持来源绘制顺序
|
||||
// 入参: ctx 取消上下文, source 来源编辑器, sourcePage 来源页, ids 正文标识, annotations 注解标识, page 目标页, options 导入配置, strictLinks 拒绝跨页链接
|
||||
// 返回: []string 正文标识, []string 注解标识, error 迁移或提交错误
|
||||
func (e *Editor) importSelection(ctx context.Context, source *Editor, sourcePage int, ids, annotations []string, page int, options ObjectImportOptions, strictLinks bool) ([]string, []string, error) {
|
||||
progress := editorProgress(options.OnProgress).withContext(ctx)
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
if !finite(options.DX) || !finite(options.DY) {
|
||||
return nil, fmt.Errorf("import requires finite offsets")
|
||||
return nil, nil, fmt.Errorf("import requires finite offsets")
|
||||
}
|
||||
if source.encryption != nil && e.encryption == nil && !options.AllowDecrypted {
|
||||
return nil, ErrEncryptionPolicyRequired
|
||||
return nil, nil, ErrEncryptionPolicyRequired
|
||||
}
|
||||
objects, err := source.Objects(sourcePage, ids)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
target, err := e.page(page)
|
||||
if err != nil || len(objects) == 0 {
|
||||
return nil, err
|
||||
if err != nil || len(objects) == 0 && len(annotations) == 0 {
|
||||
return nil, nil, err
|
||||
}
|
||||
if source == e {
|
||||
if err := progress.report("commit", 0, 0); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
return e.CopyObjectsContext(ctx, page, objects, options.DX, options.DY)
|
||||
copied, err := e.CopyObjectsContext(ctx, page, objects, options.DX, options.DY)
|
||||
return copied, nil, err
|
||||
}
|
||||
reader, err := source.readerContext(ctx, progress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
defer reader.Close()
|
||||
doc, err := reader.Doc()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
ref := doc.Pages.Page[sourcePage]
|
||||
base, migration, err := e.prepareImport(ctx, reader, doc, map[string]bool{ref.ID: true}, false, progress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
migration.ids[editorImportKey(ref.ID)], migration.strictLinks = target.ID, true
|
||||
migration.ids[editorImportKey(ref.ID)], migration.strictLinks = target.ID, strictLinks
|
||||
pageName := reader.ResPath(ref.BaseLoc)
|
||||
content, err := reader.PageContentByIndex(sourcePage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
for _, value := range content.PageRes {
|
||||
name, err := migration.resolve(pageName, "", value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
if err := migration.resourceIndex(name); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
layers := make([][]byte, len(objects))
|
||||
for i, object := range objects {
|
||||
if err := progress.report("objects", i, len(objects)); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
var data []byte
|
||||
var attrs ofdAttrs
|
||||
@@ -187,32 +231,48 @@ func (e *Editor) ImportObjectsContext(ctx context.Context, source *Editor, sourc
|
||||
data, err = editorObjectXML(object)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
data, err = editorXMLContainer("Layer", attrs, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
root, err := parseEditorXMLContext(ctx, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
layers[i], err = migration.encode(editorImportEntry{name: pageName, data: data}, root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
notes := &AnnotationSelection{editor: e, document: e.documentIdentity()}
|
||||
for _, id := range annotations {
|
||||
data, err := source.annotationXML(sourcePage, id)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
root, err := parseEditorXMLContext(ctx, data)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
data, err = migration.encode(editorImportEntry{name: pageName, data: data}, root)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
notes.data = append(notes.data, data)
|
||||
}
|
||||
if err := migration.encodeResources(); err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
for _, resource := range e.resources {
|
||||
delete(migration.files, resource.name)
|
||||
}
|
||||
next, err := migration.merge(base, nil, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
var copied []string
|
||||
var copied, copiedNotes []string
|
||||
err = e.Transaction(func(editor *Editor) error {
|
||||
if err := progress.report("commit", 0, 0); err != nil {
|
||||
return err
|
||||
@@ -236,13 +296,13 @@ func (e *Editor) ImportObjectsContext(ctx context.Context, source *Editor, sourc
|
||||
return err
|
||||
}
|
||||
object := layer.Objects[0]
|
||||
object.TextObject.layout = objects[i].TextObject.layout
|
||||
object.state = objects[i].state
|
||||
object.CompositeGraphicUnit.states = remapCompositeStates(objects[i].CompositeGraphicUnit.states, migration.ids)
|
||||
imported[i], err = editor.copiedObjectStyle(object, layer.DrawParam)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
imported[i].TextObject.layout = objects[i].TextObject.layout
|
||||
imported[i].state = objects[i].state
|
||||
imported[i].CompositeGraphicUnit.states = remapCompositeStates(objects[i].CompositeGraphicUnit.states, migration.ids)
|
||||
imported[i].origin = &editorObjectOrigin{editor: editor, document: editor.documentIdentity(), data: data, node: root.child("Layer").children[0], object: object}
|
||||
}
|
||||
copied, err = editor.CopyObjectsContext(ctx, page, imported, options.DX, options.DY)
|
||||
@@ -253,12 +313,17 @@ func (e *Editor) ImportObjectsContext(ctx context.Context, source *Editor, sourc
|
||||
for i, object := range objects {
|
||||
orderedIDs[i] = editorObjectID(object)
|
||||
}
|
||||
return editor.copyRichTextMetadata(source, sourcePage, orderedIDs, page, copied)
|
||||
notes.document = editor.documentIdentity()
|
||||
copiedNotes, err = editor.PasteAnnotations(page, notes, options.DX, options.DY)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return editor.copyRichTextMetadata(ctx, source, sourcePage, orderedIDs, annotations, page, copied, copiedNotes)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
return copied, err
|
||||
return copied, copiedNotes, err
|
||||
}
|
||||
|
||||
// ImportPages 将来源当前文档中的指定页面插入目标位置,保持输入顺序并作为一次撤销操作
|
||||
|
||||
Reference in new issue
Block a user