|
1 /******************************************************************************* |
|
2 * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. This program and the accompanying materials |
|
4 * are made available under the terms of the Eclipse Public License v1.0 |
|
5 * which accompanies this distribution, and is available at |
|
6 * http://www.eclipse.org/legal/epl-v10.html |
|
7 * |
|
8 * Contributors: |
|
9 * Nokia Corporation - initial implementation |
|
10 *******************************************************************************/ |
|
11 package org.eclipse.swt.internal.qt; |
|
12 |
|
13 import org.eclipse.ercp.swt.mobile.Command; |
|
14 import org.eclipse.swt.internal.CommandPresentationStrategyWrapper; |
|
15 import org.eclipse.swt.widgets.Control; |
|
16 import org.eclipse.swt.widgets.Decorations; |
|
17 import org.eclipse.swt.widgets.Display; |
|
18 import org.eclipse.swt.widgets.Menu; |
|
19 import org.eclipse.swt.widgets.Shell; |
|
20 /** |
|
21 * Manages the Command presentation cycle. This is a singleton object that gets |
|
22 * notified about the events that can have an effect on the way the Commands are |
|
23 * represented. It maintains an ordered list of Commands on the current focus |
|
24 * context with the help of {@link CommandCollection}. It also notifies the |
|
25 * currently active {@link CommandPresentationStrategy} so that the presentation |
|
26 * is updated if necessary. |
|
27 * |
|
28 * @see Command |
|
29 * @see CommandCollection |
|
30 * @see CommandPresentationStrategy |
|
31 */ |
|
32 public class CommandArranger { |
|
33 Control focusedControl; |
|
34 |
|
35 /** |
|
36 * A helper for keeping an ordered list of {@link Command}s in the current focus context. |
|
37 * The Commands are ordered according to their proximity to the currently focused control. |
|
38 * The ordered list starts with Commands from the currently focused Control if any and ends with |
|
39 * the active Shell and includes all the Commands in between. If a Control has more |
|
40 * than one Command they are ordered among themselves according to creation order. |
|
41 */ |
|
42 public class CommandCollection{ |
|
43 |
|
44 private Command[] fCommands; |
|
45 |
|
46 CommandCollection(){ |
|
47 super(); |
|
48 } |
|
49 |
|
50 /** |
|
51 * Adds the command to the collection. |
|
52 * Warning: This does not make duplicate control. |
|
53 * @param command |
|
54 */ |
|
55 void addCommand(Command command) { |
|
56 if (command == null) |
|
57 return; |
|
58 if (fCommands == null) { |
|
59 fCommands = new Command[1]; |
|
60 fCommands[0] = command; |
|
61 return; |
|
62 } |
|
63 int size = fCommands.length + 1; |
|
64 Command[] newList = new Command[size]; |
|
65 // find the insertion point so that the order is correct |
|
66 int insertPoint = 0; |
|
67 Display display = Display.getCurrent(); |
|
68 Shell activeShell = display.getActiveShell(); |
|
69 Control ctrl = display.getFocusControl(); |
|
70 while (ctrl != null && ctrl != activeShell) { |
|
71 if (ctrl == command.control) { |
|
72 // Adding a command to focused control increment by one. |
|
73 // adding Command.internal_getCommands(ctrl).length will |
|
74 // just duplicate the count for Commands already in array. |
|
75 insertPoint++; |
|
76 break; |
|
77 } |
|
78 insertPoint += Command.internal_getCommands(ctrl).length; |
|
79 ctrl = ctrl.getParent(); |
|
80 } |
|
81 System.arraycopy(fCommands, 0, newList, 0, insertPoint); |
|
82 System.arraycopy(fCommands, insertPoint, newList, insertPoint + 1, |
|
83 fCommands.length - insertPoint); |
|
84 newList[insertPoint] = command; |
|
85 fCommands = newList; |
|
86 } |
|
87 |
|
88 /** |
|
89 * Adds the list of Commands to the collection. |
|
90 * @param commands |
|
91 */ |
|
92 void addCommand( Command[] commands ){ |
|
93 if (commands == null || commands.length == 0 ) return; |
|
94 if (fCommands == null ){ |
|
95 fCommands = new Command[ commands.length ]; |
|
96 System.arraycopy(commands, 0, fCommands, 0, commands.length ); |
|
97 return; |
|
98 } |
|
99 int size = commands.length + fCommands.length; |
|
100 Command[] newList = new Command[ size ]; |
|
101 System.arraycopy(fCommands, 0, newList, 0, fCommands.length); |
|
102 System.arraycopy(commands, 0, newList, fCommands.length , commands.length ); |
|
103 fCommands = newList; |
|
104 } |
|
105 |
|
106 /** |
|
107 * Removes the command from the list. |
|
108 * @param command |
|
109 */ |
|
110 void removeCommand( Command command ){ |
|
111 if ( command == null ) return; |
|
112 if (fCommands == null || fCommands.length == 0 ) return; |
|
113 int removeIndex = -1; |
|
114 for (int i = 0; i < fCommands.length; i++) { |
|
115 if(fCommands[i] == command ){ |
|
116 removeIndex = i; |
|
117 } |
|
118 } |
|
119 if ( removeIndex == -1 ) return; |
|
120 Command[] newList = new Command[ fCommands.length -1 ]; |
|
121 System.arraycopy( fCommands, 0, newList, 0, removeIndex); |
|
122 System.arraycopy( fCommands, removeIndex + 1, newList, removeIndex, (fCommands.length - removeIndex -1) ); |
|
123 fCommands = newList; |
|
124 } |
|
125 |
|
126 /** |
|
127 * Returns the number of the Commands |
|
128 * |
|
129 * @return boolean |
|
130 */ |
|
131 public int getSize(){ |
|
132 int size = 0; |
|
133 if (fCommands != null ) size = fCommands.length; |
|
134 return size; |
|
135 } |
|
136 |
|
137 /** |
|
138 * Retrieves the Commands of the types indicated by the commandTypes array. |
|
139 * The order of the commandTypes array has no significance. Passing a null parameter |
|
140 * or an empty array retrieves all the available Commands. |
|
141 * |
|
142 * @param commandTypes |
|
143 * @return Command list |
|
144 */ |
|
145 public Command[] getCommands( int[] commandTypes ){ |
|
146 if ( commandTypes == null || commandTypes.length == 0 ){ |
|
147 return fCommands; |
|
148 } |
|
149 int size = getSize(); |
|
150 Command[] filteredCommands = new Command[size]; |
|
151 int index = 0; |
|
152 for (int i = 0; i < fCommands.length ; i++) { |
|
153 for(int j = 0; j<commandTypes.length; j++){ |
|
154 if ( fCommands[i].type == commandTypes[j] ){ |
|
155 filteredCommands[index]=fCommands[i]; |
|
156 index++; |
|
157 break; |
|
158 } |
|
159 } |
|
160 } |
|
161 if( size > (index) ){// Some commands filtered resize the Array |
|
162 Command[] shrunk = new Command[index]; |
|
163 System.arraycopy( filteredCommands, 0, shrunk, 0, index); |
|
164 return shrunk; |
|
165 } |
|
166 return filteredCommands; |
|
167 } |
|
168 }// CommandCollection |
|
169 |
|
170 private CommandCollection currentCommands; |
|
171 private CommandPresentationStrategy strategy; |
|
172 private Command defaultCommand; |
|
173 |
|
174 public CommandArranger(){ |
|
175 super(); |
|
176 currentCommands = new CommandCollection(); |
|
177 strategy = CommandPresentationStrategyWrapper.createStrategy(); |
|
178 } |
|
179 |
|
180 |
|
181 |
|
182 /** |
|
183 * Called when the application changes the QMenuBar. |
|
184 * This method does not handle the cases when the QMenuBar |
|
185 * may change when the active top-level Shell changes. Since |
|
186 * this does not cause a menu bar change on all platforms. |
|
187 * |
|
188 * @see org.eclipse.swt.widgets.Decorations#setMenuBar(Menu) |
|
189 * |
|
190 **/ |
|
191 public void menuBarChanged( Decorations decorations ){ |
|
192 |
|
193 if ( currentCommands == null || currentCommands.getSize() < 1 ) return; |
|
194 // if the changed menu bar is not on the active shell ignore and leave it to focus change. |
|
195 if (decorations.getShell() != decorations.getDisplay().getActiveShell() )return; |
|
196 // Call internal_getOwnMenuBar because the menu bar can be set to null in Decorations and |
|
197 // we may need to create the internal one. |
|
198 int menuBarHandle = decorations.internal_getOwnMenuBar(); |
|
199 |
|
200 strategy.handleMenuBarChanged( menuBarHandle, currentCommands ); |
|
201 } |
|
202 |
|
203 /** |
|
204 * Called when a new Control gains focus. |
|
205 * |
|
206 * @see Control#qt_swt_event_focusWasGained() |
|
207 */ |
|
208 public void focusedControlChanged(){ |
|
209 Display display = Display.getCurrent(); |
|
210 Control focusControl = display.getFocusControl(); |
|
211 if (focusControl == focusedControl) { |
|
212 return; |
|
213 } |
|
214 focusedControl = focusControl; |
|
215 |
|
216 Shell activeShell = display.getActiveShell(); |
|
217 CommandCollection oldCollection = currentCommands; |
|
218 currentCommands = new CommandCollection(); |
|
219 |
|
220 Control ctrl = focusControl; |
|
221 while ( ctrl!= null && ctrl != activeShell ){ |
|
222 if ( Command.internal_getCommands(ctrl).length > 0 ){ |
|
223 currentCommands.addCommand( Command.internal_getCommands(ctrl) ); |
|
224 } |
|
225 ctrl = ctrl.getParent(); |
|
226 } |
|
227 if (activeShell != null && Command.internal_getCommands(activeShell).length > 0 ){ |
|
228 currentCommands.addCommand( Command.internal_getCommands(activeShell) ); |
|
229 } |
|
230 |
|
231 if (strategy != null) { |
|
232 strategy.handleFocusChange(focusControl, oldCollection, currentCommands); |
|
233 } |
|
234 } |
|
235 |
|
236 /** |
|
237 * Called when a new Command is created |
|
238 * @param command |
|
239 */ |
|
240 public void commandAdded( Command command ){ |
|
241 if( isInFocusContext(command.control)){ |
|
242 currentCommands.addCommand(command); |
|
243 strategy.handleCommandListChange(command, null, currentCommands); |
|
244 } |
|
245 } |
|
246 |
|
247 /** |
|
248 * Called when a Command is disposed |
|
249 * @param command |
|
250 */ |
|
251 public void commandRemoved( Command command ){ |
|
252 if ( command == defaultCommand ) defaultCommand = null; |
|
253 if (isInFocusContext(command.control)){ |
|
254 currentCommands.removeCommand( command ); |
|
255 strategy.handleCommandListChange(null, command, currentCommands); |
|
256 } |
|
257 } |
|
258 |
|
259 /** |
|
260 * Called when the Display is getting disposed. |
|
261 */ |
|
262 public void dispose(){ |
|
263 strategy.dispose(); |
|
264 strategy = null; |
|
265 currentCommands = null; |
|
266 } |
|
267 /** |
|
268 * Called when a Command is set default |
|
269 * |
|
270 * @param command |
|
271 * @see Command#setDefaultCommand(); |
|
272 */ |
|
273 public void setDefaultCommand(Command command ){ |
|
274 defaultCommand = command; |
|
275 if(isInFocusContext(command.control)){ |
|
276 strategy.handleDefaultCommandChange(command); |
|
277 } |
|
278 } |
|
279 |
|
280 /** |
|
281 * Returns the default command or null if there is none. |
|
282 * |
|
283 * @return |
|
284 * @see Command#isDefaultCommand() |
|
285 */ |
|
286 public Command getDefaultCommand(){ |
|
287 return defaultCommand; |
|
288 } |
|
289 |
|
290 /** |
|
291 * Sets a new {@link CommandPresentationStrategy}. It also disposes to old one. |
|
292 * |
|
293 * @param commandPresentationStrategy |
|
294 */ |
|
295 public void setPresentationStrategy( CommandPresentationStrategy commandPresentationStrategy ){ |
|
296 CommandPresentationStrategy oldStrategy = strategy; |
|
297 strategy = commandPresentationStrategy; |
|
298 if (oldStrategy != null ){ |
|
299 oldStrategy.dispose(); |
|
300 } |
|
301 } |
|
302 |
|
303 private boolean isInFocusContext(Control control){ |
|
304 Display display = control.getDisplay(); |
|
305 Shell activeShell = display.getActiveShell(); |
|
306 Control focused = display.getFocusControl(); |
|
307 if( focused == null )return false; |
|
308 if(control.getShell() != activeShell) return false; |
|
309 if( control == focused ) return true; |
|
310 return isFocusAncestor(focused, control); |
|
311 } |
|
312 |
|
313 private boolean isFocusAncestor(Control node, Control parent){ |
|
314 Control nodeParent = node.getParent(); |
|
315 if( nodeParent == parent )return true; |
|
316 if (nodeParent == null || nodeParent == node.getShell() )return false; |
|
317 return isFocusAncestor(nodeParent, parent); |
|
318 } |
|
319 |
|
320 } |