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.workbench;
35
36 import info.magnolia.i18nsystem.SimpleTranslator;
37 import info.magnolia.ui.vaadin.icon.Icon;
38 import info.magnolia.ui.workbench.definition.ContentPresenterDefinition;
39 import info.magnolia.ui.workbench.list.ListPresenterDefinition;
40 import info.magnolia.ui.workbench.search.SearchPresenterDefinition;
41 import info.magnolia.ui.workbench.tree.TreePresenterDefinition;
42 import info.magnolia.ui.workbench.tree.TreeView;
43
44 import java.io.Serializable;
45 import java.util.HashMap;
46 import java.util.Map;
47
48 import javax.inject.Inject;
49
50 import org.apache.commons.lang.StringUtils;
51
52 import com.vaadin.data.Property;
53 import com.vaadin.event.FieldEvents;
54 import com.vaadin.event.ShortcutAction;
55 import com.vaadin.event.ShortcutListener;
56 import com.vaadin.shared.ui.MarginInfo;
57 import com.vaadin.ui.Button;
58 import com.vaadin.ui.Button.ClickEvent;
59 import com.vaadin.ui.Component;
60 import com.vaadin.ui.CssLayout;
61 import com.vaadin.ui.NativeButton;
62 import com.vaadin.ui.Panel;
63 import com.vaadin.ui.TextField;
64 import com.vaadin.ui.VerticalLayout;
65 import com.vaadin.ui.themes.BaseTheme;
66
67
68
69
70 public class WorkbenchViewImpl extends VerticalLayout implements WorkbenchView, Serializable {
71
72 private final CssLayout toolBar = new CssLayout();
73
74 private final CssLayout viewModes = new CssLayout();
75
76 private final CssLayout searchBox = new CssLayout();
77
78 protected final Panel keyboardEventPanel;
79
80 private TextField searchField;
81
82 private Button clearSearchBoxButton;
83
84 private Icon searchIcon;
85
86 private Icon searchArrow;
87
88 private StatusBarView statusBar;
89
90 private Map<String, ContentView> contentViews = new HashMap<String, ContentView>();
91
92 private Map<String, Button> contentViewsButton = new HashMap<String, Button>();
93
94 private String currentViewType = TreePresenterDefinition.VIEW_TYPE;
95
96
97
98
99 private String previousViewType = currentViewType;
100
101 private final Property.ValueChangeListener searchFieldListener = new Property.ValueChangeListener() {
102
103 @Override
104 public void valueChange(Property.ValueChangeEvent event) {
105 listener.onSearch(searchField.getValue().toString());
106
107 boolean hasSearchContent = !searchField.getValue().isEmpty();
108 if (hasSearchContent) {
109 searchBox.addStyleName("has-content");
110 } else {
111 searchBox.removeStyleName("has-content");
112 }
113 searchField.focus();
114 }
115 };
116
117 private WorkbenchView.Listener listener;
118 private final SimpleTranslator i18n;
119
120 @Inject
121 public WorkbenchViewImpl(SimpleTranslator i18n) {
122 this.i18n = i18n;
123
124 setSizeFull();
125 setMargin(new MarginInfo(true, false, false, true));
126 addStyleName("workbench");
127
128 viewModes.setStyleName("view-modes");
129
130 clearSearchBoxButton = new Button();
131 clearSearchBoxButton.setStyleName("m-closebutton");
132 clearSearchBoxButton.addStyleName("icon-delete-search");
133 clearSearchBoxButton.addStyleName("searchbox-clearbutton");
134 clearSearchBoxButton.addClickListener(new Button.ClickListener() {
135
136 @Override
137 public void buttonClick(ClickEvent event) {
138 searchField.setValue("");
139 }
140 });
141
142 searchIcon = new Icon("search");
143 searchIcon.addStyleName("searchbox-icon");
144
145 searchArrow = new Icon("arrow2_s");
146 searchArrow.addStyleName("searchbox-arrow");
147
148 searchField = buildSearchField();
149
150 searchBox.setVisible(false);
151 searchBox.addComponent(searchField);
152 searchBox.addComponent(clearSearchBoxButton);
153 searchBox.addComponent(searchIcon);
154 searchBox.addComponent(searchArrow);
155 searchBox.setStyleName("searchbox");
156
157 toolBar.addStyleName("toolbar");
158 toolBar.setWidth(100, Unit.PERCENTAGE);
159 toolBar.addComponent(viewModes);
160 toolBar.addComponent(searchBox);
161
162 addComponent(toolBar);
163 setExpandRatio(toolBar, 0);
164
165 keyboardEventPanel = new Panel();
166 keyboardEventPanel.setSizeFull();
167 keyboardEventPanel.addStyleName("keyboard-panel");
168 addComponent(keyboardEventPanel, 1);
169 setExpandRatio(keyboardEventPanel, 1);
170
171 bindKeyboardHandlers();
172 }
173
174 public void bindKeyboardHandlers() {
175
176 final ShortcutListener enterShortcut = new ShortcutListener("Enter shortcut", ShortcutAction.KeyCode.ENTER, null) {
177 @Override
178 public void handleAction(Object sender, Object target) {
179 getSelectedView().onShortcutKey(ShortcutAction.KeyCode.ENTER, null);
180 }
181 };
182 keyboardEventPanel.addShortcutListener(enterShortcut);
183
184 final ShortcutListener deleteShortcut = new ShortcutListener("Delete shortcut", ShortcutAction.KeyCode.DELETE, null) {
185 @Override
186 public void handleAction(Object sender, Object target) {
187 getSelectedView().onShortcutKey(ShortcutAction.KeyCode.DELETE, null);
188 }
189 };
190
191
192
193 }
194
195 @Override
196 public void setSearchQuery(String query) {
197 if (searchField == null) {
198 return;
199 }
200
201 searchField.removeValueChangeListener(searchFieldListener);
202 if (StringUtils.isNotBlank(query)) {
203 searchField.setValue(query);
204 searchField.focus();
205 } else {
206 searchField.setValue("");
207 searchBox.removeStyleName("has-content");
208 }
209 searchField.addValueChangeListener(searchFieldListener);
210
211 }
212
213 @Override
214 public void addContentView(String viewType, ContentView view, ContentPresenterDefinition contentViewDefintion) {
215 contentViews.put(viewType, view);
216
217 if (view instanceof TreeView) {
218 ((TreeView) view).setActionManager(keyboardEventPanel);
219 }
220
221
222 if (contentViews.containsKey(ListPresenterDefinition.VIEW_TYPE) && contentViews.containsKey(SearchPresenterDefinition.VIEW_TYPE)) {
223 searchBox.setVisible(true);
224 }
225
226 if (contentViewDefintion instanceof SearchPresenterDefinition) {
227
228 return;
229 }
230
231
232 Button button = buildButton(viewType, contentViewDefintion.getIcon(), contentViewDefintion.isActive());
233 contentViewsButton.put(viewType, button);
234 viewModes.addComponent(button);
235
236 if (contentViewDefintion.isActive()) {
237 currentViewType = previousViewType = viewType;
238 }
239 }
240
241 @Override
242 public void setViewType(String type) {
243
244 final Component c = contentViews.get(type).asVaadinComponent();
245
246
247 keyboardEventPanel.setContent(c);
248
249 if (type != SearchPresenterDefinition.VIEW_TYPE) {
250 previousViewType = type;
251 setSearchQuery(null);
252 }
253 setViewTypeStyling(type);
254
255 currentViewType = type;
256 }
257
258 private void fireViewTypeChangedEvent(String viewType) {
259 this.listener.onViewTypeChanged(viewType);
260 }
261
262 @Override
263 public void setStatusBarView(StatusBarView statusBar) {
264 Component c = statusBar.asVaadinComponent();
265 if (this.statusBar == null) {
266 addComponent(c, getComponentCount());
267 } else {
268 replaceComponent(this.statusBar.asVaadinComponent(), c);
269 }
270 setExpandRatio(c, 0);
271 this.statusBar = statusBar;
272 }
273
274 @Override
275 public ContentView getSelectedView() {
276 return contentViews.get(currentViewType);
277 }
278
279 @Override
280 public Component asVaadinComponent() {
281 return this;
282 }
283
284 @Override
285 public void setListener(WorkbenchView.Listener listener) {
286 this.listener = listener;
287 }
288
289 private Button buildButton(final String viewType, final String icon, final boolean active) {
290 NativeButton button = new NativeButton(null, new Button.ClickListener() {
291 @Override
292 public void buttonClick(Button.ClickEvent event) {
293 fireViewTypeChangedEvent(viewType);
294 }
295 });
296 button.setStyleName(BaseTheme.BUTTON_LINK);
297
298 button.setHtmlContentAllowed(true);
299 button.setCaption("<span class=\"" + icon + "\"></span><span class=\"view-type-arrow view-type-arrow-" + viewType + " icon-arrow2_n\"></span>");
300
301 if (active) {
302 button.addStyleName("active");
303 }
304 return button;
305 }
306
307 private void setViewTypeStyling(final String viewType) {
308 for (Map.Entry<String, Button> entry : contentViewsButton.entrySet()) {
309 entry.getValue().removeStyleName("active");
310 if (entry.getKey().equals(viewType)) {
311 entry.getValue().addStyleName("active");
312 }
313 }
314
315 if (viewType.equals(SearchPresenterDefinition.VIEW_TYPE) && contentViews.containsKey(ListPresenterDefinition.VIEW_TYPE)) {
316 contentViewsButton.get(ListPresenterDefinition.VIEW_TYPE).addStyleName("active");
317 }
318 }
319
320 private TextField buildSearchField() {
321 final TextField field = new TextField();
322 final String inputPrompt = i18n.translate("toolbar.search.prompt");
323
324 field.setInputPrompt(inputPrompt);
325 field.setSizeUndefined();
326 field.addStyleName("searchfield");
327
328
329 field.setImmediate(true);
330 field.addValueChangeListener(searchFieldListener);
331
332 field.addFocusListener(new FieldEvents.FocusListener() {
333 @Override
334 public void focus(FieldEvents.FocusEvent event) {
335
336 TextField tf = (TextField) event.getSource();
337 tf.setCursorPosition(tf.getValue().length());
338 }
339 });
340
341
342
343 return field;
344 }
345
346 @Override
347 public void setMultiselect(boolean multiselect) {
348 for (String type : contentViews.keySet()) {
349 contentViews.get(type).setMultiselect(multiselect);
350 }
351 }
352 }