javauis/eswt_qt/org.eclipse.swt/Eclipse_SWT_PI/qt/org/eclipse/swt/internal/qt/CommandArranger.java
branchRCL_3
changeset 65 ae942d28ec0e
equal deleted inserted replaced
60:6c158198356e 65:ae942d28ec0e
       
     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.widgets.Control;
       
    15 import org.eclipse.swt.widgets.Decorations;
       
    16 import org.eclipse.swt.widgets.Display;
       
    17 import org.eclipse.swt.widgets.Internal_PackageSupport;
       
    18 import org.eclipse.swt.widgets.Menu;
       
    19 import org.eclipse.swt.widgets.Shell;
       
    20 import org.eclipse.swt.widgets.Widget;
       
    21 
       
    22 /**
       
    23  * Manages the Command presentation cycle. This is a singleton object that gets
       
    24  * notified about the events that can have an effect on the way the Commands are
       
    25  * represented. It maintains an ordered list of Commands on the current focus
       
    26  * context with the help of {@link CommandCollection}. It also notifies the
       
    27  * currently active {@link CommandPresentationStrategy} so that the presentation
       
    28  * is updated if necessary.
       
    29  * 
       
    30  * @see Command
       
    31  * @see CommandCollection
       
    32  * @see CommandPresentationStrategy
       
    33  */
       
    34 public class CommandArranger {
       
    35 
       
    36 /**
       
    37  * A helper for keeping an ordered list of {@link Command}s in the current focus
       
    38  * context. The Commands are ordered according to their proximity to the
       
    39  * currently focused control. The ordered list starts with Commands from the
       
    40  * currently focused Control if any and ends with the active Shell and includes
       
    41  * all the Commands in between. If a Control has more than one Command they are
       
    42  * ordered among themselves according to creation order.
       
    43  */
       
    44 public class CommandCollection {
       
    45 
       
    46 private Command[] fCommands;
       
    47 
       
    48 CommandCollection() {
       
    49     super();
       
    50 }
       
    51 
       
    52 /**
       
    53  * Adds the command to the collection. Warning: This does not make duplicate
       
    54  * control.
       
    55  * 
       
    56  * @param command
       
    57  */
       
    58 void addCommand(Command command) {
       
    59     if (command == null)
       
    60         return;
       
    61     if (fCommands == null) {
       
    62         fCommands = new Command[1];
       
    63         fCommands[0] = command;
       
    64         return;
       
    65     }
       
    66     int size = fCommands.length + 1;
       
    67     Command[] newList = new Command[size];
       
    68     // find the insertion point so that the order is correct
       
    69     int insertPoint = 0;
       
    70     Shell activeShell = display.getActiveShell();
       
    71     Control ctrl = display.getFocusControl();
       
    72     while (ctrl != null && ctrl != activeShell) {
       
    73         if (ctrl == command.control) {
       
    74             // Adding a command to focused control increment by one.
       
    75             // adding Command.internal_getCommands(ctrl).length will
       
    76             // just duplicate the count for Commands already in array.
       
    77             insertPoint++;
       
    78             break;
       
    79         }
       
    80         insertPoint += Command.internal_getCommands(ctrl).length;
       
    81         ctrl = ctrl.getParent();
       
    82     }
       
    83     System.arraycopy(fCommands, 0, newList, 0, insertPoint);
       
    84     System.arraycopy(fCommands, insertPoint, newList, insertPoint + 1, fCommands.length
       
    85         - insertPoint);
       
    86     newList[insertPoint] = command;
       
    87     fCommands = newList;
       
    88 }
       
    89 
       
    90 /**
       
    91  * Adds the list of Commands to the collection.
       
    92  * 
       
    93  * @param commands
       
    94  */
       
    95 void addCommand(Command[] commands) {
       
    96     if (commands == null || commands.length == 0)
       
    97         return;
       
    98     if (fCommands == null) {
       
    99         fCommands = new Command[commands.length];
       
   100         System.arraycopy(commands, 0, fCommands, 0, commands.length);
       
   101         return;
       
   102     }
       
   103     int size = commands.length + fCommands.length;
       
   104     Command[] newList = new Command[size];
       
   105     System.arraycopy(fCommands, 0, newList, 0, fCommands.length);
       
   106     System.arraycopy(commands, 0, newList, fCommands.length, commands.length);
       
   107     fCommands = newList;
       
   108 }
       
   109 
       
   110 /**
       
   111  * Removes the command from the list.
       
   112  * 
       
   113  * @param command
       
   114  */
       
   115 void removeCommand(Command command) {
       
   116     if (command == null)
       
   117         return;
       
   118     if (fCommands == null || fCommands.length == 0)
       
   119         return;
       
   120     int removeIndex = -1;
       
   121     for (int i = 0; i < fCommands.length; i++) {
       
   122         if (fCommands[i] == command) {
       
   123             removeIndex = i;
       
   124         }
       
   125     }
       
   126     if (removeIndex == -1)
       
   127         return;
       
   128     Command[] newList = new Command[fCommands.length - 1];
       
   129     System.arraycopy(fCommands, 0, newList, 0, removeIndex);
       
   130     System.arraycopy(fCommands, removeIndex + 1, newList, removeIndex, (fCommands.length
       
   131         - removeIndex - 1));
       
   132     fCommands = newList;
       
   133 }
       
   134 
       
   135 /**
       
   136  * Returns the number of the Commands
       
   137  * 
       
   138  * @return boolean
       
   139  */
       
   140 int getSize() {
       
   141     int size = 0;
       
   142     if (fCommands != null)
       
   143         size = fCommands.length;
       
   144     return size;
       
   145 }
       
   146 
       
   147 /**
       
   148  * Retrieves the Commands of the types indicated by the commandTypes array. The
       
   149  * order of the commandTypes array has no significance. Passing a null parameter
       
   150  * or an empty array retrieves all the available Commands.
       
   151  * 
       
   152  * @param commandTypes
       
   153  * @return Command list
       
   154  */
       
   155 Command[] getCommands(int[] commandTypes) {
       
   156     if (commandTypes == null || commandTypes.length == 0) {
       
   157         return fCommands;
       
   158     }
       
   159     int size = getSize();
       
   160     Command[] filteredCommands = new Command[size];
       
   161     int index = 0;
       
   162     for (int i = 0; i < fCommands.length; i++) {
       
   163         for (int j = 0; j < commandTypes.length; j++) {
       
   164             if (fCommands[i].type == commandTypes[j]) {
       
   165                 filteredCommands[index] = fCommands[i];
       
   166                 index++;
       
   167                 break;
       
   168             }
       
   169         }
       
   170     }
       
   171     if (size > (index)) {// Some commands filtered resize the Array
       
   172         Command[] shrunk = new Command[index];
       
   173         System.arraycopy(filteredCommands, 0, shrunk, 0, index);
       
   174         return shrunk;
       
   175     }
       
   176     return filteredCommands;
       
   177 }
       
   178 
       
   179 }// CommandCollection
       
   180 
       
   181 private CommandCollection currentCommands;
       
   182 private Command defaultCommand;
       
   183 private Display display;
       
   184 Control focusedControl;
       
   185 Shell lastKnownActiveShell;
       
   186 private Command[] positiveKeyCommands;
       
   187 private Command negativeKeyCommand;
       
   188 
       
   189 
       
   190 public CommandArranger(Display display) {
       
   191     super();
       
   192     this.display = display;
       
   193     currentCommands = new CommandCollection();
       
   194 }
       
   195 
       
   196 /**
       
   197  * Called when the application changes the QMenuBar. This method does not handle
       
   198  * the cases when the QMenuBar may change when the active top-level Shell
       
   199  * changes. Since this does not cause a menu bar change on all platforms.
       
   200  * 
       
   201  * @see org.eclipse.swt.widgets.Decorations#setMenuBar(Menu)
       
   202  * 
       
   203  **/
       
   204 public void menuBarChanged(Decorations decorations) {
       
   205     if (currentCommands == null || currentCommands.getSize() < 1)
       
   206         return;
       
   207     // if the changed menu bar is not on the active shell ignore and leave
       
   208     // it to focus change.
       
   209     if (decorations.getShell() != decorations.getDisplay().getActiveShell())
       
   210         return;
       
   211     // Call internal_getOwnMenuBar because the menu bar can be set to null
       
   212     // in Decorations and
       
   213     // we may need to create the internal one.
       
   214     int menuBarHandle = decorations.internal_getOwnMenuBar();
       
   215 
       
   216     handleMenuBarChanged(menuBarHandle, currentCommands);
       
   217 }
       
   218 
       
   219 /**
       
   220  * Called when a new Shell becomes active.
       
   221  * 
       
   222  * @see Control#qt_swt_event_focusWasGained() //TODO
       
   223  */
       
   224 public void shellActivityChanged() {
       
   225     if (display == null) {
       
   226         return;
       
   227     }
       
   228 
       
   229     Shell activeShell = display.getActiveShell();
       
   230     
       
   231     if (activeShell == lastKnownActiveShell) {
       
   232         return;
       
   233     }
       
   234     lastKnownActiveShell = activeShell;
       
   235     
       
   236     cleanPositiveCommands();
       
   237     cleanNegativeCommand();
       
   238     
       
   239     currentCommands = new CommandCollection();
       
   240 
       
   241     if (activeShell != null && Command.internal_getCommands(activeShell).length > 0) {
       
   242         currentCommands.addCommand(Command.internal_getCommands(activeShell));
       
   243     }
       
   244 
       
   245     // Determine where the commands go
       
   246     if (currentCommands.getSize() > 0) {
       
   247         Command[] add = currentCommands.getCommands(null);
       
   248         updateCommandPositions(add);
       
   249         placePositiveCommands();
       
   250         placeNegativeCommand();
       
   251     }
       
   252 }
       
   253 
       
   254 /**
       
   255  * Called when a new Command is created
       
   256  * 
       
   257  * @param command
       
   258  */
       
   259 public void commandAdded(Command command) {
       
   260     if (isInFocusContext(command.control)) {
       
   261         currentCommands.addCommand(command);
       
   262         handleCommandListChange(command, null, currentCommands);
       
   263     }
       
   264 }
       
   265 
       
   266 /**
       
   267  * Called when a Command is disposed
       
   268  * 
       
   269  * @param command
       
   270  */
       
   271 public void commandRemoved(Command command) {
       
   272     if (command == defaultCommand)
       
   273         defaultCommand = null;
       
   274     if (isInFocusContext(command.control)) {
       
   275         currentCommands.removeCommand(command);
       
   276         handleCommandListChange(null, command, currentCommands);
       
   277     }
       
   278 }
       
   279 
       
   280 /**
       
   281  * Called when the Display is getting disposed.
       
   282  */
       
   283 public void dispose() {
       
   284     currentCommands = null;
       
   285     display = null;
       
   286     positiveKeyCommands = null;
       
   287     negativeKeyCommand = null;
       
   288     defaultCommand = null;
       
   289     lastKnownActiveShell = null;
       
   290 }
       
   291 
       
   292 /**
       
   293  * Called when a Command is set default
       
   294  * 
       
   295  * @param command
       
   296  * @see Command#setDefaultCommand();
       
   297  */
       
   298 public void setDefaultCommand(Command command) {
       
   299     defaultCommand = command;
       
   300     if (isInFocusContext(command.control)) {
       
   301         handleDefaultCommandChange(command);
       
   302     }
       
   303 }
       
   304 
       
   305 /**
       
   306  * Returns the default command or null if there is none.
       
   307  * 
       
   308  * @return
       
   309  * @see Command#isDefaultCommand()
       
   310  */
       
   311 public Command getDefaultCommand() {
       
   312     return defaultCommand;
       
   313 }
       
   314 
       
   315 
       
   316 private boolean isInFocusContext(Control control) {
       
   317     Display display = control.getDisplay();
       
   318     Shell activeShell = display.getActiveShell();
       
   319     return control == activeShell;
       
   320 }
       
   321 
       
   322 private void handleCommandListChange(Command added, Command removed, CommandCollection commands) {
       
   323     cleanNegativeCommand();
       
   324     cleanPositiveCommands();
       
   325     updateCommandPositions(commands.getCommands(null));
       
   326     placeNegativeCommand();
       
   327     placePositiveCommands();
       
   328 }
       
   329 
       
   330 private void handleDefaultCommandChange(Command defaultCommand) {
       
   331     this.defaultCommand = defaultCommand;
       
   332     cleanPositiveCommands();
       
   333     placePositiveCommands();
       
   334 }
       
   335 
       
   336 private void updateCommandPositions(Command[] commands) {
       
   337     positiveKeyCommands = new Command[commands.length];
       
   338     int positiveKeyIndex = 0;
       
   339     for (int i = 0; i < commands.length; i++) {
       
   340         Command cmd = commands[i];
       
   341         if (cmd.isDefaultCommand()) {
       
   342             defaultCommand = cmd;
       
   343             continue;
       
   344         }
       
   345         if (CommandUtils.isNegativeType(cmd.type)) {
       
   346             if (negativeKeyCommand == null || negativeKeyCommand.isDisposed()) {
       
   347                 negativeKeyCommand = cmd;
       
   348             } else if (negativeKeyCommand.getPriority() <= cmd.getPriority()) {
       
   349                 positiveKeyCommands[positiveKeyIndex] = negativeKeyCommand;
       
   350                 positiveKeyIndex++;
       
   351                 negativeKeyCommand = cmd;
       
   352             } else {
       
   353                 positiveKeyCommands[positiveKeyIndex] = cmd;
       
   354                 positiveKeyIndex++;
       
   355             }
       
   356             continue;
       
   357         }
       
   358         positiveKeyCommands[positiveKeyIndex] = cmd;
       
   359         positiveKeyIndex++;
       
   360     }
       
   361     if ((positiveKeyIndex) < positiveKeyCommands.length) {// needs to shrink
       
   362         Command[] rightSized = new Command[positiveKeyIndex];
       
   363         System.arraycopy(positiveKeyCommands, 0, rightSized, 0, rightSized.length);
       
   364         positiveKeyCommands = rightSized;
       
   365     }
       
   366 }
       
   367 
       
   368 private void cleanPositiveCommands() {
       
   369     boolean useBar = false;
       
   370     if ((positiveKeyCommands != null && positiveKeyCommands.length > 1)
       
   371         || (defaultCommand != null && positiveKeyCommands != null)) {
       
   372         useBar = true;
       
   373     }
       
   374     if (defaultCommand != null && !defaultCommand.isDisposed()
       
   375         && !defaultCommand.control.isDisposed()) {
       
   376         if (useBar) {
       
   377             OS.QWidget_removeAction(defaultCommand.control.getShell().internal_getOwnMenuBar(),
       
   378                 topHandle(defaultCommand));
       
   379         } else {
       
   380             OS.QWidget_removeAction(topHandle(defaultCommand.control), topHandle(defaultCommand));
       
   381         }
       
   382     }
       
   383     if (positiveKeyCommands != null) {
       
   384         for (int i = 0; i < positiveKeyCommands.length; i++) {
       
   385             Command cmd = positiveKeyCommands[i];
       
   386             if (cmd == null || cmd.isDisposed() || cmd.control.isDisposed()) {
       
   387                 continue;
       
   388             }
       
   389             int handle = 0;
       
   390             if (useBar) {
       
   391                 handle = cmd.control.getShell().internal_getOwnMenuBar();
       
   392             } else {
       
   393                 handle = topHandle(positiveKeyCommands[0].control);
       
   394             }
       
   395             OS.QWidget_removeAction(handle, topHandle(cmd));
       
   396 
       
   397         }
       
   398     }
       
   399 }
       
   400 
       
   401 private void cleanNegativeCommand() {
       
   402     if (negativeKeyCommand != null && !negativeKeyCommand.isDisposed()
       
   403         && !negativeKeyCommand.control.isDisposed()) {
       
   404         OS.QWidget_removeAction(topHandle(negativeKeyCommand.control),
       
   405             topHandle(negativeKeyCommand));
       
   406     }
       
   407 }
       
   408 
       
   409 private void placeNegativeCommand() {
       
   410     if (negativeKeyCommand != null) {
       
   411         OS.QWidget_addAction(Internal_PackageSupport.topHandle(negativeKeyCommand.control),
       
   412             topHandle(negativeKeyCommand));
       
   413     }
       
   414 }
       
   415 
       
   416 private void placePositiveCommands() {
       
   417     if (defaultCommand != null) {
       
   418         int defaultCmdHandle = topHandle(defaultCommand);
       
   419         if (positiveKeyCommands != null) {
       
   420             OS.QMenuBar_addAction(defaultCommand.control.getShell().internal_getOwnMenuBar(),
       
   421                 defaultCmdHandle);
       
   422         } else {
       
   423             OS.QWidget_addAction(Internal_PackageSupport.topHandle(defaultCommand.control),
       
   424                 defaultCmdHandle);
       
   425         }
       
   426     }
       
   427     if (positiveKeyCommands != null) {
       
   428         if (positiveKeyCommands.length == 1 && defaultCommand == null) {
       
   429             OS.QWidget_addAction(Internal_PackageSupport.topHandle(positiveKeyCommands[0].control),
       
   430                 topHandle(positiveKeyCommands[0]));
       
   431         } else {
       
   432             CommandUtils.sort(positiveKeyCommands);
       
   433             for (int i = 0; i < positiveKeyCommands.length; i++) {
       
   434                 OS.QMenuBar_addAction(positiveKeyCommands[i].control.getShell()
       
   435                     .internal_getOwnMenuBar(), topHandle(positiveKeyCommands[i]));
       
   436             }
       
   437         }
       
   438     }
       
   439 }
       
   440 
       
   441 private void handleMenuBarChanged(int newMenuBar, CommandCollection commands) {
       
   442     placePositiveCommands();
       
   443 }
       
   444 
       
   445 private static final int topHandle(Widget w) {
       
   446     return Internal_PackageSupport.topHandle(w);
       
   447 }
       
   448 
       
   449 }