I was using Google Guice (http://code.google.com/p/google-guice/), so I:

* created an interface (where applicable) representing the state in
which I was interested.
* bound that interface to some implementation within the ui package
that knew about the UI
* injected a Provider<MyInterface> to my Action constructor
* called provider.get() in my perform method to get the current state.

A practical example might help:

My app managed consultant invoices, and on one of my tabs, I had a
list view where the consultant would select the expense report they
wanted to manage within their open invoice (which would then load a
table view of expenses in a different part of a SplitPane).

I created a binding annotation called @CurrentExpenseReport and had a
data object called ExpenseReportData.  For my EditExpenseReportAction,
I injected a provider that would provide the current expense report,
like so:

class EditExpenseReportAction {
    private final Provider<ExpenseReportData> expenseReport;

    public EditExpenseReportAction(@CurrentExpenseReport
Provider<ExpenseReportData> expenseReport) {
        this.expenseReport = expenseReport;
    }

    @Override
    public void perform() {
        ExpenseReportData expenseReport = this.expenseReport.get();

        // Now I can operate on the selected expense report without having
        // my action know anything about the structure of the UI!
    }
}

Cheers,
-T

On Thu, Sep 9, 2010 at 1:37 PM, Roger L. Whitcomb
<[email protected]> wrote:
> How did you do the "dependency injection" within the actions?  I'm looking at 
> my code, and I'm thinking along these lines too.  Having the invoking 
> component (esp. the MenuItem) helps for some things, but, as you say, often 
> you need other kinds of context within the application, regardless of the UI 
> context.
>
> Roger Whitcomb | Architect, Engineering | [email protected] | Ingres 
> | 500 Arguello Street | Suite 200 | Redwood City | CA | 94063 | USA  +1 
> 650-587-5596 | fax: +1 650-587-5550
>
> -----Original Message-----
> From: Todd Volkert [mailto:[email protected]]
> Sent: Thursday, September 09, 2010 10:33 AM
> To: [email protected]
> Cc: [email protected]
> Subject: Re: Best practice for implementing Actions
>
> FWIW, I ran into this issue in one of my Pivot apps and took a
> different approach altogether.  Instead of looking at the context from
> which the action was invoked, I looked at the state of the app in the
> abstract sense.
>
> For instance, I might look at the selected path of a TreeView to see
> which node they right-clicked on, or I might look at the selected item
> of a list view cross-referenced with the selected items of a table
> view.
>
> I my cases, I needed more than just how they were invoked.  Very
> specific to my case, I used dependency injection within the actions to
> get the necessary state without hard-coupling it to the UI.
>
> This doesn't invalidate the thought that we might want to pass the
> "invocation context" to the action's perform() method, but maybe it's
> food for thought.
>
> Cheers,
> -T
>
> On Thu, Sep 9, 2010 at 1:24 PM, Roger L. Whitcomb
> <[email protected]> wrote:
>> The Stock Tracker tutorial has it in 1.5.x also, I just left out the
>> Tutorial code from my list.  And yes, the Component is available in
>> there as well.
>>
>> Let me think about how that works in what I have prototyped as well.  I
>> think that helps with the ugly case of having global variables that are
>> referenced directly by class name.
>>
>> Roger Whitcomb | Architect, Engineering | [email protected] |
>> Ingres | 500 Arguello Street | Suite 200 | Redwood City | CA | 94063 |
>> USA  +1 650-587-5596 | fax: +1 650-587-5550
>>
>> -----Original Message-----
>> From: Greg Brown [mailto:[email protected]]
>> Sent: Thursday, September 09, 2010 10:10 AM
>> To: [email protected]
>> Cc: [email protected]
>> Subject: Re: Best practice for implementing Actions
>>
>> Yes, that is exactly what I did. There is also some code in the Stock
>> Tracker tutorial that calls perform() (it may only be in the 2.0
>> branch), but a Component argument also works there.
>>
>> On Sep 9, 2010, at 1:07 PM, Roger L. Whitcomb wrote:
>>
>>> So, looking for where the Action.perform() method is called from:
>>>
>>> -          In Window.java from a key press - the context would have to
>>> be the Window component
>>>
>>> -          In Button.java - obviously the Button component (Menu.Item
>>> and MenuBar.Item are both derived from this)
>>>
>>> That's all the places I can find - I guess that covers all the cases?
>>> So, Component it should be.
>>>
>>>
>>>
>>> Roger Whitcomb | Architect, Engineering | [email protected]|
>>> Ingres | 500 Arguello Street | Suite 200 | Redwood City | CA | 94063 |
>>> USA
>>>
>> <http://www.google.com/maps?f=q&hl=en&geocode=&q=500+Arguello+Street+%7C
>>>
>> +Suite+200+%7C+Redwood+City+%7C+CA+%7C+94063+%7C+USA+&sll=37.0625,-95.67
>>> 7068&sspn=50.557552,73.037109&ie=UTF8&t=h&z=16&iwloc=addr>  | +1
>>> 650-587-5596 | fax: +1 650-587-5550
>>>
>>> From: Greg Brown [mailto:[email protected]]
>>> Sent: Thursday, September 09, 2010 9:55 AM
>>> To: [email protected]
>>> Cc: Pivot Dev
>>> Subject: Re: Best practice for implementing Actions
>>>
>>>
>>>
>>> Ha. I think you have identified a valid issue with the Action
>> interface:
>>> the perform() method does not provide the implementor with any
>>> information about the object that triggered the action.
>>>
>>>
>>>
>>> Now, this was originally by design - the thinking was that it should
>> be
>>> possible to execute an action regardless of the UI element that
>> invoked
>>> it. Since actions can potentially be triggered by multiple elements,
>>> they should not generally have a dependency on a particular element.
>>> However, that premise doesn't account for shared actions, or the
>>> possibility that the developer may actually want to execute different
>>> action behaviors based on the source value.
>>>
>>>
>>>
>>> In order to resolve this, I think we'll need to add an argument to the
>>> perform() method that identifies the action's source. If we add it to
>>> 1.5.2, it will be a breaking API change, which we generally try to
>> avoid
>>> in maintenance releases. However, I have already made one API change
>> for
>>> 1.5.2 (to the ResultList class, to resolve a serious performance
>> issue),
>>> so it is not out of the question. Since this is a major functional
>>> limitation, it is probably worth doing.
>>>
>>>
>>>
>>> The only question in my mind is - what should the type of the source
>>> argument be? It could be an Object, but I could also see an argument
>> for
>>> making it a Component (Action is defined in the org.apache.pivot.wtk
>>> package, after all).
>>>
>>>
>>>
>>> Thoughts/comments?
>>>
>>>
>>>
>>> Greg
>>>
>>>
>>>
>>> On Sep 9, 2010, at 10:33 AM, Roger L. Whitcomb wrote:
>>>
>>>
>>>
>>>
>>>
>>> My application has a large tree in the left-hand side with context
>> menus
>>> (different) on every node of the tree.  So, the context menu actions
>> are
>>> highly context-sensitive (the "Properties" item, obviously, would need
>>> to know the exact selected object that the context menu was brought up
>>> on in order to get the right Properties dialog).
>>>
>>>
>>>
>>> So, my question is:  what is "best practice" as far as Pivot goes in
>>> order to transmit this context into the Action.perform() method?  The
>>> "Expenses" tutorial seems to rely on global variables and using
>>> "getSelectedRow" on that TableView object.  So, is this the best way?
>>> Is there some way I don't see to get the context directly in the
>> Action
>>> object?
>>>
>>>
>>>
>>> Thanks.
>>>
>>>
>>>
>>> Roger Whitcomb
>>>
>>> Architect, Engineering
>>>
>>> Ingres Corporation
>>>
>>> [email protected]
>>>
>>>
>>>
>>> PHONE +1 650.587.5596
>>>
>>> FAX +1 650.587.5550
>>>
>>>
>>>
>>> www.ingres.com <http://www.ingres.com/>
>>>
>>>
>>>
>>> This transmission is confidential and intended solely for the use of
>> the
>>> recipient named above. It may contain confidential, proprietary, or
>>> legally privileged information. If you are not the intended recipient,
>>> you are hereby notified that any unauthorized review, use, disclosure
>> or
>>> distribution is strictly prohibited. If you have received this
>>> transmission in error, please contact the sender by reply e-mail and
>>> delete the original transmission and all copies from your system.
>>>
>>>
>>>
>>>
>>>
>>
>>
>

Reply via email to