Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8133831

findMatchingStyles/User agent precedence

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Unresolved
    • Icon: P3 P3
    • tbd
    • 8u40, 9
    • javafx
    • x86
    • windows_8

      FULL PRODUCT VERSION :
      Microsoft Windows [Version 6.3.9600]
      (c) 2013 Microsoft Corporation. All rights reserved.

      C:\Users\Owner>java -version
      java version "1.8.0_60"
      Java(TM) SE Runtime Environment (build 1.8.0_60-b26)
      Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)

      C:\Users\Owner>

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows [Version 6.3.9600]
      (c) 2013 Microsoft Corporation. All rights reserved.

      C:\Users\Owner>ver

      Microsoft Windows [Version 6.3.9600]

      C:\Users\Owner>

      A DESCRIPTION OF THE PROBLEM :
      In the most recent release it was changed so that getUserAgentStyleSheet could be overridden for Region allowing makers of custom controls to add a default style sheet.

      https://bugs.openjdk.java.net/browse/JDK-8096754

      However there is a slight issue that went unnoticed with this. Because the global user agent style sheets are applied before the region user agent style sheet, end users of custom control libraries can not set a *global* user agent style sheet to override the custom control defaults.

      Allow me to clarify. In a previous bug report I reported that there is no way to set the global application theme prior to the start. What the real problem is that JavaFX programmers do not want to rebuild Caspian and Modena entirely themselves. Setting a style sheet per scene is also undesirable. Like QApp in the Qt framework we want to set a global style sheet that can override the default Caspian and Modena. We can accomplish this currently with StyleManager.getInstance().addUserAgentStyle however there is a slight bug that it does not work until the primary stage is shown which is a separate issue.

      Now the problem is that if I make a custom control and override getUserAgentStyleSheet to provide a default style sheet for this custom control the StyleManager work around above does not allow end users of the library that provides this custom control to override its defaults. The reason is because inside findMatchingStyles the global user agent style sheet is applied, then the region user agent style sheet. So there is no way for end users to *globally* override the default styles to custom controls. The emphasis is on globally because if the end user of a custom control like ControlsFX sets their style sheet on the scene it will override the custom control defaults, but the entire problem is there's no standard way to do this globally for all scene's and all stages as one would expect. This is also why the getUserAgentStyleSheet solution for providing CSS defaults to custom controls is inconsistent with how the core JavaFX controls are styled.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Create a custom control and apply default styling to it by overriding getUserAgentStyle()

      Create this custom control add it to a scene and show the stage.

      After the stage is shown use StyleManager.getInstance().addUserAgentStyle to try to override the custom control's style *globally*

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      I would expect my global user agent style sheet to take precedence over the custom control's default user agent style sheet. This would be consistent as end user's of my custom control could *globally* override its default style just as they could with any internal JavaFX control.
      ACTUAL -
      The custom control's user agent style sheet took precedence over the global one and there was no way to globally override the custom control's default style.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      package org.dockfx.demo;

      import com.sun.javafx.css.StyleManager;

      import javafx.application.Application;
      import javafx.scene.Scene;
      import javafx.scene.control.Label;
      import javafx.stage.Stage;

      public class GlobalCustomControlOverride extends Application {

      public class CustomControl extends Label {
      @Override public String getUserAgentStylesheet() {
      return GlobalCustomControlOverride.class.getResource("CustomControl.css").toExternalForm();
      }
      }

          public static void main(String[] args) {
              launch(args);
          }
          
          @Override
          public void start(Stage primaryStage) {
              primaryStage.setTitle("Custom Control Global Override Bug");
              CustomControl customControl = new CustomControl();
              customControl.setText("Custom Control Text");
              
              primaryStage.setScene(new Scene(customControl, 300, 250));
              primaryStage.show();
              
              // this is overridden by the custom control's user agent stylesheet
              // which stops end users of this custom control from providing a global
              // style sheet for their application
              // this works for all internal javafx control's just not the custom ones
              // this is caused by the precedence in {@link StyleManager#findMatchingStyles
              StyleManager.getInstance().addUserAgentStylesheet(
               GlobalCustomControlOverride.class.getResource("EndUserTheme.css").toExternalForm());
          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      There is currently no work around.

      SUPPORT :
      YES

            aghaisas Ajit Ghaisas
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated: