Update on double click of EA Element - enterprise-architect

We are opening the Customized Form in place of Properties view of EA Element on Double Click of an element in diagram or project browser i.e using EA_OnContextItemDoubleClicked Event (We are using show-dialog to open the customized form and returning false such that properties view should not open on double click). In the customized form we are trying to update the EA Element using the API element.Name and updating it. But the issue is when we update the element name it is getting reflected in project browser but if we open the EA properties view of the updated EA Element and click OK button the update will be reverted back to the old value (Old Name).
Please find the code below.
public virtual bool EA_OnContextItemDoubleClicked(EA.Repository Repository,string GUID, EA.ObjectType ot)
{
EA.Element ele= Repository.GetElementByGuid(GUID);
ele.Name = "Test";
ele.Update();
repository.AdviseElementChange(ele.ElementID);
}

What you are doing is playing with unsecured weapons. NEVER use Execute unless it's unavoidable (if the API lacks functionality, if performance is a must). So in your code the Execute has no reason. Set the name in to "test" before the Update and remove the Execute statement.
Besides that: t_object.ea_guid=GUID will never do anything since you will not have any result set. Or maybe it will throw an exception since GUID is no field. I guess you meant
Repository.Execute("Update t_object set t_object.Name='test' where t_object.ea_guid='" + GUID + "'");
But then again: see above!

Using this API repository.AdviseElementChange(element.ElementID) the above problem was solved.

Related

Enterprise Architect SynchTaggedValues not working

In Enterprise Architect element.SynchTaggedValues()is not working from an Add-in
but it works from the script inside EA.
Please find the code I used below.
Initially have creating an activity Element.
EA.Element element = package.Elements.AddNew("Activity1", "Activity");
element.Stereotype = "Activity";
element.Update();
Later trying to synch TaggedValues for existing element.
element= repository.GetElementByGuid("{13D2915D-C249-4449-AA3C-8D807C54251C}");
bool ok = element.SynchTaggedValues("BPMN2.0", "Activity");
It returned false. No Sync is done here. How can I do this?
I'd recommend to just create the element correctly in the first place:
EA.Element element = package.Elements.AddNew("Activity1", "BPMN2.0::Activity");

Newly created packages only show up after manual refresh

I am creating new packages using the Object Model and C#.
I am creating packages with subpackages recursively, and that works fine. However, my changes don't show up in EA after the script is done working unless I manually refresh the project with ctrlshiftF11, after which my created packages show up as intended.
I am updating the newly created package newPackage.Update();, aswell as refreshing the packages of the parent package parentPackage.Packages.Refresh();.
After recursively creating all the packages I additionally call Model.Update(), Repository.Models.Refresh();, Model.Packages.Refresh(); aswell as Repository.Exit().
EA seems to redraw the view, but doesn't show the newly created packages.
Am I missing any call at the end that updates the view?
I'm using this code:
eaApplication = new EA.App(); // Create interface to EA
eaRepository = eaApplication.Repository;
eaRepository.EnableUIUpdates = true;
eaRepository.OpenFile(pathToEAPfile)
EA.Package eaModel = eaRepository.Models.GetAt(0);
EA.Package testModelPackage = (getting it via for loop);
EA.Package newPack = testModelPackage.Packages.AddNew("foopackage", "System.__ComObject");
newPack.Update();
testModelPackage.Packages.Refresh();
eaRepository.RefreshModelView(0);
eaRepository.Exit();
I suppose you call this from an external application. Any EA client does not receive notice of underlying database updates. Only when the user explicitly reads the appropriate parts.
You either need to run the above code inside EA as add-in or refresh manually.
Answer to initial question: The following was a reply to the initial vague question. I leave that for reference by others.
Call
Repository.RefreshModelView(0)
to reload the whole view from root on. Or pass the PackageId of the package you want to refresh.
N.B. All your additional calls are superfluous. Call Update() only for objects that have changed. The Refresh() calls are only needed if you traverse a changed collection afterwards (after addition or deletion of objects).

CQ5 / AEM5.6 Workflow: Access workflow instance properties from inside OR Split

