I'm using a modified version of JosAH's text-based menu system and am trying to figure out how to use reflection to create a list of items from a class' declared subclasses. Because different menu items use different parameters in order to manipulate the underlying data, I'm having a problem generalizing their instantiation.
For example, the assignment was to create a custom linked list, so the menu options would consist of Print, Insert, Save, Quit etc. Printing and insertion just require a reference to the linked list in order to parse the input and call the appropriate functions in the linked list. Save additionally requires the file to save to while Quit doesn't require any additional arguments.
public class MenuList extends TextMenu { //TextMenu extends MenuItem
List<MenuItem> items;
public MenuList (Object data, File file) {} //calls fillList
//calls createList which fills a List<MenuItem> and copies it to this.items
protected void fillList(Object data, File file) {
this.items.addAll( createList(this.getClass(), ... args?) );
}
private static class MenuQuit extends MenuItem {
public MenuQuit() {} //does not need data
}
private static class MenuOne extends MenuItem {
public MenuOne(Object data) {} //manipulates data
}
private static class MenuTwo extends MenuItem {
public MenuOne(Object data) {} //also manipulates data
}
private static class MenuThree extends MenuItem {
//manipulates data and saves to file
public MenuThree(Object data, File file) {}
}
private static class NestedMenu extends MenuList {
//needs parameters to pass to it's own menuItems
public NestedMenu(Object data, File file) {}
}
}
public static List<MenuItem> createList(Class cls, ...args? ) {
List<MenuItem> items = new ArrayList<MenuItem>();
try {
Classes<?>[] param = { parse(args)? };
Class<?>[] menuList = cls.getDeclaredClasses();
for(Class<?> c : menuList) {
if(MenuItem.class.isAssignableFrom(c)) {//only adding the MenuItems
Constructor<?> ct = c.getConstructor(param);
Object menuItem = ct.newInstance( ...args? );
items.add( (MenuItem) menuItem );
}
}
} catch (Exception e) { }
}
Is there any way to generalize createList so that the menu items are created with the necessary parameters?
Also, because of how long I've been working on this, I'm completely open to the possibility that this is a completely overengineered solution and that I should scrap large parts, or perhaps the entirety, of this idea.
Edit: I don't know if this is best place to add this piece information-
This was a solution I had been thinking about, and after reading through some responses and comments, it might be the correct one. If MenuItem always accepts a single Object as a parameter, I can make that assumption when calling getConstructor and newInstance. Afterwards, I'll just leave it up the specific class to cast Object into something useful that they can pull their on data from.
public class MenuItem {
Object data;
public MenuItem(Object data) {
this.data = data;
parseData();
}
protected abstract void parseData();
}
private static class MenuQuit extends MenuItem {
public MenuQuit(Object data) { super(data) } //nothing additional needed
protected void parseData() {} //does nothing
}
private static class MenuSave extends MenuItem { //as outlined above
private CustomLinkedList list;
private File saveFile;
public MenuSave(Object data) {
super(data);
}
//may be able to use reflection to generalize this
protected void parseData() {
this.list = ((MyCustomData) data).list;
this.saveFile = ((MyCustomData) data).saveFile;
}
}
public class MyCustomData {
public CustomLinkedList list;
public File saveFile;
public int otherData;
public MyCustomData(CustomLinkedList a, File b, int c) {} //assignment
}
I was trying to avoid this method because it starts adding complexity to the subclassed MenuItems, which I was hoping to keep as simple as possible. Is there a way to improve this solution?
Not exactly an answer,
but since I'm generally not a big fan of reflection here is another idea:
You could add data and file to your base class MenuItem and leave them null where they are not applicable.
Hmmm. What would happen if you had arguments in the cases that don't need data and just ignore them?
Related
As you can see from the image below I want to select something from my table ( which changes whenever I press a button from the vertical box to the left i.e "Overview", "Orders" ... ) and delete the record from an array ( i.e. where the content comes from ).
The method I approached bellow works but it is not elegant since I have to create at most 8 if statements for each button id. Is there any way to delete the content dynamically. Is there any way for the JVM to figure out which record belongs to which array list?
TableController
#FXML
private TableView<Object> defaultTableView;
public void delete(){
if( MockServer.getServer().currentButton.equals("btnIngredients"))
MockServer.getServer().removeIngredient(defaultTableView.getSelectionModel().getSelectedItem());
else if ( MockServer.------.equals("btnOrders"))
MockServer.getServer().removeOrder(defaultTableView.getSelectionModel().getSelectedItem());
}
Controller
#FXML
private TableController tableController;
#FXML
public void deleteRecord(ActionEvent event){
tableController.delete();
}
MockServer
public class MockServer implements ServerInterface {
public Restaurant restaurant;
public ArrayList<Dish> dishes = new ArrayList<Dish>();
public ArrayList<Drone> drones = new ArrayList<Drone>();
public ArrayList<Ingredient> ingredients = new ArrayList<Ingredient>();
public ArrayList<Order> orders = new ArrayList<Order>();
public ArrayList<Staff> staff = new ArrayList<Staff>();
public MockServer(){}
public ArrayList<Ingredient> getIngredients() { return this.ingredients; }
public ArrayList<Order> getOrders() { return this.orders; }
public ArrayList<Staff> getStaff() { return this.staff; }
....
static public ServerInterface getServer(){
return server;
}
#Override
public void removeIngredient(Ingredient ingredient) {
int index = this.ingredients.indexOf(ingredient);
this.ingredients.remove(index);
this.notifyUpdate();
}
}
This pseudocode will need refactoring since I don't have all the code that you are using but I wish that you will get the general idea
Ok I believe that in the button click code you have to tell your mock server which list is currently used try adding this to the mock server
List currentList = null;
public void setCurrentList(String listName) { // you can use integer but the best is to use enum type setCurrentList(enum) this way you will get tapeSafety
switch(listName){
case "ingredients" : currentList = ingredients ; break;
//other cases
default : throw new Exception(" list not referred error with key value"+listName);
}
}
public void delete(Object o){
int index = this.currentList.indexOf(o);
this.currentList.remove(index);
}
now you can update you controller delete as bellow
public void delete(){
MockServer.getServer().delete(defaultTableView.getSelectionModel().getSelectedItem());
}
Why this should work?
you have to know that there is a good practice that says code to an interface, not an implementation
As you know List in java is an interface so when I assigned the ingredients object this interface will reference the same ArrayList as the object and it will take all it behaviours (how to search for an ingredient object etc...) this way when we will use the currentList on runtime after a button click we are sure that the currentList will be the same as the clicked list and pointing to the same list in the memory
Wish this simple and really resume explanation could help you
I am designing a game with multiple levels. I have a setup class that sets up the board based on the argument it receives, which indicates which level it should set up. Here is the class:
public class BoardState {
public BoardState(InitialState state) {
switch (state) {
case EMPTY:
setupEmptyState();
break;
case INTEGRATIONTEST:
setupIntegrationTestState();
break;
case LEVEL_1:
setupLevelOne();
break;
case LEVEL_2:
setupLevelTwo();
break;
default:
throw new Error("Invalid level selection");
}
}
private void setupEmptyState() { }
private void setupIntegrationTestState() { }
private void setupLevelOne() { }
private void setupLevelTwo() { }
}
This works fine, but every time I add a new level I have to add code in three places: The InitialState enum which defines the list of accepted states, the switch statement in the constructor, and the body of the class, where I have to add a method to set up the level in question.
One nice thing that I want to keep is the fact that my GUI automatically populates with a new button for each level I add based on the enum defining the list of levels.
How can I refactor this code so that there is less overhead associated with adding a new level?
Often when you need to reduce code duplication, an interface arise. This time (based on your comment in OP) it seems you need to add different objects to the board depending on which level you are:
import java.util.List;
public interface LevelSettings {
List<GameObject> startingObjects();
}
Now, BoardState looks like that (no more setupX() methods)
import java.util.List;
public class BoardState {
private final List<GameObject> gameObjects;
public BoardState(LevelSettings settings) {
this.gameObjects = settings.startingObjects();
}
}
Since you also specified it is nice for you to have an enum to dynamically creates buttons on the GUI, one can combine the best of both world (interface and enum) by implementing the interface in an enum...
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public enum InitialState implements LevelSettings {
EMPTY {
#Override
public List<GameObject> startingObjects() {
return Collections.emptyList();
}
},
INTEGRATIONTEST {
#Override
public List<GameObject> startingObjects() {
GameObject g1 = new GameObject("dummy 1");
GameObject g2 = new GameObject("dummy 2");
return Arrays.asList(g1, g2);
}
},
LEVEL_1 {
#Override
public List<GameObject> startingObjects() {
//read a config file to get the starting objects informations
//or also hardcoded (not preferred)
}
},
LEVEL_2 {
#Override
public List<GameObject> startingObjects() {
//read a config file to get the starting objects
//or also hardcoded (not preferred)
}
};
}
And that's it basically. If you need to add LEVEL_3 do it in InitialState and everything will follow.
Going one step further
From here it goes beyond what you requested, feel free to ignore this part if you are not convinced.
As a good practice I would store these configurations only in config files to reduce even more the code duplication and gain in flexibility:
import java.util.List;
public enum InitialState implements LevelSettings {
EMPTY {
#Override
public List<GameObject> startingObjects() {
return readFromFile("empty.level");
}
},
INTEGRATIONTEST {
#Override
public List<GameObject> startingObjects() {
return readFromFile("integration_test.level");
}
},
LEVEL_1 {
#Override
public List<GameObject> startingObjects() {
return readFromFile("1.level");
}
},
LEVEL_2 {
#Override
public List<GameObject> startingObjects() {
return readFromFile("2.level");
}
};
private static List<GameObject> readFromFile(String filename) {
//Open file
//Serialize its content in GameObjects
//return them as a list
}
}
So that when you decide to add a new level you actually only need to know the filename in which the level's configuration is stored.
Going another step further
What you will see there is really tricky and I don't advice you to use it in production code (but it reduces code duplication) !
import java.util.List;
public enum InitialState implements LevelSettings {
EMPTY, INTEGRATIONTEST, LEVEL_1, LEVEL_2;
#Override
public List<GameObject> startingObjects() {
return readFromFile(this.name() + ".level");
}
private static List<GameObject> readFromFile(String filename) {
//Open file
//Serialize its content in GameObjects
//return them as a list
}
}
Here we rely on enum names themselves to find the corresponding correct file. This code works because it is based on the convention that the files are named accordingly to the enum names with the ".level" extension. When you need to add a new level, just add it to the enum and that's it...
You could use inheritance, polymorphism is the keyword here.
Set up your InitialState class as abstract base class (or interface if you have no common fields) and define a method public abstract void setup();.
abstract class InitialState {
public abstract void setup();
}
Then, for each of your original switch cases, derive a class from your base class, for example LevelOne, and implement its specific by overriding setup().
class LevelOne extends InitialState {
#Override
public void setup() {
// The code from "setupLevelOne()" goes here
}
}
Your BoardState class reduces to this:
public class BoardState {
public BoardState(InitialState state) {
// At runtime, the right method of the actual
// state type will be called dynamically
state.setup();
}
}
However, if you need to set interal state of your BoardState class, consider defining the setup method as public abstract void setup(BoardState boardState), so you can access its getter and setter methods.
This appraoch could also foster reuse of code, as you could add several abstract layers for different types of levels.
well you can refactor all of the work into a one method.
say it takes an int as the ID of the level, while it loads a JSON file containing structured information of each level, and creates the given level.
for example :
"levels" : [
"level" : {
"id" : "001",
"size" : "200",
"difficulty" : "2"
},
"level" : {
"id" : "002",
"size" : "300",
"difficulty" : "3"
}
]
then, in your code:
public void setupLevel(int id) throws levelNotFoundException{
//somehow like this
Document doc = parse("levels.json");
for(element elm: doc.get("levels")){
if(Integer.parseInt(elm.get("id")).equals(id)){
//setup your level
}
}
}
and then somewhere you call your method:
int levelId = getNextLevel();
try{
setupLevel(levelId);
} catch (LevelNotFoundException e){e.printStackTrace();}
or you can use XML, or simply hard code it, and store all levels in an array
I am implementing the frontend of an application in GWT (see attached picture) and I have view class which is getting bigger as more widgets are added to the frontend.
As stated in GWT tutorial, the view class must implement the Display interface of the presenter class. y problem is I have a lot a methods in that interface and as I implement them in the view class, it becomes too big. That's why I would like to refactor the code to reduce the size of the view class by implementing those methods in others
classes and reference them where needed in the view class;for instand by grouping them per group box (one class per group box).
Below is a sample code: Note that in the real application we have more widgets per group box.
The problem I am facing will be well explained as you read through the whole posting because I will be adding more details.
code to be refactored:
ContactPrewsenter.java
public class ContactPresenter {
public interface Display
{
void methodA();
void methodB();
void methodC();
void methodD();
void methodE();
void methodF();
.
.
.
void methodM();
}
public ContactPresenter()
{
//Some stuff here
}
......
......
#Override
public void bind(){
//Some stuff here
}
}
ContactView.java:
public class ContactView implements ContactPresenter.Display
{
private final Listbox listBoxA;
private final Listbox listBoxB;
private final Listbox listBoxC;
private final Listbox listBoxD;
private final Listbox listBoxE;
private final Listbox listBoxF;
private final Listbox listBoxG;
private final Listbox listBoxH;
private final Listbox listBoxI;
private final Listbox listBoxJ;
private final Listbox listBoxK;
private final Listbox listBoxL;
private final Listbox listBoxM;
public ContactView()
{
listBoxA = new ListBox();
listBoxB = new ListBox();
VerticalPanel vPanel1= new VerticalPanel();
vPanel1.add(listBoxA);
vPanel1.add(listBoxB);
GrooupBox groupBox1 = new GroupBox();
groupBox1.add(vPanel1);
listBoxC = new ListBox();
listBoxD = new ListBox();
VerticalPanel vPanel2 = new VerticalPanel();
vPanel2.add(listBoxC);
vPanel2.add(listBoxD);
GrooupBox groupBox2 = new GroupBox();
groupBox2.add(vPanel2);
listBoxE = new ListBox();
listBoxF = new ListBox();
VerticalPanel vPanel3 = new VerticalPanel();
vPanel3.add(listBoxE);
vPanel3.add(listBoxF);
GrooupBox groupBox3 = new GroupBox();
groupBox3.add(vPanel3);
listBoxE = new ListBox();
listBoxF = new ListBox();
VerticalPanel vPanel4 = new VerticalPanel();
vPanel4.add(ListBoxE);
vPanel4.add(ListBoxF);
....
GrooupBox groupBox3 = new GroupBox();
groupBox3.add(vPanel4);
listBoxG = new ListBox();
listBoxH = new ListBox();
....
VerticalPanel vPanel = new VerticalPanel();
vPanel.add(ListBoxG);
vPanel.add(ListBoxH);
....
GrooupBox groupBox4 = new GroupBox();
groupBox4.add(vPanel);
......
//create Horizontal/vertical panels, docklayout panel as well, to position the group boxes on the gui
....
}
#Override
void methodA(){
//uses listBoxA
}
#Override
void methodB(){
//used listBoxB
}
#Override
void methodC(){
//uses listBoxC
}
#Override
void methodD(){
//uses listBoxD
}
#Override
void methodE(){
//uses listBoxE
}
#Override
void methodF(){
//uses listBoxF
}
#Override
void methodG(){
//uses listBoxG
}
#Override
void methodH(){
//uses listBoxH
}
.
.
.
#Override
void methodM(){
//uses listBoxM
}
}
I have tried as follows:
ContactPreseter.java
public class ContactPresenter
{
public interface Display extends groupBox1View.Display, groupBox2View.Display, groupBox3View.Display, groupBox4View.Display
{
}
}
preseter classes of each group box
public class groupBox1Presenter
{
public interface Display
{
void methodA();
void methodB();
}
}
public class groupBox2Presenter
{
public interface Display
{
void methodC();
void methodD();
}
}
public class groupBox3Presenter
{
public interface Display
{
void methodE();
void methodF();
}
}
public class groupBox4Presenter
{
public interface Display
{
void methodG();
void methodH();
}
}
ContactView.java
public abstract class ContactView implements ContactPresenter.Display
{
// adds group boxes to horizontal/vertical panels, and docklayout panel
}
Below are the view classes for each group box:
But here I eclipse forces me to implement all the methods of the interface ContactPresenter.Display in each of these classes whereas , I wanted it to be the way you see implemented here.
I was wondering if there were a way to play with access modifiers in order to achieve that ? If not, please I would you to help with ideas how to do it ?
public groupBox1View extends ContactView implements groupBox1Presenter
{
public groupBox1View()
{
}
#Override
void methodA(){
//uses listBoxA
}
#Override
void methodB(){
//used listBoxB
}
}
public groupBox2View extends ContactView implements groupBox2Presenter
{
public groupBox2View()
{
}
#Override
void methodC(){
//uses listBoxC
}
#Override
void methodD(){
//used listBoxD
}
}
public groupBox3View extends ContactView implements groupBox3Presenter
{
public groupBox3View()
{
}
#Override
void methodE(){
//uses listBoxE
}
#Override
void methodF(){
//used listBoxF
}
}
public groupBox4View extends ContactView implements groupBox4Presenter
{
public groupBox4View()
{
}
#Override
void methodG(){
//uses listBoxG
}
#Override
void methodH(){
//used listBoxH
}
}
You are right, your view is growing too big. You need to cut it into components which are handling their own concerns.
The editor framework will prove helpful but has it's own caveats.
In the end, you have one presenter, working with the whole thing, but only reading and writing one contact object.
You build your view from multiple components, each may have it's own presenter and is responsible for one part of your large contact object.
An example: Instead of running 10 listboxes of generic type, make that 10 semantically different components, responsible for selection of different types of data: AgeListBox, CityListBox, FooListBox, BarListBox.
This will seperate the data provisioning for the boxes out of your central presenter, and into the specific presenters for each listbox.
Start at the lowest level and combine editing views for each semantic unit and combine them to larger return objects:
NameEditor, AgeEditor, FooEditor, BarEditor are combined into an AddressEditor, which assembles with a CVEditor into something bigger until you finally arrive at the contact level.
I hope this makes sense to you.
UPdate: You asked for code, let's try some pseudocode:
Let's say you have a profile you want to edit. It contains of
the user's personal data
contains the user address
a bunch of email or mobile addresses
an image or connection to Gravatar
payment information
the list of tags the user is interested in
the list of channels he subscribed
Newsletter/marketing information
public class UserProfile {
PersonalData person;
List<NewsTopic> topicsOfInterest;
List<NewsChannel> subscriptions;
MarketingInfo marketingInfo;
// bean stuff, constr, equals etc.
}
public class PersonalData {
String name;
String firstName;
List<ContactDevice>phoneAndMailList;
ImageContainer userImage;
BankAccount paymentData;
}
You get the idea, I guess...
You can now write ONE view class, detailing all the information you see here, resulting in a monolitic monster view and the matching monster presenter. Or you follow the advice in the gwtproject and cut the view in small as possible pieces (components). That is, subviews and presenters that form a hierarchy, matching the one of your UserProfile class. This is basically what the editor framework is really good at.
In the editor fw, the views are called "Editors" (makes sense), and they get fed the data from top editor down to the smallest part by an EditorDriver class. GWT will generate most of the code for you, which is very cool, but also is not working so perfect, if you have optional parts in the profile.
If we would implement this ourselves, you will build a structure like the following (I avoid the "Editor" and replaced by "Dialog"):
public class UserProfileDialogView extends Component implements HasValue<UserProfile> {
// subviews
#UiField
PersonalDataDialog personDataDlg;
#UiField
UserTopicListDialog topicListDlg;
#UiField
SubscriptionListDialog subscriptionListDlg;
#UiField
MarketingInfoDialog marketingInfoDlg;
#Overwrite
public UserProfile getValue() {
// we do not need to copy back the data from the sub-dialogs, because we gave them the values from the profile itself.
// Beware, substructures cannot be null in such a case!
return userProfile;
}
#Ovewrite
public void setValue(UserProfile profile) {
this.userProfile = profile;
// option one: manually distribute the profile parts
personDataDlg.getPresenter().setValue(profile.getPerson());
topicListDlg.getPresenter().setValue(profile.getTopicsOfInterest());
subscriptionListDlg.getPresenter().setValue(profile.getSubscriptions());
// option two: use eventbus and valuechanged event, dialogs are
}
}
There is now a variance of concerns: Who will set the value in the sub-dialogs. You can forward to the presenter of the sub-dialog, or you set it directly in the sub-dialog.
Anyway, what should get clear to you now, is that you do not have only one presenter to rule all parts of the view. You need to split the presenters to be responsible for one subview each. What I found useful in such a large dialog tree, was to have a separate model class, that keeps the object currently beeing edited and provides change communication logic for other dialogs. For example, if you add a list of topics, and you add one topic, the dialog for the channel subscription selection may want to know, that there is now one more topic to be shown in the topic-filter.
My question is conceptual about synchronizing data and events in programming a gui. (This example shows batch state being the facilitator of taking classes that implement the same interface and dynamical updating cells in two different frames.This code is where I got my idea. )
I am assuming that I will create new instances of this batch state object specifically in the classes where an event is triggered(panel) and the reaction to that event(another panel) . I will do this by adding the classes that need to communicate to the a list of bsListeners. Then call the batch state function like "setSelectedCell()" to iterate over each class to synchronize them.
The Problem
This would work perfect if the object both shared the same arrayList but since they are both new instances they don't. I tried changing things to static and it is freaking out especially in the interface. Is this approach logical I am brand new to programming gui's? Sorry this is a novel.
interface BatchStateListener {
public void valueChanged(Cell cell, String newValue);
public void selectedCellChanged(Cell newSelectedCell)
}
class BatchState {
private String[][] values;
private Cell selectedCell;
private List<BatchStateListener> listeners;
public BatchState(int records, int fields) {
values = new String[records][fields];
selectedCell = null;
listeners = new ArrayList<BatchStateListener>();
}
public void addListener(BatchStateListener l) {
listeners.add(l);
}
public void setValue(Cell cell, String value) {
values[cell.record][cell.field] = value;
for (BatchStateListener l : listeners) {
l.valueChanged(cell, value);
}
}
public String getValue(Cell cell) {
return values[cell.record][cell.field];
}
public void setSelectedCell(Cell selCell) {
selectedCell = selCell;
for (BatchStateListener l : listeners) {
l.selectedCellChanged(selCell);
}
}
public Cell getSelectedCell() {
return selectedCell;
}
}
My questions was a bit confusing, but I came to my answer. I was just wondering how to implement this BatchState class in my code. I found that if I make it in main and pass it to the constructors frames/panels that need to communicate with each other they all can share reference to it.
I have an object, Supply, that can either be an ElecSupply or GasSupply (see related question).
Regardless of which subclass is being edited, they all have a list of BillingPeriods.
I now need to instantiate N number of BillingPeriodEditors based on the contents of that list, and am pretty baffled as to how I should do it.
I am using GWTP. Here is the code of the SupplyEditor I have just got working:
public class SupplyEditor extends Composite implements ValueAwareEditor<Supply>
{
private static SupplyEditorUiBinder uiBinder = GWT.create(SupplyEditorUiBinder.class);
interface SupplyEditorUiBinder extends UiBinder<Widget, SupplyEditor>
{
}
#Ignore
final ElecSupplyEditor elecSupplyEditor = new ElecSupplyEditor();
#Path("")
final AbstractSubTypeEditor<Supply, ElecSupply, ElecSupplyEditor> elecSupplyEditorWrapper = new AbstractSubTypeEditor<Supply, ElecSupply, ElecSupplyEditor>(
elecSupplyEditor)
{
#Override
public void setValue(final Supply value)
{
setValue(value, value instanceof ElecSupply);
if(!(value instanceof ElecSupply))
{
showGasFields();
}
else
{
showElecFields();
}
}
};
#Ignore
final GasSupplyEditor gasSupplyEditor = new GasSupplyEditor();
#Path("")
final AbstractSubTypeEditor<Supply, GasSupply, GasSupplyEditor> gasSupplyEditorWrapper = new AbstractSubTypeEditor<Supply, GasSupply, GasSupplyEditor>(
gasSupplyEditor)
{
#Override
public void setValue(final Supply value)
{
setValue(value, value instanceof GasSupply);
if(!(value instanceof GasSupply))
{
showElecFields();
}
else
{
showGasFields();
}
}
};
#UiField
Panel elecPanel, gasPanel, unitSection;
public SupplyEditor()
{
initWidget(uiBinder.createAndBindUi(this));
gasPanel.add(gasSupplyEditor);
elecPanel.add(elecSupplyEditor);
}
// functions to show and hide depending on which type...
#Override
public void setValue(Supply value)
{
if(value instanceof ElecSupply)
{
showElecFields();
}
else if(value instanceof GasSupply)
{
showGasFields();
}
else
{
showNeither();
}
}
}
Now, as the list of BillingPeriods is a part of any Supply, I presume the logic for this should be in the SupplyEditor.
I got some really good help on the thread How to access PresenterWidget fields when added dynamically, but that was before I had implemented the Editor Framework at all, so I think the logic is in the wrong places.
Any help greatly appreciated. I can post more code (Presenter and View) but I didn't want to make it too hard to read and all they do is get the Supply from the datastore and call edit() on the View.
I have had a look at some examples of ListEditor but I don't really get it!
You need a ListEditor
It depends of how you want to present them in your actual view, but the same idea apply:
public class BillingPeriodListEditor implements isEditor<ListEditor<BillingPeriod,BillingPeriodEditor>>, HasRequestContext{
private class BillingPeriodEditorSource extends EditorSource<BillingPeriodEditor>{
#Override
public EmailsItemEditor create(final int index) {
// called each time u add or retrive new object on the list
// of the #ManyToOne or #ManyToMany
}
#Override
public void dispose(EmailsItemEditor subEditor) {
// called each time you remove the object from the list
}
#Override
public void setIndex(EmailsItemEditor editor, int index) {
// i would suggest track the index of the subeditor.
}
}
private ListEditor<BillingPeriod, BillingPeriodEditor> listEditor = ListEditor.of(new BillingPeriodEditorSource ());
// on add new one ...
// apply or request factory
// you must implement the HasRequestContext to
// call the create.(Proxy.class)
public void createNewBillingPeriod(){
// create a new one then add to the list
listEditor.getList().add(...)
}
}
public class BillingPeriodEditor implements Editor<BillingPeriod>{
// edit you BillingPeriod object
}
Then in you actual editor edit as is in the path Example getBillingPeriods();
BillingPeriodListEditor billingPeriods = new BillingPeriodListEditor ();
// latter on the clickhandler
billingPeriods.createNewBillingPeriod()
You are done now.