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