Is aq_inner (and friends) still needed on Dexterity-only environments? - plone

I have a browser view that on its call method has something like this:
def __call__(self):
context = aq_inner(self.context)
parent = aq_parent(context).
...
Putting a pdb at the beginning and playing with it seems that, for Dexterity there is no need to use it, is that right?
ipdb> self.context, id(self.context), self.context.__class__
(<Container at /plone/ausgaben>, 4651890160, <class 'plone.dexterity.content.Container'>)
ipdb> aq_inner(self.context), id(aq_inner(self.context)), aq_inner(self.context).__class__
(<Container at /plone/ausgaben>, 4651890160, <class 'plone.dexterity.content.Container'>)
So the result is the same using aq_inner or not.
So the question is: does Dexterity (as self.context and in our project actually everything is Dexterity based) prevent us from having to wrap everything with aq_inner and aq_parent and so on, and instead use directly the objects or __parent__ pointers?

Like AT contenttypes, DX contenttypes are also aq-wrapped. So you're going to face the same behaviour (issues :-)) as with AT.
As sdupton said in his aq_parent(instance) == instance.__parent__. The parent pointer ist still implemented thru acquisition.
But there is a small differences to AT.
If you create a new DX obj the following happens:
createContent will be called which creates the DX obj - At this point the content is not yet aq-wrapped. So if you subscripe the ObjectCreatedEvent you gonna have a not aq-wrapped obj.
addContentToContainer will be called, which adds the created DX content to the container. In container._setObject the ObjectAddedEvent will be fired. If you subscribe this event you will have a aq-wrapped dx content.
This is different in AT, of course other events are fired for this case, but the AT content is always aq-wrapped (also in the factory, while adding a new AT obj)
Please let me know, if I misunderstood something.

Related

Overriding AnimationPlayer functions

I'm trying to override my animation player functions like this:
tool
extends AnimationPlayer
func seek (seconds:float,update:bool=false ) -> void:
print("seek =>",seconds)
.seek(seconds,update)
func advance (delta:float) -> void:
print("advanced=>",delta)
.advance(delta)
func play (name:String="", custom_blend:float=-1, custom_speed:float=1.0,from_end:bool=false) -> void:
print("play")
.play(name,custom_blend,custom_speed,from_end)
but I have no idea why it isn't working, nothing is being printed when I test it
I'm particularly interested in seek(), when I move the time bar/when the animation is playing, it should be simultaneously print the seconds of where it is
Basically I'm trying to track the time bar
These methods are not virtual.
Some people "override" non-virtual Godot methods (e.g. add_child) but the instances where people report that working, it is because of the type information (or lack thereof). And I should emphasize it is not overriding, but hiding the original method from late binding.
If the code that is calling seek knows it is an AnimationPlayer, it will call seek from the AnimationPlayer class. And since seek from the AnimationPlayer class is not virtual, your code does not have a chance to run. If it were doing late binding, then it might, but you should not rely on that working.
The case we are talking about, is the animation panel in the editor. Which is written in C++ and thus would know it is dealing with an AnimationPlayer.
Hacking the animation panel
First of all, make an EditorPlugin. You can refer to the documentation on Making Plugins. But, to cover the basics:
Go to Project -> Project Settingsā€¦ -> Plugins and then click on Create.
Godot gives you a form to fill information about the Plugin.
Once you fill the form, it will create an EditorPlugin script on the sub folders of the "addons" folder you specified and with the name you specified.
You got your EditorPlugin script? Good.
The first steps are as I described in another answer.
You can get the current AnimationPlayer like this:
tool
extends EditorPlugin
var edited_animation_player:AnimationPlayer
func handles(object:Object) -> bool:
return object is AnimationPlayer
func edit(object:Object) -> void:
edited_animation_player = object
print(edited_animation_player)
And you can get a reference to the AnimationToolsPanel like this:
var animation_tools_panel:AnimationToolsPanel
func _enter_tree() -> void:
var control:= Control.new()
var animation_player_editor:Control
add_control_to_bottom_panel(control, "probe")
for sibling in control.get_parent().get_children():
if (sibling as Control).get_class() == "AnimationPlayerEditor":
animation_player_editor = sibling
break
remove_control_from_bottom_panel(control)
if animation_player_editor == null:
push_error("Unable to find animation player editor")
Alright, now that we got that, we can extract some stuff from it. In particular we want:
The control that holds the name of the current animation.
The control that holds the current time.
So, let us have variables for those two:
var animation_name_input:OptionButton
var animation_time_input:SpinBox
Now, the first child of the AnimationToolsPanel is the top bar. And the top bar contains the controls we want. So we are going to iterate over the children of the top bar to find them:
var found_option_button:OptionButton
var found_spin_box:SpinBox
for child in animation_player_editor.get_child(0).get_children():
if child is OptionButton:
found_option_button = child as OptionButton
elif child is SpinBox:
found_spin_box = child as SpinBox
if (
is_instance_valid(found_option_button)
and is_instance_valid(found_spin_box)
):
break
animation_name_input = found_option_button
animation_time_input = found_spin_box
Finally, in your _process if the references you got (the animation player, the editor panel, and the controls) are valid, you can get the animation name and time:
var index := animation_name_input.selected
var animation_name = "" if index == -1 else animation_name_input.get_item_text(index)
var animation_time := animation_time_input.value
You want to do that in _process so it updates in real time when an animation is playing from the animation panel.
Of course, the issue is that you want to subclass AnimationPlayer. Thus, in your plugin you can check if the current AnimationPlayer is one of yours, and if it isn't disable this mechanism. But if it is, you can tell your custom AnimationPlayer what is the current animation and time is according to the panel from the plugin code by calling a custom method that takes those values as parameters, and does whatever you need to do with them.

