Skip to content

Commit e938a86

Browse files
AB-xdevlcarrasco-xdevJohannesRabauer
committed
Backport upstream
Diff of f84fe78e6ae00ca532ffd38630c846de93471d78 -> 89a634d81fd6622deb22128c4cd79622f4a2598f Co-Authored-By: Luis <[email protected]> Co-Authored-By: Johannes Rabauer <[email protected]>
1 parent 4557844 commit e938a86

File tree

9 files changed

+441
-12
lines changed

9 files changed

+441
-12
lines changed

vaadin-grid-filter-demo/src/main/java/software/xdev/vaadin/ui/MainView.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ private void initUI()
7777
CustomizableFilterBuilder.builder()
7878
.withValueProvider(Person::getBirthday, "Birthday")
7979
.withIsAfterComparator()
80+
.withIsAfterOrEqualsComparator()
8081
.withIsBeforeComparator()
82+
.withIsBeforeOrEqualsComparator()
8183
.withIsBetweenComparator()
8284
)
8385
.withDatePickerI18n(datePickerI18n)

vaadin-grid-filter/src/main/java/software/xdev/vaadin/FilterComponent.java

Lines changed: 70 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,13 @@
6161
import com.vaadin.flow.component.select.Select;
6262
import com.vaadin.flow.component.textfield.BigDecimalField;
6363
import com.vaadin.flow.component.textfield.TextField;
64+
import com.vaadin.flow.data.value.ValueChangeMode;
6465
import com.vaadin.flow.router.BeforeEnterEvent;
6566
import com.vaadin.flow.router.BeforeEnterObserver;
6667
import com.vaadin.flow.router.QueryParameters;
6768

6869
import software.xdev.vaadin.builder.CustomizableFilterBuilder;
70+
import software.xdev.vaadin.comparators.ContainsComparator;
6971
import software.xdev.vaadin.comparators.FilterComparator;
7072
import software.xdev.vaadin.comparators.utl.DateHelper;
7173
import software.xdev.vaadin.daterange_picker.business.DateRange;
@@ -102,11 +104,13 @@ public class FilterComponent<T> extends Composite<VerticalLayout> implements Bef
102104
public static final String BTN_CANCEL_FILTER_FILTER_COMPONENT = "btnCancelFilterFilterComponent";
103105
public static final String DATE_RANGE_PICKER_QUERY_FILTER_COMPONENT = "dateRangePickerQueryFilterComponent";
104106
public static final String DELETED_INITIAL_CONDITION_STRING = "deletedInitialCondition";
107+
public static final String BTN_RESET_FILTER_FILTER_COMPONENT = "btnResetFilterFilterComponent";
105108

106109
private final UI ui;
107110
private final Button btnAddNewFilter = new Button("Add filter");
108111
private final Button btnAcceptFilter = new Button(VaadinIcon.CHECK.create());
109112
private final Button btnCancelFilter = new Button(VaadinIcon.CLOSE.create());
113+
private final Button btnResetFilter = new Button(VaadinIcon.ROTATE_RIGHT.create());
110114
private final Select<FilterField<T, ?>> selFields = new Select<>();
111115
private final Select<FilterComparator> selOperations = new Select<>();
112116
private final TextField txtSearchQuery = new TextField();
@@ -130,6 +134,7 @@ private static DateRangePicker<DateRange> createDateRangePicker()
130134

131135
// Data
132136
private final List<ChipBadgeExtension<FilterCondition<T, ?>>> chipBadges = new ArrayList<>();
137+
private final List<ChipBadgeExtension<FilterCondition<T, ?>>> initialChipBadges = new ArrayList<>();
133138

