protected void onPropertyChange(
     JXHeader h, String propertyName, Object oldValue, final Object newValue) {
   if ("title".equals(propertyName)) {
     titleLabel.setText(h.getTitle());
   } else if ("description".equals(propertyName)) {
     descriptionPane.setText(h.getDescription());
   } else if ("icon".equals(propertyName)) {
     imagePanel.setIcon(h.getIcon());
   } else if ("enabled".equals(propertyName)) {
     boolean enabled = h.isEnabled();
     titleLabel.setEnabled(enabled);
     descriptionPane.setEnabled(enabled);
     imagePanel.setEnabled(enabled);
   } else if ("titleFont".equals(propertyName)) {
     titleLabel.setFont((Font) newValue);
   } else if ("descriptionFont".equals(propertyName)) {
     descriptionPane.setFont((Font) newValue);
   } else if ("titleForeground".equals(propertyName)) {
     titleLabel.setForeground((Color) newValue);
   } else if ("descriptionForeground".equals(propertyName)) {
     descriptionPane.setForeground((Color) newValue);
   } else if ("iconPosition".equals(propertyName)) {
     resetLayout(h);
   }
 }
  protected void installDefaults(JXHeader h) {
    gradientLightColor = UIManager.getColor("JXHeader.startBackground");
    if (gradientLightColor == null) {
      // fallback to white
      gradientLightColor = Color.WHITE;
    }
    gradientDarkColor = UIManager.getColor("JXHeader.background");
    // for backwards compatibility (mostly for substance and synthetica,
    // I suspect) I'll fall back on the "control" color if JXHeader.background
    // isn't specified.
    if (gradientDarkColor == null) {
      gradientDarkColor = UIManager.getColor("control");
    }

    Painter p = h.getBackgroundPainter();
    if (p == null || p instanceof PainterUIResource) {
      h.setBackgroundPainter(createBackgroundPainter());
    }

    // title properties
    Font titleFont = h.getTitleFont();
    if (titleFont == null || titleFont instanceof FontUIResource) {
      titleFont = UIManager.getFont("JXHeader.titleFont");
      // fallback to label font
      titleLabel.setFont(titleFont != null ? titleFont : UIManager.getFont("Label.font"));
    }

    Color titleForeground = h.getTitleForeground();
    if (titleForeground == null || titleForeground instanceof ColorUIResource) {
      titleForeground = UIManager.getColor("JXHeader.titleForeground");
      // fallback to label foreground
      titleLabel.setForeground(
          titleForeground != null ? titleForeground : UIManager.getColor("Label.foreground"));
    }

    titleLabel.setText(h.getTitle());

    // description properties
    Font descFont = h.getDescriptionFont();
    if (descFont == null || descFont instanceof FontUIResource) {
      descFont = UIManager.getFont("JXHeader.descriptionFont");
      // fallback to label font
      descriptionPane.setFont(descFont != null ? descFont : UIManager.getFont("Label.font"));
    }

    Color descForeground = h.getDescriptionForeground();
    if (descForeground == null || descForeground instanceof ColorUIResource) {
      descForeground = UIManager.getColor("JXHeader.descriptionForeground");
      // fallback to label foreground
      descriptionPane.setForeground(
          descForeground != null ? descForeground : UIManager.getColor("Label.foreground"));
    }

    descriptionPane.setText(h.getDescription());
  }
  /**
   * Configures the specified component appropriate for the look and feel. This method is invoked
   * when the <code>ComponentUI</code> instance is being installed as the UI delegate on the
   * specified component. This method should completely configure the component for the look and
   * feel, including the following:
   *
   * <ol>
   *   <li>Install any default property values for color, fonts, borders, icons, opacity, etc. on
   *       the component. Whenever possible, property values initialized by the client program
   *       should <i>not</i> be overridden.
   *   <li>Install a <code>LayoutManager</code> on the component if necessary.
   *   <li>Create/add any required sub-components to the component.
   *   <li>Create/install event listeners on the component.
   *   <li>Create/install a <code>PropertyChangeListener</code> on the component in order to detect
   *       and respond to component property changes appropriately.
   *   <li>Install keyboard UI (mnemonics, traversal, etc.) on the component.
   *   <li>Initialize any appropriate instance data.
   * </ol>
   *
   * @param c the component where this UI delegate is being installed
   * @see #uninstallUI
   * @see javax.swing.JComponent#setUI
   * @see javax.swing.JComponent#updateUI
   */
  @Override
  public void installUI(JComponent c) {
    super.installUI(c);
    assert c instanceof JXHeader;
    JXHeader header = (JXHeader) c;

    titleLabel = new JLabel();
    descriptionPane = new DescriptionPane();
    descriptionPane.setLineWrap(true);
    descriptionPane.setOpaque(false);

    installDefaults(header);

    imagePanel = new JLabel();
    imagePanel.setIcon(
        header.getIcon() == null ? UIManager.getIcon("Header.defaultIcon") : header.getIcon());

    installComponents(header);
    installListeners(header);
  }