]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.browsing.ui.swt/src/org/simantics/browsing/ui/swt/DefaultIsCheckedProcessor.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.browsing.ui.swt / src / org / simantics / browsing / ui / swt / DefaultIsCheckedProcessor.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.browsing.ui.swt;
13
14 import java.util.HashMap;
15
16 import org.eclipse.swt.SWT;
17 import org.eclipse.swt.widgets.Event;
18 import org.eclipse.swt.widgets.Listener;
19 import org.eclipse.swt.widgets.Tree;
20 import org.eclipse.swt.widgets.TreeItem;
21 import org.eclipse.swt.widgets.Widget;
22 import org.simantics.browsing.ui.BuiltinKeys;
23 import org.simantics.browsing.ui.CheckedState;
24 import org.simantics.browsing.ui.GraphExplorer;
25 import org.simantics.browsing.ui.NodeContext;
26 import org.simantics.browsing.ui.PrimitiveQueryUpdater;
27 import org.simantics.browsing.ui.NodeContext.PrimitiveQueryKey;
28 import org.simantics.browsing.ui.common.processors.AbstractPrimitiveQueryProcessor;
29 import org.simantics.browsing.ui.common.processors.IsCheckedProcessor;
30 import org.simantics.browsing.ui.common.processors.ProcessorLifecycle;
31
32 /**
33  * @author Tuukka Lehtonen
34  */
35 public class DefaultIsCheckedProcessor extends AbstractPrimitiveQueryProcessor<CheckedState> implements
36 IsCheckedProcessor, ProcessorLifecycle {
37
38     private static final boolean DEBUG = false;
39
40     /**
41      * The map of node contexts that currently have another checked state than
42      * {@link CheckedState#NOT_CHECKED}.
43      */
44     private final HashMap<NodeContext, CheckedState>          checkedStates  = new HashMap<NodeContext, CheckedState>();
45     private final HashMap<NodeContext, PrimitiveQueryUpdater> checkedQueries = new HashMap<NodeContext, PrimitiveQueryUpdater>();
46
47     private final CheckedState                                defaultState;
48
49     private Tree                                              tree;
50
51     private boolean                                           viewerSupportsChecking;
52
53     public DefaultIsCheckedProcessor() {
54         this(CheckedState.NOT_CHECKED);
55     }
56
57     public DefaultIsCheckedProcessor(CheckedState defaultState) {
58         if (defaultState == null)
59             throw new NullPointerException("null default state");
60         this.defaultState = defaultState;
61     }
62
63     @Override
64     public Object getIdentifier() {
65         return BuiltinKeys.IS_CHECKED;
66     }
67
68     @Override
69     public String toString() {
70         return "IsCheckedProcessor";
71     }
72
73     @Override
74     public CheckedState query(PrimitiveQueryUpdater updater, NodeContext context, PrimitiveQueryKey<CheckedState> key) {
75         // Don't gather records if the Tree we are attached to does not support
76         // checked items. This optimizes memory consumption while allowing this
77         // processor to exist in the attached GraphExplorer.
78         if (!viewerSupportsChecking)
79             return defaultState;
80
81         CheckedState checked = checkedStates.get(context);
82
83         if (DEBUG)
84             System.out.println("isChecked(" + updater + ", " + context + "): " + checked);
85
86         checkedQueries.put(context, updater);
87         return checked != null ? checked : CheckedState.NOT_CHECKED;
88     }
89
90     @Override
91     public boolean setChecked(NodeContext context, CheckedState checked) {
92         return _setChecked(context, checked);
93     }
94
95     private boolean _setChecked(NodeContext context, CheckedState checked) {
96         if (checked != defaultState) {
97             return this.checkedStates.put(context, checked) != checked;
98         } else {
99             return this.checkedStates.remove(context) != null;
100         }
101     }
102
103     Listener treeListener = new Listener() {
104         @Override
105         public void handleEvent(Event event) {
106             NodeContext context = (NodeContext) event.item.getData();
107             switch (event.type) {
108                 case SWT.Selection:
109                     if (event.detail == SWT.CHECK && event.item != null) {
110                         TreeItem item = (TreeItem) event.item;
111                         boolean checked = item.getChecked();
112                         boolean grayed = item.getGrayed();
113                         nodeStatusChanged(context, toCheckedState(checked, grayed));
114                     }
115                     break;
116             }
117         }
118     };
119
120     protected void nodeStatusChanged(NodeContext context, CheckedState checked) {
121         if (DEBUG)
122             System.out.println("isChecked status changed for " + context + ": " + checked);
123
124         _setChecked(context, checked);
125 //        PrimitiveQueryUpdater updater = checkedQueries.get(context);
126 //        if (updater != null)
127 //            updater.scheduleReplace(context, BuiltinKeys.IS_CHECKED, checked);
128     }
129
130     @Override
131     public void attached(GraphExplorer explorer) {
132         if (DEBUG)
133             System.out.println(this + " attaching to " + explorer);
134
135         Object control = explorer.getControl();
136         if (control instanceof Tree) {
137             this.tree = (Tree) control;
138             viewerSupportsChecking = supportsChecking(tree);
139             if (viewerSupportsChecking) {
140                 if (DEBUG)
141                     System.out.println("\ttree supports checking, adding listener");
142                 tree.addListener(SWT.Selection, treeListener);
143             }
144         } else {
145             System.out.println("WARNING: " + getClass().getSimpleName() + " attached to unsupported control: " + control);
146         }
147     }
148
149     @Override
150     public void clear() {
151         checkedStates.clear();
152         checkedQueries.clear();
153     }
154
155     @Override
156     public void detached(GraphExplorer explorer) {
157         if (DEBUG)
158             System.out.println(this + " detaching from " + explorer);
159
160         clear();
161         if (tree != null) {
162             if (viewerSupportsChecking) {
163                 if (DEBUG)
164                     System.out.println("\ttree supported checking, removing listener");
165                 tree.removeListener(SWT.Selection, treeListener);
166             }
167             tree = null;
168             viewerSupportsChecking = false;
169         }
170     }
171
172     private static boolean supportsChecking(Widget control) {
173         return (control.getStyle() & SWT.CHECK) != 0;
174     }
175
176     private static CheckedState toCheckedState(boolean checked, boolean grayed) {
177         if (checked)
178             return grayed ? CheckedState.GRAYED : CheckedState.CHECKED;
179         return CheckedState.NOT_CHECKED;
180     }
181
182 }