134139
private int initialConditionIdCounter = 1;
135140
private String editingBadgeId;
@@ -160,12 +165,13 @@ public FilterComponent(final Grid<T> dataGrid)
160165
private void initUI()
161166
{
162167
final VerticalLayout vlRoot = this.getContent();
163-
vlRoot.add(this.btnAddNewFilter, this.hlFilter, this.hlChipBadges);
168+
vlRoot.add(new HorizontalLayout(this.btnAddNewFilter, this.btnResetFilter), this.hlFilter, this.hlChipBadges);
164169

165170
// click listener
166171
this.btnAddNewFilter.addClickListener(e -> this.onShowFilterInput());
167172
this.btnCancelFilter.addClickListener(e -> this.hlFilter.removeAll());
168173
this.btnAcceptFilter.addClickListener(e -> this.onAcceptFilter());
174+
this.btnResetFilter.addClickListener(e -> this.onResetFilter());
169175

170176
// value change listener
171177
this.selFields.addValueChangeListener(e -> this.onFieldChange(this.selFields.getValue()));
@@ -182,6 +188,11 @@ private void initUI()
182188
this.btnAcceptFilter.setEnabled(e.getValue() != null && this.selOperations.getValue() != null));
183189
this.selSearchQuery.addValueChangeListener(e ->
184190
this.btnAcceptFilter.setEnabled(e.getValue() != null && this.selOperations.getValue() != null));
191+
this.txtSearchQuery.addValueChangeListener(e ->
192+
this.btnAcceptFilter.setEnabled(!e.getValue().isBlank() && this.selOperations.getValue() != null));
193+
194+
this.nmbSearchQuery.setValueChangeMode(ValueChangeMode.EAGER);
195+
this.txtSearchQuery.setValueChangeMode(ValueChangeMode.EAGER);
185196

186197
// renderer
187198
this.selFields.setTextRenderer(FilterField::getDescription);
@@ -193,9 +204,12 @@ private void initUI()
193204
this.btnAcceptFilter.addClickShortcut(Key.ENTER);
194205
this.btnCancelFilter.addClickShortcut(Key.ESCAPE);
195206

207+
this.btnResetFilter.setEnabled(false);
208+
196209
// ids
197210
this.btnAcceptFilter.setId(BTN_ACCEPT_FILTER_FILTER_COMPONENT);
198211
this.btnCancelFilter.setId(BTN_CANCEL_FILTER_FILTER_COMPONENT);
212+
this.btnResetFilter.setId(BTN_RESET_FILTER_FILTER_COMPONENT);
199213
this.selFields.setId(SEL_FIELDS_FILTER_COMPONENT);
200214
this.selOperations.setId(SEL_OPERATIONS_FILTER_COMPONENT);
201215
this.txtSearchQuery.setId(TXT_SEARCH_QUERY_FILTER_COMPONENT);
@@ -207,6 +221,30 @@ private void initUI()
207221
this.dateRangePickerQuery.setId(DATE_RANGE_PICKER_QUERY_FILTER_COMPONENT);
208222
}
209223

224+
private void onResetFilter()
225+
{
226+
final List<ChipBadgeExtension<FilterCondition<T, ?>>> copyChipBadges = new ArrayList<>(this.chipBadges);
227+
for(final ChipBadgeExtension<FilterCondition<T, ?>> chipBadge : copyChipBadges)
228+
{
229+
this.removeChipBadgeCondition(chipBadge);
230+
}
231+
232+
// Creating the initial filter again
233+
this.chipBadges.addAll(this.initialChipBadges);
234+
this.initialChipBadges.forEach(this.hlChipBadges::add);
235+
this.updateGridFilter();
236+
237+
// Remove query parameter
238+
this.ui.getPage().fetchCurrentURL(currentUrl ->
239+
this.ui
240+
.getPage()
241+
.getHistory()
242+
.replaceState(null, currentUrl.getPath()));
243+
244+
// Disable reset button again
245+
this.btnResetFilter.setEnabled(false);
246+
}
247+
210248
private void onOperatorChanged()
211249
{
212250
this.btnAcceptFilter.setEnabled(this.shouldTheAcceptButtonBeEnabled());
@@ -219,10 +257,14 @@ private void onOperatorChanged()
219257

220258
// Change to a text field if the field is of type enum with condition 'contains'
221259
if(isSelSearchQueryVisible
222-
&& this.selOperations.getValue().getDescription().contains("contains"))
260+
&& this.selOperations.getValue()
261+
.getDescription()
262+
.equals(ContainsComparator.CONTAINS_COMPARATOR_DESCRIPTION))
223263
{
224264
this.selSearchQuery.setVisible(false);
225265
this.txtSearchQuery.setVisible(true);
266+
267+
this.btnAcceptFilter.setEnabled(this.shouldTheAcceptButtonBeEnabled());
226268
}
227269
else if(!isSelSearchQueryVisible)
228270
{
@@ -260,6 +302,10 @@ private void onShowFilterInput()
260302

261303
if(this.hlFilter.getChildren().findAny().isEmpty())
262304
{
305+
// Needed if the previous condition was an editable initial condition
306+
// The editable initial condition makes the cancel button invisible
307+
this.btnCancelFilter.setVisible(true);
308+
263309
this.selFields.setValue(null);
264310
this.selOperations.setItems(Collections.emptyList());
265311
this.selOperations.setEnabled(false);
@@ -334,6 +380,9 @@ private void onAcceptFilter()
334380

335381
// Removing all filter components after accepting
336382
this.hlFilter.removeAll();
383+
384+
// When something changes from the initial start, enable the reset button
385+
this.btnResetFilter.setEnabled(true);
337386
}
338387

339388
private ChipBadgeExtension<FilterCondition<T, ?>> createBadgeConditionAndApplyFilter(
@@ -402,7 +451,7 @@ private void onAcceptFilter()
402451
}
403452

404453
this.chipBadges.add(badge);
405-
this.hlChipBadges.add(badge, badge);
454+
this.hlChipBadges.add(badge);
406455

407456
this.updateGridFilter();
408457

@@ -421,11 +470,16 @@ private void deactivateDeleteButtonFromChipComponents(
421470
{
422471
this.removeChipBadgeCondition(badge);
423472

424-
if(badge.getBadgeId() != null && !badge.getBadgeId().equals(NO_BADGE_ID_STRING))
473+
if(!this.identifier.isBlank()
474+
&& badge.getBadgeId() != null
475+
&& !badge.getBadgeId().equals(NO_BADGE_ID_STRING))
425476
{
426477
badge.setBadgeId(DELETED_INITIAL_CONDITION_STRING);
427478
this.addQueryParameter(badge);
428479
}
480+
481+
// Activate the reset button
482+
this.btnResetFilter.setEnabled(true);
429483
});
430484
}
431485
}
@@ -436,8 +490,10 @@ private void deactivateDeleteButtonFromChipComponents(
436490
@SuppressWarnings("PMD.CognitiveComplexity") // Fixed in v2
437491
private void formatLocalDateChipBadgeText(final ChipBadge<FilterCondition<T, ?>> chipBadge)
438492
{
493+
final FilterCondition<T, ?> filterField = chipBadge.getItem();
494+
439495
if(this.dateRangePickerQuery.isVisible()
440-
&& chipBadge.getItem().getSelectedCondition().getDescription().equals(IS_BETWEEN_COMPARATOR_DESCRIPTION))
496+
&& filterField.getSelectedCondition().getDescription().equals(IS_BETWEEN_COMPARATOR_DESCRIPTION))
441497
{
442498
chipBadge.setItemLabelGenerator((ItemLabelGenerator<FilterCondition<T, ?>>)tFilterCondition ->
443499
{
@@ -476,7 +532,7 @@ private void formatLocalDateChipBadgeText(final ChipBadge<FilterCondition<T, ?>>
476532
return createChipComponentString(tFilterCondition, dateString);
477533
});
478534
}
479-
else if(this.dateSearchQuery.isVisible())
535+
else if(this.dateSearchQuery.isVisible() && filterField.getItem().getType().equals(LocalDate.class))
480536
{
481537
chipBadge.setItemLabelGenerator((ItemLabelGenerator<FilterCondition<T, ?>>)tFilterCondition ->
482538
{
@@ -506,7 +562,7 @@ else if(this.dateSearchQuery.isVisible())
506562
return createChipComponentString(tFilterCondition, dateString);
507563
});
508564
}
509-
else if(this.dateTimeSearchQuery.isVisible())
565+
else if(this.dateTimeSearchQuery.isVisible() && filterField.getItem().getType().equals(LocalDateTime.class))
510566
{
511567
chipBadge.setItemLabelGenerator((ItemLabelGenerator<FilterCondition<T, ?>>)tFilterCondition ->
512568
{
@@ -657,7 +713,7 @@ else if(this.selSearchQuery.isVisible())
657713
else
658714
{
659715
// For txtSearchQuery
660-
valueNotNull = true;
716+
valueNotNull = !this.txtSearchQuery.getValue().isBlank();
661717
}
662718

663719
return valueNotNull && this.selOperations.getValue() != null;
@@ -1116,6 +1172,8 @@ public void beforeEnter(final BeforeEnterEvent beforeEnterEvent)
11161172

11171173
this.removeInitialConditionIfBadgeIdAlreadyExists(this.queryBadgeIdList);
11181174
this.createConditionsFromQueryParameters();
1175+
1176+
this.btnResetFilter.setEnabled(true);
11191177
}
11201178
}
11211179
}
@@ -1318,7 +1376,7 @@ public FilterComponent<T> withInitialFilter(
13181376
this.selFields.setItems(this.filterFieldList);
13191377
}
13201378

1321-
final ChipBadge<FilterCondition<T, ?>> chipBadge = this.createBadgeConditionAndApplyFilter(
1379+
final ChipBadgeExtension<FilterCondition<T, ?>> chipBadge = this.createBadgeConditionAndApplyFilter(
13221380
finalFilterField,
13231381
selectedCondition,
13241382
searchQuery,
@@ -1328,6 +1386,9 @@ public FilterComponent<T> withInitialFilter(
13281386
// Just needed if the url parameters are activated
13291387
chipBadge.setBadgeId(badgeId);
13301388

1389+
// Needed for resetting the conditions
1390+
this.initialChipBadges.add(chipBadge);
1391+
13311392
return this;
13321393
}
13331394

vaadin-grid-filter/src/main/java/software/xdev/vaadin/comparators/ContainsComparator.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
*/
2828
public final class ContainsComparator implements FilterComparator
2929
{
30+
public static final String CONTAINS_COMPARATOR_DESCRIPTION = "contains";
31+
3032
private static ContainsComparator instance;
3133

3234
private ContainsComparator()
@@ -46,7 +48,7 @@ public static ContainsComparator getInstance()
4648
@Override
4749
public String getDescription()
4850
{
49-
return "contains";
51+
return CONTAINS_COMPARATOR_DESCRIPTION;
5052
}
5153

5254
@Override
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright © 2024 XDEV Software (https://xdev.software)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package software.xdev.vaadin.comparators;
17+
18+
import java.util.function.Predicate;
19+
20+
import com.vaadin.flow.function.ValueProvider;
21+
22+
import software.xdev.vaadin.comparators.utl.TypeHelper;
23+
24+
25+
public final class GreaterThanOrEqualsComparator implements FilterComparator
26+
{
27+
public static final String GREATER_THAN_OR_EQUALS_COMPARATOR_DESCRIPTION = "is greater than or equals";
28+
29+
public static GreaterThanOrEqualsComparator instance;
30+
31+
private GreaterThanOrEqualsComparator()
32+
{
33+
}
34+
35+
public static GreaterThanOrEqualsComparator getInstance()
36+
{
37+
if(instance == null)
38+
{
39+
instance = new GreaterThanOrEqualsComparator();
40+
}
41+
42+
return instance;
43+
}
44+
45+
@Override
46+
public String getDescription()
47+
{
48+
return GREATER_THAN_OR_EQUALS_COMPARATOR_DESCRIPTION;
49+
}
50+
51+
@Override
52+
public boolean isApplicable(final Class<?> clazz)
53+
{
54+
return Number.class.isAssignableFrom(clazz);
55+
}
56+
57+
@Override
58+
public <B, T> Predicate<B> compare(final ValueProvider<B, T> provider, final String searchQuery)
59+
{
60+
return item ->
61+
{
62+
final T apply = provider.apply(item);
63+
64+
TypeHelper.checkIfTypeIsApplicable(this, apply.getClass());
65+
66+
if(apply instanceof final Number numb && TypeHelper.isDouble(searchQuery))
67+
{
68+
return numb.doubleValue() >= (Double.parseDouble(searchQuery));
69+
}
70+
71+
return false;
72+
};
73+
}
74+
}

0 commit comments

Comments
 (0)