TL;DR version:
In CQ workflows, is there a difference between what's available to the OR Split compared to the Process Step?
Is it possible to access the /history/ nodes of a workflow instance from within an OR Split?
How?!
The whole story:
I'm working on a workflow in CQ5 / AEM5.6.
In this workflow I have a custom dialog, which stores a couple of properties on the workflow instance.
The path to the property I'm having trouble with is: /workflow/instances/[this instance]/history/[workItem id]/workItem/metaData and I've called the property "reject-or-approve".
The dialog sets the property fine (via a dropdown that lets you set it to "reject" or "approve"), and I can access other properties on this node via a process step (in ecma script) using:
var actionReason;
var history = workflowSession.getHistory(workItem.getWorkflow());
// loop backwards through workItems
// and as soon as we find a Action Reason that is not empty
// store that as 'actionReason' and break.
for (var index = history.size() - 1; index >= 0; index--) {
var previous = history.get(index);
var tempActionReason = previous.getWorkItem().getMetaDataMap().get('action-message');
if ((tempActionReason != '')&&(tempActionReason != null)) {
actionReason = tempActionReason;
break;
}
}
The process step is not the problem though. Where I'm having trouble is when I try to do the same thing from inside an OR Split.
When I try the same workflowSession.getHistory(workItem.getWorkflow()) in an OR Split, it throws an error saying workItem is not defined.
I've tried storing this property on the payload instead (i.e. storing it under the page's jcr:content), and in that case the property does seem to be available to the OR Split, but my problems with that are:
This reject-or-approve property is only relevant to the current workflow instance, so storing it on the page's jcr:content doesn't really make sense. jcr:content properties will persist after the workflow is closed, and will be accessible to future workflow instances. I could work around this (i.e. don't let workflows do anything based on the property unless I'm sure this instance has written to the property already), but this doesn't feel right and is probably error-prone.
For some reason, when running through the custom dialog in my workflow, only the Admin user group seems to be able to write to the jcr:content property. When I use the dialog as any other user group (which I need to do for this workflow design), the dialog looks as though it's working, but never actually writes to the jcr:content property.
So for a couple of different reasons I'd rather keep this property local to the workflow instance instead of storing it on the page's jcr:content -- however, if anyone can think of a reason why my dialog isn't setting the property on the jcr:content when I use any group other than admin, that would give me a workaround even if it's not exactly the solution I'm looking for.
Thanks in advance if anyone can help! I know this is kind of obscure, but I've been stuck on it for ages.
a couple of days ago i ran into the same issue. The issue here is that you don't have the workItem object, because you don't really have an existing workItem. Imagine the following: you are going through the workflow, you got a couple of workItems, with means, either process step, either inbox item. When you are in an or split, you don't have existing workItems, you can ensure by visiting the /workItems node of the workflow instance. Your workaround seems to be the only way to go through this "issue".
I've solved it. It's not all that elegant looking, but it seems to be a pretty solid solution.
Here's some background:
Dialogs seem to reliably let you store properties either on:
the payload's jcr:content node (which wasn't practical for me, because the payload is locked during the workflow, and doesn't let non-admins write to its jcr:content)
the workItem/metaData for the current workflow step
However, Split steps don't have access to workItem. I found a fairly un-helpful confirmation of that here: http://blogs.adobe.com/dmcmahon/2013/03/26/cq5-failure-running-script-etcworkflowscriptscaworkitem-ecma-referenceerror-workitem-is-not-defined/
So basically the issue was, the Dialog step could store the property, but the OR Split couldn't access it.
My workaround was to add a Process step straight after the Dialog in my workflow. Process steps do have access to workItem, so they can read the property set by the Dialog. I never particularly wanted to store this data on the payload's jcr:content, so I looked for another location. It turns out the workflow metaData (at the top level of the workflow instance node, rather than workItem/metaData, which is inside the /history sub-node) is accessible to both the Process step and the OR Split. So, my Process step now reads the workItem's approveReject property (set by the Dialog), and then writes it to the workflow's metaData node. Then, the OR Split reads the property from its new location, and does its magic.
The way you access the workflow metaData from the Process step and the OR Split is not consistent, but you can get there from both.
Here's some code: (complete with comments. You're welcome)
In the dialog where you choose to approve or reject, the name of the field is set to rejectApprove. There's no ./ or anything before it. This tells it to store the property on the workItem/metaData node for the current workflow step under /history/.
Straight after the dialog, a Process step runs this:
var rejectApprove;
var history = workflowSession.getHistory(workItem.getWorkflow());
// loop backwards through workItems
// and as soon as we find a rejectApprove that is not empty
// store that as 'rejectApprove' and break.
for (var index = history.size() - 1; index >= 0; index--) {
var previous = history.get(index);
var tempRejectApprove = previous.getWorkItem().getMetaDataMap().get('rejectApprove');
if ((tempRejectApprove != '')&&(tempRejectApprove != null)) {
rejectApprove = tempRejectApprove;
break;
}
}
// steps up from the workflow step into the workflow metaData,
// and stores the rejectApprove property there
// (where it can be accessed by an OR Split)
workItem.getWorkflowData().getMetaData().put('rejectApprove', rejectApprove);
Then after the Process step, the OR Split has the following in its tabs:
function check() {
var match = 'approve';
if (workflowData.getMetaData().get('rejectApprove') == match) {
return true;
} else {
return false;
}
}
Note: use this for the tab for the "approve" path, then copy it and replace var match = 'approve' with var match = 'reject'
So the key here is that from a Process step:
workItem.getWorkflowData().getMetaData().put('rejectApprove', rejectApprove);
writes to the same property that:
workflowData.getMetaData().get('rejectApprove') reads from when you execute it in an OR Split.
To suit our business requirements, there's more to the workflow I've implemented than just this, but the method above seems to be a pretty reliable way to get values that are entered in a dialog, and access them from within an OR Split.
It seems pretty silly that the OR Split can't access the workItem directly, and I'd be interested to know if there's a less roundabout way of doing this, but for now this has solved my problem.
I really hope someone else has this same problem, and finds this useful, because it took me waaay to long to figure out, to only apply it once!

