View Javadoc
1   /**
2    * This file Copyright (c) 2018 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.ui.contentapp;
35  
36  import static info.magnolia.ui.contentapp.FilteringMode.OFF;
37  
38  import java.util.stream.Stream;
39  
40  import org.apache.commons.lang3.StringUtils;
41  
42  import com.vaadin.data.provider.DataProvider;
43  import com.vaadin.data.provider.DataProviderWrapper;
44  import com.vaadin.data.provider.HierarchicalDataProvider;
45  import com.vaadin.data.provider.HierarchicalQuery;
46  import com.vaadin.data.provider.Query;
47  import com.vaadin.ui.ComboBox;
48  import com.vaadin.ui.ItemCaptionGenerator;
49  
50  /**
51   * {@link com.vaadin.data.provider.DataProviderWrapper} that suppresses the wrapped data provider's filtering logic and will post-filter the results with a caption filter in memory..
52   *
53   * @param <T> type of item
54   * @param <F> type of wrapped provider filter
55   */
56  public class CaptionFilteringDataProviderWrapper<T, F> extends DataProviderWrapper<T, String, F> {
57  
58      public static <T, F> CaptionFilteringDataProviderWrapper<T, F> wrap(DataProvider<T, F> src) {
59          return new CaptionFilteringDataProviderWrapper<>(src);
60      }
61  
62      private FilteringMode filteringMode = OFF;
63      private ItemCaptionGenerator<T> itemCaptionGenerator = Object::toString;
64  
65      private CaptionFilteringDataProviderWrapper(DataProvider<T, F> dataProvider) {
66          super(dataProvider);
67      }
68  
69      public CaptionFilteringDataProviderWrapper<T, F> withItemCaptionGenerator(ItemCaptionGenerator<T> itemCaptionGenerator) {
70          this.itemCaptionGenerator = itemCaptionGenerator;
71          return this;
72      }
73  
74      public CaptionFilteringDataProviderWrapper<T, F> withFilteringMode(FilteringMode filteringMode) {
75          this.filteringMode = filteringMode;
76          return this;
77      }
78  
79      @Override
80      public Stream<T> fetch(Query<T, String> t) {
81          final Stream<T> stream;
82          if (dataProvider instanceof HierarchicalDataProvider) {
83              stream = super.fetch(new HierarchicalQuery<>(t.getFilter().orElse(null), null));
84          } else {
85              stream = super.fetch(new Query<>(t.getFilter().orElse(null)));
86          }
87          return stream //All items, The penalty we have here is that we still fetch the whole bunch of items from backend and filter them in place...
88                  .filter(item -> getCaptionFilter().test(itemCaptionGenerator.apply(item), t.getFilter().orElse(StringUtils.EMPTY))) //...but we don't have to pass the caption filtering logic and implement this in each and every data provider
89                  .skip(t.getOffset())
90                  .limit(t.getLimit());
91      }
92  
93      @Override
94      public int size(Query<T, String> t) {
95          return (int) fetch(t).count();
96      }
97  
98      /**
99       * @return null as we don't modify the filter here (Vaadin way) but implement filtering in {@link #fetch(com.vaadin.data.provider.Query)}.
100      */
101     @Override
102     protected F getFilter(Query<T, String> query) {
103         return null;
104     }
105 
106     private ComboBox.CaptionFilter getCaptionFilter() {
107         switch (filteringMode) {
108         case CONTAINS:
109             return StringUtils::containsIgnoreCase;
110         case STARTSWITH:
111             return StringUtils::startsWithIgnoreCase;
112         default:
113             return (itemCaption, filterText) -> true;
114         }
115     }
116 
117 }