Search code examples
qooxdoo

Command handling in Qooxdoo multi window application


I want to create a Qooxdoo application that consists of a Desktop with multiple Windows. The Desktop (and not each Window) also has a (common) ToolBar.
Now I want to have a command to "save" the document of the active window. This command can be triggered by the keyboard shortcut "Ctrl+S" as well as a button on the toolbar.

To handle the "Ctrl+S" to reach the currently active window the qx.ui.command.GroupManager (as described by https://qooxdoo.org/documentation/v7.5/#/desktop/gui/interaction?id=working-with-commands and https://qooxdoo.org/qxl.demobrowser/#ui~CommandGroupManager.html) is supposed to be the best solution. And I could easily implement that in my code.

But now I'm struggling to make the toolbar save button also call the save command of the currently active window as I don't know how to bind it correctly to the GroupManager.

An example code to get started in the playground https://qooxdoo.org/qxl.playground/:

// NOTE: run this script only once. Before running it again you need to reload
// the page as it seems that the commands are accumulation and not reset.
// I guess that this is a bug in the Playground

const root = this.getRoot();

qx.Class.define('test.Application',
{
  extend : qx.application.Standalone,
  members: {
    main: function() {
      const layout = new qx.ui.layout.VBox(5);
      const container = new qx.ui.container.Composite(layout);
      root.add(container, {edge: 0});
      const windowManager = new qx.ui.window.Manager();
      const desktop = new qx.ui.window.Desktop(windowManager);

      this._manager = new qx.ui.command.GroupManager();
      
      const menuBar = new qx.ui.menubar.MenuBar();
      let menu = new qx.ui.menu.Menu();
      
      ///////////////////////////
      // TODO: Call _doSave() of the active window!
      let saveMenuButton = new qx.ui.menu.Button('Save','@MaterialIcons/save/16');
      ///////////////////////////
      
      menu.add(saveMenuButton);
      var fileMenu = new qx.ui.menubar.Button('File', null, menu);
      menuBar.add(fileMenu);
      const toolBar = new qx.ui.toolbar.ToolBar();
      
      ///////////////////////////
      // TODO: Call _doSave() of the active window!
      let saveToolBarButton = new qx.ui.toolbar.Button('Save','@MaterialIcons/save/16');
      ///////////////////////////
      
      toolBar.add(saveToolBarButton);
      container.add(menuBar,{flex:0});
      container.add(toolBar,{flex:0});
      container.add(desktop,{flex:1});
      
      this._foo1 = new test.Window('foo1', this);
      desktop.add(this._foo1);
      this._foo1.open();
      this._foo1.moveTo(100,20);
      
      this._foo2 = new test.Window('foo2', this);
      desktop.add(this._foo2);
      this._foo2.open();
      this._foo2.moveTo(200,100);

      this._foo3 = new test.Window('foo3', this);
      desktop.add(this._foo3);
      this._foo3.open();
      this._foo3.moveTo(300,180);
    },
    getGroupManager() {
      return this._manager;
    }
  }
});

qx.Class.define('test.Window', {
  extend: qx.ui.window.Window,
  construct(windowName, controller) {
    this.base(arguments, windowName);
    this._name = windowName;
    
    let commandGroup = new qx.ui.command.Group();
    const cmd = new qx.ui.command.Command("Ctrl+S");
    cmd.addListener('execute', this._doSave, this);
    commandGroup.add('save', cmd);
    controller.getGroupManager().add(commandGroup);
    this.addListener('changeActive', () => {
      if (this.isActive()) {
        controller.getGroupManager().setActive(commandGroup);
      }
    }, this);
  },
  members: {
    _doSave() {
      alert("save " + this._name);
    }
  }
});

a = new test.Application();

How should the saveMenuButton.setCommand() and saveToolBarButton.setCommand() should look like to always call the command of the active window?


Solution

  • You can control a current active window via Desktop class:

    let saveToolBarButton = new qx.ui.toolbar.Button('Save');
    saveToolBarButton.addListener("click", function(){
      desktop.getActiveWindow()._doSave();
    }, this);

    Would be great for your solution imo is to create a separate command and add this command to buttons:

    const saveActiveWindowCommand = new qx.ui.command.Command();
    saveActiveWindowCommand.addListener("execute", function(){
      desktop.getActiveWindow()._doSave();
    }, this);
    
    let saveMenuButton = new qx.ui.menu.Button('Save');
    saveMenuButton.setCommand(saveActiveWindowCommand);
    
    let saveToolBarButton = new qx.ui.toolbar.Button('Save');
    saveToolBarButton.setCommand(saveActiveWindowCommand);

    EDIT: You could set commands dynamically for "Main Panel" menu buttons. Because there is only one instance of command pressing "Ctrl+S" will trigger only one command but maybe you would like that main bar save buttons have extra logic. You have in application class next method which will be called from window class when changeActive event happens.

        setSaveCommand(command){
          this.saveMenuButton.setCommand(command);
          this.saveToolBarButton.setCommand(command);
        },
    

    and in your Window class:

          if (this.isActive()) {
            controller.setSaveCommand(cmd);
            controller.getGroupManager().setActive(commandGroup);
          }