Griffon
  1. Griffon
  2. GRIFFON-289

When using a ShutdownHandler, the window will always close before the canShutdown's are invoked. Should be configurable.

    Details

    • Type: New Feature New Feature
    • Status: Closed Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 0.9.2-beta-2
    • Fix Version/s: 0.9.2-beta-3
    • Component/s: rt
    • Labels:
      None
    • Environment:
      SwingApplication
    • Number of attachments :
      0

      Description

      When I am using a ShutdownHandler opening a confirmbox the application window vanishes before the confirmbox is shown. Users are used to get the confirmation as a modal dialog over the appliation window.
      To provide this behavior you should be able to specify this when creating the application.

      An example to do so could be a property hideBeforeHandler:

      application(title: 'ShutDownApp',
        size: [320,480],
        hideBeforeHandler: true,
        locationByPlatform:true,
        iconImage: imageIcon('/griffon-icon-48x48.png').image,
        iconImages: [imageIcon('/griffon-icon-48x48.png').image,
                     imageIcon('/griffon-icon-32x32.png').image,
                     imageIcon('/griffon-icon-16x16.png').image]) {
          label('Content Goes Here')
      }
      

      I would suggest to use false as future default behavior (App-Window will not be closed before the canShutdown's) and implemented it this way, but if you don't agree, let me know.

        Activity

        Hide
        Andres Almiray added a comment -

        Nice. I like the idea of a WindowDisplayHandler for each Window, however the current code will not allow that. Perhaps we can modify DefaultWindowDisplayHandler to work in multiplex mode. Or better yet, Have MultiplexingWindowDisplayHandler as the default value of WindowManager.windowDisplayHandler. This class will delegate to DefaultWindowDisplayHandler for each window that has not registered a custom handler (using the attributeDelegate you suggested, slightly modified); something along the lines of

        addAttributeDelegate { builder, node, attributes ->
            def windowDisplayHandler = attributes.remove('windowDisplayHandler')
            if(windowDisplayHandler && builder.app instanceof SwingGriffonApplication) {
                builder.app.windowDisplayHandler.registerHandler(node, windowDisplayHandler)
                if(windowDisplayHandler instanceof ShutdownHandler) {
                    builder.app.addShutdownHandler(windowDisplayHandler)
                }
            }
        }
        

        MultiplexingWindowDisplayHandler could look like this

        class MultiplexingWindowDisplayHandler implements WindowDisplayHandler {
            private static final Map<Window, WindowDisplayHandler> HANDLERS = [:]
            void unregisterHandler(Window window) {
                if(window) HANDLERS.remove(window)
            }
            void registerHandler(Window window, WindowDisplayHandler handler) {
                if(window) HANDLERS.put(window, handler)
            }
        
            void hide(Window window, GriffonApplication app) {
                fetchHandler(window).hide(window)
            }
            void show(Window window, GriffonApplication app) {
                fetchHandler(window).show(window)
            }
            private static WindowDisplayHandler fetchHandler(Window window) {
                WindowDisplayHandler handler = HANDLERS.get(window)
                if(!handler) {
                    handler = new DefaultWindowDisplayHandler()
                    HANDLERS.put(window, handler)
                }
                handler
            }  
        }
        

        WindowManager should inform MultiplexingWindowDisplayHandler when a Window is removed from its windows List (by calling unregisterHandler() on it).

        Show
        Andres Almiray added a comment - Nice. I like the idea of a WindowDisplayHandler for each Window, however the current code will not allow that. Perhaps we can modify DefaultWindowDisplayHandler to work in multiplex mode. Or better yet, Have MultiplexingWindowDisplayHandler as the default value of WindowManager.windowDisplayHandler. This class will delegate to DefaultWindowDisplayHandler for each window that has not registered a custom handler (using the attributeDelegate you suggested, slightly modified); something along the lines of addAttributeDelegate { builder, node, attributes -> def windowDisplayHandler = attributes.remove('windowDisplayHandler') if (windowDisplayHandler && builder.app instanceof SwingGriffonApplication) { builder.app.windowDisplayHandler.registerHandler(node, windowDisplayHandler) if (windowDisplayHandler instanceof ShutdownHandler) { builder.app.addShutdownHandler(windowDisplayHandler) } } } MultiplexingWindowDisplayHandler could look like this class MultiplexingWindowDisplayHandler implements WindowDisplayHandler { private static final Map<Window, WindowDisplayHandler> HANDLERS = [:] void unregisterHandler(Window window) { if (window) HANDLERS.remove(window) } void registerHandler(Window window, WindowDisplayHandler handler) { if (window) HANDLERS.put(window, handler) } void hide(Window window, GriffonApplication app) { fetchHandler(window).hide(window) } void show(Window window, GriffonApplication app) { fetchHandler(window).show(window) } private static WindowDisplayHandler fetchHandler(Window window) { WindowDisplayHandler handler = HANDLERS.get(window) if (!handler) { handler = new DefaultWindowDisplayHandler() HANDLERS.put(window, handler) } handler } } WindowManager should inform MultiplexingWindowDisplayHandler when a Window is removed from its windows List (by calling unregisterHandler() on it).
        Hide
        Andres Almiray added a comment -

        One last thing. It would probably be best to update the View code with a window reference, like this

        application(title: 'ShutDownApp',
                    id: 'myWindowId',
        ...
                windowDisplayHandler: [confirmShutdown: { app, visibleWindows ->
                  return visibleWindows.size() > 1 || optionPane().showConfirmDialog(myWindowId, "Do you really want to exit?", "Exit", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION
                }] as ShutdownAwareWindowDisplayHandler
        ) {
          label('Content Goes Here')
        }
        
        Show
        Andres Almiray added a comment - One last thing. It would probably be best to update the View code with a window reference, like this application(title: 'ShutDownApp', id: 'myWindowId', ... windowDisplayHandler: [confirmShutdown: { app, visibleWindows -> return visibleWindows.size() > 1 || optionPane().showConfirmDialog(myWindowId, "Do you really want to exit?" , "Exit" , JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION }] as ShutdownAwareWindowDisplayHandler ) { label('Content Goes Here') }
        Hide
        Andres Almiray added a comment -

        Found a solution using a windowManager DSL

        swing {
            windowManager {
                myWindowName = [
                    show: {window, app -> ... },
                    hide: {window, app -> ... }
                ]
                myOtherWindowName = [
                    show: {window, app -> ... }
                ]
            }     
        }
        

        The catch is that each managed window requires a name: property (which is standard in Swing). Now, the behavior required by this issue can be attained as follows

        in griffon-app/conf/Config.groovy

        swing {
            windowManager {
                myWindowName = [
                    hide: {w, app -> if(app.config.shutdown.proceed) w.dispose()}
                ]
            }
        }
        

        in griffon-app/cong/Events.groovy

        import javax.swing.JOptionPane
        
        onBootstrapEnd = { app ->
            app.config.shutdown.proceed = false
        
            app.addShutdownHandler([
                canShutdown: { a ->
                    app.config.shutdown.proceed = JOptionPane.showConfirmDialog(
                        app.windowManager.windows.find{it.focused},
                        "Do you really want to exit?", // <- mind i18n via resource bundles ??
                        "Exit",
                        JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION
                    return app.config.shutdown.proceed
                },
                onShutdown: { a -> }
            ] as griffon.core.ShutdownHandler)
        }
        
        onShutdownAborted = { app ->
            app.config.shutdown.proceed = false
        }
        
        Show
        Andres Almiray added a comment - Found a solution using a windowManager DSL swing { windowManager { myWindowName = [ show: {window, app -> ... }, hide: {window, app -> ... } ] myOtherWindowName = [ show: {window, app -> ... } ] } } The catch is that each managed window requires a name: property (which is standard in Swing). Now, the behavior required by this issue can be attained as follows in griffon-app/conf/Config.groovy swing { windowManager { myWindowName = [ hide: {w, app -> if (app.config.shutdown.proceed) w.dispose()} ] } } in griffon-app/cong/Events.groovy import javax.swing.JOptionPane onBootstrapEnd = { app -> app.config.shutdown.proceed = false app.addShutdownHandler([ canShutdown: { a -> app.config.shutdown.proceed = JOptionPane.showConfirmDialog( app.windowManager.windows.find{it.focused}, "Do you really want to exit?" , // <- mind i18n via resource bundles ?? "Exit" , JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION return app.config.shutdown.proceed }, onShutdown: { a -> } ] as griffon.core.ShutdownHandler) } onShutdownAborted = { app -> app.config.shutdown.proceed = false }
        Hide
        Andres Almiray added a comment -

        The WindowManager DSL is now in place. There's an additional class (ShutdownHandlerAdapter) that provides an empty implementation for ShutdownHandler.

        Is there anything else we should do before closing this issue?

        Show
        Andres Almiray added a comment - The WindowManager DSL is now in place. There's an additional class (ShutdownHandlerAdapter) that provides an empty implementation for ShutdownHandler. Is there anything else we should do before closing this issue?
        Hide
        Alexander Klein added a comment -

        I just saw that defaultHandler is used as a fallback handler - this would have been the last important thing to do.

        So no, I think we can close the issue.
        Thanks for implementing, Andres.

        Show
        Alexander Klein added a comment - I just saw that defaultHandler is used as a fallback handler - this would have been the last important thing to do. So no, I think we can close the issue. Thanks for implementing, Andres.

          People

          • Assignee:
            Alexander Klein
            Reporter:
            Alexander Klein
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Time Tracking

              Estimated:
              Original Estimate - 30 minutes
              30m
              Remaining:
              Remaining Estimate - 30 minutes
              30m
              Logged:
              Time Spent - Not Specified
              Not Specified