Reacting to document modifications

Discussion forum for C++ and script developers who are using the QCAD development platform or who are looking to contribute to QCAD (translations, documentation, etc).

Moderator: andrew

Forum rules

Always indicate your operating system and QCAD version.

Attach drawing files, scripts and screenshots.

Post one question per topic.

User avatar
andrew
Site Admin
Posts: 9037
Joined: Fri Mar 30, 2007 6:07 am

Reacting to document modifications

Post by andrew » Thu Jul 14, 2016 9:35 am

From a QCAD developer:
How can I react to or intercept modifications to a document? For example to move an entity when another entity has been moved or to prevent an entity from being deleted.

User avatar
andrew
Site Admin
Posts: 9037
Joined: Fri Mar 30, 2007 6:07 am

Re: Reacting to document modifications

Post by andrew » Thu Jul 14, 2016 9:52 am

What you are looking for is called a "listener" in QCAD.

The listeners that are notified whenever a document changes are:
- RTransactionListener
- RInterTransactionListener

The difference is that the transaction has been settled when RTransactionListener is notified. When RInterTransactionListener is notified, the transaction is still in progress and may be amended if desired.

You can find an example for an RTransactionListener (in ECMAScript) at:
https://github.com/qcad/qcad/blob/maste ... istener.js
To try the example with your QCAD installation, choose Misc > Examples > Listeners > Transaction Listener. This installs a transaction listener and prints information about every transaction to the command line history of QCAD.

Other listeners exist to:
- react to changes of layers (RLayerListener)
- react to changes of blocks (RBLockListener)
- react when entities are being exported / displayed (REntityExportListener)
- react when documents are being exported / saved (RExportListener)
- react when documents are being imported / loaded (RImportListener)
- react when the focus changes from one document to another (RFocusListener)
- react when the state of the document changes from modified to unmodified and vice versa (RModifiedListener)
- react to mouse coordinate changes (RMouseCoordinateListener)
- react to new documents being created (RNewDocumentListener)

For a complete overview, please refer to:
http://www.qcad.org/doc/qcad/latest/dev ... tated.html
And search for "listener".

Ghost_of_Magellan
Full Member
Posts: 58
Joined: Wed Mar 16, 2016 5:10 pm

Re: Reacting to document modifications

Post by Ghost_of_Magellan » Thu Aug 04, 2016 2:59 pm

Greetings.
First of all, good question and good answer.

I have tried to apply a listening function on the code I'm working on. I did the call on the .js file I was already working and it seems to call correctly in the example provided.
I wanted to make a few changes though, I tried to make it so that the notification only happens when entities are added or deleted. According to your post I'm let to believe the (REntityExportListener) Is whan I'm looking for. Do correct me if I'm wrong.

I tried:

Code: Select all

