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.vaadin.grid.MagnoliaTable;
41
42 import javax.inject.Inject;
43
44 import com.vaadin.data.Container;
45 import com.vaadin.data.Container.ItemSetChangeEvent;
46 import com.vaadin.data.Item;
47 import com.vaadin.data.Property;
48 import com.vaadin.data.Property.ValueChangeEvent;
49 import com.vaadin.data.Property.ValueChangeListener;
50 import com.vaadin.event.ItemClickEvent;
51 import com.vaadin.event.MouseEvents.ClickEvent;
52 import com.vaadin.shared.ui.label.ContentMode;
53 import com.vaadin.ui.Component;
54 import com.vaadin.ui.Label;
55 import com.vaadin.ui.Table;
56 import com.vaadin.ui.Table.GeneratedRow;
57 import com.vaadin.ui.VerticalLayout;
58
59
60
61
62 public abstract class AbstractPulseListView implements PulseListView {
63
64 private final String[] order;
65
66 private final String[] headers;
67
68 private final Table itemTable = new MagnoliaTable();
69
70 private final VerticalLayout root = new VerticalLayout();
71
72 private final PulseItemCategoryNavigator navigator;
73
74 private final SimpleTranslator i18n;
75
76 private PulseListView.Listener listener;
77
78 private Label emptyPlaceHolder;
79
80 private PulseListFooter footer;
81
82 private Property.ValueChangeListener selectionListener = new Property.ValueChangeListener() {
83 @Override
84 public void valueChange(ValueChangeEvent event) {
85 footer.updateStatus();
86 }
87 };
88
89 private ValueChangeListener groupingListener = new ValueChangeListener() {
90 @Override
91 public void valueChange(ValueChangeEvent event) {
92 doGrouping((Boolean) event.getProperty().getValue());
93 }
94 };
95
96
97
98
99 private Table.RowGenerator groupingRowGenerator = new Table.RowGenerator() {
100
101 @Override
102 public GeneratedRow generateRow(Table table, Object itemId) {
103
104
105
106
107
108
109 String id = (String) table.getContainerProperty(itemId, "id").getValue();
110
111 if (id != null && id.startsWith(PulseConstants.GROUP_PLACEHOLDER_ITEMID)) {
112 Item item = table.getItem(itemId);
113 return generateGroupingRow(item);
114 }
115
116 return null;
117 }
118 };
119
120 private boolean isGrouping = false;
121
122 @Inject
123 public AbstractPulseListView(SimpleTranslator i18n, String[] order, String[] headers, String emptyMessage, PulseItemCategory... categories) {
124 this.i18n = i18n;
125 this.order = order;
126 this.headers = headers;
127 navigator = new PulseItemCategoryNavigator(i18n, true, false, categories);
128 navigator.addGroupingListener(new ValueChangeListener() {
129 @Override
130 public void valueChange(ValueChangeEvent event) {
131 isGrouping = (Boolean)event.getProperty().getValue();
132 }
133 });
134 root.setSizeFull();
135 construct(emptyMessage);
136 }
137
138 @Override
139 public void refresh() {}
140
141 @Override
142 public void setDataSource(Container dataSource) {
143 itemTable.setContainerDataSource(dataSource);
144 itemTable.setVisibleColumns(order);
145 itemTable.setColumnHeaders(headers);
146
147 int size = dataSource.size();
148 setComponentVisibility(size != 0);
149 footer.setTotalAmount(size);
150 }
151
152 @Override
153 public void setListener(PulseListView.Listener listener) {
154 this.listener = listener;
155
156
157 this.footer.setMessagesListener(listener);
158 }
159
160 @Override
161 public void updateCategoryBadgeCount(PulseItemCategory category, int count) {
162 navigator.updateCategoryBadgeCount(category, count);
163 }
164
165 @Override
166 public Component asVaadinComponent() {
167 return root;
168 }
169
170 public void setFooter(PulseListFooter footer) {
171 if (this.footer != null) {
172 root.removeComponent(this.footer);
173 }
174 this.footer = footer;
175 root.addComponent(footer);
176 footer.setHeight("60px");
177 }
178
179 protected final Listener getListener() {
180 return listener;
181 }
182
183 private void construct(String emptyMessage) {
184 root.addComponent(navigator);
185 navigator.addCategoryChangeListener(new PulseItemCategoryNavigator.ItemCategoryChangedListener() {
186 @Override
187 public void itemCategoryChanged(PulseItemCategoryNavigator.CategoryChangedEvent event) {
188 final PulseItemCategory category = event.getCategory();
189 onItemCategoryChanged(category);
190 }
191 });
192
193 emptyPlaceHolder = new Label();
194 emptyPlaceHolder.setContentMode(ContentMode.HTML);
195 emptyPlaceHolder.setValue(String.format("<span class=\"icon-pulse\"></span><div class=\"message\">%s</div>", emptyMessage));
196 emptyPlaceHolder.addStyleName("emptyplaceholder");
197
198 root.addComponent(emptyPlaceHolder);
199
200 constructTable();
201
202
203 footer = new PulseListFooter(itemTable, i18n, false);
204 root.addComponent(footer);
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 footer.setTotalAmount(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 footer.setVisible(entriesAvailable);
250 emptyPlaceHolder.setVisible(!entriesAvailable);
251 }
252
253
254
255
256 abstract protected GeneratedRow generateGroupingRow(Item item);
257
258 protected SimpleTranslator getI18n() {
259 return i18n;
260 }
261
262 protected Table getItemTable() {
263 return itemTable;
264 }
265
266 @Override
267 public void setTabActive(PulseItemCategory category) {
268 navigator.setActive(category);
269 onItemCategoryChanged(category);
270 }
271
272 protected PulseListFooter getFooter() {
273 return footer;
274 }
275
276 protected void onItemClicked(ClickEvent event, final Object itemId) {
277 String itemIdAsString = String.valueOf(itemId);
278
279 if (itemIdAsString.startsWith(PulseConstants.GROUP_PLACEHOLDER_ITEMID)) {
280 return;
281 }
282 if (event.isDoubleClick()) {
283 listener.onItemClicked(itemIdAsString);
284 } else {
285 if (itemTable.isSelected(itemIdAsString)) {
286 itemTable.unselect(itemIdAsString);
287 }
288 }
289 }
290
291 private void onItemCategoryChanged(final PulseItemCategory category) {
292 listener.filterByItemCategory(category);
293
294 itemTable.setValue(null);
295
296 boolean isGroupingEnabled = category == PulseItemCategory.ALL_TASKS || category == PulseItemCategory.ALL_MESSAGES;
297 navigator.enableGroupBy(isGroupingEnabled);
298
299 doGrouping(isGroupingEnabled && isGrouping);
300
301 refresh();
302 }
303
304
305
306
307 protected class PulseNewItemColumnGenerator implements Table.ColumnGenerator {
308
309
310 public PulseNewItemColumnGenerator() {
311 }
312
313 @Override
314 public Object generateCell(Table source, Object itemId, Object columnId) {
315 Property<Boolean> newProperty = source.getContainerProperty(itemId, columnId);
316 boolean isNew = newProperty != null && newProperty.getValue();
317 if (isNew) {
318 return "<span class=\"icon icon-tick new-message\"></span>";
319 }
320 return null;
321 }
322 }
323 }