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.context.MgnlContext;
38 import info.magnolia.ui.api.overlay.ConfirmationCallback;
39 import info.magnolia.ui.framework.AdmincentralNodeTypes;
40 import info.magnolia.ui.api.shell.Shell;
41 import info.magnolia.ui.vaadin.integration.jcr.AbstractJcrNodeAdapter;
42 import info.magnolia.ui.vaadin.overlay.MessageStyleTypeEnum;
43
44 import org.apache.commons.lang.StringUtils;
45
46 import com.vaadin.data.Property;
47 import com.vaadin.event.FieldEvents.BlurEvent;
48 import com.vaadin.event.FieldEvents.BlurListener;
49 import com.vaadin.event.FieldEvents.FocusEvent;
50 import com.vaadin.event.FieldEvents.FocusListener;
51 import com.vaadin.event.LayoutEvents.LayoutClickEvent;
52 import com.vaadin.event.LayoutEvents.LayoutClickListener;
53 import com.vaadin.event.ShortcutListener;
54 import com.vaadin.shared.ui.label.ContentMode;
55 import com.vaadin.ui.Button.ClickEvent;
56 import com.vaadin.ui.Button.ClickListener;
57 import com.vaadin.ui.CustomComponent;
58 import com.vaadin.ui.HorizontalLayout;
59 import com.vaadin.ui.Label;
60 import com.vaadin.ui.NativeButton;
61 import com.vaadin.ui.TextField;
62
63
64
65
66 public final class FavoritesEntry extends CustomComponent {
67
68 private HorizontalLayout root = new HorizontalLayout();
69 private String location;
70 private String title;
71 private String group;
72 private String relPath;
73 private TextField titleField;
74 private NativeButton editButton;
75 private NativeButton removeButton;
76 private boolean editable;
77 private boolean selected;
78 private EnterKeyShortcutListener enterKeyShortcutListener;
79 private EscapeKeyShortcutListener escapeKeyShortcutListener;
80 private Shell shell;
81
82
83 public FavoritesEntry(final AbstractJcrNodeAdapter favorite, final FavoritesView.Listener listener, final Shell shell) {
84 super();
85 this.shell = shell;
86 construct(favorite, listener);
87 }
88
89
90
91
92 public void reset() {
93 setEditable(false);
94 setSelected(false);
95 }
96
97 private void setEditable(boolean editable) {
98 this.editable = editable;
99 String icon = "icon-tick";
100 if (editable) {
101 titleField.addStyleName("editable");
102 titleField.focus();
103 titleField.selectAll();
104 } else {
105 icon = "icon-edit";
106 titleField.removeStyleName("editable");
107
108 titleField.setValue(title);
109 }
110 titleField.setReadOnly(!editable);
111 editButton.setCaption("<span class=\"" + icon + "\"></span>");
112 }
113
114 private void setSelected(boolean selected) {
115 this.selected = selected;
116 if (selected) {
117 addStyleName("selected");
118 } else {
119 removeStyleName("selected");
120 }
121 titleField.setReadOnly(true);
122 editButton.setVisible(selected);
123 editButton.setCaption("<span class=\"icon-edit\"></span>");
124 removeButton.setVisible(selected);
125 }
126
127 private void construct(final AbstractJcrNodeAdapter favorite, final FavoritesView.Listener listener) {
128 addStyleName("favorites-entry");
129 setSizeUndefined();
130 root.setSizeUndefined();
131
132 this.enterKeyShortcutListener = new EnterKeyShortcutListener(listener);
133 this.escapeKeyShortcutListener = new EscapeKeyShortcutListener();
134
135 final String nodeName = favorite.getNodeName();
136 this.location = favorite.getItemProperty(AdmincentralNodeTypes.Favorite.URL).getValue().toString();
137 this.title = favorite.getItemProperty(AdmincentralNodeTypes.Favorite.TITLE).getValue().toString();
138 this.relPath = nodeName;
139 try {
140 this.group = MgnlContext.doInSystemContext(new MgnlContext.Op<String, Throwable>() {
141
142 @Override
143 public String exec() throws Throwable {
144 final Property<?> property = favorite.getItemProperty(AdmincentralNodeTypes.Favorite.GROUP);
145 if (property != null) {
146 return property.getValue().toString();
147 }
148 return null;
149 }
150 });
151 } catch (Throwable e) {
152 throw new RuntimeException(e);
153 }
154
155 if (StringUtils.isNotBlank(this.group)) {
156 this.relPath = this.group + "/" + nodeName;
157 }
158
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
172 titleField = new TextField();
173 titleField.setValue(title);
174 titleField.setReadOnly(true);
175
176 titleField.addFocusListener(new FocusListener() {
177
178 @Override
179 public void focus(FocusEvent event) {
180 iconLabel.removeShortcutListener(enterKeyShortcutListener);
181 titleField.addShortcutListener(enterKeyShortcutListener);
182 titleField.addShortcutListener(escapeKeyShortcutListener);
183 }
184 });
185
186 titleField.addBlurListener(new BlurListener() {
187
188 @Override
189 public void blur(BlurEvent event) {
190 titleField.removeShortcutListener(enterKeyShortcutListener);
191 titleField.removeShortcutListener(escapeKeyShortcutListener);
192 }
193 });
194
195 root.addComponent(titleField);
196
197 editButton = new NativeButton();
198 editButton.setHtmlContentAllowed(true);
199 editButton.setCaption("<span class=\"icon-edit\"></span>");
200 editButton.addStyleName("favorite-action");
201 editButton.addClickListener(new ClickListener() {
202
203 @Override
204 public void buttonClick(ClickEvent event) {
205 if (selected && !editable) {
206 setEditable(true);
207 return;
208 }
209 doEditTitle(listener);
210 }
211 });
212 editButton.setVisible(false);
213 root.addComponent(editButton);
214
215 removeButton = new NativeButton();
216 removeButton.setHtmlContentAllowed(true);
217 removeButton.setCaption("<span class=\"icon-trash\"></span>");
218 removeButton.addStyleName("favorite-action");
219 removeButton.addClickListener(new ClickListener() {
220
221 @Override
222 public void buttonClick(ClickEvent event) {
223 shell.openConfirmation(MessageStyleTypeEnum.WARNING, MessagesUtil.get("confirmation.delete.title.generic"), MessagesUtil.get("confirmation.cannot.undo"), MessagesUtil.get("confirmation.delete.yes"), MessagesUtil.get("confirmation.no"), true, new ConfirmationCallback() {
224
225 @Override
226 public void onSuccess() {
227 listener.removeFavorite(relPath);
228 }
229
230 @Override
231 public void onCancel() {
232
233 }
234 });
235 }
236 });
237 removeButton.setVisible(false);
238 root.addComponent(removeButton);
239
240 root.addLayoutClickListener(new LayoutClickListener() {
241
242 @Override
243 public void layoutClick(LayoutClickEvent event) {
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 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
271 boolean titleHasChanged = !title.equals(titleField.getValue());
272 if (editable && titleHasChanged) {
273 listener.editFavorite(relPath, titleField.getValue());
274 }
275 setEditable(false);
276 }
277
278 private class EnterKeyShortcutListener extends ShortcutListener {
279 private FavoritesView.Listener listener;
280
281 public EnterKeyShortcutListener(final FavoritesView.Listener listener) {
282 super("", KeyCode.ENTER, null);
283 this.listener = listener;
284 }
285
286 @Override
287 public void handleAction(Object sender, Object target) {
288 if (editable) {
289 doEditTitle(listener);
290 } else {
291 setEditable(true);
292 }
293 }
294 }
295
296 private class EscapeKeyShortcutListener extends ShortcutListener {
297
298 public EscapeKeyShortcutListener() {
299 super("", KeyCode.ESCAPE, null);
300 }
301
302 @Override
303 public void handleAction(Object sender, Object target) {
304 reset();
305 }
306 }
307 }