]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/color/ColorGradientComposite.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.utils.ui / src / org / simantics / utils / ui / color / ColorGradientComposite.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 package org.simantics.utils.ui.color;
13
14
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.HashMap;
18
19 import org.eclipse.jface.layout.GridDataFactory;
20 import org.eclipse.jface.util.IPropertyChangeListener;
21 import org.eclipse.jface.util.PropertyChangeEvent;
22 import org.eclipse.jface.viewers.CellEditor;
23 import org.eclipse.jface.viewers.ColorCellEditor;
24 import org.eclipse.jface.viewers.ICellEditorListener;
25 import org.eclipse.jface.viewers.ICellModifier;
26 import org.eclipse.jface.viewers.ILabelProviderListener;
27 import org.eclipse.jface.viewers.ISelectionChangedListener;
28 import org.eclipse.jface.viewers.IStructuredContentProvider;
29 import org.eclipse.jface.viewers.IStructuredSelection;
30 import org.eclipse.jface.viewers.ITableLabelProvider;
31 import org.eclipse.jface.viewers.SelectionChangedEvent;
32 import org.eclipse.jface.viewers.StructuredSelection;
33 import org.eclipse.jface.viewers.TableViewer;
34 import org.eclipse.jface.viewers.TextCellEditor;
35 import org.eclipse.jface.viewers.Viewer;
36 import org.eclipse.swt.SWT;
37 import org.eclipse.swt.events.SelectionEvent;
38 import org.eclipse.swt.events.SelectionListener;
39 import org.eclipse.swt.graphics.Image;
40 import org.eclipse.swt.graphics.RGB;
41 import org.eclipse.swt.layout.FillLayout;
42 import org.eclipse.swt.layout.GridLayout;
43 import org.eclipse.swt.widgets.Button;
44 import org.eclipse.swt.widgets.ColorDialog;
45 import org.eclipse.swt.widgets.Composite;
46 import org.eclipse.swt.widgets.Table;
47 import org.eclipse.swt.widgets.TableColumn;
48 import org.eclipse.swt.widgets.TableItem;
49
50 /**
51  * Widget to create and edit color gradients
52  * 
53  * @author Marko Luukkainen
54  *
55  */
56 public class ColorGradientComposite extends Composite implements ISelectionChangedListener, ICellEditorListener, IPropertyChangeListener{
57         private static int ICON_WIDTH = 36;
58         private static int ICON_HEIGHT = 14;
59         
60         private static final String COLOR_ID = "Color";
61         private static final String VALUE_ID = "Value";
62         
63         
64         private ColorGradientCanvas gradientComposite;
65         private TableViewer viewer;
66         private Button addButton;
67         private Button editButton;
68         private Button removeButton;
69         private Button rgbButton;
70         private Button hsvButton;
71         private int type = ColorGradient.RGB;
72         
73         private ArrayList<ColorValue> values = new ArrayList<ColorValue>();
74         private HashMap<ColorValue,Image> images = new HashMap<ColorValue,Image>();
75         
76         public ColorGradientComposite(Composite parent, int style) {
77                 super(parent,style);
78                 GridLayout layout = new GridLayout(2,false);
79             this.setLayout(layout);
80             gradientComposite = new ColorGradientCanvas(this,SWT.HORIZONTAL);
81             
82            
83             
84 //          Group typeComposite = new Group(this,SWT.NONE);
85 //          typeComposite.setText("Interpolation");
86             Composite typeComposite = new Composite(this, SWT.NONE);
87             
88             typeComposite.setLayout(new GridLayout(1,false));
89             rgbButton = new Button(typeComposite,SWT.RADIO);
90             rgbButton.setSelection(true);
91             rgbButton.addSelectionListener(new SelectionListener() {
92                 public void widgetDefaultSelected(SelectionEvent e) {
93                         widgetSelected(e);
94                 }
95                 public void widgetSelected(SelectionEvent e) {
96                         rgbButton.setSelection(true);
97                         hsvButton.setSelection(false);
98                         type = ColorGradient.RGB;
99                         gradientComposite.setGradient(new ColorGradient(values,type));
100                 }
101             });
102             rgbButton.setText("RGB");
103             hsvButton = new Button(typeComposite,SWT.RADIO);
104             hsvButton.addSelectionListener(new SelectionListener() {
105                 public void widgetDefaultSelected(SelectionEvent e) {
106                         widgetSelected(e);
107                 }
108                 public void widgetSelected(SelectionEvent e) {
109                         hsvButton.setSelection(true);
110                         rgbButton.setSelection(false);
111                         type = ColorGradient.HSV;
112                         gradientComposite.setGradient(new ColorGradient(values,type));
113                 }
114             });
115             hsvButton.setText("HSV");
116            
117             viewer = new TableViewer(this,SWT.SINGLE | SWT.BORDER | SWT.FULL_SELECTION);
118             final Table table = viewer.getTable();
119             
120             table.setLinesVisible(true);
121             table.setHeaderVisible(true);
122             
123             viewer.addSelectionChangedListener(this);
124             viewer.addPostSelectionChangedListener(this);
125             
126             TableColumn column = new TableColumn(table,SWT.RIGHT);
127             column.setText("Color");
128             column.setWidth(60);
129             column.setMoveable(false);
130             column.setResizable(false);
131             column = new TableColumn(table,SWT.LEFT);
132             column.setText("Value");
133             column.setWidth(300);
134             column.setMoveable(false);
135             
136             viewer.setColumnProperties(new String[]{COLOR_ID,VALUE_ID});
137             
138             viewer.setLabelProvider(new TableLabelProvider());
139             viewer.setContentProvider(new TableContentProvider());
140             viewer.setInput(values);
141             
142             final ColorCellEditor colorEditor = new ColorCellEditor(table);
143             final TextCellEditor valueEditor = new TextCellEditor(table);
144             colorEditor.addListener(this);
145             valueEditor.addListener(this);
146             valueEditor.addPropertyChangeListener(this);
147             viewer.setCellEditors(new CellEditor[]{colorEditor,valueEditor});
148             
149             viewer.setCellModifier(new TableCellEditorModifier());    
150             
151             Composite buttonComposite = new Composite(this,SWT.NONE);
152
153             buttonComposite.setLayout(new FillLayout(SWT.VERTICAL));
154             
155             addButton = new Button(buttonComposite,SWT.PUSH);
156             addButton.setText("Add new color");
157             addButton.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { 
158                 public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {    
159                         ColorDialog dialog = new ColorDialog(ColorGradientComposite.this.getShell(), SWT.NONE);
160                 
161                 RGB rgb = dialog.open();
162                 if (rgb != null) {
163                     Color c = new Color(rgb.red,rgb.green,rgb.blue);
164                     Double value;
165                     if (values.size() == 0) {
166                         value = 0.0;
167                     } else if (values.size() == 1) {
168                         value = 100.0;
169                     } else {
170                         StructuredSelection selection = (StructuredSelection)viewer.getSelection();
171                         if (selection.size() == 1) {
172                                 // add new color next to the selection
173                                 ColorValue v = (ColorValue)selection.getFirstElement();
174                                 int index = values.indexOf(v);
175                                 if (index == values.size() -1) {
176                                         index--;
177                                 }
178                                 value = (values.get(index+1).getValue()-values.get(index).getValue())*0.5;
179                                 value += values.get(index).getValue();
180                         } else {
181                                 // add new color to largest gap
182                                 int index = 0;
183                                 double r = 0.0;
184                                 for (int i = 0; i < values.size() -1; i++) {
185                                         double v1 = values.get(i).getValue();
186                                         double v2 = values.get(i+1).getValue();
187                                         double vr = v2 -v1;
188                                         if (vr > r) {
189                                                 r=vr;
190                                                 index = i;
191                                         }
192                                 }
193                                 value = values.get(index).getValue() + r *0.5;
194                         }
195                     }
196                     addColor(c,value);
197                 }
198             }
199         });
200             editButton = new Button(buttonComposite,SWT.PUSH);
201             editButton.setText("Edit color");
202             editButton.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { 
203                 public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {    
204                         TableItem selection[] = table.getSelection();
205                         if (selection.length > 0) {
206                                 TableItem selected = selection[0];
207                                 Object obj = selected.getData();
208                                 if (obj instanceof ColorValue) {
209                                         ColorDialog dialog = new ColorDialog(ColorGradientComposite.this.getShell(), SWT.NONE);
210                                         dialog.setRGB(getRGB(((ColorValue)obj).getColor()));
211                                         RGB rgb = dialog.open();
212                         if (rgb != null) {
213                                 modifyColorValueColor((ColorValue)obj,rgb);
214                         }
215                                 }                       
216                         }
217                 }
218         });
219             editButton.setEnabled(false);
220             removeButton = new Button(buttonComposite,SWT.PUSH);
221             removeButton.setText("Remove color");
222             removeButton.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() { 
223                 public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {    
224                         TableItem selection[] = table.getSelection();
225                         if (selection.length > 0) {
226                                 TableItem selected = selection[0];
227                                 Object o = selected.getData();
228                                 if (o instanceof ColorValue) {
229                                         Image i = images.get(o);
230                                         i.dispose();
231                                         images.remove(o);
232                                         values.remove(o);
233                                         updateWidgets();
234                                 }                       
235                         }
236                 }
237         });
238             removeButton.setEnabled(false);
239             
240             GridDataFactory.fillDefaults().span(1, 1).grab(true, false).align(SWT.FILL, SWT.CENTER).hint(SWT.DEFAULT, 32).applyTo(gradientComposite);
241             GridDataFactory.fillDefaults().grab(true, false).align(SWT.FILL, SWT.CENTER).hint(SWT.DEFAULT, 100).applyTo(table);
242             GridDataFactory.fillDefaults().grab(false, true).align(SWT.LEFT, SWT.FILL).applyTo(typeComposite);
243             GridDataFactory.fillDefaults().span(1, 1).grab(true, false).align(SWT.FILL, SWT.TOP).applyTo(buttonComposite);
244             
245             
246         }
247
248         public void addColor(Color color, double value) {
249                 addColor(new ColorValue(color,value));
250         }
251         
252         public void addColor(ColorValue value) {
253                 values.add(value);
254                 Image image = ColorIconCreator.createImage(value.getColor(), ICON_WIDTH, ICON_HEIGHT, SWT.BORDER);
255                 images.put(value,image);
256                 updateWidgets();
257                 //viewer.refresh(true);
258         }
259         
260         private void updateWidgets() {
261                 Collections.sort(values,new ColorValueComparator());    
262                 gradientComposite.setGradient(new ColorGradient(values,type));
263                 viewer.refresh();
264                 
265         }
266
267         public ColorGradient getGradient() {
268                 return new ColorGradient(values,type);
269         }
270
271         public void dispose() {
272                 for (Image i : images.values())
273                         i.dispose();
274                 super.dispose();
275         }
276         
277         public void setGradient(ColorGradient gradient) {
278                 for (Image i : images.values())
279                         i.dispose();
280                 values.clear();
281                 images.clear();
282                 type = gradient.getType();
283                 for (ColorValue value : gradient.getColorValues())
284                         addColor(value);
285                 if (type == ColorGradient.HSV) {
286                         rgbButton.setSelection(false);
287                         hsvButton.setSelection(true);
288                 } else if (type == ColorGradient.RGB) {
289                         hsvButton.setSelection(false);
290                         rgbButton.setSelection(true);
291                 }
292                 
293         }
294         
295         private RGB getRGB(Color color) {
296                 RGB rgb = new RGB(color.getR(),color.getG(),color.getB());
297                 return rgb;
298         }
299         
300         private void modifyColorValueValue(ColorValue cValue, String string) {
301                 try {
302                         double d = Double.parseDouble(string);
303                         values.remove(cValue);
304                         Image image = images.get(cValue);
305                         images.remove(cValue);
306                         ColorValue newCValue = new ColorValue(cValue.getColor(),d);
307                         values.add(newCValue);
308                         images.put(newCValue,image);
309                         updateWidgets();
310                         
311                 } catch (NumberFormatException e) {
312                         return;
313                 }
314         }
315         
316         private void modifyColorValueColor(ColorValue cValue, RGB rgb) {
317                 values.remove(cValue);
318                 Image oldImage = images.get(cValue);
319                 oldImage.dispose();
320                 images.remove(cValue);
321                 
322                 Color newColor = new Color(rgb.red,rgb.green,rgb.blue);
323                 ColorValue newCValue = new ColorValue(newColor,cValue.getValue());
324                 values.add(newCValue);
325                 Image newImage = ColorIconCreator.createImage(newColor, ICON_WIDTH, ICON_HEIGHT, SWT.BORDER);
326                 images.put(newCValue,newImage);
327                 updateWidgets();
328         }
329         
330         /**
331          * Enables and disables "Edit color" and "Remove color" buttons depending on selected item
332          */
333         public void selectionChanged(SelectionChangedEvent event) {
334                 Object obj = ((IStructuredSelection)event.getSelection()).getFirstElement();
335                 if (obj == null) {
336                         editButton.setEnabled(false);
337                         removeButton.setEnabled(false);
338                 } else {
339                         editButton.setEnabled(true);
340                         removeButton.setEnabled(true);
341                 }
342         }
343         
344         /*
345          * FIXME :
346          * If item is opened for editing selectionChanged won't get null selection and
347          * "Edit" & "Remove" buttons are enabled when there's no valid selection
348          * 
349          * There seems to be no way to get event when cellEditor is activated...
350          */
351         
352         public void applyEditorValue() {
353                 // TODO Auto-generated method stub
354                 editButton.setEnabled(false);
355                 removeButton.setEnabled(false); 
356         }
357         
358         public void cancelEditor() {
359                 // TODO Auto-generated method stub
360                 editButton.setEnabled(false);
361                 removeButton.setEnabled(false); 
362         }
363         
364         public void editorValueChanged(boolean oldValidState, boolean newValidState) {
365                 // TODO Auto-generated method stub
366                 editButton.setEnabled(false);
367                 removeButton.setEnabled(false); 
368         }
369         
370         public void propertyChange(PropertyChangeEvent event) {
371                 editButton.setEnabled(false);
372                 removeButton.setEnabled(false); 
373                 
374         }
375         /**
376          * @author Marko Luukkainen
377          *
378          */
379         private class TableLabelProvider implements ITableLabelProvider {
380                 private ArrayList<ILabelProviderListener> listeners = new ArrayList<ILabelProviderListener>();
381                                 
382                 /* (non-Javadoc)
383                  * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
384                  */
385                 public void dispose() {
386                                                 
387                 }
388                 /* (non-Javadoc)
389                  * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int)
390                  */
391                 public Image getColumnImage(Object element, int columnIndex) {
392                         //System.out.println("TableLabelProvider.getColumnImage() " + element + " , " + columnIndex);
393                         ColorValue value = (ColorValue)element;
394                         if (columnIndex == 0)
395                                 return images.get(value);
396                         return null;
397                 }
398                 /* (non-Javadoc)
399                  * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int)
400                  */
401                 public String getColumnText(Object element, int columnIndex) {
402                         //System.out.println("TableLabelProvider.getColumnText() " + element + " , " + columnIndex);
403                         ColorValue value = (ColorValue)element;
404                         if (columnIndex == 1)
405                                 return Double.toString(value.getValue());
406                         return null;
407                 }
408                 /* (non-Javadoc)
409                  * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java.lang.Object, java.lang.String)
410                  */
411                 public boolean isLabelProperty(Object element, String property) {
412                         return true;
413                 }
414                 /* (non-Javadoc)
415                  * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse.jface.viewers.ILabelProviderListener)
416                  */
417                 public void addListener(ILabelProviderListener listener) {
418                         if(!listeners.contains(listener))
419                                 listeners.add(listener);                        
420                 }
421                 /* (non-Javadoc)
422                  * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse.jface.viewers.ILabelProviderListener)
423                  */
424                 public void removeListener(ILabelProviderListener listener) {
425                         listeners.remove(listener);
426                 }
427                 
428                 
429         }
430         
431         /**
432          * @author Marko Luukkainen
433          *
434          */
435         private class TableContentProvider implements IStructuredContentProvider {
436                 public void dispose() {
437                         
438                 }
439                 public Object[] getElements(Object inputElement) {
440                         ColorValue valueArray[] = new ColorValue[values.size()];
441                         // values.toArray(valueArray);
442             // to get correct ordering (smallest last)
443             // we must reverse the order of the list
444             for (int i = 0; i < values.size(); i++) {
445                             valueArray[i] = values.get(values.size() - 1 -i);
446             }
447             //System.out.println("TableContentProvider.getElements() : array size " + valueArray.length);
448                         return valueArray;
449                 }
450                 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
451                         //System.out.println("TableContentProvider.inputChanged()");
452                         
453                 }
454         }
455         
456         /**
457          * @author Marko Luukkainen
458          *
459          */
460         private class TableCellEditorModifier implements ICellModifier {
461                 public boolean canModify(Object element, String property) {
462                         //System.out.println("TableCellEditorModifier.canModify()" + element + " , " + property);
463                         if (property == VALUE_ID)
464                                 return true;
465                         // this is commented out because it's hard so select the row when both rows have editors
466                         // now the color can be changed with "Edit Color" button
467                         //if (property == COLOR_ID)
468                         //      return true;
469                         return false;
470                 }
471                 public Object getValue(Object element, String property) {
472                         //System.out.println("TableCellEditorModifier.getValue()" + element + " , " + property);
473                         if (property == VALUE_ID)
474                                 return Double.toString(((ColorValue)element).getValue());
475                         if (property == COLOR_ID) 
476                                 return getRGB(((ColorValue)element).getColor());
477                         return null;
478                         
479                 }
480                 public void modify(Object element, String property, Object value) {
481                         TableItem item = (TableItem)element;
482                         Object obj = item.getData();
483                         //System.out.println("TableCellEditorModifier.modify()" + element + " , " + property + " , " + value);
484                         if (property == VALUE_ID)
485                                 modifyColorValueValue((ColorValue)obj,(String)value);
486                         if (property == COLOR_ID)
487                                 modifyColorValueColor((ColorValue)obj,(RGB)value);
488                 }
489                 
490         }
491 }
492
493