1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.ui.admincentral.shellapp.pulse.item.list;
35
36 import info.magnolia.i18nsystem.SimpleTranslator;
37 import info.magnolia.ui.admincentral.shellapp.pulse.data.PulseConstants;
38 import info.magnolia.ui.admincentral.shellapp.pulse.item.detail.PulseItemCategory;
39 import info.magnolia.ui.admincentral.shellapp.pulse.item.detail.PulseItemCategoryNavigator;
40 import info.magnolia.ui.admincentral.shellapp.pulse.item.list.footer.PulseListFooterView;
41 import info.magnolia.ui.vaadin.grid.MagnoliaTable;
42
43 import java.util.List;
44 import java.util.Set;
45
46 import javax.inject.Inject;
47
48 import com.google.common.collect.Lists;
49 import com.vaadin.data.Container;
50 import com.vaadin.data.Container.ItemSetChangeEvent;
51 import com.vaadin.data.Item;
52 import com.vaadin.data.Property;
53 import com.vaadin.data.Property.ValueChangeEvent;
54 import com.vaadin.data.Property.ValueChangeListener;
55 import com.vaadin.event.ItemClickEvent;
56 import com.vaadin.event.MouseEvents.ClickEvent;
57 import com.vaadin.shared.ui.label.ContentMode;
58 import com.vaadin.ui.Component;
59 import com.vaadin.ui.Label;
60 import com.vaadin.ui.Table;
61 import com.vaadin.ui.Table.GeneratedRow;
62 import com.vaadin.ui.VerticalLayout;
63
64
65
66
67 public abstract class AbstractPulseListView implements PulseListView {
68
69 private final String[] order;
70
71 private final String[] headers;
72
73 private final Table itemTable = new MagnoliaTable();
74
75 private final VerticalLayout root = new VerticalLayout();
76
77 private final PulseItemCategoryNavigator navigator;
78
79 private final SimpleTranslator i18n;
80
81 private PulseListView.Listener listener;
82
83 private Label emptyPlaceHolder;
84
85 private Component footer;
86
87 private Property.ValueChangeListener selectionListener = new Property.ValueChangeListener() {
88 @Override
89 public void valueChange(ValueChangeEvent event) {
90 listener.onSelectionChanged((Set<Object>) event.getProperty().getValue());
91 }
92 };
93
94 private ValueChangeListener groupingListener = new ValueChangeListener() {
95 @Override
96 public void valueChange(ValueChangeEvent event) {
97 doGrouping((Boolean) event.getProperty().getValue());
98 }
99 };
100
101
102
103
104 private Table.RowGenerator groupingRowGenerator = new Table.RowGenerator() {
105
106 @Override
107 public GeneratedRow generateRow(Table table, Object itemId) {
108
109
110
111
112
113
114 String id = (String) table.getContainerProperty(itemId, "id").getValue();
115
116 if (id != null && id.startsWith(PulseConstants.GROUP_PLACEHOLDER_ITEMID)) {
117 Item item = table.getItem(itemId);
118 return generateGroupingRow(item);
119 }
120
121 return null;
122 }
123 };
124
125 private boolean isGrouping = false;
126
127 @Inject
128 public AbstractPulseListView(SimpleTranslator i18n, String[] order, String[] headers, String emptyMessage, PulseItemCategory... categories) {
129 this.i18n = i18n;
130 this.order = order;
131 this.headers = headers;
132 navigator = new PulseItemCategoryNavigator(i18n, true, false, categories);
133 navigator.addGroupingListener(new ValueChangeListener() {
134 @Override
135 public void valueChange(ValueChangeEvent event) {
136 isGrouping = (Boolean) event.getProperty().getValue();
137 }
138 });
139 root.setSizeFull();
140 construct(emptyMessage);
141 }
142
143 @Override
144 @Deprecated
145 public void refresh() {
146 }
147
148 @Override
149 public void setDataSource(Container dataSource) {
150 itemTable.setContainerDataSource(dataSource);
151 itemTable.setVisibleColumns(order);
152 itemTable.setColumnHeaders(headers);
153
154 int size = dataSource.size();
155 setComponentVisibility(size != 0);
156 }
157
158 @Override
159 public void setListener(PulseListView.Listener listener) {
160 this.listener = listener;
161 }
162
163 @Override
164 public void updateCategoryBadgeCount(PulseItemCategory category, int count) {
165 navigator.updateCategoryBadgeCount(category, count);
166 }
167
168 @Override
169 public Component asVaadinComponent() {
170 return root;
171 }
172
173 @Override
174 public void setFooter(PulseListFooterView footer) {
175 if (this.footer != null) {
176 root.removeComponent(this.footer);
177 }
178 this.footer = footer.asVaadinComponent();
179 root.addComponent(this.footer);
180 this.footer.setHeight("60px");
181 }
182
183 protected final Listener getListener() {
184 return listener;
185 }
186
187 private void construct(String emptyMessage) {
188 root.addComponent(navigator);
189 navigator.addCategoryChangeListener(new PulseItemCategoryNavigator.ItemCategoryChangedListener() {
190 @Override
191 public void itemCategoryChanged(PulseItemCategoryNavigator.CategoryChangedEvent event) {
192 final PulseItemCategory category = event.getCategory();
193 onItemCategoryChanged(category);
194 }
195 });
196
197 emptyPlaceHolder = new Label();
198 emptyPlaceHolder.setContentMode(ContentMode.HTML);
199 emptyPlaceHolder.setValue(String.format("<span class=\"icon-pulse\"></span><div class=\"message\">%s</div>", emptyMessage));
200 emptyPlaceHolder.addStyleName("emptyplaceholder");
201
202 root.addComponent(emptyPlaceHolder);
203
204 constructTable();
205 }
206
207 private void constructTable() {
208 root.addComponent(itemTable);
209 root.setExpandRatio(itemTable, 1f);
210 itemTable.setSizeFull();
211 itemTable.addStyleName("message-table");
212 itemTable.setSelectable(true);
213 itemTable.setMultiSelect(true);
214 itemTable.setRowGenerator(groupingRowGenerator);
215
216 navigator.addGroupingListener(groupingListener);
217
218 itemTable.addItemClickListener(new ItemClickEvent.ItemClickListener() {
219 @Override
220 public void itemClick(ItemClickEvent event) {
221 onItemClicked(event, event.getItemId());
222 }
223 });
224
225 itemTable.addValueChangeListener(selectionListener);
226 itemTable.addItemSetChangeListener(new Container.ItemSetChangeListener() {
227 @Override
228 public void containerItemSetChange(ItemSetChangeEvent event) {
229 itemTable.setValue(null);
230 long totalEntriesAmount = listener.getTotalEntriesAmount();
231 setComponentVisibility(totalEntriesAmount > 0);
232 listener.onItemSetChanged(totalEntriesAmount);
233 }
234 });
235 }
236
237 private void doGrouping(boolean checked) {
238 listener.setGrouping(checked);
239 }
240
241 private void setComponentVisibility(boolean entriesAvailable) {
242 if (!entriesAvailable) {
243 root.setExpandRatio(emptyPlaceHolder, 1f);
244 } else {
245 root.setExpandRatio(emptyPlaceHolder, 0f);
246 }
247
248 itemTable.setVisible(entriesAvailable);
249 if (footer != null) {
250 footer.setVisible(entriesAvailable);
251 }
252 emptyPlaceHolder.setVisible(!entriesAvailable);
253 }
254
255
256
257
258 abstract protected GeneratedRow generateGroupingRow(Item item);
259
260 protected SimpleTranslator getI18n() {
261 return i18n;
262 }
263
264 protected Table getItemTable() {
265 return itemTable;
266 }
267
268 @Override
269 public void setTabActive(PulseItemCategory category) {
270 navigator.setActive(category);
271 onItemCategoryChanged(category);
272 }
273
274 @Override
275 public List<Object> getSelectedItemIds() {
276 Set<Object> itemIds = (Set<Object>) getItemTable().getValue();
277 return Lists.newArrayList(itemIds);
278 }
279
280 protected void onItemClicked(ClickEvent event, final Object itemId) {
281 String itemIdAsString = String.valueOf(itemId);
282
283 if (itemIdAsString.startsWith(PulseConstants.GROUP_PLACEHOLDER_ITEMID)) {
284 return;
285 }
286 if (event.isDoubleClick()) {
287 listener.onItemClicked(itemIdAsString);
288 } else {
289 if (itemTable.isSelected(itemIdAsString)) {
290 itemTable.unselect(itemIdAsString);
291 }
292 }
293 }
294
295 private void onItemCategoryChanged(final PulseItemCategory category) {
296 listener.filterByItemCategory(category);
297
298 itemTable.setValue(null);
299
300 boolean isGroupingEnabled = category == PulseItemCategory.ALL_TASKS || category == PulseItemCategory.ALL_MESSAGES;
301 navigator.enableGroupBy(isGroupingEnabled);
302
303 doGrouping(isGroupingEnabled && isGrouping);
304 }
305
306
307
308
309 protected class PulseNewItemColumnGenerator implements Table.ColumnGenerator {
310
311
312 public PulseNewItemColumnGenerator() {
313 }
314
315 @Override
316 public Object generateCell(Table source, Object itemId, Object columnId) {
317 Property<Boolean> newProperty = source.getContainerProperty(itemId, columnId);
318 boolean isNew = newProperty != null && newProperty.getValue();
319 if (isNew) {
320 return "<span class=\"icon icon-tick new-message\"></span>";
321 }
322 return null;
323 }
324 }
325 }