AutoRefresh = new REntityExportListenerAdapter();	//Considera alterações às entidades
appWin.addEntityExportListener(AutoRefresh);
// ...
AutoRefresh.transactionUpdated.connect(function(document, vl_changes) {    //detects change?
       //does something 
}
I receive on: AutoRefresh.transactionUpdated.connect(function(document, vl_changes) the error:
Uncaught exception at scripts/IuSYS/iuSYS_Cam/iuSYS_Cam.js:1683: TypeError: Result of expression 'AutoRefresh.transactionUpdated' [undefined] is not an object.
I've tried swimming through the vast ocean of information that is the Qcad documentation but returned only with questions.
For one, after reading the docs, I've grown suspicious that this function RTransactionListener is not called when any entity is changed, but is only called when a specific entity is changed, as in indicated in: REntityExportListener. I would like confirmation on this.
Assuming this does what I need it to, I suppose the "transactionUpdated" part needs to be replaced by something else. May I request assistance here?

Somewhat off-topic.
Currently, I am searching for specific entities by making:

Code: Select all

for (i = 0; i < entityIds.length; i++) {
		entity = doc.queryEntity(entityIds[i]);
		Entity_ID = Entity_to_text(entity);
				if (Entity_ID == custom_ID){
					//Does stuff
					break;
				}
		}
}
the custom_ID sometimes comes from the autorefresh fucntion and others comes from a tablewidget that holds the IDs of every entity on the document. Sometimes I need to cross reference the data between the table and the entitylist so Ibasically I need to do a for within a for to find the correct IDs. My question is: Is there a more effective way, in code size and processing speed, to find an entity in the entityIds pool that this one? Some way, perhaps that uses inbuilt Qcad instructions?

I love you all.
Thanks for the assistance.
Last edited by Ghost_of_Magellan on Thu Aug 04, 2016 3:28 pm, edited 1 time in total.

User avatar
andrew
Site Admin
Posts: 9037
Joined: Fri Mar 30, 2007 6:07 am

Re: Reacting to document modifications

Post by andrew » Thu Aug 04, 2016 3:10 pm

You appear to be mixing up RTransactionListenerAdapter and REntityExportListener in your post.

The code you've posted using RTransactionListenerAdapter looks fine though. You also might want to look at this complete and working example for RTransactionListenerAdapter:
https://github.com/qcad/qcad/blob/maste ... istener.js

I'm guessing the exception is caused by something else (perhaps in the // ... skipped code part).
Also, please make sure you are using the latest version of QCAD.

Please split unrelated questions into separate topics, thanks.

Ghost_of_Magellan
Full Member
Posts: 58
Joined: Wed Mar 16, 2016 5:10 pm

Re: Reacting to document modifications

Post by Ghost_of_Magellan » Thu Aug 04, 2016 3:28 pm

Apologies, you are absolutely correct.
And yes, my example with the transaction method works perfectly. I just wanted to limit it only to changes in entities.

The example is the same, but with;

Code: Select all

AutoRefresh = new REntityExportListenerAdapter();	//Considera alterações às entidades
appWin.addEntityExportListener(AutoRefresh);
I suppose it's best if I change my original post.

User avatar
andrew
Site Admin
Posts: 9037
Joined: Fri Mar 30, 2007 6:07 am

Re: Reacting to document modifications

Post by andrew » Thu Aug 04, 2016 3:33 pm

RTransactionListenerAdapter would be the correct listener to use to monitor changes. REntityExportListenerAdapter listens to entities being exported (e.g. to a graphics scene or to a file).

User avatar
andrew
Site Admin
Posts: 9037
Joined: Fri Mar 30, 2007 6:07 am

Re: Reacting to document modifications

Post by andrew » Thu Aug 04, 2016 3:46 pm

Ghost_of_Magellan: I've split your other question to this new topic:
http://www.qcad.org/rsforum/viewtopic.php?f=30&t=4339

Ghost_of_Magellan
Full Member
Posts: 58
Joined: Wed Mar 16, 2016 5:10 pm

Re: Reacting to document modifications

Post by Ghost_of_Magellan » Thu Aug 04, 2016 4:18 pm

Thank you, andrew.
Btw, I believe it's also relevant to mention that the listener is changed when an entity is added, deleted AND when the points are changed.

Example: Existing line from 0:0 to 0;10. Same entity is changed to 10;0 to 0;10. Listener activated.

Just is case anybody was wondering.

Thank you.

Ghost_of_Magellan
Full Member
Posts: 58
Joined: Wed Mar 16, 2016 5:10 pm

Re: Reacting to document modifications

Post by Ghost_of_Magellan » Fri Aug 05, 2016 11:58 am

Just wondering if there is any manner of flag in this process that is activated according to the type of change that is made on an entity.

For example, RTransactionListenerAdapter indicates that a change occured, and some other listener additionally informs that the change was in the color of the entity, or the inicial or ending point of the line or arc.

I am asking too much, perhaps?

Thank you

User avatar
andrew
Site Admin
Posts: 9037
Joined: Fri Mar 30, 2007 6:07 am

Re: Reacting to document modifications

Post by andrew » Fri Aug 05, 2016 12:07 pm


Ghost_of_Magellan
Full Member
Posts: 58
Joined: Wed Mar 16, 2016 5:10 pm

Re: Reacting to document modifications

Post by Ghost_of_Magellan » Fri Aug 05, 2016 2:55 pm

So let's see.
As a simple test I did:

Code: Select all

    AutoRefresh.transactionUpdated.connect(function(document, vl_changes) {
        if (isNull(document) || isNull(vl_changes)) {
            return;
        }
        vl_objIds = vl_changes.getAffectedObjects();
        //Since vl_objIds gets me the id of the changed entity anyway I use it to get the specific change
        vl_change = vl_changes.getPropertyChanges(vl_objIds[i]);
The result of vl_change is:
RPropertyChange(RPropertyTypeId(9, "", "", "", "Color") , QVariant(RColor, ) -> QVariant(RColor, )) when color is changed.
RPropertyChange(RPropertyTypeId(117, "", "", "End Point", "X") , QVariant(double, 19) -> QVariant(double, 28)) ,RPropertyChange(RPropertyTypeId(118, "", "", "End Point", "Y") , QVariant(double, 19) -> QVariant(double, 17)) ,RPropertyChange(RPropertyTypeId(30, "", "", "", "Total Length") , QVariant(double, 9.43398) -> QVariant(double, 17.2047)) when the end point is changed.

Is there anyway to get a simpler result or am I supposed to take this and split/slice this as a string to get the Id type of the change?

Edit:
I can get by with the following If, like me, you're a noob, and you only want the type of change and not any details of the change itself, this will do:
vl_change_list = vl_changes.getPropertyChanges(vl_objIds);
vl_change_list = vl_change_list[0].toString();
var vl_pos1 = vl_change_list.search("Id")+3;    
var vl_pos2 = vl_change_list.search(",");       
vl_change_list = vl_change_list.slice(vl_pos1, vl_pos2);



The result will be the ID of the change. 9 for color, in this case but there's end point X, end point Y, lenght, etc.
Not the best solution, nor the most professional, but for now, it works.

Is there a way to get clearer results?

Thank you very much.
Last edited by Ghost_of_Magellan on Fri Aug 05, 2016 4:47 pm, edited 1 time in total.

Ghost_of_Magellan
Full Member
Posts: 58
Joined: Wed Mar 16, 2016 5:10 pm

Re: Reacting to document modifications

Post by Ghost_of_Magellan » Fri Aug 05, 2016 4:55 pm

On the same line of thought.

I noticed that the getPropertyChanged that I used on the example on my last post did not seem to tell me which color it was changed to, and changed from. Is there any way to receive that information through this process we were discussing? Or does this method do that already but I messed up somewhere?

Might have something to do with this, but I can't seem to make it work.

Thank you very much.

User avatar
andrew
Site Admin
Posts: 9037
Joined: Fri Mar 30, 2007 6:07 am

Re: Reacting to document modifications

Post by andrew » Fri Aug 05, 2016 6:02 pm

getPropertyChanges returns an array. You can iterate through that array using a for loop.

As you can see in the API doc, each item in the array is of type RPropertyChange.

Please click the above link to see how you can extract the ID of the property that was changed, the new value, the old value, etc.

Parsing strings to fetch information is certainly not the recommended way to retrieve any information from entities, document, transactions, etc. These output strings you are using are meant for debugging only and can change significantly in any future update which means your code will break.

Ghost_of_Magellan
Full Member
Posts: 58
Joined: Wed Mar 16, 2016 5:10 pm

Re: Reacting to document modifications

Post by Ghost_of_Magellan » Mon Aug 08, 2016 10:10 am

andrew wrote:Parsing strings to fetch information is certainly not the recommended way to retrieve any information from entities, document, transactions, etc. These output strings you are using are meant for debugging only and can change significantly in any future update which means your code will break.
Thank you for the heads up.
I tried applying the RPropertyChange method, as you said and came up with a few problems (probably doing something stupid, as usual). This is what I have tried:

vl_objIds = vl_changes.getAffectedObjects();
vl_change_list = vl_changes.getPropertyChanges(vl_objIds);
test1 = vl_change_list.getNewValue();
test2 = vl_change_list.getOldValue();
test3 = vl_change_list.getPropertyTypeId();


Give an error, saying that getNewValue[undefined] is not a function. So I have obviously messed up in this one.

vl_objIds = vl_changes.getAffectedObjects();
vl_change_list = vl_changes.getPropertyChanges(vl_objIds);
test1 = vl_change_list.getNewValue;
test2 = vl_change_list.getOldValue;
test3 = vl_change_list.getPropertyTypeId;

The first thing that I find odd is that vl_changes.getPropertyChanges(vl_objIds) returns: RPropertyChange(RPropertyTypeId(9, "", "", "", "Color") , QVariant(RColor, ) -> QVariant(RColor, )). The QVariants that supposedly holds the color seems to be empty. Then, the test1 to 3 that I placed return empty.

Then I tried to use the vl_change_list as an array.
vl_objIds = vl_changes.getAffectedObjects();
vl_change_list = vl_changes.getPropertyChanges(vl_objIds);
test1 = vl_change_list[0].getNewValue;
test2 = vl_change_list[0].getOldValue;
test3 = vl_change_list[0].getPropertyTypeId;

all 3 test variables return: function () { [native code] }. which I have to say I have absolutely no idea what it means.


I apreciate any assistance.
thank you very much.

User avatar
andrew
Site Admin
Posts: 9037
Joined: Fri Mar 30, 2007 6:07 am

Re: Reacting to document modifications

Post by andrew » Mon Aug 08, 2016 10:32 am

Ghost_of_Magellan wrote:Then I tried to use the vl_change_list as an array.
vl_objIds = vl_changes.getAffectedObjects();
vl_change_list = vl_changes.getPropertyChanges(vl_objIds);
test1 = vl_change_list[0].getNewValue;
test2 = vl_change_list[0].getOldValue;
test3 = vl_change_list[0].getPropertyTypeId;

all 3 test variables return: function () { [native code] }. which I have to say I have absolutely no idea what it means.


This was pretty close. Try test1 = vl_change_list[0].getNewValue(); Note the ().

Post Reply

Return to “QCAD Programming, Script Programming and Contributing”