In N2CMS, can you disable the prompt to 'Update links leading to' the item you just edited?

I am using N2CMS to manage the content of my site without using the page routing from N2. Hence when I edit a piece of content, it's quite useless when N2 asks me: "Update links leading to..." "Add permanent redirect at previous URL?". Can I disable this behaviour?
Converting Page into Part is inherently bad idea. It may be temporary fix for the problem you have, but it will bounce back at you in a bad way.
Instead, you can do this
Turn LinkTracker off in web.config
linkTracker enabled="false" permanentRedirectEnabled="false"
Copy CommandFactory.cs from N2 Source into your solution, and rename it to MyCommandFactory.cs.
Add Service replacement attribute
[Service(typeof(ICommandFactory), Replaces = typeof(CommandFactory))]
In a constructor, change this line
updateReferences = new MyUpdateReferencesCommand();
Write your own empty Update reference command class
public class MyUpdateReferencesCommand : UpdateReferencesCommand
{
public override void Process(CommandContext state)
{
}
}
As far as I can see from the source code, N2 expects always to show you the "Update links leading to..." page if the ContentItem is a Page (i.e. [PageDefinition] attribute or .IsPage = true) and the address has been updated. The solution in our case was to make the 'page' in question into a 'part' using [PartDefinition].

Problem importing ZEXP files programmatically

I'm developing a Plone Product that needs to import objects programmatically previously exported to ZEXP files. It's working perfectly, except the navigation bar. When one object is imported, it does so correctly, but the navication bar is not updated. The object can be accessed through it's URL and it's parent container contents tab.
Bellow is the code I used to import the objects. It's based on zope's ObjectManager._importObjectFromFile implementation.
def importDocument( app, fileName, container ):
app._p_jar.sync()
owner = 1
connection = container._p_jar
ob = connection.importFile( config.REMOTE_DIR + fileName, customImporters={ magic: importXML, } )
id = ob.id
if hasattr(id, 'im_func'): id = id()
try:
container._setObject( id, ob, set_owner = owner, suppress_events=False )
except AttributeError:
print "AttributeError"
# Try to make ownership implicit if possible in the context
# that the object was imported into
ob = container._getOb( id )
ob.manage_changeOwnershipType( explicit = 0 )
transaction.commit()
return True
I've noticed that the _setObject implementation fires an ObjectAddedEvent event in it's code, and it's after that event that the menu gets updated when I use the ZMI interface to import an object, so I figure something is listening to this event and handling the menu, but oddly, it doesn't happen when using my code.
Generally speaking, importing zexp objects is not supported (in part due to cases like this where unexpected or unintended results may occur). If it works, great. If it doesn't, you are "on your own" and probably better off copying the Data.fs file to a new software stack.
That said, I'm not sure I understand why clear and rebuild the catalog (ZMI -> portal_catalog -> tab 'advance' -> 'clear & rebuild') is not the answer here. According to its description its job is to "walk the entire portal looking for content objects which should be indexed in the catalog and index them".
Unless I misunderstand, you've just described a situation where newly imported content "should be indexed" because it hasn't been indexed yet.
If you are worried about the length of time required to clear and rebuild, try running it from the command line with something like this:
http://svn.plone.org/svn/plone/plone.org/Products.PloneOrg/trunk/scripts/catalog_rebuild.py
If you are worried about crawling the whole site, then call indexObject() on each object (http://dev.plone.org/plone/browser/plone.org/Products.PloneOrg/trunk/scripts/catalog_rebuild.py#L109)
Maybe try manually rebuilding the whole catalog after the import is complete? It might give you more hints to what is wrong ...
ZMI -> portal_catalog -> tab 'advance' -> 'clear & rebuild'.
You may need to "publish" the object after import to make it visible.
Use the manage_importObject method instead.