Own toolbar buttons
My problem was to do a process that deals with a list of records. This list is the result of a search. This search shall be flexible. My idea was to use the search facility of the normal list view of database tables and create a button that does anything with all these records.
I talked to CarlosRuiz and Red1 in chat and got these ideas:
- Red1 told me to get parameters via Context. (I do not believe this works. I copied the chat transscript down here)
- CarlosRuiz proposed to use forms and showed me http://www.adempiere.com/ManPageX_GenerateShipments(manual) as an example
- CarlosRuiz linked me to http://www.adempiere.com/ADempiere_Multiple_Record_Action_Field where icanceras did it in a really nice way
investigation of the problem
One has to know that a Callout works as part of the GUI Layer (in the View). A Process works as part of the model. Because of a model is never allowed to know anything about his view it is not possible to get information about the shown records when using a process.
If I use a Callout for my button I know no way of getting parameters into my program. I can't create a parameter list like in a process.
Solution A: One can configure both a callout and a procedure in one table column description. ADempiere will first start the Callout and second the procedure (after asking for parameters). In this way you can connect the view and the model via a static variable.
Why this is a bad hack: A Solution with a static variable carrying data between two callback methods is not multitasking-clean (User has to open two windows and press a button in every window very fast to crash this). It has reasons that the model should never know about the view. The right solution would be only on the view layer. A kind of Callout with a parameter window would be better.
shortened chat transscripts
getting the search list via Context (does probably not work)
<tbayen> I want to start a process on a limited selection of records. First I search with the normal search field then I want to start a process that has access to the record list. <tbayen> I would like to use the selection of records I see on the screen. I want to use the search input window which is flexible enough for me. <red1> hm.. that is a new but good idea <red1> that means processing on what records are present in the rows <red1> should be easy too as those records are accessible via Ctx <red1> and more dynamic <tbayen> Yes, that's what I think. When it does not work out of the box: How would you enter a search query in a SrvProcess? <red1> it does work <red1> cos.. we have two kinds of button action <red1> one is to act on the present record <red1> one is to act on its own further query of records <red1> both must be using params passed from Ctx <red1> such as Tab, Window <tbayen> How do I access this information from Ctx? <red1> getCtx() <red1> context.get"whatever" <red1> but thinking needed.. as the Ctx is hardcoded for the present record <red1> u be needing to create a new process to attach to it <red1> so if u search for such process (hardcoded but maybe not as it may just be a process class) <red1> in the Table window (System Admin) look at the Process or Class field <tbayen> Does Context contain info about the actual shown record list? <tbayen> I worked with it some weeks ago. AFAIR it only contains Info about the status of all the gui but there is no chance to get the information which of these windows is my actual. <CarlosRuiz> the correct is AFAITFAS <CarlosRuiz> As Far As I Think For A Second <CarlosRuiz> :D <tbayen> Someone in the forum explained me that's right because the SrvProcess runs on the model level but "actual shown records" belongs to the view level. <red1> let me call up the process and GBTYIAS <tbayen> It seems I need a solution on the view level.
<CarlosRuiz> Thomas - what you're describing is something similar to the Generate Shipments form/process <CarlosRuiz> like this <CarlosRuiz> http://www.adempiere.com/ManPageX_GenerateShipments(manual) <CarlosRuiz> a list of records is presented to a user based on some criteria above <CarlosRuiz> the user select the records that wants to process <CarlosRuiz> and push the button below to start the process <tbayen> Yes. Something like that. <CarlosRuiz> there are three classes involved on that <CarlosRuiz> indeed four <CarlosRuiz> the swing view -> VInOutGen <CarlosRuiz> the zk view -> WInOutGen <CarlosRuiz> the model -> InOutGen <CarlosRuiz> and the process behind -> InOutGenerate <tbayen> So you tell me I should first read about custom forms.
creating an own toolbar
<tbayen> Getting access to the already shown search list will be a good feature anyway. I had another idea: Can I create a new Icon in the window and do it from there? <tbayen> What do you think about my idea of a new button in the toolbar? <CarlosRuiz> new button for? let me check something in wiki .... <CarlosRuiz> sure - I'll add a link here about another idea that a guy posted on wiki <CarlosRuiz> similar <CarlosRuiz> gotcha <CarlosRuiz> this is the page <CarlosRuiz> http://www.adempiere.com/ADempiere_Multiple_Record_Action_Field <hengsin> tbayen, a way to apply document action ( complete, prepared, etc ) or process to all/selected records will be great <hengsin> right now, I think we can do delete ( very hacky ) and export only. <CarlosRuiz> hengsin, ivanceras proposed on the page I linked above a possible way to do that - have you checked that approach? <hengsin> yeah, I've look at it before, the idea is good but the UI and code still needs a lot of work
new try in December 2012
I still have the idea to solve this. nmicaud and CarlosRuiz made a contribution for an csv export/import utility. In my opinion this has to be a process. But this process has to know which window you want to export. Perhaps it has to know which tab you use. So despite the fact that there has to be a border between the model and the view and therefor a models's process can not know about the view's state it has to be possible to give the process some parameters. It should be possible to use extra parameters to give a process the number of a window it should work with.
For these processes it would be good to set some parameters from defaults that are given by a special context.
How does the call of a process work?
Processes are started from APanel.actionButton() which itself is called from APanel.actionPerformed() (this is part of the ActionListener Interface and seems to be called for every kind of GUI Action in the Swing Window). The APanel creates the WindowNo that is used inside iDempiere to differentiate between the different windows. This number is part of the context variable names concerning this window. At the end of APanel.actionButton() there is a call of new ProcessModalDialog(...). While constructing the Dialog GUI it calls new ProcessParameterPanel(int WindowNo, ProcessInfo pi).
In ProcessParamter.createField(...) is created a GridFieldVO Object (which knows about our WindowNo) and a GridField Object mField (which knows about the GridFieldVO). Some line later in the code we call mfield.getDefault(). That is the function where the default value for the process parameters will be set.
This method uses Context Variable replacing and Formulas with "@SQL=..." Syntax.
How to get the view information into the getDefault() method
There are two options to get the needed information through:
- use windowNo. This seems the more easier option. I could modify GridField.getDefault() so that it extends a special variable like "@WindowNo".
- extend the Context. We can copy the Context and extend it (or extend it without copying - what is the normal usage for this???). This would allow to enter more variables later on.
- My thesis: The content contains already a lot of informations about the GUI: How much windows are open, which tabs they have, etc. Does it hurt to give an extra field with the actual window? In principle no! There ist just one issue: All given fields are global. The Context is the same in all windows. If we insert information about the active window we should have different Contexts for every Window (every Procedure call). We have to copy it before we extend it. Is it worth it?!?