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.favorites;
35
36 import info.magnolia.i18nsystem.SimpleTranslator;
37 import info.magnolia.ui.admincentral.shellapp.favorites.EditingEvent.EditingListener;
38 import info.magnolia.ui.admincentral.shellapp.favorites.SelectedEvent.SelectedListener;
39 import info.magnolia.ui.api.overlay.ConfirmationCallback;
40 import info.magnolia.ui.api.shell.Shell;
41 import info.magnolia.ui.framework.AdmincentralNodeTypes;
42 import info.magnolia.ui.vaadin.integration.jcr.AbstractJcrNodeAdapter;
43 import info.magnolia.ui.vaadin.overlay.MessageStyleTypeEnum;
44
45 import java.util.Iterator;
46 import java.util.Map;
47
48 import org.apache.commons.lang.StringUtils;
49
50 import com.vaadin.event.FieldEvents.BlurEvent;
51 import com.vaadin.event.FieldEvents.BlurListener;
52 import com.vaadin.event.FieldEvents.FocusEvent;
53 import com.vaadin.event.FieldEvents.FocusListener;
54 import com.vaadin.event.LayoutEvents.LayoutClickEvent;
55 import com.vaadin.event.LayoutEvents.LayoutClickListener;
56 import com.vaadin.event.ShortcutListener;
57 import com.vaadin.ui.Button.ClickEvent;
58 import com.vaadin.ui.Button.ClickListener;
59 import com.vaadin.ui.Component;
60 import com.vaadin.ui.CssLayout;
61 import com.vaadin.ui.DragAndDropWrapper.DragStartMode;
62 import com.vaadin.ui.NativeButton;
63 import com.vaadin.ui.TextField;
64
65
66
67
68 public final class FavoritesGroup extends CssLayout implements SelectedEvent.SelectedNotifier {
69
70 private TextField titleField;
71 private NativeButton editButton;
72 private NativeButton removeButton;
73 private String title;
74 private String relPath;
75 private boolean editable;
76 private boolean selected;
77 private CssLayout wrapper;
78 private EnterKeyShortcutListener enterKeyShortcutListener;
79 private EscapeKeyShortcutListener escapeKeyShortcutListener;
80 private Shell shell;
81 private FavoritesView view;
82 private Component currentlySelectedFavEntry;
83 private final SimpleTranslator i18n;
84
85
86
87
88 public FavoritesGroup(SimpleTranslator i18n) {
89 this.i18n = i18n;
90 addStyleName("no-group");
91 }
92
93 public FavoritesGroup(final AbstractJcrNodeAdapter favoritesGroup, final FavoritesView.Listener listener, final Shell shell, final FavoritesView view, final SimpleTranslator i18n) {
94 this.shell = shell;
95 this.view = view;
96 this.i18n = i18n;
97
98 addStyleName("favorites-group");
99 construct(favoritesGroup, listener);
100
101 final Map<String, AbstractJcrNodeAdapter> nodeAdapters = favoritesGroup.getChildren();
102
103 for (String key : nodeAdapters.keySet()) {
104 final AbstractJcrNodeAdapter fav = nodeAdapters.get(key);
105 final FavoritesEntry favEntry = new FavoritesEntry(fav, listener, shell, i18n);
106 favEntry.addSelectedListener(new SelectedListener() {
107
108 @Override
109 public void onSelected(SelectedEvent event) {
110 currentlySelectedFavEntry = event.getComponent();
111 view.updateSelection(event.getComponent());
112 }
113 });
114 favEntry.setGroup(this.relPath);
115 final EntryDragAndDropWrapper wrapper = new EntryDragAndDropWrapper(favEntry, listener);
116 favEntry.addEditingListener(new EditingListener() {
117
118 @Override
119 public void onEdit(EditingEvent event) {
120 if (event.isEditing()) {
121 wrapper.setDragStartMode(DragStartMode.NONE);
122 } else {
123 wrapper.setDragStartMode(DragStartMode.WRAPPER);
124 }
125 }
126 });
127 addComponent(wrapper);
128 }
129 }
130
131 public String getRelPath() {
132 return this.relPath;
133 }
134
135
136
137
138 public void reset() {
139
140 if (titleField != null) {
141 setEditable(false);
142 setSelected(false);
143 }
144 Iterator<Component> components = iterator();
145 while (components.hasNext()) {
146 Component component = components.next();
147 if (component instanceof EntryDragAndDropWrapper) {
148 component = ((EntryDragAndDropWrapper) component).getWrappedComponent();
149 } else if (component instanceof FavoritesEntry) {
150 if (component == currentlySelectedFavEntry) {
151 continue;
152 }
153 FavoritesEntry fav = (FavoritesEntry) component;
154 fav.reset();
155 }
156 }
157 }
158
159 @Override
160 public void addSelectedListener(SelectedListener listener) {
161 addListener("onSelected", SelectedEvent.class, listener, SelectedEvent.SELECTED_METHOD);
162 }
163
164 @Override
165 public void removeSelectedListener(SelectedListener listener) {
166 removeListener(SelectedEvent.class, listener, SelectedEvent.SELECTED_METHOD);
167 }
168
169 private void setEditable(boolean editable) {
170 this.editable = editable;
171 String icon = "icon-tick";
172 if (editable) {
173 titleField.addStyleName("editable");
174 titleField.focus();
175 titleField.selectAll();
176 } else {
177 icon = "icon-edit";
178
179 titleField.setValue(title);
180 titleField.removeStyleName("editable");
181 }
182 titleField.setReadOnly(!editable);
183 editButton.setCaption("<span class=\"" + icon + "\"></span>");
184 }
185
186 private void setSelected(boolean selected) {
187 this.selected = selected;
188 if (selected) {
189 wrapper.addStyleName("selected");
190 fireEvent(new SelectedEvent(this));
191 } else {
192 wrapper.removeStyleName("selected");
193 }
194 titleField.setReadOnly(true);
195 editButton.setVisible(selected);
196 editButton.setCaption("<span class=\"icon-edit\"></span>");
197 removeButton.setVisible(selected);
198 }
199
200 private void construct(final AbstractJcrNodeAdapter favoritesGroup, final FavoritesView.Listener listener) {
201 wrapper = new CssLayout();
202 wrapper.addStyleName("favorites-group-title");
203
204 this.enterKeyShortcutListener = new EnterKeyShortcutListener(listener);
205 this.escapeKeyShortcutListener = new EscapeKeyShortcutListener();
206
207 this.relPath = favoritesGroup.getNodeName();
208 this.title = favoritesGroup.getItemProperty(AdmincentralNodeTypes.Favorite.TITLE).getValue().toString();
209
210 titleField = new TextField();
211 titleField.setValue(title);
212 titleField.setReadOnly(true);
213 titleField.addFocusListener(new FocusListener() {
214
215 @Override
216 public void focus(FocusEvent event) {
217 titleField.addShortcutListener(enterKeyShortcutListener);
218 titleField.addShortcutListener(escapeKeyShortcutListener);
219 }
220 });
221
222 titleField.addBlurListener(new BlurListener() {
223
224 @Override
225 public void blur(BlurEvent event) {
226 titleField.removeShortcutListener(enterKeyShortcutListener);
227 titleField.removeShortcutListener(escapeKeyShortcutListener);
228 }
229 });
230
231 wrapper.addComponent(titleField);
232
233 editButton = new NativeButton();
234 editButton.setHtmlContentAllowed(true);
235 editButton.setCaption("<span class=\"icon-edit\"></span>");
236 editButton.addStyleName("favorite-action");
237 editButton.addClickListener(new ClickListener() {
238
239 @Override
240 public void buttonClick(ClickEvent event) {
241 if (selected && !editable) {
242 setEditable(true);
243 return;
244 }
245 doEditTitle(listener);
246 }
247 });
248 editButton.setVisible(false);
249 wrapper.addComponent(editButton);
250
251 removeButton = new NativeButton();
252 removeButton.setHtmlContentAllowed(true);
253 removeButton.setCaption("<span class=\"icon-trash\"></span>");
254 removeButton.addStyleName("favorite-action");
255 removeButton.addClickListener(new ClickListener() {
256
257 @Override
258 public void buttonClick(ClickEvent event) {
259 shell.openConfirmation(MessageStyleTypeEnum.WARNING, i18n.translate("favorites.group.confirmation.title"), i18n.translate("confirmation.cannot.undo"), i18n.translate("confirmation.delete.yes"), i18n.translate("confirmation.no"), true, new ConfirmationCallback() {
260
261 @Override
262 public void onSuccess() {
263 listener.removeGroup(relPath);
264 }
265
266 @Override
267 public void onCancel() {
268
269 }
270 });
271 }
272 });
273 removeButton.setVisible(false);
274 wrapper.addComponent(removeButton);
275
276 addLayoutClickListener(new LayoutClickListener() {
277
278 @Override
279 public void layoutClick(LayoutClickEvent event) {
280
281 if (event.getClickedComponent() == titleField) {
282 if (!editable) {
283 setSelected(!selected);
284 }
285 }
286 }
287 });
288
289 addComponent(new GroupDragAndDropWrapper(wrapper, listener, this));
290 }
291
292 private void doEditTitle(final FavoritesView.Listener listener) {
293 if (StringUtils.isBlank(titleField.getValue())) {
294 shell.openNotification(MessageStyleTypeEnum.ERROR, true, i18n.translate("favorites.title.required"));
295 return;
296 }
297 boolean titleHasChanged = !title.equals(titleField.getValue());
298 if (editable && titleHasChanged) {
299 listener.editGroup(relPath, titleField.getValue());
300 }
301 setEditable(false);
302 }
303
304 private class EnterKeyShortcutListener extends ShortcutListener {
305 private FavoritesView.Listener listener;
306
307 public EnterKeyShortcutListener(final FavoritesView.Listener listener) {
308 super("", KeyCode.ENTER, null);
309 this.listener = listener;
310 }
311
312 @Override
313 public void handleAction(Object sender, Object target) {
314 if (editable) {
315 doEditTitle(listener);
316 } else {
317 setEditable(true);
318 }
319 }
320 }
321
322 private class EscapeKeyShortcutListener extends ShortcutListener {
323
324 public EscapeKeyShortcutListener() {
325 super("", KeyCode.ESCAPE, null);
326 }
327
328 @Override
329 public void handleAction(Object sender, Object target) {
330 reset();
331 }
332 }
333 }