Script - Copy AllEntities from multiple open documents to one

Use this forum for all posts and questions about the free QCAD Community Edition version 3

Moderator: andrew

Post Reply
Philip
Newbie Member
Posts: 8
Joined: Mon Jun 17, 2024 10:31 pm

Script - Copy AllEntities from multiple open documents to one

Post by Philip » Wed Jul 02, 2025 3:06 pm

Hi,

can you please help me with following java script code for QCAD Community Edition:

Code: Select all

	var di_dest = EAction.getDocumentInterface();
	var mdiArea = EAction.getMdiArea();
	var windows = mdiArea.subWindowList();
	numOfWindows = windows.length;
	for (var n=1; n<numOfWindows; n++) {
		var subWin = windows[n];
		mdiArea.setActiveSubWindow(subWin);
        	sourceDocument = subWin.getDocument();
		sourceDocument.selectAllEntities();
		var op = new RCopyOperation(new RVector(0,0), sourceDocument);
		di_dest.applyOperation(op);
	}
The precondition / setup: is to load multiple files in QCAD. Open the first document (tab) and execute the script above.
The expectation: is that the code above will copy all entities from all files (tabs) but the first to the first file document (as this was the one you had open when you executed the script.
The observed behaviour: is that the code copys only the entitys of the last file / document / tab onto the first document (tab).
Question: Does someone understand why and what I can do to get desired behaviour?
Thank you very much for your help :-)

CVH
Premier Member
Posts: 4920
Joined: Wed Sep 27, 2017 4:17 pm

Re: Script - Copy AllEntities from multiple open documents to one

Post by CVH » Wed Jul 02, 2025 5:27 pm

Hi,

Can it be that the documents in question have common Layer names and/or Block names.
Then I suspect that you are overwriting Layers and or Blocks in the destination document.
Essentially ending up with the last copy and overwrite.

Code: Select all

	var di_dest = EAction.getDocumentInterface();
	var mdiArea = EAction.getMdiArea();
	var windows = mdiArea.subWindowList();
	numOfWindows = windows.length;
	for (var n=1; n<numOfWindows; n++) {
		var subWin = windows[n];
		mdiArea.setActiveSubWindow(subWin);
        	sourceDocument = subWin.getDocument();
		sourceDocument.selectAllEntities();
		var op = new RCopyOperation(new RVector(0,0), sourceDocument);
                // Not clearing objects that already exists:
                // This may include Entities, Layers or Blocks
		op.setClear(false);
		op.setAllowAll(true);
		di_dest.applyOperation(op);
	}
	
	// Set first document tab active:
	subWin = windows[0];
	mdiArea.setActiveSubWindow(subWin);
	
For selected Block References their referenced Block content that might be ambiguous.
# EDIT # See lower.

Regards,
CVH
Last edited by CVH on Wed Jul 02, 2025 10:25 pm, edited 1 time in total.

Philip
Newbie Member
Posts: 8
Joined: Mon Jun 17, 2024 10:31 pm

Re: Script - Copy AllEntities from multiple open documents to one

Post by Philip » Wed Jul 02, 2025 6:16 pm

Hi CVH,
thank you very much for your help! I admire your experiance.
Alltough I also would like to copy blocks I tested the script with documents that had no blocks at all. The files I tested had only arcs and line elements. I have attached two files that I used (as exsample) but I think it is reproducable also with other random files. The Issue occurs regardless of the fact that there are no blocks, and layers or entityIDs are unique. I am puzzeled - I would also expect that a operation is overwritten - but why (and how to fix)?
Kind regards
Philip
Attachments
FormerF.dxf
(44 KiB) Downloaded 169 times
FormerH.dxf
(45.79 KiB) Downloaded 157 times

CVH
Premier Member
Posts: 4920
Joined: Wed Sep 27, 2017 4:17 pm

Re: Script - Copy AllEntities from multiple open documents to one

Post by CVH » Wed Jul 02, 2025 10:24 pm

For the record:
FormerH.dxf and FormerF.dxf as tab 2 and 3 ...
... are copied to the document in tab 1 with the provided code.
The document in tab 1 was a new file with only a simple text entity reading '1'.

Afterwards this document has 3 layers:
- Layer '0' still contains the text reading '1'.
- Layer 'layer 1' contains a copy of the entities from FormerH.dxf (red)
- Layer 'Outside' contains a copy of the entities from FormerF.dxf (cyan)

A selection was made of the entities in the current active Block and that is Model_Space for the 3 documents.

FormerH.dxf: Layer '0', FormerF.dxf: Layers '0' and 'layer 1' were empty.
Nothing on this layers was selected to copy over.
The required Layers where the copied entities lived on, are created (or overwritten) in the target when they don't exist.
If an empty Layer 'layer 2' existed in FormerF.dxf then it would not be created in tab 1 ...
... Because none of the selected lived on that.
Another flag allows/forces that: op.setCopyAllLayers(true);


Missed something ... op.setAllowAll(true) allows to copy things to locked or frozen layers.
Otherwise the transaction would fail. (Added in the above and new code)


:arrow: There is a fundamental difference between Blocks and Block references.
It is common that the term 'Block' is used for both what may be misleading depending the context.

Blocks (definitions) are the things that are listed in the Block List.
A Block reference is an entity while a Block (definition) is a predefined collection of entities.
From that perspective the Block 'Model_Space' is nothing else than a collection that defines its content.
Drawing in Model_Space is then just the same as editing any other Block (definition) from the Block List.
What is displayed in the drawing panel is the content of the active Block in the Block List.

