View Javadoc
1   /**
2    * This file Copyright (c) 2012-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.admincentral.shellapp.pulse.item.detail;
35  
36  import info.magnolia.i18nsystem.SimpleTranslator;
37  
38  import java.util.HashMap;
39  import java.util.Iterator;
40  import java.util.Map;
41  
42  import org.apache.commons.lang3.StringUtils;
43  
44  import com.vaadin.event.LayoutEvents.LayoutClickEvent;
45  import com.vaadin.event.LayoutEvents.LayoutClickListener;
46  import com.vaadin.ui.Component;
47  import com.vaadin.ui.CssLayout;
48  import com.vaadin.v7.data.Property.ValueChangeListener;
49  import com.vaadin.v7.ui.CheckBox;
50  import com.vaadin.v7.ui.HorizontalLayout;
51  import com.vaadin.v7.ui.Label;
52  
53  /**
54   * Generic item category navigation component in Pulse. An item can be e.g. a Task, a Message, etc.
55   */
56  public final class PulseItemCategoryNavigator extends CssLayout {
57  
58      private CheckBox groupByCheckBox;
59  
60      private Map<PulseItemCategory, ItemCategoryTab> itemCategoryTabs = new HashMap<PulseItemCategory, ItemCategoryTab>();
61  
62      private final SimpleTranslator i18n;
63  
64      private boolean isTopRow;
65  
66      private boolean showGroupBy;
67  
68      public PulseItemCategoryNavigator(SimpleTranslator i18n, boolean showGroupBy, boolean isTopRow, PulseItemCategory... categories) {
69          super();
70          this.i18n = i18n;
71          setStyleName("navigator");
72          this.isTopRow = isTopRow;
73          this.showGroupBy = showGroupBy;
74          construct(categories);
75      }
76  
77      private void construct(PulseItemCategory... categories) {
78          setSizeUndefined();
79  
80          for (final PulseItemCategory category : categories) {
81              ItemCategoryTab tab = new ItemCategoryTab(category);
82              if (category == PulseItemCategory.ALL_MESSAGES || category == PulseItemCategory.UNCLAIMED || category == PulseItemCategory.TASKS) {
83                  tab.setActive(true);
84              }
85              itemCategoryTabs.put(category, tab);
86              addComponent(tab);
87          }
88          if (isTopRow) {
89              addStyleName("top-row");
90          }
91  
92          initCheckbox(categories);
93      }
94  
95      private void initCheckbox(PulseItemCategory... categories) {
96          final String caption = i18n.translate("pulse.items.groupby");
97          groupByCheckBox = new CheckBox(StringUtils.abbreviate(caption, 15));
98          groupByCheckBox.addStyleName("navigator-grouping");
99          groupByCheckBox.setVisible(false);
100         // tooltip
101         groupByCheckBox.setDescription(caption);
102 
103         if (showGroupBy) {
104             addComponent(groupByCheckBox);
105             for (final PulseItemCategory category : categories) {
106                 if (category == PulseItemCategory.ALL_MESSAGES) {
107                     enableGroupBy(true);
108                 }
109             }
110         }
111     }
112 
113     public void addGroupingListener(ValueChangeListener listener) {
114         groupByCheckBox.addValueChangeListener(listener);
115     }
116 
117     public void enableGroupBy(boolean enable) {
118         groupByCheckBox.setVisible(enable);
119     }
120 
121     /**
122      * Category changed event.
123      */
124     public static class CategoryChangedEvent extends Component.Event {
125 
126         public static final java.lang.reflect.Method ITEM_CATEGORY_CHANGED;
127 
128         static {
129             try {
130                 ITEM_CATEGORY_CHANGED = ItemCategoryChangedListener.class.getDeclaredMethod("itemCategoryChanged", new Class[]{CategoryChangedEvent.class});
131             } catch (final java.lang.NoSuchMethodException e) {
132                 throw new java.lang.RuntimeException(e);
133             }
134         }
135 
136         private final PulseItemCategory category;
137 
138         public CategoryChangedEvent(Component source, PulseItemCategory category) {
139             super(source);
140             this.category = category;
141         }
142 
143         public PulseItemCategory getCategory() {
144             return category;
145         }
146     }
147 
148     /**
149      * ItemCategoryChangedListener.
150      */
151     public interface ItemCategoryChangedListener {
152 
153         public void itemCategoryChanged(final CategoryChangedEvent event);
154     }
155 
156     public void addCategoryChangeListener(final ItemCategoryChangedListener listener) {
157         addListener("category_changed", CategoryChangedEvent.class, listener, CategoryChangedEvent.ITEM_CATEGORY_CHANGED);
158     }
159 
160     private void fireCategoryChangedEvent(PulseItemCategory category) {
161         Iterator<Component> iterator = iterator();
162         while (iterator.hasNext()) {
163             Component component = iterator.next();
164             if (component instanceof ItemCategoryTab) {
165                 ItemCategoryTab button = (ItemCategoryTab) component;
166                 button.setActive(button.category == category);
167             }
168         }
169         fireEvent(new CategoryChangedEvent(this, category));
170     }
171 
172     /**
173      * Item category button.
174      */
175     public class ItemCategoryTab extends HorizontalLayout {
176 
177         private final PulseItemCategory category;
178         private final Label categoryLabel;
179         private final Label badge;
180 
181         public ItemCategoryTab(PulseItemCategory category) {
182             super();
183             this.category = category;
184             this.addStyleName("navigator-tab");
185             this.setSizeUndefined();
186 
187             categoryLabel = new Label(i18n.translate(category.getKey()));
188             categoryLabel.addStyleName("category");
189 
190             badge = new Label();
191             badge.addStyleName("badge");
192             if (category == PulseItemCategory.ONGOING) {
193                 badge.addStyleName("empty-circle-gray");
194             }
195             badge.setVisible(false);
196 
197             this.addComponent(categoryLabel);
198             this.addComponent(badge);
199             this.addLayoutClickListener(new LayoutClickListener() {
200 
201                 @Override
202                 public void layoutClick(LayoutClickEvent event) {
203                     fireCategoryChangedEvent(ItemCategoryTab.this.category);
204                 }
205             });
206         }
207 
208         public void setActive(boolean active) {
209             if (active) {
210                 addStyleName("active");
211             } else {
212                 removeStyleName("active");
213             }
214         }
215 
216         public void updateItemsCount(int count) {
217             if (count <= 0) {
218                 badge.setVisible(false);
219             } else {
220                 String countAsString = String.valueOf(count);
221                 if (count > 99) {
222                     countAsString = "99+";
223                 }
224                 badge.setValue(countAsString);
225                 badge.setVisible(true);
226             }
227         }
228 
229         public String getLabel() {
230             return categoryLabel.getValue();
231         }
232     }
233 
234     public void updateCategoryBadgeCount(PulseItemCategory category, int count) {
235         itemCategoryTabs.get(category).updateItemsCount(count);
236     }
237 
238     /**
239      * Sets the passed category as selected and un-select all the others.
240      */
241     public void setActive(PulseItemCategory category) {
242         for (ItemCategoryTab tab : itemCategoryTabs.values()) {
243             tab.setActive(false);
244         }
245         itemCategoryTabs.get(category).setActive(true);
246     }
247 }