View Javadoc
1   /**
2    * This file Copyright (c) 2013-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.workbench;
35  
36  import info.magnolia.i18nsystem.SimpleTranslator;
37  import info.magnolia.icons.MagnoliaIcons;
38  import info.magnolia.ui.api.view.View;
39  import info.magnolia.ui.framework.ioc.AdmincentralFlavour;
40  import info.magnolia.ui.theme.ResurfaceTheme;
41  import info.magnolia.ui.workbench.contenttool.ContentToolDefinition;
42  import info.magnolia.ui.workbench.definition.ContentPresenterDefinition;
43  import info.magnolia.ui.workbench.list.ListPresenterDefinition;
44  import info.magnolia.ui.workbench.search.SearchPresenterDefinition;
45  import info.magnolia.ui.workbench.tree.TreeView;
46  
47  import java.io.Serializable;
48  import java.util.HashMap;
49  import java.util.Map;
50  
51  import com.vaadin.event.ShortcutAction;
52  import com.vaadin.event.ShortcutListener;
53  import com.vaadin.ui.Alignment;
54  import com.vaadin.ui.Button;
55  import com.vaadin.ui.Component;
56  import com.vaadin.ui.HorizontalLayout;
57  import com.vaadin.ui.Label;
58  import com.vaadin.ui.Panel;
59  import com.vaadin.ui.VerticalLayout;
60  
61  /**
62   * Implementation of the workbench view.
63   */
64  public class WorkbenchViewImpl extends VerticalLayout implements WorkbenchView, Serializable {
65  
66      private final HorizontalLayout toolBar = new HorizontalLayout();
67  
68      private final HorizontalLayout viewModes = new HorizontalLayout();
69  
70      protected final Panel keyboardEventPanel;
71  
72      private StatusBarView statusBar;
73  
74      private Map<String, ContentView> contentViews = new HashMap<String, ContentView>();
75  
76      private Map<String, Button> contentViewsButton = new HashMap<String, Button>();
77  
78      private String currentViewType;
79  
80      private WorkbenchView.Listener listener;
81  
82      private Label title;
83  
84      public WorkbenchViewImpl() {
85          setSizeFull();
86          addStyleName("workbench");
87          setSpacing(false);
88          setMargin(false);
89  
90          toolBar.addStyleName("toolbar");
91          toolBar.setWidth(100.0F, Unit.PERCENTAGE);
92          toolBar.setSpacing(false);
93          toolBar.setDefaultComponentAlignment(Alignment.BOTTOM_LEFT);
94  
95          title = new Label();
96          title.addStyleName("heading-1");
97          title.setVisible(false);
98          toolBar.addComponent(title);
99          toolBar.setExpandRatio(title, 0);
100 
101         Label spacer = new Label();
102         toolBar.addComponent(spacer);
103         toolBar.setExpandRatio(spacer, 1f);
104 
105         viewModes.setStyleName("view-modes");
106         viewModes.setSpacing(true);
107         toolBar.addComponent(viewModes);
108         toolBar.setComponentAlignment(viewModes, Alignment.BOTTOM_RIGHT);
109         toolBar.setExpandRatio(viewModes, 0);
110 
111         addComponent(toolBar);
112         setExpandRatio(toolBar, 0.0F);
113 
114         this.keyboardEventPanel = new Panel();
115         this.keyboardEventPanel.setSizeFull();
116         this.keyboardEventPanel.addStyleName("keyboard-panel");
117         addComponent(keyboardEventPanel, 1);
118         setExpandRatio(keyboardEventPanel, 1.0F);
119 
120         bindKeyboardHandlers();
121     }
122 
123     /**
124      * @deprecated since 5.4.3. Use default constructor instead.
125      */
126     @Deprecated
127     public WorkbenchViewImpl(SimpleTranslator i18n) {
128         this();
129     }
130 
131     public void bindKeyboardHandlers() {
132 
133         final ShortcutListener enterShortcut = new ShortcutListener("Enter shortcut", ShortcutAction.KeyCode.ENTER, null) {
134             @Override
135             public void handleAction(Object sender, Object target) {
136                 getSelectedView().onShortcutKey(KeyCode.ENTER, null);
137             }
138         };
139         keyboardEventPanel.addShortcutListener(enterShortcut);
140 
141         final ShortcutListener deleteShortcut = new ShortcutListener("Delete shortcut", ShortcutAction.KeyCode.DELETE, null) {
142             @Override
143             public void handleAction(Object sender, Object target) {
144                 getSelectedView().onShortcutKey(KeyCode.DELETE, null);
145             }
146         };
147         // MGNLUI-2106 disable the delete shortcut until we apply it without disrupting inplace-editing
148         // keyboardEventPanel.addShortcutListener(deleteShortcut);
149     }
150 
151     @Override
152     public void setSearchQuery(String query) {
153         if (listener != null) {
154             listener.onSearchQueryChange(query);
155         }
156     }
157 
158 
159     /**
160      * Adds a content view by given view type, content view and content view definition.
161      * @deprecated since 5.4.3. Use addContentView( viewType, view, viewTypeIcon) instead. Interface method will become deprecated on magnolia-ui 5.5.
162      */
163     @Deprecated
164     @Override
165     public void addContentView(String viewType, ContentView view, ContentPresenterDefinition contentViewDefintion) {
166         addContentView(viewType, view, contentViewDefintion.getIcon());
167     }
168 
169     /**
170      * Adds a content view by given view type, content view and view type icon.
171      */
172     public void addContentView(String viewType, ContentView view, String viewTypeIcon) {
173         contentViews.put(viewType, view);
174 
175         if (view instanceof TreeView) {
176             ((TreeView) view).setActionManager(keyboardEventPanel);
177         }
178 
179         // display search-box only if both list and search content presenters are configured
180         if (contentViews.containsKey(ListPresenterDefinition.VIEW_TYPE) && contentViews.containsKey(SearchPresenterDefinition.VIEW_TYPE)) {
181             int contentToolsCount = toolBar.getComponentCount();
182             if (contentToolsCount > 1) { // components > 1 because first component in the toolbar is switcher between tree/list view
183                 toolBar.getComponent(contentToolsCount - 1).setVisible(true);
184             }
185         }
186 
187         if (SearchPresenterDefinition.VIEW_TYPE.equals(viewType)) {
188             // do not add a view-type button for search
189             return;
190         }
191 
192         // set button
193         Button button;
194         if (!AdmincentralFlavour.get().isM5()) {
195             button = new Button(MagnoliaIcons.forCssClass(viewTypeIcon).orElse(MagnoliaIcons.VIEW_LIST),
196                     clickEvent -> fireViewTypeChangedEvent(viewType));
197         } else {
198             button = buildButton(viewType, viewTypeIcon);
199         }
200         button.addStyleName(ResurfaceTheme.BUTTON_ICON);
201         contentViewsButton.put(viewType, button);
202         viewModes.addComponent(button);
203     }
204 
205     @Override
206     public void setViewType(String type) {
207         final Component c = contentViews.get(type).asVaadinComponent();
208 
209         keyboardEventPanel.setContent(c);
210 
211         if (SearchPresenterDefinition.VIEW_TYPE.equals(currentViewType) && !SearchPresenterDefinition.VIEW_TYPE.equals(type)) {
212             setSearchQuery(null);
213         }
214         setViewTypeStyling(type);
215         currentViewType = type;
216     }
217 
218     private void fireViewTypeChangedEvent(String viewType) {
219         this.listener.onViewTypeChanged(viewType);
220     }
221 
222     @Override
223     public void setStatusBarView(StatusBarView statusBar) {
224         if (AdmincentralFlavour.get().isM5()) {
225             Component c = statusBar.asVaadinComponent();
226             if (this.statusBar == null) {
227                 addComponent(c, getComponentCount()); // add last
228             } else {
229                 replaceComponent(this.statusBar.asVaadinComponent(), c);
230             }
231             setExpandRatio(c, 0);
232         }
233         this.statusBar = statusBar;
234     }
235 
236     @Override
237     public View getStatusBarView() {
238         return this.statusBar;
239     }
240 
241     @Override
242     public ContentView getSelectedView() {
243         return contentViews.get(currentViewType);
244     }
245 
246     @Override
247     public Component asVaadinComponent() {
248         return this;
249     }
250 
251     @Override
252     public void setListener(WorkbenchView.Listener listener) {
253         this.listener = listener;
254     }
255 
256     @Override
257     public void setTitle(String title) {
258         this.title.setValue(title);
259         this.title.setVisible(true);
260     }
261 
262     @Deprecated
263     private Button buildButton(final String viewType, final String icon) {
264         Button button = new Button();
265         button.addClickListener((Button.ClickListener) event -> fireViewTypeChangedEvent(viewType));
266         button.setCaptionAsHtml(true);
267         button.setCaption("<span class=\"" + icon + "\"></span>");
268         return button;
269     }
270 
271     private void setViewTypeStyling(final String viewType) {
272         for (Map.Entry<String, Button> entry : contentViewsButton.entrySet()) {
273             entry.getValue().removeStyleName("active");
274             if (entry.getKey().equals(viewType)) {
275                 entry.getValue().addStyleName("active");
276             }
277         }
278         // search is a list view
279         if (viewType.equals(SearchPresenterDefinition.VIEW_TYPE) && contentViews.containsKey(ListPresenterDefinition.VIEW_TYPE)) {
280             contentViewsButton.get(ListPresenterDefinition.VIEW_TYPE).addStyleName("active");
281         }
282     }
283 
284     @Override
285     public void setMultiselect(boolean multiselect) {
286         for (String type : contentViews.keySet()) {
287             contentViews.get(type).setMultiselect(multiselect);
288         }
289     }
290 
291     @Override
292     public void addContentTool(View view) {
293         addContentTool(view, ContentToolDefinition.Alignment.RIGHT, 0);
294     }
295 
296     public void addContentTool(View view, ContentToolDefinition.Alignment alignment, float expandRatio) {
297         final Component toolComponent = view.asVaadinComponent();
298 
299         toolComponent.addStyleName("content-tool");
300 
301         toolBar.addComponent(toolComponent, 1);
302         toolBar.setExpandRatio(toolComponent, expandRatio);
303 
304         Alignment vaadinAlignment;
305         switch (alignment) {
306         case RIGHT:
307             vaadinAlignment = Alignment.BOTTOM_RIGHT;
308             break;
309         case LEFT:
310             vaadinAlignment = Alignment.BOTTOM_LEFT;
311             break;
312         case CENTER:
313             vaadinAlignment = Alignment.BOTTOM_CENTER;
314             break;
315         default:
316             vaadinAlignment = Alignment.BOTTOM_RIGHT;
317         }
318 
319         toolBar.setComponentAlignment(toolComponent, vaadinAlignment);
320     }
321 }