Pasting in Writer or how to create a SwDoc deep copy?

Jan-Marek Glogowski glogow at fbihome.de
Wed Jun 25 04:09:01 PDT 2014


Hi Writer devs and everybody interested,

after struggling for a week to come of with working code to create a
deep copy of an SwDoc, this morning I woke up and came to the
conclusion: everything works as expected from my understanding of Paste
in Writer.

So this is my attempt to "dump my brain" and hopefully get additional
ideas from other devs.

= The problem =

Currently SwDoc::CreateCopy works by creating a new SwDoc and copying
the content using SwDoc::Paste.

The content start point is selected by this call:

SwNodeIndex aSourceIdx( rSource.GetNodes().GetEndOfExtras(), 2 );

AFAIK this selects the first node *after* the content start node. That
first page is supposed to be something like a start page / start
paragraph node. I don't know yet how to debug these SwNodes structure
effectively, so it's just a guess.

The actual paste operation is done using CopyRange, the content of first
copied paragraph is merged into the first target paragraph. This almost
works as expected, except that it loses all first paragraph anchored
Flys. This problem exists since ages; it also happens with OOo 3.2.1,
the current office suite version we're using in Munich.

You can easily check this by mail merging (MM) an empty document with a
single paragraph anchored fly, like a draw line with two datasets. The
first document contains the line and an additional / two paragraph(s),
with the line anchored at the 2nd paragraph, all other pages just
contain a single paragraph and no line.
This is "correct", as MM handles the first page differently - something
I would like to get rid of.

Even "funnier" things happen, if the MM document is a single page with a
complex header and a page anchored fly:
* The copied document has two pages!
* The first page has the default header.
* The second page contains the original header.
* The page anchored fly moves to the first / empty page.
* The first paragraph anchored fly on the second page is gone (is a
section a fly - well the first section is gone too).
* The first paragraph anchored draw object moves somewhere else

Especially the last bullet point is interesting. The offsets of the
paragraph anchor draw object changes indefinitly. For my test document
this is just broken on the 2nd merged document, but otherwise broken in
all working copies  (also see
https://bugs.freedesktop.org/show_bug.cgi?id=80395 - not my bug, but I
guess the same problem).

Caolán pulled https://gerrit.libreoffice.org/#/c/9860 into master. This
this saves multiple documents in various MM states for the first three
merged documents, when using a dbgutil build.

The first WorkDoc is always after the "CreateCopy", the second WorkDoc
right before SwFEShell::Paste.

And BTW:

  SwFEShell::Paste( SwDoc* pClpDoc, bool bIncludingPageFrames )

has the same "problem", as it also uses the above code to select the
starting node for the copy. There is a partial "fix"  for my "copy"
problem, if the MM document has headers:
  https://gerrit.libreoffice.org/#/c/9862/1

But well - it crashs for me with documents without headers - just saw
that after the gerrit push for review.

= My attempts to fix it =

My best idea is to use

SwNodeIndex aSourceIdx( rSource.GetNodes().GetEndOfExtras(), *1* );

in the case of pasting a whole document. This appends a new paragraph at
the position, instead of merging the first paragraph from the source
into the first paragraph of the target.

So for the "CreateCopy" case, this would leave me with deleting the
first paragraph.

I tried

1.
SwNodeIndex aTargetIdx( pRet->GetNodes().GetEndOfExtras(), 2 );
pRet->GetNodes().Delete( aTargetIdx, 1 );

and a variant of

2.
SwPaM aPara( <document content start );
this->DelFullPara(aPara);

3.
and a variant of SwWrtShell::SelAll and SwFEShell::Paste,
which currently just segfaults,

=>
but couldn't come up with working code. I would like to prevent to write
just an other paste function for the CreateCopy special case.

AFAIK this is not usable for SwFEShell::Paste, as one expects the
"paragraph merge" for clipboard content.
OTOH I don't know, where the code is actually used - copy and paste in
the GUI seems not affected. But copy multiple paragraphs with anchored
lines didn't always include that line - with or without the change from
2 => 1.

So from my POV both paste should at least copy all the skipped,
paragraph anchored flys of the first node in the SwFEShell::Paste case
(don't know yet how).

And probably the suggested change to SwDoc::Paste should also be applied
to SwFEShell::Paste.

Thanks for your input,

Jan-Marek


More information about the LibreOffice mailing list