javauis/eswt_qt/org.eclipse.swt/Eclipse_SWT_PI/qt/org/eclipse/swt/internal/qt/CommandArranger.java
branchRCL_3
changeset 65 ae942d28ec0e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/eswt_qt/org.eclipse.swt/Eclipse_SWT_PI/qt/org/eclipse/swt/internal/qt/CommandArranger.java	Tue Aug 31 15:09:22 2010 +0300
@@ -0,0 +1,449 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Nokia Corporation - initial implementation
+ *******************************************************************************/
+package org.eclipse.swt.internal.qt;
+
+import org.eclipse.ercp.swt.mobile.Command;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Decorations;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Internal_PackageSupport;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Widget;
+
+/**
+ * Manages the Command presentation cycle. This is a singleton object that gets
+ * notified about the events that can have an effect on the way the Commands are
+ * represented. It maintains an ordered list of Commands on the current focus
+ * context with the help of {@link CommandCollection}. It also notifies the
+ * currently active {@link CommandPresentationStrategy} so that the presentation
+ * is updated if necessary.
+ * 
+ * @see Command
+ * @see CommandCollection
+ * @see CommandPresentationStrategy
+ */
+public class CommandArranger {
+
+/**
+ * A helper for keeping an ordered list of {@link Command}s in the current focus
+ * context. The Commands are ordered according to their proximity to the
+ * currently focused control. The ordered list starts with Commands from the
+ * currently focused Control if any and ends with the active Shell and includes
+ * all the Commands in between. If a Control has more than one Command they are
+ * ordered among themselves according to creation order.
+ */
+public class CommandCollection {
+
+private Command[] fCommands;
+
+CommandCollection() {
+    super();
+}
+
+/**
+ * Adds the command to the collection. Warning: This does not make duplicate
+ * control.
+ * 
+ * @param command
+ */
+void addCommand(Command command) {
+    if (command == null)
+        return;
+    if (fCommands == null) {
+        fCommands = new Command[1];
+        fCommands[0] = command;
+        return;
+    }
+    int size = fCommands.length + 1;
+    Command[] newList = new Command[size];
+    // find the insertion point so that the order is correct
+    int insertPoint = 0;
+    Shell activeShell = display.getActiveShell();
+    Control ctrl = display.getFocusControl();
+    while (ctrl != null && ctrl != activeShell) {
+        if (ctrl == command.control) {
+            // Adding a command to focused control increment by one.
+            // adding Command.internal_getCommands(ctrl).length will
+            // just duplicate the count for Commands already in array.
+            insertPoint++;
+            break;
+        }
+        insertPoint += Command.internal_getCommands(ctrl).length;
+        ctrl = ctrl.getParent();
+    }
+    System.arraycopy(fCommands, 0, newList, 0, insertPoint);
+    System.arraycopy(fCommands, insertPoint, newList, insertPoint + 1, fCommands.length
+        - insertPoint);
+    newList[insertPoint] = command;
+    fCommands = newList;
+}
+
+/**
+ * Adds the list of Commands to the collection.
+ * 
+ * @param commands
+ */
+void addCommand(Command[] commands) {
+    if (commands == null || commands.length == 0)
+        return;
+    if (fCommands == null) {
+        fCommands = new Command[commands.length];
+        System.arraycopy(commands, 0, fCommands, 0, commands.length);
+        return;
+    }
+    int size = commands.length + fCommands.length;
+    Command[] newList = new Command[size];
+    System.arraycopy(fCommands, 0, newList, 0, fCommands.length);
+    System.arraycopy(commands, 0, newList, fCommands.length, commands.length);
+    fCommands = newList;
+}
+
+/**
+ * Removes the command from the list.
+ * 
+ * @param command
+ */
+void removeCommand(Command command) {
+    if (command == null)
+        return;
+    if (fCommands == null || fCommands.length == 0)
+        return;
+    int removeIndex = -1;
+    for (int i = 0; i < fCommands.length; i++) {
+        if (fCommands[i] == command) {
+            removeIndex = i;
+        }
+    }
+    if (removeIndex == -1)
+        return;
+    Command[] newList = new Command[fCommands.length - 1];
+    System.arraycopy(fCommands, 0, newList, 0, removeIndex);
+    System.arraycopy(fCommands, removeIndex + 1, newList, removeIndex, (fCommands.length
+        - removeIndex - 1));
+    fCommands = newList;
+}
+
+/**
+ * Returns the number of the Commands
+ * 
+ * @return boolean
+ */
+int getSize() {
+    int size = 0;
+    if (fCommands != null)
+        size = fCommands.length;
+    return size;
+}
+
+/**
+ * Retrieves the Commands of the types indicated by the commandTypes array. The
+ * order of the commandTypes array has no significance. Passing a null parameter
+ * or an empty array retrieves all the available Commands.
+ * 
+ * @param commandTypes
+ * @return Command list
+ */
+Command[] getCommands(int[] commandTypes) {
+    if (commandTypes == null || commandTypes.length == 0) {
+        return fCommands;
+    }
+    int size = getSize();
+    Command[] filteredCommands = new Command[size];
+    int index = 0;
+    for (int i = 0; i < fCommands.length; i++) {
+        for (int j = 0; j < commandTypes.length; j++) {
+            if (fCommands[i].type == commandTypes[j]) {
+                filteredCommands[index] = fCommands[i];
+                index++;
+                break;
+            }
+        }
+    }
+    if (size > (index)) {// Some commands filtered resize the Array
+        Command[] shrunk = new Command[index];
+        System.arraycopy(filteredCommands, 0, shrunk, 0, index);
+        return shrunk;
+    }
+    return filteredCommands;
+}
+
+}// CommandCollection
+
+private CommandCollection currentCommands;
+private Command defaultCommand;
+private Display display;
+Control focusedControl;
+Shell lastKnownActiveShell;
+private Command[] positiveKeyCommands;
+private Command negativeKeyCommand;
+
+
+public CommandArranger(Display display) {
+    super();
+    this.display = display;
+    currentCommands = new CommandCollection();
+}
+
+/**
+ * Called when the application changes the QMenuBar. This method does not handle
+ * the cases when the QMenuBar may change when the active top-level Shell
+ * changes. Since this does not cause a menu bar change on all platforms.
+ * 
+ * @see org.eclipse.swt.widgets.Decorations#setMenuBar(Menu)
+ * 
+ **/
+public void menuBarChanged(Decorations decorations) {
+    if (currentCommands == null || currentCommands.getSize() < 1)
+        return;
+    // if the changed menu bar is not on the active shell ignore and leave
+    // it to focus change.
+    if (decorations.getShell() != decorations.getDisplay().getActiveShell())
+        return;
+    // Call internal_getOwnMenuBar because the menu bar can be set to null
+    // in Decorations and
+    // we may need to create the internal one.
+    int menuBarHandle = decorations.internal_getOwnMenuBar();
+
+    handleMenuBarChanged(menuBarHandle, currentCommands);
+}
+
+/**
+ * Called when a new Shell becomes active.
+ * 
+ * @see Control#qt_swt_event_focusWasGained() //TODO
+ */
+public void shellActivityChanged() {
+    if (display == null) {
+        return;
+    }
+
+    Shell activeShell = display.getActiveShell();
+    
+    if (activeShell == lastKnownActiveShell) {
+        return;
+    }
+    lastKnownActiveShell = activeShell;
+    
+    cleanPositiveCommands();
+    cleanNegativeCommand();
+    
+    currentCommands = new CommandCollection();
+
+    if (activeShell != null && Command.internal_getCommands(activeShell).length > 0) {
+        currentCommands.addCommand(Command.internal_getCommands(activeShell));
+    }
+
+    // Determine where the commands go
+    if (currentCommands.getSize() > 0) {
+        Command[] add = currentCommands.getCommands(null);
+        updateCommandPositions(add);
+        placePositiveCommands();
+        placeNegativeCommand();
+    }
+}
+
+/**
+ * Called when a new Command is created
+ * 
+ * @param command
+ */
+public void commandAdded(Command command) {
+    if (isInFocusContext(command.control)) {
+        currentCommands.addCommand(command);
+        handleCommandListChange(command, null, currentCommands);
+    }
+}
+
+/**
+ * Called when a Command is disposed
+ * 
+ * @param command
+ */
+public void commandRemoved(Command command) {
+    if (command == defaultCommand)
+        defaultCommand = null;
+    if (isInFocusContext(command.control)) {
+        currentCommands.removeCommand(command);
+        handleCommandListChange(null, command, currentCommands);
+    }
+}
+
+/**
+ * Called when the Display is getting disposed.
+ */
+public void dispose() {
+    currentCommands = null;
+    display = null;
+    positiveKeyCommands = null;
+    negativeKeyCommand = null;
+    defaultCommand = null;
+    lastKnownActiveShell = null;
+}
+
+/**
+ * Called when a Command is set default
+ * 
+ * @param command
+ * @see Command#setDefaultCommand();
+ */
+public void setDefaultCommand(Command command) {
+    defaultCommand = command;
+    if (isInFocusContext(command.control)) {
+        handleDefaultCommandChange(command);
+    }
+}
+
+/**
+ * Returns the default command or null if there is none.
+ * 
+ * @return
+ * @see Command#isDefaultCommand()
+ */
+public Command getDefaultCommand() {
+    return defaultCommand;
+}
+
+
+private boolean isInFocusContext(Control control) {
+    Display display = control.getDisplay();
+    Shell activeShell = display.getActiveShell();
+    return control == activeShell;
+}
+
+private void handleCommandListChange(Command added, Command removed, CommandCollection commands) {
+    cleanNegativeCommand();
+    cleanPositiveCommands();
+    updateCommandPositions(commands.getCommands(null));
+    placeNegativeCommand();
+    placePositiveCommands();
+}
+
+private void handleDefaultCommandChange(Command defaultCommand) {
+    this.defaultCommand = defaultCommand;
+    cleanPositiveCommands();
+    placePositiveCommands();
+}
+
+private void updateCommandPositions(Command[] commands) {
+    positiveKeyCommands = new Command[commands.length];
+    int positiveKeyIndex = 0;
+    for (int i = 0; i < commands.length; i++) {
+        Command cmd = commands[i];
+        if (cmd.isDefaultCommand()) {
+            defaultCommand = cmd;
+            continue;
+        }
+        if (CommandUtils.isNegativeType(cmd.type)) {
+            if (negativeKeyCommand == null || negativeKeyCommand.isDisposed()) {
+                negativeKeyCommand = cmd;
+            } else if (negativeKeyCommand.getPriority() <= cmd.getPriority()) {
+                positiveKeyCommands[positiveKeyIndex] = negativeKeyCommand;
+                positiveKeyIndex++;
+                negativeKeyCommand = cmd;
+            } else {
+                positiveKeyCommands[positiveKeyIndex] = cmd;
+                positiveKeyIndex++;
+            }
+            continue;
+        }
+        positiveKeyCommands[positiveKeyIndex] = cmd;
+        positiveKeyIndex++;
+    }
+    if ((positiveKeyIndex) < positiveKeyCommands.length) {// needs to shrink
+        Command[] rightSized = new Command[positiveKeyIndex];
+        System.arraycopy(positiveKeyCommands, 0, rightSized, 0, rightSized.length);
+        positiveKeyCommands = rightSized;
+    }
+}
+
+private void cleanPositiveCommands() {
+    boolean useBar = false;
+    if ((positiveKeyCommands != null && positiveKeyCommands.length > 1)
+        || (defaultCommand != null && positiveKeyCommands != null)) {
+        useBar = true;
+    }
+    if (defaultCommand != null && !defaultCommand.isDisposed()
+        && !defaultCommand.control.isDisposed()) {
+        if (useBar) {
+            OS.QWidget_removeAction(defaultCommand.control.getShell().internal_getOwnMenuBar(),
+                topHandle(defaultCommand));
+        } else {
+            OS.QWidget_removeAction(topHandle(defaultCommand.control), topHandle(defaultCommand));
+        }
+    }
+    if (positiveKeyCommands != null) {
+        for (int i = 0; i < positiveKeyCommands.length; i++) {
+            Command cmd = positiveKeyCommands[i];
+            if (cmd == null || cmd.isDisposed() || cmd.control.isDisposed()) {
+                continue;
+            }
+            int handle = 0;
+            if (useBar) {
+                handle = cmd.control.getShell().internal_getOwnMenuBar();
+            } else {
+                handle = topHandle(positiveKeyCommands[0].control);
+            }
+            OS.QWidget_removeAction(handle, topHandle(cmd));
+
+        }
+    }
+}
+
+private void cleanNegativeCommand() {
+    if (negativeKeyCommand != null && !negativeKeyCommand.isDisposed()
+        && !negativeKeyCommand.control.isDisposed()) {
+        OS.QWidget_removeAction(topHandle(negativeKeyCommand.control),
+            topHandle(negativeKeyCommand));
+    }
+}
+
+private void placeNegativeCommand() {
+    if (negativeKeyCommand != null) {
+        OS.QWidget_addAction(Internal_PackageSupport.topHandle(negativeKeyCommand.control),
+            topHandle(negativeKeyCommand));
+    }
+}
+
+private void placePositiveCommands() {
+    if (defaultCommand != null) {
+        int defaultCmdHandle = topHandle(defaultCommand);
+        if (positiveKeyCommands != null) {
+            OS.QMenuBar_addAction(defaultCommand.control.getShell().internal_getOwnMenuBar(),
+                defaultCmdHandle);
+        } else {
+            OS.QWidget_addAction(Internal_PackageSupport.topHandle(defaultCommand.control),
+                defaultCmdHandle);
+        }
+    }
+    if (positiveKeyCommands != null) {
+        if (positiveKeyCommands.length == 1 && defaultCommand == null) {
+            OS.QWidget_addAction(Internal_PackageSupport.topHandle(positiveKeyCommands[0].control),
+                topHandle(positiveKeyCommands[0]));
+        } else {
+            CommandUtils.sort(positiveKeyCommands);
+            for (int i = 0; i < positiveKeyCommands.length; i++) {
+                OS.QMenuBar_addAction(positiveKeyCommands[i].control.getShell()
+                    .internal_getOwnMenuBar(), topHandle(positiveKeyCommands[i]));
+            }
+        }
+    }
+}
+
+private void handleMenuBarChanged(int newMenuBar, CommandCollection commands) {
+    placePositiveCommands();
+}
+
+private static final int topHandle(Widget w) {
+    return Internal_PackageSupport.topHandle(w);
+}
+
+}