Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support ReusableItemComponent in FxFor #121

Merged
merged 1 commit into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion docs/features/2-for.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ fxFor.of(container, items, myComponentProvider);
```

This will create a component for each item in the list `items` and add it to the children of the `container` (e.g. a VBox).
If the component implements the `ReusableItemComponent` interface, `setItem` will be called instead of creating a new instance.
For more information see [this section](7-componentlistcell.md#reusableitemcomponent-).

Currently, no information is passed to the created component. In order to pass static information you can add
parameters like you would when using the `show`-method using a map.

When a new component is created, the parameters `item` and `list` are automatically added to the map. The `item` parameter contains the current item of the component and the `list` parameter contains the list of all items.
When a new component is created, the parameters `item` and `list` are automatically added to the map.
The `item` parameter contains the current item of the component and the `list` parameter contains the list of all items.
If parameters with the same key are already present in the map, they will not be overwritten.

```java
Expand Down
8 changes: 5 additions & 3 deletions docs/features/7-componentlistcell.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Component List Cells [![Javadocs](https://javadoc.io/badge2/org.fulib/fulibFx/Javadocs.svg?color=green)](https://javadoc.io/doc/org.fulib/fulibFx/latest/org/fulib/fx/constructs/listview/ComponentListCell.html)

Component List Cells can be used to display a subcomponent as a cell in a ListView. Whenever an item is added to or removed from the list, the subcomponent updates accordingly.
The `ComponentListCell` class is a subclass of the `ListCell` class and can be used in the same way. The `ComponentListCell` can be used to set the cell factory of a `ListView` to display a subcomponent for each item in the list.
Component List Cells can be used to display a subcomponent as a cell in a ListView.
Whenever an item is added to or removed from the list, the subcomponent updates accordingly.
The `ComponentListCell` class is a subclass of the `ListCell` class and can be used in the same way.
The `ComponentListCell` can be used to set the cell factory of a `ListView` to display a subcomponent for each item in the list.

```java
@Controller
Expand All @@ -28,7 +30,7 @@ public class MainController {
}
```

### ReusableItemComponent [![Javadocs](https://javadoc.io/badge2/org.fulib/fulibFx/Javadocs.svg?color=green)](https://javadoc.io/doc/org.fulib/fulibFx/latest/org/fulib/fx/constructs/listview/ReusableItemComponent.html)
### ReusableItemComponent [![Javadocs](https://javadoc.io/badge2/org.fulib/fulibFx/Javadocs.svg?color=green)](https://javadoc.io/doc/org.fulib/fulibFx/latest/org/fulib/fx/constructs/ReusableItemComponent.html)
If the component implements the `ReusableItemComponent` interface, the `ComponentListCell` will call the `setItem` method of the component whenever the item changes. This allows the component to update its view based on the new item.
If the component doesn't implement this interface, it will be destroyed and a new component will be created whenever the item changes.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.fulib.fx.constructs.listview;
package org.fulib.fx.constructs;

import org.jetbrains.annotations.NotNull;

/**
* Interface for components that can be reused in a list view.
* Interface for components that can be reused inside other constructs.
* If a component implements this interface, it can be reused when its item changes instead of being destroyed and recreated.
* <p>
* The component is fully responsible for updating its display when the item changes.
Expand Down
40 changes: 35 additions & 5 deletions framework/src/main/java/org/fulib/fx/constructs/forloop/For.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.Parent;
import org.fulib.fx.constructs.ReusableItemComponent;
import org.fulib.fx.controller.ControllerManager;
import org.fulib.fx.util.ControllerUtil;
import org.fulib.fx.util.ReflectionUtil;
import org.jetbrains.annotations.NotNull;

import javax.inject.Provider;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;

Expand Down Expand Up @@ -59,21 +61,44 @@ public class For<Node extends javafx.scene.Node, Item> {
this.children.set(i, children.set(change.getPermutation(i), this.children.get(i)));
}
}

// If items were replaced, either update the components or remove and add them
if (change.wasReplaced()) {
int i = 0;
for (Item item : change.getRemoved()) {
Node node = itemsToNodes.get(item);
Item added = change.getAddedSubList().get(i++);
if (node instanceof ReusableItemComponent<?>) {
//noinspection unchecked
((ReusableItemComponent<Item>) node).setItem(added);
} else {
remove(item);
add(added, change.getFrom() + i - 1);
}
}
return; // All removed and added changes were already handled here
}

if (change.wasRemoved()) {
for (Item item : change.getRemoved()) {
remove(item);
}
}

if (change.wasAdded()) {
int i = 0;
// Add the new items in the correct order
for (Item item : change.getAddedSubList()) {
add(item, change.getFrom() + i++);
}
addAll(change.getAddedSubList(), change.getFrom());
}
}
};

private void addAll(List<? extends Item> toAdd, int from) {
int i = 0;
// Add the new items in the correct order
for (Item item : toAdd) {
add(item, from + i++);
}
}

/**
* Use the factory methods to create a new For loop.
*
Expand Down Expand Up @@ -217,6 +242,11 @@ private void add(Item item, int index) {
params.putIfAbsent("list", this.items);
controllerManager.init(node, params);
controllerManager.render(node, params);

if (node instanceof ReusableItemComponent<?>) {
//noinspection unchecked
((ReusableItemComponent<Item>) node).setItem(item);
}
}

// Add the node to the container
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.ListCell;
import org.fulib.fx.FulibFxApp;
import org.fulib.fx.constructs.ReusableItemComponent;

import javax.inject.Provider;
import java.util.HashMap;
Expand Down
4 changes: 4 additions & 0 deletions framework/src/test/java/org/fulib/fx/app/FrameworkTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,11 @@ public void simpleForTest() {
FX_SCHEDULER.scheduleDirect(() -> list.add(1, "World"));
waitForFxEvents();

FX_SCHEDULER.scheduleDirect(() -> list.set(1, "Everyone"));
waitForFxEvents();

assertEquals(3, container.getChildren().size());

}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@

import org.fulib.fx.annotation.controller.Component;
import javafx.scene.control.Button;
import org.fulib.fx.constructs.ReusableItemComponent;
import org.jetbrains.annotations.NotNull;

import javax.inject.Inject;

@Component
public class ButtonSubComponent extends Button {
public class ButtonSubComponent extends Button implements ReusableItemComponent<String> {

@Inject
public ButtonSubComponent() {
this.setText("Sub Component Button");
}

@Override
public void setItem(@NotNull String item) {
this.setText(item);
}
}