Interaction of two Controllers in JavaFX - binding

Good day! I would like to ask how these particular situation is done in JAVAFX.
I have made a layout as being pointed out here (link to layout question)
My question is since the keyboard layout is from a different FXML with a different Controller class and with the mainLayout having a different FXML with its own controller class, , how do you code such thing that when I press key 'A', it will display on the textfield found in the mainLayout? Does it have to do with bindings? If so, how? Please?

bear in mind that JavaFX and FXML follow the MVC principle.
an easy (although perhaps not optimal) solution would look like this:
public class Main extends Application {
#Override
public void start(Stage stage) throws Exception {
FXMLLoader layout1Loader = new FXMLLoader(getClass().getResource("layout1.fxml"));
FXMLLoader layout2loader = new FXMLLoader(getClass().getResource("layout2.fxml"));
Node layout1 = (Node) layout1Loader.load();
Node layout2 = (Node) layout2loader.load();
final Layout1Controller l1Controller = layout1Loader.getController();
final Layout2Controller l2Controller = layout2loader.getController();
l2Controller.but2.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent actionEvent) {
l1Controller.toggleStatus(actionEvent);
}
});
Parent root = (Parent) layout1;
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
...
}

Related

how to inflate different layouts in Firebase Recycler Adapter

I have a chat activity and trying to inflate different layouts for the sender and receiver. so far I can retrieve data for the firebase realtime database but sender and receiver have the same layout, I have created layout second layout and tried with viewType but can't figure out how to assign the current user to a cretin layout, please help :(
chat activity
if (!employee)
{
FirebaseRecyclerOptions options = new FirebaseRecyclerOptions.Builder<ChatMessageModel>()
.setQuery(FirebaseDatabase.getInstance().getReference().child("client_emp_messages")
.child(formattedDate+uid), ChatMessageModel.class)
.build();
}
else
{
// employee
Bundle bundle = getIntent().getExtras();
String d = bundle.getString("path_to_client_realtime_db");
options = new FirebaseRecyclerOptions.Builder<ChatMessageModel>()
.setQuery(FirebaseDatabase.getInstance().getReference().child("client_emp_messages")
.child(d), ChatMessageModel.class)
.build();
}
adapter = new ChatAdapter(options);
nMessageList.setAdapter(adapter);
chat adapter
public class ChatAdapter extends FirebaseRecyclerAdapter<ChatMessageModel, ChatAdapter.ChatViewHolder>
{
public ChatAdapter(#NonNull FirebaseRecyclerOptions<ChatMessageModel> options) {
super(options);
}
#Override
protected void onBindViewHolder(#NonNull ChatViewHolder holder, int i, #NonNull ChatMessageModel model) {
holder.nMessage_text_view.setText(model.getMessage());
}
#NonNull
#Override
public ChatViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_single_layout, parent, false);
return new ChatViewHolder(view);
}
class ChatViewHolder extends RecyclerView.ViewHolder
{
TextView nMessage_text_view;
public ChatViewHolder(#NonNull View itemView) {
super(itemView);
nMessage_text_view = itemView.findViewById(R.id.message_text_view);
}
}
}
What I suggest you is to make one layout. like the sender on the right side and receiver on the left side. you can use it with the help of a linear layout or relative layout. and set their visibility Invisible.
So download the message data from the database and check it by user id token. If it data matches with the current user token then display it in the right column and set visibility Visible and vice versa.
For that, you just need to store the user token with the message in the database.
Hope you understand it. Thanks

vaadin 10 - Push - Label won't update