A Block Reference is a singular entity just like an Arc or a Line entity.
The difference is that a Block reference displays a virtual copy of the content in the referenced Block (definition).
And all that in a certain place, scale, rotation, ...
A Block Reference lives on a certain layer and is part of a certain Block (definition) content like any other entity.

One can select entities but one can not select a Block (definition) in the same sense.
The entities of that Block are not visible in direct in another Block, while drawing in Model_Space for example.
Only a representation may be visible as Block Reference what is an entity and what can be selected.

Block (definitions) are intended to group geometry that belongs together.
That may include various entities living on various layers, any type of entities including Block References to yet other Blocks.
Then Layers are intended to control the attributes of the entities that live on it: Black/red, continuous/dashed/dotted, thick/thin, ...
Block content is typically some geometry that can be used in various places.
For example a screw head or that screw seen from the side, some type of chair, some symbol, ...

If a Block Reference based on Block 'ABC' existed in FormerF.dxf then that Block Reference entity is copied over.
A new Block reference is created in the target referencing Block 'ABC'.
If that Block did not exist in the target, the content is copied to a new Block (definition) 'ABC' in the target.

Block 'ABC' may already exist in the target but there is no certainty that the content is the same as in the source.
Copying and overwriting blindly would also affect other existing Block References in the target already based on Block 'ABC'.
Afterwards they would represent the new and perhaps different content while the former content is overwritten and lost.

It seems that an RCopyOperation does not overwrites Block content.
The new Block References based on Block 'ABC' will represent the content of the existent Block 'ABC'.
I can't find a flag to force that like with an RPasteOperation.


On the safe side ...
... The original screw heads or chairs in tab 1 are not replaced by the content of the Blocks with the same name in sources 2 or 3.

In the GUI that is handled differently.
CP + PS may overwrite Block content or create a copy with a suffix to diversify.
Refer to these tool scripts for the essence: Copy.js & Paste.js


Using an RPasteOperation we can copy and overwrite Block content blindly or not.
If ambiguous the last copied Block definition will overwrite all former.
There must be at least one Block Reference based on the intended Block in the sources.

Code: Select all

    var di_dest = EAction.getDocumentInterface();
    var mdiArea = EAction.getMdiArea();
    var windows = mdiArea.subWindowList();
    numOfWindows = windows.length;
    for (var n=1; n<numOfWindows; n++) {
        var subWin = windows[n];
        mdiArea.setActiveSubWindow(subWin);
        var sourceDocument = subWin.getDocument();
        sourceDocument.selectAllEntities();
        var op = new RPasteOperation(sourceDocument);
        op.setText("Copy tab %1".arg(n+1));    // Undo/Redo text or tooltip
        op.setOffset(new RVector(0,0));
        op.setOverwriteBlocks(true);    // False to keep any existent Block its content
        op.setOverwriteLayers(true);
        op.setAllowAll(true);
        di_dest.applyOperation(op);
    }
    
    // Set first document tab active:
    subWin = windows[0];
    mdiArea.setActiveSubWindow(subWin);
Copying (unused) Block definitions between documents is yet another story.

Regards,
CVH

Philip
Newbie Member
Posts: 8
Joined: Mon Jun 17, 2024 10:31 pm

Re: Script - Copy AllEntities from multiple open documents to one

Post by Philip » Thu Jul 03, 2025 7:26 am

Hi,

first of all: THANK YOU CVH !!
You rock ! Your posts have have solved the problem.

I found out that following essencial line was missing in my code:

Code: Select all

op.setClear(false); 
The documentation is very limited on this: https://qcad.org/doc/qcad/3.0/developer ... ation.html but this line made the difference. Not that it is of importance (as I will proceed using your proposed approach with RPasteOperation) but do you know what it does?

Thank you for explaning the difference between Blocks and Block references. I have learnt about it before but it was a good reminder. :-)

As mentioned I will continue with RPasteOperation considering the benefits. One thing that I had difficulties with (and that might help others reading this): It is not necessary to use a copy function before using RPasteOperation. The items to be pasted (inserted) seem to be sufficiently defined by the selection (in the code above

Code: Select all

sourceDocument.selectAllEntities();
- please correct me if I missunderstood this. :-)

CVH
Premier Member
Posts: 4920
Joined: Wed Sep 27, 2017 4:17 pm

Re: Script - Copy AllEntities from multiple open documents to one

Post by CVH » Thu Jul 03, 2025 9:07 am

RCopyOperation and RPasteOperation are in fact specialized operations that both preform a copy.

If we think of Copy/Paste we need to copy the things before we can paste them.
- Copy copies thing from the source to for example a Clipboard.
- Paste copies the content of the Clipboard to the target.
Both copy things over. :wink:

For the ins and outs study the related code in C++ (Reads about the same as JS)
RCopyOperation.cpp and RCopyOperation.h
RPasteOperation.cpp and RPasteOperation.h

The apply() function of both call copy() of:
RClipboardOperation.cpp and RClipboardOperation.h

RCopyOperation has several fixed parameters while these are configurable for RPasteOperation.
It also reveals what really happened with Clear = true
The target document dest is cleared before anything else, intended to clear the Clipboard before copying new content.

It even seem that your code can be simplified, copy() acts on selected or on all by flag.
selectAllEntities() will only select those that can be selected.
Philip wrote:
Thu Jul 03, 2025 7:26 am
The documentation is very limited on this:
Indeed, sometimes it is.
Also see bottom of this reference ... A bit outdated to some concerns.

Regards,
CVH

Post Reply

Return to “QCAD Community Edition”