1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.vectomatic.svg.edit.client;
19
20 import java.util.HashMap;
21 import java.util.Map;
22
23 import org.vectomatic.dom.svg.OMSVGSVGElement;
24 import org.vectomatic.dom.svg.ui.SVGImage;
25 import org.vectomatic.dom.svg.utils.SVGConstants;
26 import org.vectomatic.svg.edit.client.command.EditTitleCommandFactory;
27 import org.vectomatic.svg.edit.client.engine.SVGModel;
28 import org.vectomatic.svg.edit.client.event.RotationEvent;
29 import org.vectomatic.svg.edit.client.event.RotationHandler;
30 import org.vectomatic.svg.edit.client.gxt.layout.AbsoluteLayerLayout;
31 import org.vectomatic.svg.edit.client.gxt.layout.AbsoluteLayerLayoutData;
32 import org.vectomatic.svg.edit.client.gxt.widget.Compass;
33 import org.vectomatic.svg.edit.client.gxt.widget.KeyNavExt;
34 import org.vectomatic.svg.edit.client.gxt.widget.SVGTreePanelDragSource;
35 import org.vectomatic.svg.edit.client.gxt.widget.SVGTreePanelDropTarget;
36 import org.vectomatic.svg.edit.client.gxt.widget.TreePanelExt;
37 import org.vectomatic.svg.edit.client.model.ModelConstants;
38 import org.vectomatic.svg.edit.client.model.ValidationError.Severity;
39 import org.vectomatic.svg.edit.client.model.svg.SVGElementModel;
40 import org.vectomatic.svg.edit.client.utils.DecoratedImageCache.HAlign;
41 import org.vectomatic.svg.edit.client.utils.DecoratedImageCache.VAlign;
42
43 import com.extjs.gxt.ui.client.Style;
44 import com.extjs.gxt.ui.client.Style.LayoutRegion;
45 import com.extjs.gxt.ui.client.data.ChangeEvent;
46 import com.extjs.gxt.ui.client.data.ChangeListener;
47 import com.extjs.gxt.ui.client.data.ModelData;
48 import com.extjs.gxt.ui.client.data.ModelIconProvider;
49 import com.extjs.gxt.ui.client.dnd.DND.Feedback;
50 import com.extjs.gxt.ui.client.event.BaseEvent;
51 import com.extjs.gxt.ui.client.event.ComponentEvent;
52 import com.extjs.gxt.ui.client.event.DragEvent;
53 import com.extjs.gxt.ui.client.event.Events;
54 import com.extjs.gxt.ui.client.event.Listener;
55 import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
56 import com.extjs.gxt.ui.client.event.SelectionProvider;
57 import com.extjs.gxt.ui.client.event.SelectionService;
58 import com.extjs.gxt.ui.client.event.SliderEvent;
59 import com.extjs.gxt.ui.client.event.TreePanelEvent;
60 import com.extjs.gxt.ui.client.store.Record;
61 import com.extjs.gxt.ui.client.store.TreeStore;
62 import com.extjs.gxt.ui.client.util.Margins;
63 import com.extjs.gxt.ui.client.util.Rectangle;
64 import com.extjs.gxt.ui.client.util.Size;
65 import com.extjs.gxt.ui.client.widget.Component;
66 import com.extjs.gxt.ui.client.widget.Editor;
67 import com.extjs.gxt.ui.client.widget.LayoutContainer;
68 import com.extjs.gxt.ui.client.widget.Slider;
69 import com.extjs.gxt.ui.client.widget.Window;
70 import com.extjs.gxt.ui.client.widget.form.TextField;
71 import com.extjs.gxt.ui.client.widget.layout.BorderLayout;
72 import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData;
73 import com.extjs.gxt.ui.client.widget.layout.FitData;
74 import com.extjs.gxt.ui.client.widget.layout.FitLayout;
75 import com.extjs.gxt.ui.client.widget.menu.Menu;
76 import com.extjs.gxt.ui.client.widget.treepanel.TreePanel.TreeNode;
77 import com.extjs.gxt.ui.client.widget.treepanel.TreePanelSelectionModel;
78 import com.extjs.gxt.ui.client.widget.treepanel.TreePanelView;
79 import com.google.gwt.core.client.GWT;
80 import com.google.gwt.dom.client.Style.Unit;
81 import com.google.gwt.event.dom.client.MouseMoveEvent;
82 import com.google.gwt.event.dom.client.MouseOutEvent;
83 import com.google.gwt.event.dom.client.MouseOutHandler;
84 import com.google.gwt.event.dom.client.MouseOverEvent;
85 import com.google.gwt.event.dom.client.MouseOverHandler;
86 import com.google.gwt.resources.client.ImageResource;
87 import com.google.gwt.user.client.ui.AbstractImagePrototype;
88
89
90
91
92
93
94
95
96
97 public class SVGWindow extends Window {
98 public static final String WINDOW_ACTIVE_STYLE = "x-window-active";
99
100
101
102 private SVGModel svgModel;
103
104
105
106 protected Compass compass;
107
108
109
110 protected Slider scaleSlider;
111
112
113
114 protected TreePanelExt<SVGElementModel> tree;
115
116
117
118 protected Menu contextMenu;
119
120
121
122 protected boolean displaysContextMenu;
123
124
125
126 protected KeyNavExt<ComponentEvent> keyNav;
127
128
129
130 protected SVGTreePanelDragSource dndSource;
131
132
133
134 protected SVGTreePanelDropTarget dndTarget;
135
136
137
138
139
140 public SVGWindow(final SVGModel svgModel) {
141 super();
142 keyNav = new KeyNavExt<ComponentEvent>(this) {
143 @Override
144 public void onKeyPress(ComponentEvent ce) {
145 svgModel.onKeyPress(ce);
146 }
147 @Override
148 public void onKeyUp(ComponentEvent ce) {
149 svgModel.onKeyUp(ce);
150 }
151 };
152 this.svgModel = svgModel;
153 setPlain(true);
154 setMaximizable(true);
155 setMinWidth(200);
156 setMinHeight(170);
157
158
159 svgModel.getRoot().addChangeListener(new ChangeListener() {
160 @Override
161 public void modelChanged(ChangeEvent event) {
162 String title = event.getSource().get(SVGConstants.SVG_TITLE_ATTRIBUTE);
163 String heading = getHeading();
164 if (!heading.equals(title)) {
165 setHeading(title);
166 }
167 }
168 });
169
170
171
172
173
174
175
176
177
178
179
180
181 LayoutContainer splitterPanel = new LayoutContainer();
182 splitterPanel.setLayout(new BorderLayout());
183
184 LayoutContainer layersContainer = new LayoutContainer();
185 GWT.log("borders: " + getBorders());
186 layersContainer.setLayout(new AbsoluteLayerLayout());
187
188
189 contextMenu = new Menu();
190
191
192 LayoutContainer svgContainer = new LayoutContainer() {
193 @Override
194 protected void onShowContextMenu(int x, int y) {
195 GWT.log("SVGWindow.onShowContextMenu");
196 displaysContextMenu = true;
197 svgModel.updateContextMenu(contextMenu);
198 super.onShowContextMenu(x, y);
199 }
200 @Override
201 protected void onHideContextMenu() {
202 GWT.log("SVGWindow.onHideContextMenu");
203 displaysContextMenu = false;
204 }
205 };
206 svgContainer.setLayout(new FitLayout() {
207 @Override
208 protected void setItemSize(Component item, Size size) {
209 GWT.log("setItemSize(" + size + ")");
210
211 svgModel.setWindowRect(size.width, size.height);
212 }
213 });
214 svgContainer.setContextMenu(contextMenu);
215 svgContainer.setScrollMode(Style.Scroll.AUTO);
216 svgContainer.setStyleAttribute("background-color", SVGConstants.CSS_WHITE_VALUE);
217 OMSVGSVGElement svg = svgModel.getSvgElement();
218 SVGImage image = new SVGImage(svg) {
219 protected void onAttach() {
220 GWT.log("onAttach");
221 svgModel.onAttach();
222 }
223 };
224 svgContainer.add(image);
225 layersContainer.add(svgContainer, new AbsoluteLayerLayoutData(
226 AbsoluteLayerLayoutData.HORIZONTAL_ATTACH_LEFT | AbsoluteLayerLayoutData.VERTICAL_ATTACH_TOP,
227 0,
228 0,
229 0,
230 0,
231 10));
232
233 svgContainer.addDomHandler(svgModel.getGrid().getMouseMoveHandler(), MouseMoveEvent.getType());
234
235
236 TreeStore<SVGElementModel> treeStore = svgModel.getStore();
237 tree = new TreePanelExt<SVGElementModel>(treeStore) {
238 @Override
239 protected void onShowContextMenu(int x, int y) {
240 displaysContextMenu = true;
241 svgModel.updateContextMenu(contextMenu);
242 super.onShowContextMenu(x, y);
243 }
244 @Override
245 protected void onHideContextMenu() {
246 displaysContextMenu = false;
247 }
248 @Override
249 protected void onDoubleClick(TreePanelEvent tpe) {
250 TreeNode treeNode = tree.findNode(tpe.getTarget());
251 SVGElementModel model = treeNode.getModel();
252 renameModel(model);
253 }
254 };
255 tree.setView(new TreePanelView<SVGElementModel>() {
256 @Override
257 public void onSelectChange(SVGElementModel model, boolean select) {
258 super.onSelectChange(model, select);
259 if (svgModel.isHighlightingMode()) {
260 svgModel.displayTwin(model, select);
261 }
262 }
263 });
264 tree.setSelectionModel(svgModel.getSelectionModel());
265 tree.setContextMenu(contextMenu);
266
267 tree.setIconProvider(new ModelIconProvider<SVGElementModel>() {
268 Map<Severity, ImageResource> severityToResource = new HashMap<Severity, ImageResource>();
269 {
270 severityToResource.put(Severity.WARNING, AppBundle.INSTANCE.warning());
271 severityToResource.put(Severity.ERROR, AppBundle.INSTANCE.error());
272 severityToResource.put(null, null);
273 }
274 @Override
275 public AbstractImagePrototype getIcon(SVGElementModel model) {
276 Severity severity = model.getSeverity();
277 return SvgrealApp.getApp().getImageCache().getImageWithDecoration(model.getMetaModel().getIcon(), severityToResource.get(severity), HAlign.LEFT, VAlign.BOTTOM);
278 }
279
280 });
281
282 tree.setWidth(150);
283 tree.setDisplayProperty(SVGConstants.SVG_TITLE_TAG);
284 tree.setTrackMouseOver(true);
285 tree.setStyleAttribute("background-color", SVGConstants.CSS_WHITE_VALUE);
286 tree.setAutoExpand(true);
287
288
289
290
291
292
293 svg.addMouseOverHandler(new MouseOverHandler() {
294 @Override
295 public void onMouseOver(MouseOverEvent event) {
296 if (!displaysContextMenu) {
297 svgModel.setHighlightingMode(true);
298 }
299 }
300 });
301 svg.addMouseOutHandler(new MouseOutHandler() {
302
303 @Override
304 public void onMouseOut(MouseOutEvent event) {
305 if (!displaysContextMenu) {
306 svgModel.setHighlightingMode(false);
307 }
308 }
309 });
310 tree.addListener(Events.OnMouseOver, new Listener<TreePanelEvent<SVGElementModel>>() {
311 public void handleEvent(TreePanelEvent<SVGElementModel> be) {
312
313
314 if (!displaysContextMenu) {
315 svgModel.setHighlightingMode(true);
316 SVGElementModel model = be.getItem();
317 if (model != null) {
318 svgModel.highlightModel(model);
319
320
321
322 }
323 }
324
325
326
327
328
329
330
331
332 }
333 });
334 tree.addListener(Events.OnMouseOut, new Listener<TreePanelEvent<SVGElementModel>>() {
335 public void handleEvent(TreePanelEvent<SVGElementModel> be) {
336 if (!displaysContextMenu) {
337 svgModel.setHighlightingMode(false);
338
339 }
340 }
341 });
342
343
344 dndSource = new SVGTreePanelDragSource(this);
345 dndTarget = new SVGTreePanelDropTarget(this);
346 dndTarget.setAllowSelfAsSource(true);
347 dndTarget.setFeedback(Feedback.BOTH);
348
349
350 BorderLayoutData layoutData = new BorderLayoutData(LayoutRegion.WEST, 150, 100, 250);
351 layoutData.setMargins(new Margins(0, 5, 0, 0));
352 layoutData.setSplit(true);
353 layoutData.setCollapsible(true);
354 splitterPanel.add(tree, layoutData);
355 splitterPanel.add(layersContainer, new BorderLayoutData(LayoutRegion.CENTER));
356
357
358
359
360
361
362 compass = GWT.create(Compass.class);
363 final OMSVGSVGElement compassSvg = compass.getSvgElement();
364 compassSvg.getStyle().setWidth(100, Unit.PX);
365 compassSvg.getStyle().setHeight(100, Unit.PX);
366 compass.addRotationHandler(new RotationHandler() {
367 @Override
368 public void onRotate(RotationEvent event) {
369 svgModel.setRotation(event.getAngle());
370 }
371 });
372 LayoutContainer compassContainer = new LayoutContainer();
373 AppCss css = AppBundle.INSTANCE.css();
374 compassContainer.addStyleName(css.compassContainer());
375 SVGImage compassImage = new SVGImage(compassSvg);
376 compassImage.addClassNameBaseVal(css.compass());
377 compassContainer.add(compassImage);
378 layersContainer.add(compassContainer, new AbsoluteLayerLayoutData(
379 AbsoluteLayerLayoutData.HORIZONTAL_ATTACH_RIGHT | AbsoluteLayerLayoutData.VERTICAL_ATTACH_TOP,
380 0,
381 0,
382 0,
383 0,
384 20));
385
386
387 LayoutContainer sliderContainer = new LayoutContainer();
388 sliderContainer.addStyleName(css.scaleSliderContainer());
389 scaleSlider = new Slider() {
390 @Override
391 protected String onFormatValue(int value) {
392 return Integer.toString((int)(svgModel.getScale() * 100)) + "%";
393 }
394
395 };
396 scaleSlider.addStyleName(css.scaleSlider());
397 sliderContainer.add(scaleSlider);
398 scaleSlider.setHeight(100);
399 scaleSlider.setMinValue(0);
400 scaleSlider.setMaxValue(100);
401 scaleSlider.setIncrement(1);
402 scaleSlider.setValue(50);
403 scaleSlider.setVertical(true);
404 layersContainer.add(sliderContainer, new AbsoluteLayerLayoutData(
405 AbsoluteLayerLayoutData.HORIZONTAL_ATTACH_RIGHT | AbsoluteLayerLayoutData.VERTICAL_ATTACH_TOP,
406 0,
407 0,
408 0,
409 0,
410 20));
411 scaleSlider.addListener(Events.Change, new Listener<SliderEvent>() {
412 @Override
413 public void handleEvent(SliderEvent be) {
414
415 int value = be.getNewValue();
416 float scale;
417 if (value >= 50) {
418 scale = 1f + (value - 50f) / 10f * 4 / 5;
419 } else {
420 scale = 1f / (1f + (49 - value) / 10f * 4 / 5);
421 }
422 svgModel.setScale(scale);
423 }
424 });
425
426
427
428
429
430
431
432
433
434
435
436
437
438 setLayout(new FitLayout());
439 add(splitterPanel, new FitData(4));
440
441
442
443
444
445
446
447 }
448
449 @Override
450 protected void moveDrag(DragEvent de) {
451 int windowBarHeight = SvgrealApp.getWindowBarHeight();
452 if (de.getY() < windowBarHeight) {
453 de.setY(windowBarHeight);
454 }
455 }
456
457 public SVGModel getSvgModel() {
458 return svgModel;
459 }
460
461 public TreePanelExt<SVGElementModel> getTree() {
462 return tree;
463 }
464
465
466
467
468
469
470 public void setScaleSlider(int value) {
471 scaleSlider.setValue(value);
472 }
473
474
475
476
477
478
479
480 public void setRotationCompass(int angleDeg) {
481 compass.setRotation(angleDeg);
482 }
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501 public void activate() {
502 GWT.log("SVGWindow(" + getHeading() + ").activate");
503 el().addStyleName(WINDOW_ACTIVE_STYLE);
504 TreePanelSelectionModel<SVGElementModel> selection = tree.getSelectionModel();
505 SelectionService.get().register(selection);
506 updateSelectionListeners();
507 }
508
509 public void updateSelectionListeners() {
510 TreePanelSelectionModel<SVGElementModel> selection = tree.getSelectionModel();
511 selection.fireEvent(Events.SelectionChange, new SelectionChangedEvent<SVGElementModel>(selection, selection.getSelectedItems()));
512 }
513
514 public void updateIcon(SVGElementModel model) {
515 tree.getView().onIconStyleChange(tree.findTreeNode(model), tree.getIconProvider().getIcon(model));
516 }
517
518 public void deactivate() {
519 GWT.log("SVGWindow(" + getHeading() + ").deactivate");
520 Object selection = tree.getSelectionModel();
521 SelectionService.get().unregister((SelectionProvider<ModelData>)selection);
522 el().removeStyleName(WINDOW_ACTIVE_STYLE);
523 }
524
525 @Override
526 protected void fitContainer() {
527 Rectangle rect = SvgrealApp.getApp().getRectangle();
528 setPosition(rect.x, rect.y);
529 setSize(rect.width, rect.height);
530 }
531
532 public void renameModel(final SVGElementModel model) {
533 final EditTitleCommandFactory commandFactory = (EditTitleCommandFactory) EditTitleCommandFactory.INSTANTIATOR.create();
534 commandFactory.start(this);
535 commandFactory.updateStatus(ModelConstants.INSTANCE.renameElementCmdFactory2());
536
537 final TextField<String> nameField = new TextField<String>();
538 Editor nameEditor = new Editor(nameField);
539 nameEditor.setAutoHeight(true);
540 nameEditor.setAutoWidth(true);
541 nameEditor.setCompleteOnEnter(true);
542 Listener<BaseEvent> editorListener = new Listener<BaseEvent>() {
543 @Override
544 public void handleEvent(BaseEvent be) {
545 GWT.log("Editor: " + be.getType());
546 if (be.getType() == Events.Complete) {
547 Record record = svgModel.getStore().getRecord(model);
548 record.set(SVGConstants.SVG_TITLE_TAG, nameField.getValue());
549 record.commit(false);
550 commandFactory.stop();
551 }
552 if (be.getType() == Events.CancelEdit) {
553 commandFactory.stop();
554 }
555 }
556 };
557 nameEditor.addListener(Events.Complete, editorListener);
558 nameEditor.addListener(Events.CancelEdit, editorListener);
559 TreeNode treeNode = tree.findTreeNode(model);
560 nameEditor.startEdit(treeNode.getElement(), model.get(SVGConstants.SVG_TITLE_TAG));
561 }
562
563
564 }
565