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.api.overlay.ConfirmationCallback;
38 import info.magnolia.ui.api.shell.Shell;
39 import info.magnolia.ui.framework.AdmincentralNodeTypes;
40 import info.magnolia.ui.vaadin.integration.jcr.AbstractJcrNodeAdapter;
41 import info.magnolia.ui.vaadin.overlay.MessageStyleTypeEnum;
42
43 import java.util.Date;
44
45 import org.apache.commons.lang3.StringUtils;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
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.shared.ui.label.ContentMode;
57 import com.vaadin.ui.Button.ClickEvent;
58 import com.vaadin.ui.Button.ClickListener;
59 import com.vaadin.ui.CustomComponent;
60 import com.vaadin.ui.HorizontalLayout;
61 import com.vaadin.ui.Label;
62 import com.vaadin.ui.NativeButton;
63 import com.vaadin.ui.TextField;
64
65
66
67
68 public final class FavoritesEntry extends CustomComponent implements EditableFavoriteItem, EditingEvent.EditingNotifier {
69
70 private static final Logger log = LoggerFactory.getLogger(FavoritesEntry.class);
71 private static long uniqueIdCounter = 23;
72
73 private HorizontalLayout root = new HorizontalLayout();
74 private String location;
75 private String title;
76 private String group = null;
77 private String nodename;
78 private TextField titleField;
79 private NativeButton editButton;
80 private NativeButton removeButton;
81 private boolean editable;
82 private EnterKeyShortcutListener enterKeyShortcutListener;
83 private EscapeKeyShortcutListener escapeKeyShortcutListener;
84 private Shell shell;
85 private final SimpleTranslator i18n;
86 private String itemId;
87 private FavoritesView.Listener listener;
88
89 public FavoritesEntry(final AbstractJcrNodeAdapter favorite, final FavoritesView.Listener listener, final Shell shell, SimpleTranslator i18n) {
90 super();
91 this.listener = listener;
92 this.shell = shell;
93 this.i18n = i18n;
94 itemId = createItemdId(favorite);
95 construct(favorite, listener);
96 }
97
98 @Override
99 public String getItemId() {
100 return itemId;
101 }
102
103 public String getRelPath() {
104 return StringUtils.isBlank(group) ? this.nodename : this.group + "/" + this.nodename;
105 }
106
107 public String getNodename() {
108 return this.nodename;
109 }
110
111 public void setGroup(String group) {
112 this.group = group;
113 }
114
115 public String getGroup() {
116 return this.group;
117 }
118
119 @Override
120 public void setToNonEditableState() {
121 setEditable(false);
122 }
123
124 private void setEditable(boolean editable) {
125 this.editable = editable;
126 String icon = "icon-tick";
127 if (editable) {
128 listener.setCurrentEditedItemId(getItemId());
129 titleField.addStyleName("editable");
130 titleField.focus();
131 titleField.selectAll();
132
133 } else {
134 icon = "icon-edit";
135 titleField.removeStyleName("editable");
136
137 titleField.setValue(title);
138 }
139 titleField.setReadOnly(!editable);
140 editButton.setCaption("<span class=\"" + icon + "\"></span>");
141 fireEvent(new EditingEvent(this, editable));
142 }
143
144
145 private void construct(final AbstractJcrNodeAdapter favorite, final FavoritesView.Listener listener) {
146 addStyleName("favorites-entry");
147 setSizeUndefined();
148 root.setSizeUndefined();
149
150 this.enterKeyShortcutListener = new EnterKeyShortcutListener(listener);
151 this.escapeKeyShortcutListener = new EscapeKeyShortcutListener();
152
153 this.nodename = favorite.getNodeName();
154 this.location = favorite.getItemProperty(AdmincentralNodeTypes.Favorite.URL).getValue().toString();
155 this.title = favorite.getItemProperty(AdmincentralNodeTypes.Favorite.TITLE).getValue().toString();
156
157 String icon = "icon-app";
158 if (favorite.getItemProperty(AdmincentralNodeTypes.Favorite.ICON).getValue() != null) {
159 icon = favorite.getItemProperty(AdmincentralNodeTypes.Favorite.ICON).getValue().toString();
160 }
161
162 final Label iconLabel = new Label();
163 iconLabel.setValue("<span class=\"" + icon + "\"></span>");
164 iconLabel.setStyleName("icon");
165 iconLabel.setContentMode(ContentMode.HTML);
166 root.addComponent(iconLabel);
167
168 titleField = new TextField();
169 titleField.setValue(title);
170 titleField.setReadOnly(true);
171
172 titleField.addFocusListener(new FocusListener() {
173
174 @Override
175 public void focus(FocusEvent event) {
176 iconLabel.removeShortcutListener(enterKeyShortcutListener);
177 titleField.addShortcutListener(enterKeyShortcutListener);
178 titleField.addShortcutListener(escapeKeyShortcutListener);
179 }
180 });
181
182 titleField.addBlurListener(new BlurListener() {
183
184 @Override
185 public void blur(BlurEvent event) {
186 titleField.removeShortcutListener(enterKeyShortcutListener);
187 titleField.removeShortcutListener(escapeKeyShortcutListener);
188 }
189 });
190
191 root.addComponent(titleField);
192
193 editButton = new NativeButton();
194 editButton.setHtmlContentAllowed(true);
195 editButton.setCaption("<span class=\"icon-edit\"></span>");
196 editButton.addStyleName("favorite-action");
197 editButton.addClickListener(new ClickListener() {
198
199 @Override
200 public void buttonClick(ClickEvent event) {
201 doEditTitle(listener);
202 }
203 });
204 editButton.setVisible(false);
205 root.addComponent(editButton);
206
207 removeButton = new NativeButton();
208 removeButton.setHtmlContentAllowed(true);
209 removeButton.setCaption("<span class=\"icon-trash\"></span>");
210 removeButton.addStyleName("favorite-action");
211 removeButton.addClickListener(new ClickListener() {
212
213 @Override
214 public void buttonClick(ClickEvent event) {
215 shell.openConfirmation(MessageStyleTypeEnum.WARNING, i18n.translate("confirmation.delete.title.generic"), i18n.translate("confirmation.cannot.undo"), i18n.translate("confirmation.delete.yes"), i18n.translate("confirmation.no"), false, new ConfirmationCallback() {
216
217 @Override
218 public void onSuccess() {
219 listener.removeFavorite(getRelPath());
220 }
221
222 @Override
223 public void onCancel() {
224
225 }
226 });
227 }
228 });
229 removeButton.setVisible(false);
230 root.addComponent(removeButton);
231
232 root.addLayoutClickListener(new LayoutClickListener() {
233 @Override
234 public void layoutClick(LayoutClickEvent event) {
235 if (event.getClickedComponent() == titleField && !editable) {
236 if (event.isDoubleClick()) {
237
238
239 } else {
240 listener.goToLocation(location);
241 }
242 }
243 }
244 });
245
246 setCompositionRoot(root);
247 setIconsVisibility(false);
248 }
249
250 @Override
251 public void addEditingListener(EditingEvent.EditingListener listener) {
252 addListener("onEdit", EditingEvent.class, listener, EditingEvent.EDITING_METHOD);
253 }
254
255 @Override
256 public void removeEditingListener(EditingEvent.EditingListener listener) {
257 removeListener(EditingEvent.class, listener, EditingEvent.EDITING_METHOD);
258 }
259
260 @Override
261 public void setIconsVisibility(boolean visible) {
262 editButton.setVisible(visible);
263 removeButton.setVisible(visible);
264 }
265
266 @Override
267 public boolean iconsAreVisible() {
268 return editButton.isVisible();
269 }
270
271 private void doEditTitle(final FavoritesView.Listener listener) {
272 if (StringUtils.isBlank(titleField.getValue())) {
273 shell.openNotification(MessageStyleTypeEnum.ERROR, true, i18n.translate("favorites.title.required"));
274 titleField.focus();
275 return;
276 }
277
278 if (editable) {
279 boolean titleHasChanged = !title.equals(titleField.getValue());
280 if (titleHasChanged) {
281 listener.editFavorite(getRelPath(), titleField.getValue());
282 }
283 setEditable(false);
284 } else {
285 setEditable(true);
286 }
287 }
288
289 private class EnterKeyShortcutListener extends ShortcutListener {
290 private FavoritesView.Listener listener;
291
292 public EnterKeyShortcutListener(final FavoritesView.Listener listener) {
293 super("", KeyCode.ENTER, null);
294 this.listener = listener;
295 }
296
297 @Override
298 public void handleAction(Object sender, Object target) {
299 if (editable) {
300 doEditTitle(listener);
301 } else {
302 setIconsVisibility(true);
303 }
304 }
305 }
306
307 private class EscapeKeyShortcutListener extends ShortcutListener {
308
309 public EscapeKeyShortcutListener() {
310 super("", KeyCode.ESCAPE, null);
311 }
312
313 @Override
314 public void handleAction(Object sender, Object target) {
315 setToNonEditableState();
316 }
317 }
318
319
320
321
322 public static String createItemdId(AbstractJcrNodeAdapter nodeAdapter) {
323 String id = null;
324 try {
325 id = nodeAdapter.getJcrItem().getIdentifier();
326 } catch (Exception ex) {
327 log.error("Failed to create an itemId from an AbstractJcrNodeAdapter", ex);
328 } finally {
329 if (id == null) {
330 uniqueIdCounter++;
331 id = String.valueOf((new Date()).getTime() + uniqueIdCounter);
332 }
333 }
334 return id;
335 }
336
337 }