MainView include InformationCOmponent:
#Push
#Route
public class MainView extends VerticalLayout {
InformationComponent infoComponent;
public MainView(#Autowired StudentRepository studentRepo, #Autowired Job jobImportCsv, #Autowired JobLauncher jobLauncher, #Value("${file.local-tmp-file}") String inputFile) {
[...] // some stuffs
infoComponent = new InformationComponent(studentRepo);
add(infoComponent);
}
//update when job process is over
private void uploadFileSuccceed() {
infoComponent.update(myUploadComponent.getFile());
}
InformationComponent:
public class InformationComponent extends HorizontalLayout {
StudentRepository studentRepo;
Label nbLineInFile = new Label();
VerticalLayout componentLeft = new VerticalLayout();;
VerticalLayout componentRight = new VerticalLayout();;
public InformationComponent(StudentRepository studentRepo) {
[...] // some init and style stuff
addLine("Nombre de lignes dans le fichier", nbLineInFile);
}
private void addLine(String label, Label value) {
componentLeft.add(new Label(label));
componentRight.add(value);
}
public void update(File file) {
try {
long nbLines = Files.lines(file.toPath(), Charset.defaultCharset()).count();
System.out.println("UPDATED! " +nbLines); // value is display in console ok!
UI.getCurrent().access(() -> nbLineInFile.setText(nbLines)); // UI is not updated!!
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
When I call InformationComponent from MainView the Label is not update in the browser.
UI.getCurrent().access(() -> nbLineInFile.setText(nbLines))
also try wwith #Push(PushMode.MANUAL) and ui.push(); but doesn't work either...
Complete source code is here: https://github.com/Tyvain/ProcessUploadedFile-Vaadin_SpringBatch/tree/push-not-working
I suspect the problem here is that uploadFileSuccceed() is run from a background thread, in which case UI.getCurrent() will return null. This would cause a NullPointerException that either kills the background thread or alternatively the exception is caught and silently ignored by the caller. Another alternative is that uploadFileSuccceed() happens through a different browser window and thus also a different UI instance, which means that the changes would be pushed in the context of the wrong UI.
For exactly these reasons, UI.getCurrent().access(...) is generally an anti pattern, even though it's unfortunately quite widely used in old examples.
You can check whether this is the cause of your problem by logging the value of UI.getCurrent() in the beginning of the update method, and comparing that to the value of UI.getCurrent() e.g. in the constructor of InformationComponent.
To properly fix the problem, you should pass the correct UI instance through the entire chain of events originating from whatever triggers the background processing to start. You should also note that it might be tempting to use the getUI() method that is available in any Component subclass, but that method is not thread safe and should thus be avoided in background threads.
As a final notice, I would recommend using the Span or Text component instead of Label in cases like this. In Vaadin 10, the Label component has been changed to use the <label> HTML element, which means that it's mainly intended to be used as the label of an input component.
Based on information provided by Leif you should do something like the following example.
At runtime, when this HorizontalLayout subclass object is attached to a parent UI object, its onAttach method is called. At that point we can remember the UI by storing its reference is a member variable named ui. Actually, an Optional<UI> is returned rather than a UI object, so we need to test for null, though it should never be null at point of onAttach.
public class InformationComponent extends HorizontalLayout {
UI ui;
StudentRepository studentRepo;
Label nbLineInFile = new Label();
VerticalLayout componentLeft = new VerticalLayout();;
VerticalLayout componentRight = new VerticalLayout();;
public InformationComponent(StudentRepository studentRepo) {
[...] // some init and style stuff
addLine("Nombre de lignes dans le fichier", nbLineInFile);
}
private void addLine(String label, Label value) {
componentLeft.add(new Label(label));
componentRight.add(value);
}
public void update(File file) {
try {
long nbLines = Files.lines(file.toPath(), Charset.defaultCharset()).count();
System.out.println("UPDATED! " +nbLines); // value is display in console ok!
this.ui.access(() -> nbLineInFile.setText(nbLines)); // UI is not updated!!
} catch (IOException e) {
throw new RuntimeException(e);
} catch (UIDetachedException e) {
// Do here what is needed to do if UI is no longer attached, user has closed the browser
}
#Override // Called when this component (this `HorizontalLayout`) is attached to a `UI` object.
public void onAttach() {
ui = this.getUI().orElseThrow( () -> new IllegalStateException("No UI found, which should be impossible at point of `onAttach` being called.") );
}

Appium PageObject - When / Where to instantiate the page?

In my team we're doing cross platform UI testing using Appium and the Appium Java-Client.
The current structure of our project is something like:
mobile
pages
SignInPage
steps
SignInSteps
The steps are "glued" together using Cucuember.
SignInPage looks something like this:
public class SignInPage {
public SignInPage(AppiumDriver driver) {
PageFactory.initElements(new AppiumFieldDecorator(driver, 15, TimeUnit.SECONDS), this);
}
// region Identifiers
final String IOS_USERNAME_FIELD = "SignInUsernameField";
final String ANDROID_USERNAME_FIELD = "new UiSelector().resourceIdMatches(\".*id/username.*\")";
final String IOS_PASSWORD_FIELD = "SignInPasswordField";
final String ANDROID_PASSWORD_FIELD = "new UiSelector().resourceIdMatches(\".*id/password_editText.*\")";
final String IOS_SIGN_IN_BUTTON = "SignInButton";
final String ANDROID_SIGN_IN_BUTTON = "new UiSelector().resourceIdMatches(\".*id/signInButton.*\")";
// endregion
#iOSFindBy(accessibility = IOS_USERNAME_FIELD)
#AndroidFindBy(uiAutomator = ANDROID_USERNAME_FIELD)
private MobileElement usernameField;
#iOSFindBy(accessibility = IOS_PASSWORD_FIELD)
#AndroidFindBy(uiAutomator = ANDROID_PASSWORD_FIELD)
private MobileElement passwordField;
#iOSFindBy(accessibility = IOS_SIGN_IN_BUTTON)
#AndroidFindBy(uiAutomator = ANDROID_SIGN_IN_BUTTON)
private MobileElement signInButton;
public MobileElement getUsernameField() {
return usernameField;
}
public MobileElement getPasswordField() {
return passwordField;
}
public MobileElement getSignInButton() {
return signInButton;
}
public void tapUsernameField() {
getUsernameField().click();
}
public void tapSignInButton() {
getSignInButton().click();
}
public void clearUsernameEditText() {
getUsernameField().clear();
}
}
We're not sure in terms of performance and elements lookup where is it best to create an instance of the SignInPage. Currently we have a #Before method in our SignInSteps that is executed before each Gherkin scenario starts (which is not ideal) but it helps us having a SignInPage property in the SignInSteps class that is reused by all the steps.
public class SignInSteps {
private SignInPage signInPage;
AppiumDriver driver;
#Before()
public void setUp() throws MalformedURLException {
driver = TestBase.getInstance().getDriver();
signInPage = new SignInPage(driver);
}
#Given("I fill in the username and password")
public void fill_username_and_password() throws Throwable {
signInPage.tapUsernameField();
signInPage.clearUsernameEditText();
fillEditText(signInPage.getUsernameField(), PropertiesManager.getInstance().getValueForKey(Constants.SIGN_IN_USERNAME));
fillEditText(signInPage.getPasswordField(), PropertiesManager.getInstance().getValueForKey(Constants.SIGN_IN_PASSWORD));
}
// Other sign in steps below
}
However I feel that a cleaner approach would be to create the SignInPage as a local variable inside each step method in SignInSteps. Is there any performance impact in creating the page(s) you need in each step?
Also, it's not clear to me, with our current approach (the #Before approach) why exactly does it work even when you create a page for some steps that will be executed later on (so the screen is not even visible at this point).
So maybe the larger question would be how are the elements looked up? Is it when calling PageFactory.initElements(new AppiumFieldDecorator(driver, 15, TimeUnit.SECONDS), this); or when actually accessing the annotated properties (which would be some kind of lazy initialization approach that from my knowledge Java doesn't have, unless my understanding of Java annotations is wrong).
Sorry for the long post, but these are some things that I want to understand thoroughly. So any help is highly appreciated.
Thank you!
I did some more research (debugging) and I've found the answer:
When you call PageFactory.initElements(new AppiumFieldDecorator(driver, 15, TimeUnit.SECONDS), this); the annotated properties from the page are set (decorated) via reflection (see AppiumFieldDecorator) with a proxy (ElementInterceptor) that wraps a MobileElement. Each time you call a method on the annotated property you actually call the proxy that looks up the element and forwards the method call. There is no cache in between (as opposed to WidgetInterceptor which I didn't figured out yet where it is used).
So in my case, creating the page once, or in each step doesn't really make a difference because the element lookup is performed each time you interact with it (which I guess it's good, but it might have a performance impact also).
I've also attached a few screenshots below:
Stacktrace when you call PageFactory.initElements(new AppiumFieldDecorator(driver, 15, TimeUnit.SECONDS), this);
Stacktrace when you call click on an element
Hope this helps others as well understand how the tool works.

MvvmCross Android Dialog bind programmatically

I want to use the Android.Dialog (Cross.UI) in my MvvmCross project. My first approach was to use AutoViews. As this feature is still fairly young, the alternative was to implement the dialog in touch and Droid platforms.
For now i'm just doing this for Droid and I need to programmatically bind the properties of the ViewModel to the elements of the Dialog.
My View and ViewModel code is the following:
View
public class DialogConfigurationView : MvxBindingDialogActivityView<DialogConfigurationViewModel>
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
DroidResources.Initialise(typeof(Resource.Layout));
Root = new RootElement()
{
new Section("Private Configuration")
{
new EntryElement("Name:"),
new EntryElement("Description:"),
new BooleanElement("Active?")
}
};
}
}
ViewModel
public class DialogConfigurationViewModel : MvxViewModel
{
public ConfigurationSet Configuration
{
get { return _configuration; }
set
{
if (_configuration != value)
{
_configuration = value;
RaisePropertyChanged(() => Configuration);
}
}
}
private ConfigurationSet _configuration;
}
My goal is to have a twoway bind the EntryElement("Name:") with the property ViewModel.Configuration.Name.
Can anyone help me with this? Can this be done?
I don't know if there are any monodroid.dialog mvvmcross samples floating around which don't use autoviews!
However.... the basic syntac for binding should be the same as MonoTouch.Dialog - e.g. something like:
new Section("Contact Info")
{
new StringElement("ID", ViewModel.Customer.ID ?? string.Empty),
new EntryElement("Name", "Name").Bind(this, "{'Value':{'Path':'Customer.Name'}}"),
new EntryElement("Website", "Website").Bind(this, "{'Value':{'Path':'Customer.Website'}}"),
new EntryElement("Primary Phone", "Phone").Bind(this, "{'Value':{'Path':'Customer.PrimaryPhone'}}"),
},
new Section("Primary Address")
{
new EntryElement("Address").Bind(this, "{'Value':{'Path':'Customer.PrimaryAddress.Street1'}}"),
new EntryElement("Address2").Bind(this, "{'Value':{'Path':'Customer.PrimaryAddress.Street2'}}"),
new EntryElement("City").Bind(this, "{'Value':{'Path':'Customer.PrimaryAddress.City'}}"),
new EntryElement("State").Bind(this, "{'Value':{'Path':'Customer.PrimaryAddress.State'}}"),
new EntryElement("Zip").Bind(this, "{'Value':{'Path':'Customer.PrimaryAddress.Zip'}}"),
},
from https://github.com/slodge/MvvmCross/blob/vnext/Sample%20-%20CustomerManagement/CustomerManagement/CustomerManagement.Touch/Views/BaseCustomerEditView.cs
Note that in MvvmCross bindings for MonoTouch and MonoDroid, the default binding for things like text edit boxes is generally TwoWay by default.
If you do get a sample running, then please feel free to post it to a gist or to a repo - or to blog about it - looks like we could do with some samples to work from!

Putting parameters in velocity context in Jira 4.4

I'm developing a plugin to display additional information related to a project.
So I'm developing a Project Tab Panel module but my page does not display the paramenters I put in the velocity context.
Here is the a part of plugin xml:
<project-tabpanel key="stats-tab-panel" name="Stats Tab Panel" i18n-name-key="stats-tab-panel.name" class="it.pride.jira.plugins.StatsTabPanel">
<description key="stats-tab-panel.description">The Stats Tab Panel Plugin</description>
<label key="stats-tab-panel.label"></label>
<order>10</order>
<resource type="velocity" name="view" location="templates/tabpanels/stats-tab-panel.vm"/>
Here instead the useful part of my class:
public class StatsTabPanel extends GenericProjectTabPanel {
public StatsTabPanel(JiraAuthenticationContext jiraAuthenticationContext,
FieldVisibilityManager fieldVisibilityManager) {
super(jiraAuthenticationContext, fieldVisibilityManager);
// TODO Auto-generated constructor stub
}
public String testvalue="112002";
#Override
public boolean showPanel(BrowseContext context){
return true;
}
#Override
public Map<String, Object> createVelocityParams (BrowseContext context) {
Map<String, Object> contextMap = createVelocityParams(context);
contextMap.put("testvalue", testvalue);
return contextMap;
}
}
So, as in this case, when i write `$testvalue in my template the number doesn't show up.
What am I doing wrong?
The problem is that the getHtml method that is used to return the HTML for the tab has a Map that is the Velocity context but only contains the params in the BrowseContext object. The way to fix this is to override createVelocityParams in your class, e.g.
protected Map createVelocityParams(final BrowseContext ctx) {
Map params = super.createVelocityParams(ctx);
params.put("myparam", "some value for it");
return params;
}
The problem is that method is protected so I ended up also overriding getHtml which calls createVelocityParams in a parent class.
Some Project tabs extend GenericProjectTabPanel but some such as SummaryProjectTabPanel.java seem to use UI Fragments. I suspect that Fragments is what things are moving towards.

Resources