I am trying to unit test a class which extends org.eclipse.ui.views.properties.tabbed.AbstractPropertySection
It is a GUI on top of a heap of legacy code. The AbstractPropertySection class have a
private TabbedPropertySheetPage tabbedPropertySheetPage;
field, which is initialized by its
public void createControls(Composite parent,
TabbedPropertySheetPage aTabbedPropertySheetPage)
method, and used by its
public TabbedPropertySheetWidgetFactory getWidgetFactory();
method, which in turn used by widget creation. I cannot mock it up in a way that creating a Button would actually create one. As it is both legacy and GUI, maybe it would be wiser to use the Real Thing? But how?
I am doing basically this:
private LineDecorationSection section;
private DiagramConnectionMockup data;
//contains both the model object and editPart
data = new DiagramConnectionMockup();
ConnectionDecorationFactory.getInstance();
//a descendant of the class to be tested,
//augmented with methods to handle what would be done and seen
//on the GUI
section = new LineDecorationSectionExerciser();
assertTrue(section instanceof LineDecorationSection);
//a selection containing theeditPart
ISelection selection = new SelectionMockup(data.getEditPart());
//an editor (Legacy)
IWorkbenchPart editor = new ZentaDiagramEditor();
section.setInput(editor, selection);
//------------This fails-----------
assertNotNull(section.getWidgetFactory());
LineDecorationSectionExerciser exerciser = (LineDecorationSectionExerciser)section;
Button but = ((Button)exerciser.getInternal("DefaultButton"));
//----and this prints "but=null"------------
System.out.println("but="+but);
but.setSelection(true);
The actual code is here: https://github.com/magwas/zenta/blob/001f83c8951a4840b84cd1ff402baa5b96feb4e5/org.rulez.magwas.zenta.editor/src/org/rulez/magwas/zenta/tests/propertysections/LineDecorationSectionTest.java
Question: what to add to the unit tests and mockups so that the unit tests run, and widgets get created?
In the end I have come up with real underlying data and mockups for the Property Sheet page and the goo coming with it. Maybe not the best solution, but I have put the mockup initialisation into the exerciser class.
The solution for the real-world problem is here:
https://github.com/magwas/zenta/blob/51fd9f6b9e363eb5967a3d24b22d012b5bdd6492/org.rulez.magwas.zenta.editor/src/org/rulez/magwas/zenta/tests/propertysections/LineDecorationSectionTest.java
Related
I use Vaadin 14 and would know whether it is possible to report changes in the nested list to objects in the main view.
A rough example is shown in the picture. Above you can see the sum as size (here 2), if I press Delete it should change to 1.
Is that possible and how?
concept
I don't have any code yet, it's a thought where I would like to have a hint about what would be possible, e.g. Observer Pattern or something, but code could look something like this
code:
#Rout("")
public class MainView extends VerticalLayout {
private List<CustomDetails> customDetails = new ArrayList<>();
public MainView(){
final var form = new FormLayout();
customDetails.forEach(form::add);
add(H1("Header"), form)
}
}
public class CustomDetails extends Details{
private CustomForm customForm;
private final Service service;
public CustomDetails(){
customForms = new CustomForm(service.getListOfObjects());
this.setContent(customForms)
}
}
public class CustomForm extend FormLayout{
private FormLayout formLayout = new FormLayout();
private List<Object> objects = new LinkedList<>();
public CustomForm(List<Object> list){
this.objects = list;
setUp();
add(new Paragraph("SUM: "+ list.size()), layout);
}
private void setUp(){
objects.forEarch(o->{
....
layout.add(...)
})
}
}
In Vaadin there is an utility class Binder which is used to bind data to forms. If your use case is related to this, i.e. your so called nested layout is in fact a form and objects you refer to are data beans you want bind into that form. I recommend to study that first.
If you have list editor, I would also investigate if it fits your application to implement it with Grid or IronList/VirtualList, which is backed by DataProvider. Say you edit one item, and after saving the item, you can call dataProvider.refreshItem(item) to update the view.
Observer Pattern or something...
Yes, that is a solution. It is a lot of work and has been done before.
One such library is Beanbag.
Note: I wrote this (or rather, I started writing it a day ago).
EDIT:
As of this edit, we have the ObservableCollection interface. You can use it like so:
// You have a collection called "strings".
// Wrap it in an ObservableCollection.
final ObservableCollection<String, Collection<String>, BasicObservableCollection.Default<String, Collection<String>>> observableStrings = ObservableCollections.observableCollection(strings);
// Add a removed observer.
observableStrings.addElementRemovedObserver(observation -> System.out.println("\"" + observation.getValue() + "\" was removed.");
// Remove an element.
observableStrings.remove("hello");
If you need the wrapper to have List methods, just wait until tomorrow evening EST. I'll have the code up by then and will update this post accordingly.
I have created a class which extends JavaFX's MenuBar that creates a menu bar for my application.
By default I won't specialized operations, like opening/saving a file and running a simulation, to be disabled (and they are). When a user runs the app they can select an item in the menu File>New>, and based on which component they select it will toggle on the appropriate menu options.
I was planning on doing this by having each component give a list of which items it toggles on, and then activating the appropriate items when the component is created.
However, I cannot access the list of menus from within in a function (am trying to do it with this.getMenus() but from within the function the only function that is recognized it this.getClass()).
Does anyone know why I cannot call getMenus() and how I could get access to it?
Alternatively, if you have a better idea for how I can toggle these menu items, I'd love to hear. I don't think this is a good way to do it, but it is the best idea we have come up with.
private void fileNew()
{
Menu fileNew = new Menu("New");
menuFile.getItems().add(fileNew);
for(String k: CLHM.keySet())
{
CComponent comp = CLHM.get(k);
if(comp.supportedFeatures().contains((new SupportsNew())))
{
MenuItem i = new MenuItem(comp.getName());
fileNew.getItems().add(i);
i.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent event)
{
CComponent ctemp = CLHM.get(i.getText());
ArrayList<String> menuItems = (ArrayList) ctemp.getMenuItems();
for (String s : menuItems)
{
Scanner scanner = new Scanner(s).useDelimiter("\\s>\\s");
String menu = scanner.next();
//Menu temp = this.getMenus();
/*
Here the program will parse the string of the
Menu path (e.g. File>Open) and activate the
relevant item, if it exists.
*/
}
borderPane.setCenter((Node) ctemp);
}
});
}
}
}
When you use this inside an anonymous class, it actually refers to the anonymous class instance. So in your case, this is an instance of EventHandler, which is why there are so little methods that you can call (because it is an interface type).
What you are looking for is YourExtendedMenuBar.this.getMenus(). This will tell the compiler that you are looking for the enclosing instance. Alternatively, you can simply drop the this keyword (i.e. getMenus()). Doing so will allow you to use/call any accessible members of the anonymous class and its enclosing class.
On the side note, if you replaced that anonymous class with a lambda expression, then this would have meant YourExtendedMenuBar. It is not possible to access any members of the class that the lambda expression represents, at least not directly.
P.S. I have no idea what your toggling is all about, so I can't answer until I figured out what you mean.
I have a code (swing):
javax.swing.JButton loginbutton = new javax.swing.JButton("Login");
loginbutton.setName("LoginButton126");
and test for it:
ComponentFinder finder = BasicComponentFinder.finderWithCurrentAwtHierarchy();
javax.swing.JButton loginbutton = (javax.swing.JButton) finder.findByName("LoginButton126");
but unfortunatelly I have:
Exception in thread "main" java.lang.NoClassDefFoundError: org/fest/util/Strings
What should I change ?
Best regards
I think this should work fine
By creating a new ComponentFinder that only has access to the GUI components created after it. In the following example, finder has access to MainFrame but not to LoginFrame.
// new LoginFrame();
ComponentFinder finder = BasicComponentFinder.finderWithNewAwtHierarchy();
finder.findByName("login", true); // will fail finding component of login frame
// new MainFrame();
finder.findByName("pw", true); // will work finding label of main frame
The easiest solution is to make all of the component variables be class variables so that you can access them anywhere. However, not everyone wants to do that, and some (like myself) are using GUI Editors that don't generate the components as class variables.
My solution is simple, I'd like to think, and doesn't really violate any programming standards, as far as I know (referencing what fortran was getting at). It allows for an easy and straightforward way to access components by name.
Create a Map class variable. You'll need to import HashMap at the very least. I named mine componentMap for simplicity.
private HashMap componentMap;
Add all of your components to the frame as normal.
initialize() {
//add your components and be sure
//to name them.
...
//after adding all the components,
//call this method we're about to create.
createComponentMap();
}
Define the following two methods in your class. You'll need to import
Component if you haven't already:
private void createComponentMap() {
componentMap = new HashMap<String,Component>();
Component[] components = yourForm.getContentPane().getComponents();
for (int i=0; i < components.length; i++) {
componentMap.put(components[i].getName(), components[i]);
}
}
public Component getComponentByName(String name) {
if (componentMap.containsKey(name)) {
return (Component) componentMap.get(name);
}
else return null;
}
Now you've got a HashMap that maps all the currently existing components in your frame/content pane/panel/etc to their respective names.
To now access these components, it is as simple as a call to getComponentByName(String name). If a component with that name exists, it will return that component. If not, it returns null. It is your responsibility to cast the component to the proper type. I suggest using instanceof to be sure.
If you plan on adding, removing, or renaming components at any point during runtime, I would consider adding methods that modify the HashMap according to your changes.
I'm trying to develop a little drag & drop application under Java FX. User will drop JFX components like Buttons, Menus, Labels on certain positions. When done, he will save this layout and later on he will reopen the layout and he will use it again.
Its important to store the information about all objects that are dropped on some position.
I decided to use serialization for this purpose. But I'm not able to serialize JavaFX components. I tried to serialize Buttons, Scenes, Stages, JFXPane but nothing seemed to work (I obtained NotSerializableException).
Any suggestions how to save all the components and then retrieve them ?
P.S.: I was trying to find out some method with FXML but I did not succeed.
Thank you very much for your answers :)
You are correct, JavaFX (as of 2.1) does not support serialization of components using the Java Serializable interface - so you cannot use that mechanism.
JavaFX can deserialize from an FXML document using the FXMLLoader.load() method.
The trick though, is how to write your existing components and states out to FXML?
Currently, there is nothing public from the platform which performs FXML serialization. Apparently, creating a generic scenegraph => FXML serializer is quite a complex task (and there is no public 3rd party API for this that I know of). It wouldn't be too difficult to iterate over the scenegraph and write out FXML for a limited set of components and attributes.
If the main goal of saving user components on the servers side - is to have a possibility to show the same interface to the user - why not to save all descriptive information you need about users components, and when it is needed - just rebuild user interface again, using stored descriptive information? Here is primitive example:
/* That is the class for storing information, which you need from your components*/
public class DropedComponentsCoordinates implements Serializable{
private String componentID;
private String x_coord;
private String y_coord;
//and so on, whatever you need to get from yor serializable objects;
//getters and setters are assumed but not typed here.
}
/* I assume a variant with using FXML. If you don't - the main idea does not change*/
public class YourController implements Initializable {
List<DropedComponentsCoordinates> dropedComponentsCoordinates;
#Override
public void initialize(URL url, ResourceBundle rb) {
dropedComponentsCoordinates = new ArrayList();
}
//This function will be fired, every time
//a user has dropped a component on the place he/she wants
public void OnDropFired(ActionEvent event) {
try {
//getting the info we need from components
String componentID = getComponentID(event);
String component_xCoord = getComponent_xCoord(event);
String component_yCoord = getComponent_yCoord(event);
//putting this info to the list
DropedComponentsCoordinates dcc = new DropedComponentsCoordinates();
dcc.setX_Coord(component_xCoord);
dcc.setY_Coord(component_yCoord);
dcc.setComponentID(componentID);
} catch (Exception e) {
e.printStackTrace();
}
}
private String getComponentID(ActionEvent event){
String componentID;
/*getting cpmponentID*/
return componentID;
}
private String getComponent_xCoord(ActionEvent event){
String component_xCoord;
/*getting component_xCoord*/
return component_xCoord;
}
private String getComponent_yCoord(ActionEvent event){
String component_yCoord;
/*getting component_yCoord*/
return component_yCoord;
}
}
I've problem regarding GUI with one Menu and one Order Class.
I've created a variable to store how many items have been selected in the Menu Class.
private int totalSelected;
The var totalSelected is live updated. It can be changed anytime depending on actionPerformed() function.(Exp: totalSelected will add up all the selected items)
In the Order Class, how can I access to the live update variable totalSelected in order to retrieve the live update value? When I invoke getTotalSelected() function inside the Menu Class, I will only obtain a 0 value.
Thanks for your help ^^!
Please allow me to specify my question clearer.
public class MenuTab extends JPanel
{
private JLabel display;
private int totalSelected;
public MenuTab()
{
....
}
}
public getTotalSelected(){
return totalSelected;
}
private class SelectedListener implements ActionListener
{
public void actionPerformed()
{
.......
//Assume that totalSelected has been updated!
display = new JLabel("Total: " + totalSelected);
// OK to display totalSelected live value here.
}
}
// A new class is the confirmation of order
public class OrderConfirmedTab extends JPanel{
private JLabel displayTotal;
private MenuTab order = new MenuTab();
public OrderConfirmedTab()
{
......
int totalSelected = order.getTotalSelected();
displayTotal = new JLabel("Total: " + totalSelected);
// Problem to display totalSelected live value here.
// Will obtain 0;
// How can I obtain the live updated value from class MenuTab? Thanks!
}
}
If I read your code right, you need to make your variable be private static int totalSelected; You need to make it static so that it stays the same for all instances of the class.
I looks like your not updating the private int totalSelected; variable when a user makes a selection, so it is always 0.
Ya! I just realized that my JLabel
will not update the value
automatically. So how can I fix it?
Thanks! – Christine
If I understand you correctly you have two GUIs where changes in one (the MenuTab) will update the other (OrderConfirmedTab) in real time?
If so, you will need to increase the coupling between the two objects. If MenuTab has a reference back to OrderConfirmedTab then it can call methods to update the value as it changes.
For example, pass OrderConfirmedTab into MenuTabs constructor
MenuTab mt = new MenuTab(this); // from within OrderConfirmTabs costructor
Then when MenuTab has an actionPerformed event it can call back to OrderConfirmTab
orderConfirmTab.setTotalSelected(totalSelected); // you have to create this method in OrderConfirmTab
I hope this helps a little
You can use PropertyChangeListener and PropertyChangeSupport mechanisms to dispatch an event when the value is updated and to be notified when the variable has changed. Your JLabel is not going to update on its own; even if you were to use an object other than a primitive (note that primitives are merely values, while objects are actually implicit pointers); you will need to update your JLabel when the variable changes, since the JLabel simply stores a string, not a reference to the variables from which the string was constructed.
This is the concept of model-view-controller; your variable should be in some sort of class or classes that represent the model (the information) and which allow changes to be observed via property change events. Your view classes should simply provide display logic and no business or application-specific logic. It is the controller in which your application logic should reside; your controller should register for events on the model, and it should update the view whenever the model has changed, and it should likewise update the model when the view dispatches events that should result in the model being changed.