1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.vectomatic.svg.edit.client.gxt.form;
19
20 import org.vectomatic.dnd.DataTransferExt;
21 import org.vectomatic.dnd.DropPanel;
22 import org.vectomatic.file.ErrorCode;
23 import org.vectomatic.file.File;
24 import org.vectomatic.file.FileError;
25 import org.vectomatic.file.FileList;
26 import org.vectomatic.file.FileReader;
27 import org.vectomatic.file.FileUploadExt;
28 import org.vectomatic.file.FileUtils;
29 import org.vectomatic.file.events.LoadEndEvent;
30 import org.vectomatic.file.events.LoadEndHandler;
31 import org.vectomatic.svg.edit.client.AppBundle;
32 import org.vectomatic.svg.edit.client.SvgrealApp;
33 import org.vectomatic.svg.edit.client.model.ModelConstants;
34 import org.vectomatic.svg.edit.client.model.svg.SVGImageElementModel;
35
36 import com.extjs.gxt.ui.client.Style.Orientation;
37 import com.extjs.gxt.ui.client.event.ButtonEvent;
38 import com.extjs.gxt.ui.client.event.Events;
39 import com.extjs.gxt.ui.client.event.FieldEvent;
40 import com.extjs.gxt.ui.client.event.Listener;
41 import com.extjs.gxt.ui.client.event.SelectionListener;
42 import com.extjs.gxt.ui.client.util.Margins;
43 import com.extjs.gxt.ui.client.util.Size;
44 import com.extjs.gxt.ui.client.util.Util;
45 import com.extjs.gxt.ui.client.widget.Label;
46 import com.extjs.gxt.ui.client.widget.LayoutContainer;
47 import com.extjs.gxt.ui.client.widget.button.Button;
48 import com.extjs.gxt.ui.client.widget.form.AdapterField;
49 import com.extjs.gxt.ui.client.widget.form.Radio;
50 import com.extjs.gxt.ui.client.widget.form.RadioGroup;
51 import com.extjs.gxt.ui.client.widget.form.TextField;
52 import com.extjs.gxt.ui.client.widget.layout.CardLayout;
53 import com.extjs.gxt.ui.client.widget.layout.FitLayout;
54 import com.extjs.gxt.ui.client.widget.layout.RowData;
55 import com.extjs.gxt.ui.client.widget.layout.RowLayout;
56 import com.google.gwt.dom.client.DivElement;
57 import com.google.gwt.dom.client.Document;
58 import com.google.gwt.dom.client.Style.Visibility;
59 import com.google.gwt.dom.client.Text;
60 import com.google.gwt.event.dom.client.ChangeEvent;
61 import com.google.gwt.event.dom.client.ChangeHandler;
62 import com.google.gwt.event.dom.client.DragEnterEvent;
63 import com.google.gwt.event.dom.client.DragEnterHandler;
64 import com.google.gwt.event.dom.client.DragLeaveEvent;
65 import com.google.gwt.event.dom.client.DragLeaveHandler;
66 import com.google.gwt.event.dom.client.DragOverEvent;
67 import com.google.gwt.event.dom.client.DragOverHandler;
68 import com.google.gwt.event.dom.client.DropEvent;
69 import com.google.gwt.event.dom.client.DropHandler;
70 import com.google.gwt.event.dom.client.ErrorEvent;
71 import com.google.gwt.event.dom.client.ErrorHandler;
72 import com.google.gwt.event.dom.client.LoadEvent;
73 import com.google.gwt.event.dom.client.LoadHandler;
74 import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
75 import com.google.gwt.event.logical.shared.ValueChangeEvent;
76 import com.google.gwt.event.logical.shared.ValueChangeHandler;
77 import com.google.gwt.event.shared.GwtEvent;
78 import com.google.gwt.event.shared.HandlerRegistration;
79 import com.google.gwt.user.client.ui.Image;
80
81
82
83
84
85
86
87 public class ImageHrefField extends AdapterField implements HasValueChangeHandlers<Size> {
88 private static final String ATT_ACCEPT = "accept";
89 private static final String ATT_ACCEPT_YES = "yes";
90 private static final String ATT_ACCEPT_NO = "no";
91
92 private class ImageHrefPanel extends LayoutContainer {
93
94
95
96
97 private CardLayout cardLayout1;
98
99
100
101
102 private CardLayout cardLayout2;
103
104
105
106 private Radio externalRadio;
107
108
109
110 private Radio embeddedRadio;
111
112
113
114 private LayoutContainer externalPanel;
115
116
117
118 private LayoutContainer embeddedPanel;
119
120
121
122 private LayoutContainer statusPanel;
123
124
125
126
127 private LayoutContainer errorPanel;
128
129
130
131 private TextField<String> urlField;
132
133
134
135 private FileUploadExt fileUploadExt;
136
137
138
139
140 private String resourceName;
141
142
143
144 private FileReader reader;
145
146
147
148 private Image hiddenImage;
149
150
151
152 private Label sizeLabel;
153
154
155
156 private Label errorLabel;
157
158
159
160 private int bitmapWidth, bitmapHeight;
161
162 public ImageHrefPanel() {
163 ModelConstants constants = ModelConstants.INSTANCE;
164
165
166
167
168
169 Label externalLabel = new Label(constants.url());
170
171 urlField = new TextField<String>();
172 urlField.setToolTip(constants.urlTooltip());
173 urlField.setFireChangeEventOnSetValue(true);
174 urlField.addListener(Events.Change, new Listener<FieldEvent>() {
175 @Override
176 public void handleEvent(FieldEvent be) {
177 String value = urlField.getValue();
178 resourceName = value;
179 if (value != null && value.length() > 0) {
180 hiddenImage.setUrl(value);
181 } else {
182 reportNull();
183 }
184 setValue(value, false);
185 }
186 });
187
188 externalPanel = new LayoutContainer(new RowLayout(Orientation.HORIZONTAL));
189 externalPanel.add(externalLabel, new RowData(.10, 1, new Margins(0, 5, 0, 5)));
190 externalPanel.add(urlField, new RowData(.90, 1, new Margins(0, 5, 0, 0)));
191
192
193
194
195 final DropPanel dropArea = new DropPanel();
196 dropArea.addDragEnterHandler(new DragEnterHandler() {
197 @Override
198 public void onDragEnter(DragEnterEvent event) {
199 dropArea.getElement().setAttribute(ATT_ACCEPT, ATT_ACCEPT_YES);
200 event.stopPropagation();
201 event.preventDefault();
202 }
203 });
204 dropArea.addDragLeaveHandler(new DragLeaveHandler() {
205 @Override
206 public void onDragLeave(DragLeaveEvent event) {
207 dropArea.getElement().setAttribute(ATT_ACCEPT, ATT_ACCEPT_NO);
208 event.stopPropagation();
209 event.preventDefault();
210 }
211 });
212 dropArea.addDragOverHandler(new DragOverHandler() {
213 @Override
214 public void onDragOver(DragOverEvent event) {
215 event.stopPropagation();
216 event.preventDefault();
217 }
218 });
219 dropArea.addDropHandler(new DropHandler() {
220 @Override
221 public void onDrop(DropEvent event) {
222 dropArea.getElement().setAttribute(ATT_ACCEPT, ATT_ACCEPT_NO);
223 processFiles(event.getDataTransfer().<DataTransferExt>cast().getFiles());
224 event.stopPropagation();
225 event.preventDefault();
226 }
227 });
228 Document document = Document.get();
229 DivElement div = document.createDivElement();
230 Text text = document.createTextNode(constants.dropPanelText());
231 div.appendChild(text);
232 dropArea.getElement().appendChild(div);
233 dropArea.setStyleName(AppBundle.INSTANCE.css().imageHrefDropArea());
234 dropArea.getElement().setAttribute(ATT_ACCEPT, ATT_ACCEPT_NO);
235
236 fileUploadExt = new FileUploadExt();
237 fileUploadExt.getElement().getStyle().setVisibility(Visibility.HIDDEN);
238 fileUploadExt.addChangeHandler(new ChangeHandler() {
239 @Override
240 public void onChange(ChangeEvent event) {
241 processFiles(fileUploadExt.getFiles());
242 }
243 });
244 Button openButton = new Button(constants.openLocalImageButton());
245 openButton.addSelectionListener(new SelectionListener<ButtonEvent>() {
246 @Override
247 public void componentSelected(ButtonEvent ce) {
248 fileUploadExt.click();
249 }
250 });
251
252 embeddedPanel = new LayoutContainer(new RowLayout(Orientation.HORIZONTAL));
253 embeddedPanel.add(dropArea, new RowData(.85, 1, new Margins(0, 5, 0, 5)));
254 embeddedPanel.add(openButton, new RowData(.15, 1, new Margins(0, 5, 0, 0)));
255
256
257
258
259 statusPanel = new LayoutContainer(new RowLayout(Orientation.HORIZONTAL));
260 sizeLabel = new Label();
261 Button resetButton = new Button(constants.resetHrefButton());
262 resetButton.setToolTip(constants.resetHrefTooltip());
263 statusPanel.add(sizeLabel, new RowData(.85, 1, new Margins(0, 5, 0, 5)));
264 statusPanel.add(resetButton, new RowData(.15, 1, new Margins(0, 5, 0, 0)));
265 resetButton.addSelectionListener(new SelectionListener<ButtonEvent>() {
266 @Override
267 public void componentSelected(ButtonEvent ce) {
268 ValueChangeEvent.fire(ImageHrefField.this, new Size(bitmapWidth, bitmapHeight));
269 }
270 });
271
272
273
274
275 errorPanel = new LayoutContainer(new FitLayout());
276 errorLabel = new Label();
277 errorPanel.add(errorLabel);
278
279
280
281
282 externalRadio = new Radio();
283 externalRadio.setBoxLabel(constants.externalRadio());
284 externalRadio.setFireChangeEventOnSetValue(true);
285 embeddedRadio = new Radio();
286 embeddedRadio.setBoxLabel(constants.embeddedRadio());
287 embeddedRadio.setFireChangeEventOnSetValue(true);
288
289 RadioGroup radioGroup = new RadioGroup(constants.dropPanelText());
290 radioGroup.add(externalRadio);
291 radioGroup.add(embeddedRadio);
292 radioGroup.setSelectionRequired(true);
293 radioGroup.addListener(Events.Change, new Listener<FieldEvent>() {
294 @Override
295 public void handleEvent(FieldEvent be) {
296 cardLayout1.setActiveItem(isExternal() ? externalPanel : embeddedPanel);
297 }
298 });
299
300 LayoutContainer cardPanel1 = new LayoutContainer();
301 cardLayout1 = new CardLayout();
302 cardPanel1.setHeight(25);
303 cardPanel1.setLayout(cardLayout1);
304 cardPanel1.add(externalPanel);
305 cardPanel1.add(embeddedPanel);
306
307 LayoutContainer cardPanel2 = new LayoutContainer();
308 cardLayout2 = new CardLayout();
309 cardPanel2.setHeight(25);
310 cardPanel2.setLayout(cardLayout2);
311 cardPanel2.add(statusPanel);
312 cardPanel2.add(errorPanel);
313
314 hiddenImage = new Image();
315 hiddenImage.getElement().getStyle().setVisibility(Visibility.HIDDEN);
316 hiddenImage.addLoadHandler(new LoadHandler() {
317 @Override
318 public void onLoad(LoadEvent event) {
319 String w = hiddenImage.getElement().getAttribute("width");
320
321 bitmapWidth = hiddenImage.getWidth();
322 bitmapHeight = hiddenImage.getHeight();
323 sizeLabel.setText(ModelConstants.INSTANCE.originalSizeLabel() + ": " + bitmapWidth + "x" + bitmapHeight);
324 cardLayout2.setActiveItem(statusPanel);
325 }
326 });
327 hiddenImage.addErrorHandler(new ErrorHandler() {
328 @Override
329 public void onError(ErrorEvent event) {
330
331 reportError(null);
332 }
333 });
334
335 setLayout(new RowLayout(Orientation.VERTICAL));
336 add(radioGroup, new RowData(1, -1, new Margins(5, 5, 0, 5)));
337 add(cardPanel1, new RowData(1, -1, new Margins(0, 0, 5, 0)));
338 add(cardPanel2, new RowData(1, -1));
339 add(hiddenImage);
340 add(fileUploadExt);
341 setBorders(true);
342 setHeight(90);
343 }
344
345 public boolean isExternal() {
346 return externalRadio.getValue();
347 }
348
349 public void update(String value) {
350
351 if (SVGImageElementModel.isDataUrl(value)) {
352 if (!embeddedRadio.getValue()) {
353 embeddedRadio.setValue(true);
354 }
355 hiddenImage.setUrl(value);
356 } else if (value != null && value.length() > 0) {
357 if (!externalRadio.getValue()) {
358 externalRadio.setValue(true);
359 }
360 if (!Util.equalWithNull(value, urlField.getValue())) {
361 urlField.setFireChangeEventOnSetValue(false);
362 urlField.setValue(value);
363 urlField.setFireChangeEventOnSetValue(true);
364 }
365 hiddenImage.setUrl(value);
366 } else {
367 reportNull();
368 }
369 }
370
371 public void processFiles(FileList files) {
372 for (File file : files) {
373 final String type = file.getType();
374 if (type.startsWith("image")) {
375 if (reader == null) {
376 reader = new FileReader();
377 reader.addErrorHandler(new org.vectomatic.file.events.ErrorHandler() {
378 @Override
379 public void onError(org.vectomatic.file.events.ErrorEvent event) {
380 FileError error = reader.getError();
381 String errorDesc = "";
382 if (error != null) {
383 ErrorCode errorCode = error.getCode();
384 if (errorCode != null) {
385 errorDesc = errorCode.name();
386 }
387 }
388 reportError(errorDesc);
389 setValue(null, false);
390 }
391 });
392 reader.addLoadEndHandler(new LoadEndHandler() {
393
394 @Override
395 public void onLoadEnd(LoadEndEvent event) {
396 if (reader.getError() == null) {
397 try {
398 String result = reader.getStringResult();
399 String url = FileUtils.createDataUrl(type, result);
400 setValue(url, false);
401 } catch(Throwable t) {
402 reportError(t.getMessage());
403 setValue(null, false);
404 }
405 }
406 }
407 });
408 }
409 try {
410 reader.readAsBinaryString(file);
411 resourceName = file.getName();
412 } catch(Throwable t) {
413
414
415 reportError(t.getMessage());
416 setValue(null, false);
417 }
418 break;
419 }
420 }
421 }
422
423 public void reportError(String message) {
424
425 StringBuilder builder = new StringBuilder(ModelConstants.INSTANCE.imageLoadError());
426 if (message != null && message.length() > 0) {
427 builder.append(": ");
428 builder.append(message);
429 }
430 errorLabel.setText(builder.toString());
431 cardLayout2.setActiveItem(errorPanel);
432 }
433
434 public void reportNull() {
435 errorLabel.setText(ModelConstants.INSTANCE.noImage());
436 cardLayout2.setActiveItem(errorPanel);
437 }
438
439
440 public String getResourceName() {
441 return resourceName;
442 }
443 }
444
445 public ImageHrefField() {
446 super(null);
447 widget = new ImageHrefPanel();
448 setResizeWidget(true);
449 setFireChangeEventOnSetValue(true);
450 }
451
452 @Override
453 public void setValue(Object value) {
454 setValue(value, true);
455 }
456
457 public void setValue(Object value, boolean update) {
458 if (update) {
459 ((ImageHrefPanel)widget).update((String)value);
460 this.value = value;
461 } else {
462
463 super.setValue(value);
464 }
465 }
466
467 @Override
468 public Object getValue() {
469 return value;
470 }
471
472 public String getResourceName() {
473 return ((ImageHrefPanel)widget).getResourceName();
474 }
475
476
477
478
479
480 @Override
481 public void fireEvent(GwtEvent<?> event) {
482 SvgrealApp.getApp().getEventBus().fireEventFromSource(event, this);
483 }
484
485 @Override
486 public HandlerRegistration addValueChangeHandler(ValueChangeHandler<Size> handler) {
487 return SvgrealApp.getApp().getEventBus().addHandlerToSource(ValueChangeEvent.getType(), this, handler);
488 }
489 }