View Javadoc

1   /**********************************************
2    * Copyright (C) 2011 Lukas Laag
3    * This file is part of svgreal.
4    * 
5    * svgreal is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    * 
10   * svgreal is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   * 
15   * You should have received a copy of the GNU General Public License
16   * along with svgreal.  If not, see http://www.gnu.org/licenses/
17   **********************************************/
18  package org.vectomatic.svg.edit.client.gxt.panels;
19  
20  import java.util.ArrayList;
21  import java.util.Arrays;
22  import java.util.List;
23  
24  import org.vectomatic.dom.svg.OMCSSPrimitiveValue;
25  import org.vectomatic.svg.edit.client.AppConstants;
26  import org.vectomatic.svg.edit.client.SvgrealApp;
27  import org.vectomatic.svg.edit.client.gxt.widget.DashArrayCell;
28  import org.vectomatic.svg.edit.client.model.svg.CssContextModel;
29  import org.vectomatic.svg.edit.client.model.svg.DashArray;
30  import org.vectomatic.svg.edit.client.model.svg.DashArray.Dash;
31  import org.vectomatic.svg.edit.client.model.svg.DashArrayStore;
32  
33  import com.extjs.gxt.ui.client.Style.Orientation;
34  import com.extjs.gxt.ui.client.data.ModelData;
35  import com.extjs.gxt.ui.client.event.ButtonEvent;
36  import com.extjs.gxt.ui.client.event.EventType;
37  import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
38  import com.extjs.gxt.ui.client.event.SelectionChangedListener;
39  import com.extjs.gxt.ui.client.event.SelectionListener;
40  import com.extjs.gxt.ui.client.store.ListStore;
41  import com.extjs.gxt.ui.client.store.Store;
42  import com.extjs.gxt.ui.client.store.StoreEvent;
43  import com.extjs.gxt.ui.client.store.StoreListener;
44  import com.extjs.gxt.ui.client.util.Margins;
45  import com.extjs.gxt.ui.client.util.Padding;
46  import com.extjs.gxt.ui.client.widget.Label;
47  import com.extjs.gxt.ui.client.widget.LayoutContainer;
48  import com.extjs.gxt.ui.client.widget.Window;
49  import com.extjs.gxt.ui.client.widget.button.Button;
50  import com.extjs.gxt.ui.client.widget.form.ComboBox.TriggerAction;
51  import com.extjs.gxt.ui.client.widget.form.SimpleComboBox;
52  import com.extjs.gxt.ui.client.widget.form.SpinnerField;
53  import com.extjs.gxt.ui.client.widget.grid.CellEditor;
54  import com.extjs.gxt.ui.client.widget.grid.ColumnConfig;
55  import com.extjs.gxt.ui.client.widget.grid.ColumnData;
56  import com.extjs.gxt.ui.client.widget.grid.ColumnModel;
57  import com.extjs.gxt.ui.client.widget.grid.EditorGrid;
58  import com.extjs.gxt.ui.client.widget.grid.EditorGrid.ClicksToEdit;
59  import com.extjs.gxt.ui.client.widget.grid.Grid;
60  import com.extjs.gxt.ui.client.widget.grid.GridCellRenderer;
61  import com.extjs.gxt.ui.client.widget.grid.GridSelectionModel;
62  import com.extjs.gxt.ui.client.widget.layout.RowData;
63  import com.extjs.gxt.ui.client.widget.layout.RowLayout;
64  import com.extjs.gxt.ui.client.widget.layout.VBoxLayout;
65  import com.extjs.gxt.ui.client.widget.layout.VBoxLayout.VBoxLayoutAlign;
66  import com.extjs.gxt.ui.client.widget.layout.VBoxLayoutData;
67  import com.google.gwt.core.client.GWT;
68  import com.google.gwt.dom.client.Style;
69  import com.google.gwt.event.logical.shared.CloseEvent;
70  import com.google.gwt.event.logical.shared.CloseHandler;
71  import com.google.gwt.event.logical.shared.HasCloseHandlers;
72  import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
73  import com.google.gwt.event.logical.shared.ValueChangeEvent;
74  import com.google.gwt.event.logical.shared.ValueChangeHandler;
75  import com.google.gwt.event.shared.GwtEvent;
76  import com.google.gwt.event.shared.HandlerRegistration;
77  
78  /**
79   * Window class to implement a dash pattern editor
80   * @author laaglu
81   */
82  public class DashArrayEditor extends Window implements HasCloseHandlers<DashArrayEditor>, HasValueChangeHandlers<DashArray> {
83  	/**
84  	 * A store of defined dash arrays
85  	 */
86  	private DashArrayStore dashArrays;
87  	/**
88  	 * The dash array currently being edited
89  	 */
90  	private GridSelectionModel<DashArray> dashArraySelectionModel;
91  	/**
92  	 * Listens to changes in the dash array currently being edited
93  	 */
94  	private StoreListener<Dash> storeListener;
95  	private EditorGrid<Dash> dashGrid;
96  	private GridSelectionModel<Dash> dashSelectionModel;
97  	private Button removeDashArrayButton;
98  	private Button addDashButton;
99  	private Button removeDashButton;
100 	private ColumnModel dashModel;
101 	private SelectionChangedListener<Dash> dashSelectionListener;
102 	private static final ListStore<Dash> NO_DASH = new ListStore<Dash>();
103 	
104 	public DashArrayEditor() {
105 		AppConstants appConstants = AppConstants.INSTANCE;
106 		setPlain(true);
107 	    setModal(true);  
108 	    setBlinkModal(true);
109 		setMaximizable(true);
110 		setSize(500, 300);
111 		setMinWidth(500);
112 		setMinHeight(300);
113 		setHeading(appConstants.dashArrayEditor());
114 		
115 		////////////////////////////////
116 		// Left part: dash-array list
117 		////////////////////////////////
118 		Label dashArraysLabel = new Label(appConstants.dashArraysLabel());
119 		
120 		List<ColumnConfig> arrayConfigs = new ArrayList<ColumnConfig>();
121 		ColumnConfig dashArrayColumn = new ColumnConfig();
122 		dashArrayColumn.setSortable(false);
123 		dashArrayColumn.setId(DashArray.STORE_PROPERTY);
124 		dashArrayColumn.setWidth(220);
125 		dashArrayColumn.setRenderer(new GridCellRenderer<DashArray>() {
126 			@Override
127 			public Object render(DashArray model, String property,
128 					ColumnData config, int rowIndex, int colIndex,
129 					ListStore<DashArray> store, Grid<DashArray> grid) {
130 				DashArrayCell cell = new DashArrayCell();
131 				cell.setDashArray(model);
132 				return cell;
133 			}
134 		});
135 		arrayConfigs.add(dashArrayColumn);
136 		ColumnModel arrayModel = new ColumnModel(arrayConfigs);
137 		dashArrays = new DashArrayStore();
138 		dashArrays.add(CssContextModel.getDefaultDashArrays().getModels());
139 		Grid<DashArray> dashArrayGrid = new Grid<DashArray>(dashArrays, arrayModel);
140 		dashArrayGrid.setHideHeaders(true);
141 		dashArrayGrid.setBorders(true);
142 		
143 		dashArraySelectionModel = dashArrayGrid.getSelectionModel();
144 		storeListener = new StoreListener<Dash>() {
145 			public void handleEvent(StoreEvent<Dash> e) {
146 				EventType type = e.getType();
147 				if (type == Store.Add
148 				 || type == Store.Remove
149 				 || type == Store.Update) {
150 					dashArrays.fireStoreUpdateEvent();
151 					ValueChangeEvent.fire(DashArrayEditor.this, dashArraySelectionModel.getSelectedItem());
152 				}
153 			}
154 		};
155 		dashArraySelectionModel.addSelectionChangedListener(new SelectionChangedListener<DashArray>() {
156 			@Override
157 			public void selectionChanged(SelectionChangedEvent<DashArray> se) {
158 				// Cleanup previous listeners
159 				dashGrid.getStore().removeStoreListener(storeListener);
160 				dashGrid.getSelectionModel().removeSelectionListener(dashSelectionListener);
161 				
162 				// Bind to selected dash array
163 				DashArray dashArray = se.getSelectedItem();
164 				ListStore<Dash> dashStore = NO_DASH;
165 				if (dashArray != null) {
166 					dashStore = dashArray.<ListStore<Dash>>get(DashArray.STORE_PROPERTY);
167 					dashStore.addStoreListener(storeListener);
168 				}
169 				dashGrid.reconfigure(dashStore, dashModel);
170 				dashSelectionModel = new GridSelectionModel<Dash>();
171 				dashGrid.setSelectionModel(dashSelectionModel);
172 				dashSelectionModel.addSelectionChangedListener(dashSelectionListener);
173 				update();
174 				ValueChangeEvent.fire(DashArrayEditor.this, dashArray);
175 			}
176 		});
177 		
178 		Button addDashArrayButton = new Button(appConstants.addButton());
179 		addDashArrayButton.setToolTip(appConstants.addDashArrayTip());
180 		addDashArrayButton.addSelectionListener(new SelectionListener<ButtonEvent>() {	
181 			@Override
182 			public void componentSelected(ButtonEvent ce) {
183 				addDashArray();
184 			}
185 		});
186 		
187 		removeDashArrayButton = new Button(appConstants.removeButton());
188 		removeDashArrayButton.setToolTip(appConstants.removeDashArrayTip());
189 		removeDashArrayButton.addSelectionListener(new SelectionListener<ButtonEvent>() {
190 			@Override
191 			public void componentSelected(ButtonEvent ce) {
192 				removeDashArray();				
193 			}
194 		});
195 		LayoutContainer leftButtonContainer = new LayoutContainer();
196 		leftButtonContainer.setLayout(new RowLayout(Orientation.HORIZONTAL));
197 		RowData rowData = new RowData(.5, 1);
198 		leftButtonContainer.add(addDashArrayButton, rowData);
199 		leftButtonContainer.add(removeDashArrayButton, rowData);
200 		leftButtonContainer.setHeight(30);
201 		LayoutContainer leftContainer = new LayoutContainer();
202         VBoxLayout leftLayout = new VBoxLayout();  
203         leftLayout.setPadding(new Padding(5));  
204         leftLayout.setVBoxLayoutAlign(VBoxLayoutAlign.STRETCH);
205         VBoxLayoutData vbl1 = new VBoxLayoutData(new Margins(0, 0, 5, 0));
206         VBoxLayoutData vbl2 = new VBoxLayoutData(new Margins(0, 0, 5, 0));
207         vbl2.setFlex(1);
208         VBoxLayoutData vbl3 = new VBoxLayoutData(new Margins(0));
209 		leftContainer.setLayout(leftLayout);
210 		leftContainer.add(dashArraysLabel, vbl1);
211 		leftContainer.add(dashArrayGrid, vbl2);
212 		leftContainer.add(leftButtonContainer, vbl3);
213 
214 		
215 		////////////////////////////////
216 		// Right part: current dash array
217 		////////////////////////////////
218 		
219 		Label dashArrayLabel = new Label(appConstants.dashArrayLabel());
220 		
221 		List<ColumnConfig> dashConfigs = new ArrayList<ColumnConfig>();
222 
223 		SpinnerField valueField = new SpinnerField();
224 		valueField.setFireChangeEventOnSetValue(true);
225 		valueField.setAllowDecimals(false);
226 		valueField.setAllowNegative(false);
227 		ColumnConfig valueColumn = new ColumnConfig();
228 		valueColumn.setSortable(false);
229 		valueColumn.setId(Dash.VALUE_PROPERTY);
230 		valueColumn.setHeader(appConstants.dashValue());
231 		valueColumn.setWidth(160);
232 		valueColumn.setEditor(new CellEditor(valueField));
233 		dashConfigs.add(valueColumn); 
234 
235 		final SimpleComboBox<Style.Unit> unitField = new SimpleComboBox<Style.Unit>();
236 		unitField.setForceSelection(true);
237 		unitField.setTriggerAction(TriggerAction.ALL);
238 		unitField.add(Arrays.asList(Style.Unit.values()));
239 
240 		ColumnConfig unitColumn = new ColumnConfig();
241 		unitColumn.setSortable(false);
242 		unitColumn.setId(Dash.UNIT_PROPERTY);
243 		unitColumn.setHeader(appConstants.dashUnit());
244 		unitColumn.setWidth(60);
245 		CellEditor unitEditor = new CellEditor(unitField) {
246 			@Override
247 			public Object preProcessValue(Object value) {
248 				if (value == null) {
249 					return value;
250 				}
251 				return unitField.findModel((Style.Unit)value);
252 			}
253 
254 			@Override
255 			public Object postProcessValue(Object value) {
256 				if (value == null) {
257 					return value;
258 				}
259 				return ((ModelData) value).get("value");
260 			}
261 		};
262 		unitColumn.setEditor(unitEditor);
263 		dashConfigs.add(unitColumn); 
264 
265 		dashModel = new ColumnModel(dashConfigs);
266 		dashGrid = new EditorGrid<Dash>(NO_DASH, dashModel);
267 		dashGrid.setClicksToEdit(ClicksToEdit.TWO);
268 		dashGrid.setAutoExpandColumn(Dash.VALUE_PROPERTY);  
269 		dashGrid.setBorders(true);
270 		dashSelectionListener = new SelectionChangedListener<Dash>() {
271 			@Override
272 			public void selectionChanged(SelectionChangedEvent<Dash> se) {
273 				GWT.log("dashSelectionModel.selectionChanged");
274 				update();
275 			}
276 		};
277 
278 		addDashButton = new Button(appConstants.addButton());
279 		addDashButton.setToolTip(appConstants.addDashTip());
280 		addDashButton.addSelectionListener(new SelectionListener<ButtonEvent>() {
281 			@Override
282 			public void componentSelected(ButtonEvent ce) {
283 				addDash();
284 			}
285 		});
286 		
287 		removeDashButton = new Button(appConstants.removeButton());
288 		removeDashButton.setToolTip(appConstants.removeDashTip());
289 		removeDashButton.addSelectionListener(new SelectionListener<ButtonEvent>() {
290 			@Override
291 			public void componentSelected(ButtonEvent ce) {
292 				removeDash();
293 			}
294 		});
295 		LayoutContainer rightButtonContainer = new LayoutContainer();
296 		rightButtonContainer.setLayout(new RowLayout(Orientation.HORIZONTAL));
297 		rightButtonContainer.add(addDashButton, rowData);
298 		rightButtonContainer.add(removeDashButton, rowData);
299 		rightButtonContainer.setHeight(30);
300 		LayoutContainer rightContainer = new LayoutContainer();
301         VBoxLayout rightLayout = new VBoxLayout();  
302         rightLayout.setPadding(new Padding(5));
303         rightLayout.setVBoxLayoutAlign(VBoxLayoutAlign.STRETCH);
304         rightContainer.setLayout(rightLayout);
305 		rightContainer.add(dashArrayLabel, vbl1);
306 		rightContainer.add(dashGrid, vbl2);
307 		rightContainer.add(rightButtonContainer, vbl3);
308 
309 		////////////////////////////////
310 		// final assembly
311 		////////////////////////////////
312 
313 		setLayout(new RowLayout(Orientation.HORIZONTAL));
314 	    rowData.setMargins(new Margins(5));  
315 	     
316 	    add(leftContainer, rowData);  
317 	    add(rightContainer, rowData);
318 	    
319 	    Button okButton = new Button(appConstants.commitButton());
320 	    okButton.addSelectionListener(new SelectionListener<ButtonEvent>() {
321 			@Override
322 			public void componentSelected(ButtonEvent ce) {
323 				GWT.log("DashArrayEditor.ok");
324 				hide();
325 				CloseEvent.<DashArrayEditor>fire(DashArrayEditor.this, DashArrayEditor.this, false);
326 			}
327 		});
328 	    addButton(okButton);
329 	    Button cancelButton = new Button(appConstants.cancelButton());
330 	    cancelButton.addSelectionListener(new SelectionListener<ButtonEvent>() {
331 			@Override
332 			public void componentSelected(ButtonEvent ce) {
333 				GWT.log("DashArrayEditor.cancel");
334 				hide();
335 				CloseEvent.<DashArrayEditor>fire(DashArrayEditor.this, DashArrayEditor.this, true);
336 			}
337 		});
338 	    addButton(cancelButton);
339 	}
340 	
341 	@Override
342 	public void show() {
343 		super.show();
344 		layout(true);
345 	}
346 	
347 	public void addDashArray() {
348 		GWT.log("DashArrayEditor.addDashArray");
349 		dashArrays.add(DashArray.parse(""));
350 	}
351 	
352 	public void removeDashArray() {
353 		GWT.log("DashArrayEditor.removeDashArray");
354 		dashArrays.remove(dashArraySelectionModel.getSelectedItem());
355 	}
356 	
357 	public DashArrayStore getDashArrays() {
358 		return dashArrays;
359 	}
360 	
361 	public void addDash() {
362 		GWT.log("DashArrayEditor.addDash");
363 		ListStore<Dash> dashStore = dashGrid.getStore();
364 		dashStore.add(new Dash(new OMCSSPrimitiveValue(1, OMCSSPrimitiveValue.CSS_NUMBER)));
365 	}
366 	
367 	public void removeDash() {
368 		GWT.log("DashArrayEditor.removeDash");
369 		ListStore<Dash> dashStore = dashGrid.getStore();
370 		for (Dash dash : dashSelectionModel.getSelectedItems()) {
371 			dashStore.remove(dash);
372 		}
373 		update();
374 	}
375 	
376 	public void update() {
377 		removeDashArrayButton.setEnabled(dashArraySelectionModel.getSelectedItem() != null);
378 		ListStore<Dash> dashStore = dashGrid.getStore();
379 		addDashButton.setEnabled(dashStore != NO_DASH);
380 		removeDashButton.setEnabled(dashStore != NO_DASH && dashSelectionModel.getSelectedItem() != null);
381 	}
382 
383 	///////////////////////////////////////////////////
384 	// Event management
385 	///////////////////////////////////////////////////
386 
387 	@Override
388 	public HandlerRegistration addValueChangeHandler(ValueChangeHandler<DashArray> handler) {
389 		return SvgrealApp.getApp().getEventBus().addHandlerToSource(ValueChangeEvent.getType(), this, handler);
390 	}
391 
392 	@Override
393 	public HandlerRegistration addCloseHandler(CloseHandler<DashArrayEditor> handler) {
394 		return SvgrealApp.getApp().getEventBus().addHandlerToSource(CloseEvent.getType(), this, handler);
395 	}
396 	
397 	@Override
398 	public void fireEvent(GwtEvent<?> event) {
399 		SvgrealApp.getApp().getEventBus().fireEventFromSource(event, this);
400 	}
401 }