I would like to print out an appointment's summary and description when a user clicks on a particular appointment retrieved from the database.
I'm trying to implement this with something like:
lAgenda.selectedAppointments().addListener(new ListChangeListener<Appointment>() {
#Override
public void onChanged(Change<? extends Appointment> c) {
System.out.println(c.toString());
}
});
I however, only get this:
com.sun.javafx.collections.NonIterableChange$GenericAddRemoveChange#1ef0f08
com.sun.javafx.collections.NonIterableChange$SimpleAddChange#1c3e48b
com.sun.javafx.collections.NonIterableChange$GenericAddRemoveChange#d57e70
com.sun.javafx.collections.NonIterableChange$SimpleAddChange#6022e2
com.sun.javafx.collections.NonIterableChange$GenericAddRemoveChange#54ddc1
How can I retrieve other items, like the ID of the row in the database row the appointment is being retrieved from? Thank you all.
You are using the right property to be notified of the selection change.
You received a ListChangeListener.Change. As described in the javadoc, a change should be used in the this way :
lAgenda.selectedAppointments().addListener(new ListChangeListener< Appointment >() {
public void onChanged(Change<? extends Appointment> c) {
while (c.next()) {
if (c.wasPermutated()) {
for (int i = c.getFrom(); i < c.getTo(); ++i) {
//permutate
}
} else if (c.wasUpdated()) {
//update item
} else {
for (Appointment a : c.getRemoved()) {
}
for (Appointment a : c.getAddedSubList()) {
printAppointment(a);
}
}
}
}
});
Now, you could print out appointment summary and description :
private void printAppointment(Appointment a) {
System.out(a.getSummary());
System.out(a.getDescription());
}
If you need some specific properties on the appointment object (like a database id), you could create your appointment class by extending AppointmentImpl or by implementing Appointment
Related
I'm using a TreeViewer with a list of customers. I added a DoubleClickListener to the TreeViewer.
this.treeViewer.addDoubleClickListener(new IDoubleClickListener() {
#Override
public void doubleClick(DoubleClickEvent event) {
IStructuredSelection thisSelection = (IStructuredSelection) event
.getSelection();
Object selectedNode = thisSelection.getFirstElement();
if (selectedNode instanceof ICustomer) {
ICustomer customer = (ICustomer) selectedNode;
selectionService.setSelection(customer);
perspective = (MPerspective) modelService
.find("de.checkpoint.rinteln.carlofon.perspective.customer",
app);
}
if (perspective != null) {
partService.switchPerspective(perspective);
}
}
});
In the Customer-Perspective, I've got 2 Views, which use the selected customer to load his data(orders and reminders) from the DB.
In the Customer-View, everything works just fine. But once i move on the next view(Reminder or Order) the selection list Null, which I don't get.
#Inject
void setSelection(
#Optional #Named(IServiceConstants.ACTIVE_SELECTION) ICustomer customer) {
if (customer != null) {
idText.setText("" + customer.getCustomerId());
customerNameText
.setText(customer.getFirstname() + " " + customer.getLastname());
steetText.setText(customer.getStreet());
cityText.setText(customer.getCity());
steetCodeText.setText("" + customer.getCityCode());
} else {
// TODO Clear View!
}
}
And in the Reminder-View (in the same perspective as the Customer-View), the selected Customer is Null
#Inject
void setSelection(
#Optional #Named(IServiceConstants.ACTIVE_SELECTION) ICustomer customer) {
if (customer != null) {
super.treeViewer.setInput(service.loadAll());
} else {
// TODO Clear View!
}
}
Which lead to my question, do i miss something? Am I not supposed to use the same selection in different views?
I must add, that both views extend an AbstractView in which the IDoubleClickListener is implemented.
I'm trying to find an easy way of linking a TreeView of type Download to an ObservableList of the same type.
MainController.java
public class MainController {
private ObservableList<Download> downloads = FXCollections.observableArrayList();
#FXML private TreeView<Download> $TreeDownloads;
#FXML
public void initialize() {
$TreeDownloads.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
$TreeDownloads.setNodeOrientation(NodeOrientation.LEFT_TO_RIGHT);
$TreeDownloads.setShowRoot(false);
downloads.addListener(new ListChangeListener<Download>() {
#Override
public void onChanged(Change<? extends Download> c) {
if (c.wasAdded()) {
addDownloads(c.getAddedSubList());
}
if (c.wasRemoved()) {
//
}
}
});
downloads.add(new Download("3847"));
downloads.add(new Download("3567"));
downloads.add(new Download("2357"));
}
private void addDownloads(List<? extends Download> downloads) {
downloads.forEach(download -> {
TreeItem<Download> treeItem = new TreeItem<>(download);
$TreeDownloads.getRoot().getChildren().add(treeItem);
new Thread(download::start).start();
});
}
private void removeDownloads(List<? extends Download> downloads) {
// remove treeitems from the treeview that hold these downloads
}
}
Download.java
public class Download {
private DoubleProperty progress = new SimpleDoubleProperty(0D);
private StringProperty id = new SimpleStringProperty("");
public Download(String id) {
this.id.set(id);
}
public void start() {
while (progress.getValue() < 1) {
try {
Thread.sleep(1000);
progress.add(0.1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public String toString() {
return id.getValue();
}
}
How do i implement a remove by Object(Download) mechanism, and is there an easier way to bind observablelist's items to a treeview?
Still not entirely certain what the exact problem is, all pretty straightforward:
First off, your list change listener implementation is incorrect, it must advance the subChanges before accessing its state (you did run your posted code, or not ;)
downloads.addListener(new ListChangeListener<Download>() {
#Override
public void onChanged(Change<? extends Download> c) {
// this while was missing
while (c.next()) {
if (c.wasAdded()) {
addDownloads(c.getAddedSubList());
}
if (c.wasRemoved()) {
// accessing the list of removed elements is .. plain standard api
removeDownloads(c.getRemoved());
}
}
}
});
Now implement the removal of the corresponding treeItems:
private void removeDownloads(List<? extends Download> downloads) {
// remove treeitems from the treeview that hold these downloads
List<TreeItem<Download>> treeItemsToRemove = treeDownloads.getRoot().getChildren().stream()
.filter(treeItem -> downloads.contains(treeItem.getValue()))
.collect(Collectors.toList());
treeDownloads.getRoot().getChildren().removeAll(treeItemsToRemove);
}
Asides:
java naming conventions use lowercase letters for members: treeDownloads (not $TreeDownloads)
the "verifiable" in MCVE implies being runnable as-is: the poster should be the first to verify that ;) yours wasn't due to incorrect implementation of the listener
the "minimal" in MCVE means leaving out everything that's not needed: f.i. calling the threading code - which in your first snippet was particularly distracting because violating fx' threading rule is a rather common error
My Firestore Database structure looks like this:
...a Collection with Routine Objects.
...a Collection with Workout Objects. With the attributes
-> RoutineKey: Stores the Key of the Routine which the Workout is from
-> ExerciseEntryKeys: ArrayList<String> of the Keys of the ExerciseEntry from the Workout
...a Collection with ExerciseEntries Objects.
Now I want to load every Workout from a Routine and the ExerciseEntries of a Workout. To do this, I do the following after I have loaded a Routine Object.
for (final DocumentSnapshot doc : documentSnapshots.getDocuments()) {
final WorkoutSNR workout = doc.toObject(WorkoutSNR.class);
workout.setKey(doc.getId());
workoutsFromRoutine.add(workout);
fm.getColRefExerciseEntries().whereEqualTo("workoutKey", workout.getKey()).get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot documentSnapshots) {
if (documentSnapshots.isEmpty()) {
prg.setVisibility(View.GONE);
processData();
} else {
for (int i = 0; i < workout.getExcersiseEntryKeys().size(); i++) {
fm.getDocRefExerciseEntrie(workout.getExcersiseEntryKeys().get(i)).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
final ExcersiseEntrySNR entry = documentSnapshot.toObject(ExcersiseEntrySNR.class);
entry.setKey(documentSnapshot.getId());
workout.getExcersises().add(entry);
processData();
prg.setVisibility(View.GONE);
Collections.sort(workout.getExcersises(), new Comparator<ExcersiseEntrySNR>() {
#Override
public int compare(ExcersiseEntrySNR e1, ExcersiseEntrySNR e2) {
if (e1.getPosition() < e2.getPosition()) {
return -1;
} else if (e1.getPosition() > e2.getPosition()) {
return 1;
} else {
return 0;
}
}
});
}
});
}
}
}
});
}
}
});
This works like it should but as you can see I call:
processData();
prg.setVisibility(View.GONE);
Collections.sort(workout.getExcersises(), new Comparator<ExcersiseEntrySNR>() {
#Override
public int compare(ExcersiseEntrySNR e1, ExcersiseEntrySNR e2) {
if (e1.getPosition() < e2.getPosition()) {
return -1;
} else if (e1.getPosition() > e2.getPosition()) {
return 1;
} else {
return 0;
}
}
});
Evertime an ExerciseEntry has been successfully loaded. This is very unnecessary and I want to call this code only once everything(Every ExerciseEnry for every Workout of an Routine).
What is the best way to notice everything has been loaded? Does Firestore provide any function for this?
I have tried having an Integer that counts the number of successful ExerciseLoads and Workout loads but I can only access final variables inside a nested class(Is that how its called?).
How do I know when the data is completely loaded from the database?
You can add a flag to each Routine and Workout objects with the value of false and once you have downloaded those objects, to set the value to true but this is not how things are working with Firestore. You cannot know when an object from the database is completed downloaded becase Cloud Firestore is also a realtime database and getting data might never complete. That's why is named a realtime database because in any momemnt the data under those Routine and Workout objects can be changed, properties can be added or deleted.
You can use a CompletionListener only when you write or update data and you'll be notified when the operation has been acknowledged by the Database servers but you cannot use this interface when reading data.
So if anyone is wondering what my Solution at the end is, here is my current Code:
fm.getColRefWorkoutSNR().whereEqualTo("routineKey", routineKey).get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot documentSnapshots) {
final int workoutSize = documentSnapshots.getDocuments().size();
for (final DocumentSnapshot doc : documentSnapshots.getDocuments()) {
final WorkoutSNR workout = doc.toObject(WorkoutSNR.class);
workout.setKey(doc.getId());
workoutsFromRoutine.add(workout);
fm.getColRefExerciseEntries().whereEqualTo("workoutKey", workout.getKey()).get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot documentSnapshots) {
if (documentSnapshots.isEmpty()) {
prg.setVisibility(View.GONE);
processData();
} else {
if (workout.getExcersiseEntryKeys().size() > 0) {
for (int i = 0; i < workout.getExcersiseEntryKeys().size(); i++) {
fm.getDocRefExerciseEntrie(workout.getExcersiseEntryKeys().get(i)).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
final ExcersiseEntrySNR entry = documentSnapshot.toObject(ExcersiseEntrySNR.class);
entry.setKey(documentSnapshot.getId());
workout.getExcersises().add(entry);
if (workout.getExcersises().size() == workout.getExcersiseEntryKeys().size()) {
increaseFullyLoadedWorkouts();
}
if (fullyLoadedWorkouts == workoutSize) {
processData();
prg.setVisibility(View.GONE);
}
}
});
}
} else {
increaseFullyLoadedWorkouts();
if (fullyLoadedWorkouts == workoutSize) {
processData();
prg.setVisibility(View.GONE);
}
}
}
}
});
}
}
});
As you can see, I check if I have loaded every exercise for an workout and if thats the case I increase a "fullyLoadedWorkout" counter. Then I check if the counter equals the workout size and if thats the case I know that I have "fully" loaded my data.
I know thats not a good way to do this but its the only solution I can imagine at the moment. This seems to be way easier in the Realtime Database and I'm still consider switching back to it. Any suggestions for a better way are welcomed.
I want to trigger some code when a object called EventShowable have been modified in an observableList.
Here is my code.
mainApp.getCalendars().get(i).getListEvents().addListener(new ListChangeListener<EventShowable>() {
#Override
public void onChanged(ListChangeListener.Change<? extends EventShowable> c) {
while (c.next()) {
if (c.wasUpdated()) {
//this doesn't work.
//perform updated
}
if (c.wasAdded()){
//perform something }
The wasAdded() perform well but not the wasUpdate().
How to get something that works when a EventShowable have been modified ? Thanks
P.S : in the JavaDoc :
public boolean wasUpdated()
Indicates that the elements between getFrom() (inclusive) to getTo() exclusive has changed. This is the only optional event type and may not be fired by all ObservableLists.
https://docs.oracle.com/javase/8/javafx/api/javafx/collections/ListChangeListener.Change.html#wasUpdated--
Create your list using an extractor.
You haven't really given enough detail to give a complete answer, but if your EventShowable defines properties such as
public class EventShowable {
public IntegerProperty xProperty() { ... }
public StringProperty yProperty() { ... }
// ...
}
then to create a list that fires update events when x or y change you do
ObservableList<EventShowable> listEvents =
FXCollections.observableArrayList(eventShowable ->
new Observable[] { eventShowable.xProperty(), eventShowable.yProperty() });
Trying to make my CellTable Colum sortable but I'm not getting it to work. I'm having an MVP application which gets data from a rest service. To show the data within the table works fine but to sort is doesn't work.
public class LicenseUsageUserViewImpl<T> extends Composite implements LicenseUsageUserView<T> {
#UiTemplate("LicenseUsageUserView.ui.xml")
interface LicenseDataViewUiBinder extends UiBinder<ScrollPanel,LicenseUsageUserViewImpl> {}
private static LicenseDataViewUiBinder uiBinder = GWT.create(LicenseDataViewUiBinder.class);
#UiField
CellTable<GWTLicenseUser> licenseUserCellTable;
List<GWTLicenseUser> licenseUsers;
ListDataProvider<GWTLicenseUser> dataProvider;
public List<GWTLicenseUser> getLicenseUsers() {
return licenseUsers;
}
public void setLicenseUsers(List<GWTLicenseUser> licenseUsers) {
this.licenseUsers = licenseUsers;
}
#UiField Label header;
ListHandler<GWTLicenseUser> sortHandler;
public LicenseUsageUserViewImpl() {
initWidget(uiBinder.createAndBindUi(this));
initCellTable();
}
#Override
public void setLicenseUsersTable(List<GWTLicenseUser> tmpLicenseUsers) {
if (tmpLicenseUsers.isEmpty()) {
licenseUserCellTable.setVisible(false);
} else {
setLicenseUsers(tmpLicenseUsers);
licenseUserCellTable.setWidth("100%");
licenseUserCellTable.setVisible(true);
licenseUserCellTable.setPageSize(getLicenseUsers().size());
licenseUserCellTable.setRowCount(getLicenseUsers().size(), false);
licenseUserCellTable.setRowData(0, getLicenseUsers());
licenseUserCellTable.setVisibleRange(new Range(0, licenseUserCellTable.getRowCount()));
sortHandler.setList(getLicenseUsers());
dataProvider.getList().clear();
dataProvider.getList().addAll(getLicenseUsers());
}
}
#Override
public void initCellTable() {
sortHandler = new ListHandler<GWTLicenseUser>(getLicenseUsers());
licenseUserCellTable.addColumnSortHandler(sortHandler);
licenseUserCellTable.setWidth("100%");
licenseUserCellTable.setVisible(true);
licenseUserCellTable.setVisibleRange(new Range(0, licenseUserCellTable.getRowCount()));
// Create a data provider.
dataProvider = new ListDataProvider<GWTLicenseUser>();
// Connect the table to the data provider.
dataProvider.addDataDisplay(licenseUserCellTable);
licenseUserCellTable.setWidth("100%");
licenseUserCellTable.setAutoHeaderRefreshDisabled(true);
licenseUserCellTable.setAutoFooterRefreshDisabled(true);
// userID
TextColumn<GWTLicenseUser> userIdColumn = new TextColumn<GWTLicenseUser>() {
#Override
public String getValue(GWTLicenseUser object) {
if (object != null ){
return object.getUserId();
} else {
return "NULL";
}
}
};
userIdColumn.setSortable(true);
sortHandler.setComparator(userIdColumn, new Comparator<GWTLicenseUser>() {
#Override
public int compare(GWTLicenseUser o1, GWTLicenseUser o2) {
return o1.getUserId().compareTo(o2.getUserId());
}
});
licenseUserCellTable.addColumn(userIdColumn, "User ID");
// more column entries
licenseUserCellTable.getColumnSortList().push(userIdColumn);
licenseUserCellTable.getColumnSortList().push(countColumn);
licenseUserCellTable.addColumnSortHandler(sortHandler);
}
}
setLicenseUsersTable is called from my activity with the response list of my users. When I start my application and make a rest call my data is provide and put into my list also shown within the CellTable but its not sortable, but I have this sort icon before my colum name. I figured I post the whole code because I think its know easier to see what I'm trying to do.
Thanks for any help.
Remove this line:
sortHandler.setList(getLicenseUsers());
You already passed a List into the SortHandler constructor in
sortHandler = new ListHandler<GWTLicenseUser>(getLicenseUsers());
Also, instead of
setLicenseUsers(tmpLicenseUsers);
you may need to use
licenseUsers.addAll(tmpLicenseUsers);
I hope one of them fixes the problem.