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