Trouble passing a pointer between child ViewControllers in iOS6

My problem is with an iOS 6 tabbed application. My work-in-progress has 5 tabs and several tabs are gateways to other view controllers. Most pages need access to a Model object, which contains data stored as arrays, strings, and so on. A bare-bones model is populated at runtime and the user can add to it throughout the application lifespan. For example, the code listed below is from my AppDelegate file , where it is passing a pointer to the bare-bones Model to the Project View Controller. This works fine: the tab application uses the navigation controller array stack; because I know the Project page is at index 2, I can send the model to it.
My problem has to do with the sub views of the Project page. For example, as a sub view to the Project page there is (or should be) a File_IO page where the user handles file operations. The File_IO page also needs access to the Model object. But when I try to send the Model pointer from the Project page to the File_IO page, the technique I used previously (from the AppDelegate to the Project) does not work. I point to an empty Model in the FileIO ViewController.
Example code: this is in the AppDelegate, and it works fine: the bare-bones Model in the Project ViewController is populated with the data.
//To the Project View Controller...
UINavigationController *project_NavigationController =
[[tabBarController viewControllers] objectAtIndex:2];
Project_ViewController *project_ViewController =
[[project_NavigationController viewControllers] objectAtIndex:0];
//This hides the navigation bar on the project page but it also removes the bar on any subsequent pages! They need to be programmmatically reset in ViewDidLoad.
[project_NavigationController setNavigationBarHidden:YES animated:YES];
project_ViewController.currentGeoModel = newGeoModel;
Now, my Project_ViewController is embedded in a NavigationController and has 4 child ViweControllers. One is named FileIO_ViewController. I want to pass the currentModel from the Project_ViewController to the FileIO_ViewController. Under the - (void)viewDidLoad method I have tried a number of things, which do not work. For example,
UINavigationController *project_NavigationController = (UINavigationController *) self.presentedViewController;
FileIO_ViewController *fileIO_ViewController = [[project_NavigationController viewControllers] objectAtIndex:1];
fileIO_ViewController.currentModel = currentModel;
compiles but when I try to access currentModel inside the FileIO_ViewController methods, it is empty.
If anyone can take the time to help I would be very appreciative. The best answer for me would be in the form of an explicit code example showing how to pass the pointer to an object like my Model from a ViewController to another ViewController where you do not explicitly know where in the stack the child VC lies. (In my example I used Index 1 but I do not actually know at which Index the FileIO_ViewController lives as I have three other ViewControllers under the Project_ViewController. I've tried several integers with no success.)
If you do answer this, please consider me a New Guy when it comes to iOS 6 and objective C -- climbing Mount Apple has been a long haul and I isn't anywhere near the top yet!
Thanks
Tim Redfield
Norway
If you have a shared single model for your app, you shouldn't proactively pass the pointer around, you should make the model available from a single location and leave it to individual objects to access this same model when they need to. A good location for your model pointer is in your Application delegate.
In the appDelegate's .h file, declare a property for your model:
//appDelegate.h
#property (nonatomic, strong) MyAppModel* appModel;
After you instantiate your model in the appDelegate, just assign it to the property:
//appDelegate.m
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.appModel = [[MyAppModel alloc] init];
//set up bare-bones appModel here
return YES;
}
Then you can access this property from any viewController that needs model data thus:
#import appDelegate.h;
AppDelegate* appDelegate = [UIApplication sharedApplication] delegate;
MyModel* model = appDelegate.model
(Better still, make the model object into it's own Singleton object, but using the appDelegate will get you started)
If you need to pass models around, then you need to take care that you are passing them to the right object. This is where your existing code is breaking. For example you are making many assumptions about the structure of a NavigationController stack. But whenever you move back down a stack by popping a controller off the top, you lose that top controller instance completely. When you 'return' to that controller by going forwards on the stack, in fact a new instance is created (unless you have taken care to keep a pointer hanging around and make sure to push to that pointer). If you need more help on this aspect, you will need to describe exactly the layout of your app, and how you are creating your viewControllers, navigationController stack, etc.
update (following your comments)
If your changes to the model are valid throughout the app, then I don't see why you can't just access the model when you need to from wherever you happen to be in the app via appDelegate.model. If you have concurrent versions of the model, you could look at making a singleton data manager object which could handle the details of storing an array of models (or a model history) and providing the correct model as per request. The principle is the same - rather than proactively passing model objects into your viewControllers, let them request data from a centralised source as they need it.
Regarding your description "Now, my Project_ViewController is embedded in a NavigationController and has 4 child ViewControllers.", I don't think you have quite grasped the distinction between Classes, Storyboard scenes, and instances.
You have this arrangement in a part of your storyboard:
UINavigationController
| push push push
|->UIViewController1 -----> UIViewController2 -----> UIViewController3 ----->
segue segue segue
You talk about passing data directly from VC1 (say) to VC3 by accessing the NavController's stack.
What you need to consider is that the storyboard describes a template showing how instances will interrelate when they are instantiated. They are not instantiated just because the storyboard is loaded. When you have arrived at VC1, the ability to segue to VC2 and VC3 is laid out before you in the template, but neither VC2 nor VC3 - as instances - exist until you initiate the segue. The segue process instantiates it's destinationViewController Therefore it makes no sense to pass data from VC1 directly into VC3. When you are at VC1, the navController's stack only contains one item (a VC1 instance); when you segue to VC2, it then contains instances of VC1 and VC2, and it is only when you actually segue to VC3 that the instance is created and placed in the stack.
Stepping through your code:
UINavigationController *project_NavigationController =
(UINavigationController *) self.presentedViewController;
the presentedViewController property works with modal segues, where you have a presenting, and a presented, view Controller. NavControllers on the other hand work with push segues (as they push child viewControllers onto their viewControllers stack, which is where you can obtain pointers to them from).
In this context, self.presentedViewController is nil, which you are assigning to a new variable. The code does nothing, but the compiler won't complain.
FileIO_ViewController *fileIO_ViewController =
[[project_NavigationController viewControllers] objectAtIndex:1];
project_NavigationControlle is nil, so it's properties are all nil. fileIO_ViewController gets nil.
Likewise in the last line you are sending a message to nil, which is not an error, but faintly redundant.

Why did getSite() return a FormlibValidation object

I've installed collective.quickupload on a blank Plone 4.1 site,
and noticed that when you add a quickupload portlet, kss calls for field validation (plone.app.form.kss), getSite function will return a FormlibValidation object, which cause the quickupload vocabularies crash.
The traceback is here: http://pastebin.com/nvwChpZd
My question is:
Is that (getSite function returns a FormlibValidation object) a bug or intended behaviour ?
Solution to fix/work around/make collective.quickupload work ?
getSite() returns the nearest component site (where local utilities can be stored), which really just means whatever was last set with setSite(), which usually happens on traversal.
Most of the time, the only traversal hook that calls setSite() is the one that's triggered when you traverse over the Plone site. But I think the old KSS inline form validation machinery used (uses?) a hack that creates a local component site on the fly (in a view) and sets that as the local site during the remainder of the request so that it can override certain things.
You can disable validation (e.g. disable the relevant KSS file in portal_kss) or fix c.quickupload to check whether the result of getSite() is an ISiteRoot. If it isn't, it should be acquisition-wrapped, so you can do aq_parent(site) (or maybe site.parent) to get the parent in a loop until you find an ISiteRoot.

Flex: select tree node right after the dataProvider is been assigned / updated / replace

i have a Flex tree control and im trying to select a tree node 3 levels down right after the dataProvider is assigned with a collection object like the following.
basically treeItem1, treeItem2, treeItem3 are the nodes in the tree and treeitem3 is a child of treeItem2 which is a child of treeItem1. Assume these treeItem(1,2,3) are referenced correctly from the collection items.
my problem is that if i wait for the whole component to load completely then select the nodes, it open/select/scrolltoIndex correctly. However, if i were to select the node right after the dataProvider is assigned, then it doesn't even open or select (basically the this.treeService.selectedItem is always null).
can anyone point out what i did wrong? is there anything needs to happen after the dataProvider is assigned?
thanks
this.treeService.dataProvider = oPricingHelper.getCurrentPricingSercicesTreeSource();
this.treeService.expandItem(treeItem1, true);
this.treeService.expandItem(treeItem2, true);
this.treeService.selectedItem = treeItem3;
this.treeService.scrollToIndex(this.treeService.selectedIndex);
I have used the updateComplete event to know when a component (such as a DataGroup or List) has completed rendering after performing a simple task (such as updating the dataProvider reference). Of course, you have to be careful and remove listening to updateComplete because it can run a lot, unless you have a need for it to run.
Something like:
//...some function...
this.treeService.addEventListener(FlexEvent.UPDATE_COMPLETE, onTreeUpdateComplete);
this.treeService.dataProvider = oPricingHelper.getCurrentPricingSercicesTreeSource();
//...rest of some function...
private function onTreeUpdateComplete(event:FlexEvent):void {
this.treeService.removeEventListener(FlexEvent.UPDATE_COMPLETE, onTreeUpdateComplete);
this.treeService.expandItem(treeItem1, true);
this.treeService.expandItem(treeItem2, true);
this.treeService.selectedItem = treeItem3;
this.treeService.scrollToIndex(this.treeService.selectedIndex);
}
I'm not positive your experiencing the same issue but I seem to have the same type of problem with using the advanced data grid, it appears in these cases where the dataprovider is acceptable as multiple types, the components do some extra work in the background to wrap things up into something Hierarchical (HierarchicalData or HierarchicalCollectionView) and in doing so the dataprovider setter call is not synchronous (so it will return before actually having assigned the internal property storing the dataprovider). I've used callLater in this case with moderate success, callLater is generally a bad practice but basically adds a function to a list of functions to call once background processing is done, so this is assuming that something in the dataprovider setter called UIComponent.suspendBackgroundProcessing() and that it will subsequently call UIComponent.resumeBackgroundProcessing() and then it will execute the list of functions added by using callLater. Alternatively you could use setTimeout(someFunction,1000).
These are both "hacks" the real solution is to dig into the framework code and see what it's really doing when you tell it to set the dataprovider. Wherever you see that it actually has set the dataprovider you could extend that class and dispatch an event that you could listen for to run the function to do the selections after this point.
If anyone has a better solution please by all means correct me (I would love to have a better answer than this)

Flex - Is there a way to specify what direction a ComboBox will open?

Maybe I should further qualify this - Is there a way to specify which direction a ComboBox will open without copying and pasting the entire ComboBox class and ripping out the code where it determines which direction it will open in...
I'm my specific case - I need it to open upwards - always.
UPDATE: You can't fix this by subclassing it because the function that handles the direction of the opening is:
private function displayDropdown(show:Boolean, trigger:Event = null):void
And that bad boy uses a fair amount of private variables which my subclass wouldn't have access to...
If you build up the Menu object yourself, you can place the menu anywhere you want by simply setting the x,y coordinates of the menu object. You'll need to calculate those coordinates, but you might be able to do this easily without subclassing ComboBox.
I am doing something similar with PopUpButton; you might find it easier to work with PopUpButton. This is based on real code from my current project:
private function initMenu(): void {
var m:Menu = new Menu();
m.dataProvider = theMenuData;
m.addEventListener(MenuEvent.ITEM_CLICK, menuClick);
m.showRoot = false;
// m.x = ... <-- probably don't need to tweak this.
// m.y = ... <-- this is really the interesting one :-)
theMenu.popUp = m;
}
<mx:PopUpButton id="theMenu" creationComplete="initMenu()" ... />
BTW, to get the PopUpButton to act more like I wanted it (always popup, no matter where the click), setting openAlways=true in the MXML works like a charm.
I doubt it - you'd need to subclass the control (which isn't that big a deal.)
Maybe you could mess with the real estate so it's placed in such a fashion (e.g. crowded into the lower right corner) that up is naturally coerced?
I would recommend checking out this post. Yes, you do have to grab the ComboBox code and modify it, but at least now you have an idea where the modifications need to go.
You could set the MaxDropDownHeight, if you set it big enough Windows will automatically set the direction upwards.
This irritated me no end. I have uploaded a solution, its a simple Class that extends the PopUpButton and removes the logic of stage bounds detection as it failed 50% of the time anyway. My code just allows you to simply specify whether you want to open the menu up or down:
http://gist.github.com/505255

Resources