nus-cs2103-AY2223S2 / forum

12 stars 0 forks source link

Using UI during command execution #282

Closed joellow88 closed 1 year ago

joellow88 commented 1 year ago

The design of AB3 is such that the UI components calls executeCommand(String command), which is passed and executed by the Logic component. This works fine for the most part, however, this design also means that Logic has no knowledge of Ui. For most commands this works fine, however, I'm currrently facing a problem where I need to access the Ui elements during execution of a command.

The only similar command already in AB3 is help command - however, help command uses a workaround where the CommandResult object generated indicates that the command is a help command, which is then checked by the Ui. This doesn't work for me as I need to access the Ui elements before the CommandResult object is created.

Below is a small sample of what I am trying to do.

public class MainWindow extends UiPart<Stage> {
    private Stage primaryStage;
    //other code

    public Stage getPrimaryStage() { return primaryStage; }

    //Calls LogicManager#execute(String)
    private CommandResult executeCommand(String commandText) {...} 

}

public class LogicManager implements Logic {
    //other code

    //Has no knowledge of the Ui components that called it
    public CommandResult execute(String commandText) {
        //other code

        //Need to access MainWindow#getPrimaryStage() here

        //other code
        return new CommandResult(MESSAGE_SUCCESS);
    }
}

Of course, a simple solution would be to pass the primaryStage as a parameter to the MainWindow#executeCommand() function. However, that goes against the architecture of AB3 and for most of the commands, it also does not make sense to pass the primaryStage as an argument to execute(). ArchitectureDiagram

I was wondering if anyone has faced a similar issue and if there are any previous solutions to this problem.

Thank you!

damithc commented 1 year ago

I'm currrently facing a problem where I need to access the Ui elements during execution of a command.

@joellow88 perhaps give more specifics? What does this command do and exactly what information does the Logic need from the GUI?

joellow88 commented 1 year ago

I am trying to use JavaFX FileChooser object to allow the user to select a file using the OS's default file explorer. To use this, I need to pass the primaryStage object into FileChooser#showOpenDialog(Window ownerWindow). However, I have no way of accessing the primaryStage object from within the Logic module.

damithc commented 1 year ago

@joellow88 I see. Let's see if anyone has suggestions on how to accomplish this. In the meantime, you can explore if there is a way the Ui can detect if there is a need for the user to choose a file and do that pre-emptively before passing the file info to the Logic together with the rest of the command.

joellow88 commented 1 year ago

Thank you Prof! I have come up with a solution that is working so far.

My solution was to call MainWindow#execute() as per normal. However, if the command requires additional Ui input, a UiInputRequiredException will be raised. This will be caught in the MainWindow#execute() method, and handled by showing the FileChooser. The chosen file path will be converted to a string and fed back into the MainWindow#execute() method.

I'm not sure whether this is a 'recommended' use of exceptions, but the solution seems to be working so far, and it solves the original problem of not having access to Ui in the Logic component. Hopefully this is helpful to anyone who is facing the same issue as me.