]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagramEditor/DiagramLayersPage.java
Sync git svn branch with SVN repository r33406.
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / diagramEditor / DiagramLayersPage.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.modeling.ui.diagramEditor;\r
13 \r
14 import java.util.ArrayList;\r
15 import java.util.Collection;\r
16 import java.util.Collections;\r
17 import java.util.Set;\r
18 \r
19 import org.eclipse.jface.layout.GridDataFactory;\r
20 import org.eclipse.jface.layout.GridLayoutFactory;\r
21 import org.eclipse.jface.viewers.CellLabelProvider;\r
22 import org.eclipse.jface.viewers.CheckStateChangedEvent;\r
23 import org.eclipse.jface.viewers.CheckboxTreeViewer;\r
24 import org.eclipse.jface.viewers.ICheckStateListener;\r
25 import org.eclipse.jface.viewers.ICheckStateProvider;\r
26 import org.eclipse.jface.viewers.ISelection;\r
27 import org.eclipse.jface.viewers.ISelectionChangedListener;\r
28 import org.eclipse.jface.viewers.ITreeContentProvider;\r
29 import org.eclipse.jface.viewers.SelectionChangedEvent;\r
30 import org.eclipse.jface.viewers.TreeViewer;\r
31 import org.eclipse.jface.viewers.Viewer;\r
32 import org.eclipse.jface.viewers.ViewerCell;\r
33 import org.eclipse.swt.SWT;\r
34 import org.eclipse.swt.custom.TreeEditor;\r
35 import org.eclipse.swt.events.KeyAdapter;\r
36 import org.eclipse.swt.events.KeyEvent;\r
37 import org.eclipse.swt.events.SelectionEvent;\r
38 import org.eclipse.swt.events.SelectionListener;\r
39 import org.eclipse.swt.graphics.Color;\r
40 import org.eclipse.swt.graphics.GC;\r
41 import org.eclipse.swt.graphics.Point;\r
42 import org.eclipse.swt.graphics.Rectangle;\r
43 import org.eclipse.swt.widgets.Button;\r
44 import org.eclipse.swt.widgets.Composite;\r
45 import org.eclipse.swt.widgets.Control;\r
46 import org.eclipse.swt.widgets.Event;\r
47 import org.eclipse.swt.widgets.Listener;\r
48 import org.eclipse.swt.widgets.Text;\r
49 import org.eclipse.swt.widgets.Tree;\r
50 import org.eclipse.swt.widgets.TreeColumn;\r
51 import org.eclipse.swt.widgets.TreeItem;\r
52 import org.eclipse.ui.part.Page;\r
53 import org.simantics.diagram.layer.ILayersViewPage;\r
54 import org.simantics.g2d.canvas.ICanvasContext;\r
55 import org.simantics.g2d.diagram.DiagramHints;\r
56 import org.simantics.g2d.diagram.IDiagram;\r
57 import org.simantics.g2d.diagram.participant.Selection;\r
58 import org.simantics.g2d.element.ElementClass;\r
59 import org.simantics.g2d.element.IElement;\r
60 import org.simantics.g2d.element.handler.ElementLayers;\r
61 import org.simantics.g2d.layers.IEditableLayer;\r
62 import org.simantics.g2d.layers.ILayer;\r
63 import org.simantics.g2d.layers.ILayers;\r
64 import org.simantics.g2d.layers.ILayersEditor;\r
65 import org.simantics.g2d.layers.SimpleLayer;\r
66 import org.simantics.g2d.layers.ILayersEditor.ILayersEditorListener;\r
67 import org.simantics.utils.datastructures.Arrays;\r
68 import org.simantics.utils.datastructures.hints.HintListenerAdapter;\r
69 import org.simantics.utils.datastructures.hints.IHintListener;\r
70 import org.simantics.utils.datastructures.hints.IHintObservable;\r
71 import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
72 import org.simantics.utils.ui.ISelectionUtils;\r
73 \r
74 public class DiagramLayersPage extends Page implements ILayersViewPage {\r
75 \r
76     private static final String TEXT_APPLY_FOCUS_SETTINGS = "Focus Active";\r
77     private static final String TOOLTIP_APPLY_FOCUS_SETTINGS = "Only Focus Diagram Elements For Active Roles";\r
78     private static final String TEXT_IGNORE_FOCUS_SETTINGS = "Focus All";\r
79     private static final String TOOLTIP_IGNORE_FOCUS_SETTINGS = "Focus All Diagram Elements Regardless Of Active Roles";\r
80 \r
81     private static final String TEXT_APPLY_VISIBILITY_SETTINGS = "Show Active";\r
82     private static final String TOOLTIP_APPLY_VISIBILITY_SETTINGS = "Only Show Diagram Elements For Active Roles";\r
83     private static final String TEXT_IGNORE_VISIBILITY_SETTINGS = "Show All";\r
84     private static final String TOOLTIP_IGNORE_VISIBILITY_SETTINGS = "Show All Diagram Elements Regardless Of Active Roles";\r
85 \r
86     final private ICanvasContext context;\r
87     final private IDiagram diagram;\r
88     private CheckboxTreeViewer viewer;\r
89     private Composite composite;\r
90     private TreeEditor editor;\r
91 \r
92     private Collection<IElement> elements = Collections.emptySet();\r
93 \r
94     enum Attribute {\r
95         Visible,\r
96         Focusable\r
97     }\r
98 \r
99     enum Tristate {\r
100         True,\r
101         False,\r
102         Both;\r
103 \r
104         static Tristate to(Boolean b) {\r
105             return b == null ? null : b ? True : False;\r
106         }\r
107         boolean toBoolean() {\r
108             switch (this) {\r
109                 case Both:\r
110                     throw new IllegalStateException("cannot convert Tristate Both to boolean");\r
111                 case False:\r
112                     return false;\r
113                 case True:\r
114                     return true;\r
115                 default:\r
116                     return false;\r
117             }\r
118         }\r
119         Tristate toggle() {\r
120             switch (this) {\r
121                 case Both:\r
122                 case False:\r
123                     return True;\r
124                 case True:\r
125                     return False;\r
126                 default:\r
127                     return False;\r
128             }\r
129         }\r
130         Tristate merge(Tristate state) {\r
131             if (state == null)\r
132                 return this;\r
133             switch (this) {\r
134                 case Both:\r
135                     return Both;\r
136                 case False:\r
137                     switch (state) {\r
138                         case False:\r
139                             return False;\r
140                         case Both:\r
141                         case True:\r
142                             return Both;\r
143                     }\r
144                 case True:\r
145                     switch (state) {\r
146                         case True:\r
147                             return True;\r
148                         case False:\r
149                         case Both:\r
150                             return Both;\r
151                     }\r
152             }\r
153             return this;\r
154         }\r
155     }\r
156 \r
157     Boolean getAttribute(IElement e, ILayer layer, Attribute attribute) {\r
158         ElementClass ec = e.getElementClass();\r
159         for (ElementLayers el : ec.getItemsByClass(ElementLayers.class)) {\r
160             switch (attribute) {\r
161                 case Visible:\r
162                     return Boolean.valueOf(el.isVisible(e, layer));\r
163                 case Focusable:\r
164                     return Boolean.valueOf(el.isFocusable(e, layer));\r
165             }\r
166         }\r
167         return null;\r
168     }\r
169 \r
170     boolean setAttribute(IElement e, ILayer layer, Attribute attribute, boolean value) {\r
171         ElementClass ec = e.getElementClass();\r
172         for (ElementLayers el : ec.getItemsByClass(ElementLayers.class)) {\r
173             switch (attribute) {\r
174                 case Visible:\r
175                     return el.setVisibility(e, layer, value);\r
176                 case Focusable:\r
177                     return el.setFocusability(e, layer, value);\r
178             }\r
179         }\r
180         return false;\r
181     }\r
182 \r
183     Tristate getJointAttribute(Collection<IElement> elements, ILayer layer, Attribute attribute) {\r
184         Tristate state = null;\r
185         for (IElement e : elements) {\r
186             Boolean attr = getAttribute(e, layer, attribute);\r
187             if (attr == null)\r
188                 continue;\r
189 \r
190             if (state == null) {\r
191                 state = Tristate.to(attr);\r
192             } else {\r
193                 state = state.merge(Tristate.to(attr));\r
194             }\r
195         }\r
196         return state;\r
197     }\r
198 \r
199     int setAttribute(Collection<IElement> elements, ILayer layer, Attribute attribute, boolean value) {\r
200         int result = 0;\r
201         for (IElement e : elements) {\r
202             if (setAttribute(e, layer, attribute, value))\r
203                 ++result;\r
204         }\r
205         return result;\r
206     }\r
207 \r
208 \r
209     final private IHintListener selectionListener = new HintListenerAdapter() {\r
210 \r
211         @Override\r
212         public void hintChanged(IHintObservable sender, Key key, Object oldValue, Object newValue) {\r
213             Collection<IElement> es = Collections.emptySet();\r
214             if (newValue instanceof Collection<?>) {\r
215                 Collection<?> coll = (Collection<?>)newValue;\r
216                 es = new ArrayList<IElement>(coll.size());\r
217                 for (Object o : coll) {\r
218                     if (!(o instanceof IElement))\r
219                         return;\r
220                     es.add((IElement) o);\r
221                 }\r
222                 if (es.isEmpty())\r
223                     es = Collections.emptySet();\r
224             }\r
225             elements = es;\r
226             redraw();\r
227         }\r
228 \r
229         private void redraw() {\r
230             viewer.getControl().getDisplay().asyncExec(new Runnable() {\r
231                 @Override\r
232                 public void run() {\r
233                     if (viewer.getControl().isDisposed())\r
234                         return;\r
235                     viewer.getControl().redraw();\r
236                 }\r
237             });\r
238         }\r
239     };\r
240 \r
241     public DiagramLayersPage(IDiagram diagram, ICanvasContext context) {\r
242 \r
243         assert(diagram != null);\r
244 \r
245         this.diagram = diagram;\r
246         this.context = context;\r
247 \r
248         context.getDefaultHintContext().addKeyHintListener(Selection.SELECTION0, selectionListener);\r
249     }\r
250 \r
251     @Override\r
252     public void dispose() {\r
253 \r
254         context.getDefaultHintContext().removeKeyHintListener(Selection.SELECTION0, selectionListener);\r
255 \r
256         super.dispose();\r
257 \r
258     }\r
259 \r
260     @Override\r
261     public void createControl(Composite parent) {\r
262 \r
263         final ILayersEditor layers = diagram.getHint(DiagramHints.KEY_LAYERS_EDITOR);\r
264         layers.addListener(new ILayersEditorListener() {\r
265 \r
266             @Override\r
267             public void layerRemoved(ILayer layer) {\r
268                 scheduleRefresh();\r
269             }\r
270 \r
271             @Override\r
272             public void layerAdded(ILayer layer) {\r
273                 scheduleRefresh();\r
274             }\r
275 \r
276             @Override\r
277             public void layerActivated(ILayer layer) {\r
278                 scheduleRefresh();\r
279             }\r
280 \r
281             @Override\r
282             public void layerDeactivated(ILayer layer) {\r
283                 scheduleRefresh();\r
284             }\r
285 \r
286             @Override\r
287             public void ignoreFocusChanged(boolean value) {\r
288             }\r
289 \r
290             @Override\r
291             public void ignoreVisibilityChanged(boolean value) {\r
292             }\r
293 \r
294             void scheduleRefresh() {\r
295                 viewer.getControl().getDisplay().asyncExec(new Runnable() {\r
296                     @Override\r
297                     public void run() {\r
298                         viewer.refresh();\r
299                     }\r
300                 });\r
301             }\r
302         });\r
303 \r
304         composite = new Composite(parent, SWT.NONE);\r
305         GridLayoutFactory.fillDefaults().numColumns(4).applyTo(composite);\r
306 \r
307         Button addButton = new Button(composite, SWT.NONE);\r
308         addButton.setText("New");\r
309         addButton.setToolTipText("Create New Diagram Role");\r
310         addButton.addSelectionListener(new SelectionListener() {\r
311 \r
312             String findFreshName(ILayers layers, String proposal) {\r
313                 Set<ILayer> all = layers.getLayers();\r
314                 String name = proposal;\r
315                 int i = 1;\r
316                 while (true) {\r
317                     boolean match = false;\r
318                     for (ILayer layer : all) {\r
319                         if (name.equals(layer.getName())) {\r
320                             match = true;\r
321                             break;\r
322                         }\r
323                     }\r
324                     if (!match)\r
325                         return name;\r
326                     ++i;\r
327                     name = proposal + " " + i;\r
328                 }\r
329             }\r
330 \r
331             @Override\r
332             public void widgetSelected(SelectionEvent e) {\r
333                 String name = findFreshName(layers, "New Role");\r
334                 SimpleLayer layer = new SimpleLayer(name);\r
335                 layers.addLayer(layer);\r
336                 layers.activate(layer);\r
337             }\r
338 \r
339             @Override\r
340             public void widgetDefaultSelected(SelectionEvent e) {\r
341                 widgetSelected(e);\r
342             }\r
343 \r
344         });\r
345 \r
346         final Button removeButton = new Button(composite, SWT.NONE);\r
347         removeButton.setText("Remove");\r
348         removeButton.setToolTipText("Remove Selected Diagram Role");\r
349         removeButton.addSelectionListener(new SelectionListener() {\r
350             @Override\r
351             public void widgetSelected(SelectionEvent e) {\r
352                 TreeItem[] items = viewer.getTree().getSelection();\r
353                 if (items.length == 0)\r
354                     return;\r
355 \r
356                 TreeItem[] all = viewer.getTree().getItems();\r
357                 int firstIndex = Arrays.indexOf(all, items[0]);\r
358                 for (TreeItem item : items) {\r
359                     int index = Arrays.indexOf(all, item);\r
360                     all[index] = null;\r
361                     ILayer layer = (ILayer)item.getData();\r
362                     layers.removeLayer(layer);\r
363                 }\r
364                 int selectIndex = firstIndex - 1;\r
365                 if (firstIndex == 0) {\r
366                     for (int i = firstIndex; i < all.length; ++i)\r
367                         if (all[i] != null) {\r
368                             selectIndex = i;\r
369                             break;\r
370                         }\r
371                 }\r
372                 if (selectIndex >= 0) {\r
373                     viewer.getTree().select(all[selectIndex]);\r
374                 }\r
375             }\r
376 \r
377             @Override\r
378             public void widgetDefaultSelected(SelectionEvent e) {\r
379                 widgetSelected(e);\r
380             }\r
381         });\r
382 \r
383         String ignoreVisibilityText = TEXT_IGNORE_VISIBILITY_SETTINGS;\r
384         String ignoreVisibilityTooltip = TOOLTIP_IGNORE_VISIBILITY_SETTINGS;\r
385         boolean ignoreVisibility = layers.getIgnoreVisibilitySettings();\r
386         if (ignoreVisibility) {\r
387             ignoreVisibilityText = TEXT_APPLY_VISIBILITY_SETTINGS;\r
388             ignoreVisibilityTooltip = TOOLTIP_APPLY_VISIBILITY_SETTINGS;\r
389         }\r
390 \r
391         final Button ignoreVisibilityButton = new Button(composite, SWT.NONE);\r
392         ignoreVisibilityButton.setText(ignoreVisibilityText);\r
393         ignoreVisibilityButton.setToolTipText(ignoreVisibilityTooltip);\r
394         ignoreVisibilityButton.addSelectionListener(new SelectionListener() {\r
395 \r
396             @Override\r
397             public void widgetSelected(SelectionEvent e) {\r
398                 String ignoreText = TEXT_IGNORE_VISIBILITY_SETTINGS;\r
399                 String ignoreTooltip= TOOLTIP_IGNORE_VISIBILITY_SETTINGS;\r
400                 boolean ignore = layers.getIgnoreVisibilitySettings();\r
401                 if(!ignore) {\r
402                     ignoreText = TEXT_APPLY_VISIBILITY_SETTINGS;\r
403                     ignoreTooltip = TOOLTIP_APPLY_VISIBILITY_SETTINGS;\r
404                     layers.setIgnoreVisibilitySettings(true);\r
405                 } else {\r
406                     layers.setIgnoreVisibilitySettings(false);\r
407                 }\r
408                 ignoreVisibilityButton.setText(ignoreText);\r
409                 ignoreVisibilityButton.setToolTipText(ignoreTooltip);\r
410                 composite.layout();\r
411                 context.getThreadAccess().asyncExec(new Runnable() {\r
412 \r
413                     @Override\r
414                     public void run() {\r
415                         if(context.isDisposed()) return;\r
416                         context.getContentContext().setDirty();\r
417                     }\r
418 \r
419                 });\r
420             }\r
421 \r
422             @Override\r
423             public void widgetDefaultSelected(SelectionEvent e) {\r
424                 widgetSelected(e);\r
425             }\r
426 \r
427         });\r
428 \r
429         String ignoreFocusText = TEXT_IGNORE_FOCUS_SETTINGS;\r
430         String ignoreFocusTooltip = TOOLTIP_IGNORE_FOCUS_SETTINGS;\r
431         boolean ignoreFocus = layers.getIgnoreFocusSettings();\r
432         if(ignoreFocus) {\r
433             ignoreFocusText = TEXT_APPLY_FOCUS_SETTINGS;\r
434             ignoreFocusTooltip = TOOLTIP_APPLY_FOCUS_SETTINGS;\r
435         }\r
436 \r
437         final Button ignoreFocusButton = new Button(composite, SWT.NONE);\r
438         ignoreFocusButton.setText(ignoreFocusText);\r
439         ignoreFocusButton.setToolTipText(ignoreFocusTooltip);\r
440         ignoreFocusButton.addSelectionListener(new SelectionListener() {\r
441 \r
442             @Override\r
443             public void widgetSelected(SelectionEvent e) {\r
444                 String ignoreText = TEXT_IGNORE_FOCUS_SETTINGS;\r
445                 String ignoreTooltip = TOOLTIP_IGNORE_FOCUS_SETTINGS;\r
446                 boolean ignore = layers.getIgnoreFocusSettings();\r
447                 if(!ignore) {\r
448                     ignoreText = TEXT_APPLY_FOCUS_SETTINGS;\r
449                     ignoreTooltip = TOOLTIP_APPLY_FOCUS_SETTINGS;\r
450                     layers.setIgnoreFocusSettings(true);\r
451                 } else {\r
452                     layers.setIgnoreFocusSettings(false);\r
453                 }\r
454                 ignoreFocusButton.setText(ignoreText);\r
455                 ignoreFocusButton.setToolTipText(ignoreTooltip);\r
456                 composite.layout();\r
457                 context.getThreadAccess().asyncExec(new Runnable() {\r
458 \r
459                     @Override\r
460                     public void run() {\r
461                         if(context.isDisposed()) return;\r
462                         context.getContentContext().setDirty();\r
463                     }\r
464 \r
465                 });\r
466             }\r
467 \r
468             @Override\r
469             public void widgetDefaultSelected(SelectionEvent e) {\r
470                 widgetSelected(e);\r
471             }\r
472 \r
473         });\r
474 \r
475         viewer = new CheckboxTreeViewer(composite, SWT.BORDER | SWT.FULL_SELECTION );\r
476 \r
477         GridDataFactory.fillDefaults().grab(true, true).span(4, 1).applyTo(viewer.getControl());\r
478         viewer.getControl().setToolTipText("Selects the diagram to include in the exported document.");\r
479         viewer.setAutoExpandLevel(TreeViewer.ALL_LEVELS);\r
480         viewer.getTree().setHeaderVisible(true);\r
481         editor = new TreeEditor(viewer.getTree());\r
482 \r
483         final TreeColumn column1 = new TreeColumn(viewer.getTree(), SWT.LEFT);\r
484         column1.setText("Role");\r
485         column1.setWidth(100);\r
486         final TreeColumn column2 = new TreeColumn(viewer.getTree(), SWT.LEFT);\r
487         column2.setText("Show");\r
488         column2.setWidth(50);\r
489         final TreeColumn column3 = new TreeColumn(viewer.getTree(), SWT.LEFT);\r
490         column3.setText("Focus");\r
491         column3.setWidth(50);\r
492         viewer.getTree().addListener(SWT.Resize, new Listener() {\r
493             @Override\r
494             public void handleEvent(Event event) {\r
495                 Tree tree = viewer.getTree();\r
496                 Point size = tree.getSize();\r
497                 int w = Math.max(size.x - 100 - tree.getBorderWidth() * 2, 30);\r
498                 column1.setWidth(w);\r
499             }\r
500         });\r
501 \r
502         viewer.getTree().addListener(SWT.PaintItem, new Listener() {\r
503             public void handleEvent(Event event) {\r
504                 if ((event.index == 1 || event.index == 2) && !elements.isEmpty()) {\r
505                     ILayer[] lz = layers.getLayers().toArray(new ILayer[0]);\r
506 \r
507                     TreeItem item = (TreeItem)event.item;\r
508                     int index = viewer.getTree().indexOf(item);\r
509 \r
510                     int width = 0;\r
511                     if (event.index == 1)\r
512                         width = (column2.getWidth() - 1);\r
513                     if (event.index == 2)\r
514                         width = (column3.getWidth() - 1);\r
515 \r
516                     Attribute attribute = Attribute.Visible;\r
517                     if (event.index == 2)\r
518                         attribute = Attribute.Focusable;\r
519                     Tristate state = getJointAttribute(elements, lz[index], attribute);\r
520 \r
521                     Color color = null;\r
522                     switch (state) {\r
523                         case False:\r
524                             color = viewer.getTree().getDisplay().getSystemColor(SWT.COLOR_RED);\r
525                             break;\r
526                         case True:\r
527                             color = viewer.getTree().getDisplay().getSystemColor(SWT.COLOR_GREEN);\r
528                             break;\r
529                         case Both:\r
530                             color = viewer.getTree().getDisplay().getSystemColor(SWT.COLOR_GRAY);\r
531                             break;\r
532                     }\r
533 \r
534                     GC gc = event.gc;\r
535                     Color foreground = gc.getForeground();\r
536                     Color background = gc.getBackground();\r
537                     gc.setBackground(color);\r
538                     gc.setForeground(viewer.getTree().getDisplay().getSystemColor(SWT.COLOR_BLACK));\r
539                     gc.fillRectangle(event.x, event.y, width-1, event.height-1);\r
540                     Rectangle rect2 = new Rectangle(event.x, event.y, width-1, event.height-1);\r
541                     gc.drawRectangle(rect2);\r
542                     gc.setForeground(background);\r
543                     gc.setBackground(foreground);\r
544                 }\r
545             }\r
546         });\r
547         viewer.getTree().addKeyListener(new KeyAdapter() {\r
548             @Override\r
549             public void keyPressed(KeyEvent event) {\r
550                 if (event.keyCode == SWT.F2) {\r
551                     // FIXME: Eclipse currently eats F2 presses. This should be\r
552                     // implemented as a command handler or find some way to\r
553                     // force these listeners to have priority...\r
554                     System.out.println("startediting");\r
555 \r
556                     TreeItem[] items = viewer.getTree().getSelection();\r
557                     if(items.length != 1)\r
558                         return;\r
559 \r
560                     TreeItem item = items[0];\r
561 \r
562                     ILayer layer = ISelectionUtils.filterSingleSelection(viewer.getSelection(), ILayer.class);\r
563                     if (layer == null)\r
564                         return;\r
565 \r
566                     startEditing(layer, item);\r
567                 }\r
568             }\r
569         });\r
570         viewer.getTree().addListener(SWT.MouseDown, new Listener() {\r
571             public void handleEvent(Event event) {\r
572                 if (viewer.getControl().isDisposed())\r
573                     return;\r
574 \r
575                 Point pt = new Point(event.x, event.y);\r
576                 TreeItem item = viewer.getTree().getItem(pt);\r
577                 if (item == null)\r
578                     return;\r
579 \r
580                 int index = viewer.getTree().indexOf(item);\r
581                 ILayer[] lz = layers.getLayers().toArray(new ILayer[0]);\r
582                 ILayer layer = lz[index];\r
583 \r
584                 Rectangle rect = item.getBounds(0);\r
585                 if (event.count == 2 && rect.contains(pt)) {\r
586                     startEditing(layer, item);\r
587                     return;\r
588                 }\r
589 \r
590                 // Cannot adjust visibility/focusability if no elements are selected.\r
591                 if (elements.isEmpty())\r
592                     return;\r
593 \r
594                 rect = item.getBounds(1);\r
595                 if (rect.contains(pt)) {\r
596                     Tristate state = getJointAttribute(elements, layer, Attribute.Visible);\r
597                     if (setAttribute(elements, layer, Attribute.Visible, state.toggle().toBoolean()) > 0) {\r
598                         refresh();\r
599                     }\r
600                     return;\r
601                 }\r
602 \r
603                 Rectangle rect2 = item.getBounds(2);\r
604                 if (rect2.contains(pt)) {\r
605                     Tristate state = getJointAttribute(elements, layer, Attribute.Focusable);\r
606                     if (setAttribute(elements, layer, Attribute.Focusable, state.toggle().toBoolean()) > 0) {\r
607                         refresh();\r
608                     }\r
609                     return;\r
610                 }\r
611             }\r
612 \r
613             private void refresh() {\r
614                 viewer.getControl().redraw();\r
615                 context.getThreadAccess().asyncExec(new Runnable() {\r
616                     @Override\r
617                     public void run() {\r
618                         if (context.isDisposed())\r
619                             return;\r
620                         context.getContentContext().setDirty();\r
621                     }\r
622                 });\r
623             }\r
624         });\r
625 \r
626         viewer.addCheckStateListener(new ICheckStateListener(){\r
627             @Override\r
628             public void checkStateChanged(CheckStateChangedEvent event) {\r
629                 ILayer layer = (ILayer)event.getElement();\r
630                 if(event.getChecked()) layers.activate(layer);\r
631                 else layers.deactivate(layer);\r
632                 viewer.setSubtreeChecked(event.getElement(), event.getChecked());\r
633                 context.getThreadAccess().asyncExec(new Runnable() {\r
634 \r
635                     @Override\r
636                     public void run() {\r
637                         if(context.isDisposed()) return;\r
638                         context.getContentContext().setDirty();\r
639                     }\r
640 \r
641                 });\r
642             }\r
643         });\r
644 \r
645         viewer.addSelectionChangedListener(new ISelectionChangedListener() {\r
646             @Override\r
647             public void selectionChanged(SelectionChangedEvent event) {\r
648                 ISelection s = event.getSelection();\r
649                 if (s.isEmpty()) {\r
650                     removeButton.setEnabled(false);\r
651                 } else {\r
652                     removeButton.setEnabled(true);\r
653                 }\r
654             }\r
655         });\r
656 \r
657         viewer.setContentProvider(new ITreeContentProvider(){\r
658             @Override\r
659             public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {\r
660             }\r
661             @Override\r
662             public void dispose() {\r
663             }\r
664             @Override\r
665             public Object[] getElements(Object inputElement) {\r
666                 return layers.getLayers().toArray();\r
667             }\r
668             @Override\r
669             public boolean hasChildren(Object element) {\r
670                 return false;\r
671             }\r
672             @Override\r
673             public Object getParent(Object element) {\r
674                 return null;\r
675             }\r
676             @Override\r
677             public Object[] getChildren(Object parentElement) {\r
678                 return new Object[0];\r
679             }\r
680         });\r
681         viewer.setLabelProvider(new CellLabelProvider() {\r
682             @Override\r
683             public void update(ViewerCell cell) {\r
684                 if(cell.getColumnIndex() == 0) {\r
685                     ILayer layer  = (ILayer)cell.getElement();\r
686                     cell.setText(layer.getName());\r
687                 } else {\r
688                     cell.setText("");\r
689                 }\r
690             }\r
691         });\r
692         viewer.setCheckStateProvider(new ICheckStateProvider() {\r
693             @Override\r
694             public boolean isChecked(Object element) {\r
695                 ILayer layer  = (ILayer)element;\r
696                 final boolean isActive = layers.isActive(layer);\r
697                 return isActive;\r
698             }\r
699             @Override\r
700             public boolean isGrayed(Object element) {\r
701                 return false;\r
702             }\r
703         });\r
704 \r
705         viewer.setInput(this);\r
706 \r
707         for(ILayer layer : layers.getVisibleLayers()) {\r
708             viewer.setSubtreeChecked(layer, true);\r
709         }\r
710     }\r
711 \r
712     @Override\r
713     public Control getControl() {\r
714         return composite;\r
715     }\r
716 \r
717     @Override\r
718     public void setFocus() {\r
719     }\r
720 \r
721     @Override\r
722     public void addSelectionChangedListener(ISelectionChangedListener listener) {\r
723     }\r
724 \r
725     @Override\r
726     public ISelection getSelection() {\r
727         return null;\r
728     }\r
729 \r
730     @Override\r
731     public void removeSelectionChangedListener(ISelectionChangedListener listener) {\r
732     }\r
733 \r
734     @Override\r
735     public void setSelection(ISelection selection) {\r
736     }\r
737 \r
738     private boolean startEditing(final ILayer layer, final TreeItem item/*, final int columnIndex*/) {\r
739 \r
740         //        Column column = columns[columnIndex];\r
741 \r
742         String initialText = layer.getName();\r
743 \r
744         final Composite composite = new Composite(viewer.getTree(), SWT.NONE);\r
745         final Text text = new Text(composite, SWT.BORDER);\r
746         final int insetX = 0;\r
747         final int insetY = 0;\r
748         composite.addListener(SWT.Resize, new Listener() {\r
749             public void handleEvent(Event e) {\r
750                 Rectangle rect = composite.getClientArea();\r
751                 text.setBounds(rect.x + insetX, rect.y + insetY, rect.width - insetX * 2, rect.height\r
752                         - insetY * 2);\r
753             }\r
754         });\r
755         Listener textListener = new Listener() {\r
756             public void handleEvent(final Event e) {\r
757                 //String error;\r
758                 String newText;\r
759                 switch (e.type) {\r
760                     case SWT.FocusOut:\r
761                         if(layer instanceof IEditableLayer) {\r
762                             IEditableLayer l = (IEditableLayer)layer;\r
763                             l.setName(text.getText());\r
764                             System.out.println("renamed layer to " + text.getText());\r
765                             viewer.refresh();\r
766                         }\r
767 \r
768                         //                                      // Item may be disposed if the tree gets reset after a previous editing.\r
769                         //                                      if (!item.isDisposed()) {\r
770                         //                                              item.setText(columnIndex, text.getText());\r
771                         //                                              queueSelectionRefresh(context);\r
772                         //                                      }\r
773                         //                              } else {\r
774                         //                                      //                                System.out.println("validation error: " + error);\r
775                         //                              }\r
776                         composite.dispose();\r
777                         break;\r
778                     case SWT.Modify:\r
779                         //                              newText = text.getText();\r
780                         //                              error = modifier.isValid(newText);\r
781                         //                              if (error != null) {\r
782                         //                                      text.setBackground(invalidModificationColor);\r
783                         //                                      //                                System.out.println("validation error: " + error);\r
784                         //                              } else {\r
785                         //                                      text.setBackground(null);\r
786                         //                              }\r
787                         break;\r
788                     case SWT.Verify:\r
789                         newText = text.getText();\r
790                         String leftText = newText.substring(0, e.start);\r
791                         String rightText = newText.substring(e.end, newText.length());\r
792                         GC gc = new GC(text);\r
793                         Point size = gc.textExtent(leftText + e.text + rightText);\r
794                         gc.dispose();\r
795                         size = text.computeSize(size.x, SWT.DEFAULT);\r
796                         editor.horizontalAlignment = SWT.LEFT;\r
797                         Rectangle itemRect = item.getBounds(0),\r
798                         rect = viewer.getTree().getClientArea();\r
799                         editor.minimumWidth = Math.max(size.x, itemRect.width) + insetX * 2;\r
800                         int left = itemRect.x,\r
801                         right = rect.x + rect.width;\r
802                         editor.minimumWidth = Math.min(editor.minimumWidth, right - left);\r
803                         editor.minimumHeight = size.y + insetY * 2;\r
804                         editor.layout();\r
805                         break;\r
806                     case SWT.Traverse:\r
807                         switch (e.detail) {\r
808                             case SWT.TRAVERSE_RETURN:\r
809                                 if(layer instanceof IEditableLayer) {\r
810                                     IEditableLayer l = (IEditableLayer)layer;\r
811                                     l.setName(text.getText());\r
812                                     //System.out.println("renamed layer to " + text.getText());\r
813                                     viewer.refresh();\r
814                                 }\r
815                                 //                                      error = modifier.isValid(text.getText());\r
816                                 //                                      if (error == null) {\r
817                                 //                                              modifier.modify(text.getText());\r
818                                 //                                              if (!item.isDisposed()) {\r
819                                 //                                                      item.setText(columnIndex, text.getText());\r
820                                 //                                                      queueSelectionRefresh(context);\r
821                                 //                                              }\r
822                                 //                                      }\r
823                                 // FALL THROUGH\r
824                             case SWT.TRAVERSE_ESCAPE:\r
825                                 composite.dispose();\r
826                                 e.doit = false;\r
827                                 break;\r
828                             default:\r
829                                 //System.out.println("unhandled traversal: " + e.detail);\r
830                                 break;\r
831                         }\r
832                         break;\r
833                 }\r
834             }\r
835         };\r
836         text.addListener(SWT.FocusOut, textListener);\r
837         text.addListener(SWT.Traverse, textListener);\r
838         text.addListener(SWT.Verify, textListener);\r
839         text.addListener(SWT.Modify, textListener);\r
840         editor.setEditor(composite, item, 0);\r
841         text.setText(initialText);\r
842         text.selectAll();\r
843         text.setFocus();\r
844         //        lastItem[0] = item;\r
845         return true;\r
846     }\r
847 \r
848 }\r