/**
   * Paints the preview title at the given position (and returns the required height)
   *
   * @param gc the graphics context to paint into
   * @param x the left edge of the preview rectangle
   * @param y the top edge of the preview rectangle
   * @param displayName the title string to be used
   */
  int paintTitle(GC gc, int x, int y, boolean showFile, String displayName) {
    int titleHeight = 0;

    if (showFile && mIncludedWithin != null) {
      if (mManager.getMode() != INCLUDES) {
        displayName = "<include>";
      } else {
        // Skip: just paint footer instead
        displayName = null;
      }
    }

    int width = getWidth();
    int labelTop = y + 1;
    gc.setClipping(x, labelTop, width, 100);

    // Use font height rather than extent height since we want two adjacent
    // previews (which may have different display names and therefore end
    // up with slightly different extent heights) to have identical title
    // heights such that they are aligned identically
    int fontHeight = gc.getFontMetrics().getHeight();

    if (displayName != null && displayName.length() > 0) {
      gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_WHITE));
      Point extent = gc.textExtent(displayName);
      int labelLeft = Math.max(x, x + (width - extent.x) / 2);
      Image icon = null;
      Locale locale = mConfiguration.getLocale();
      if (locale != null
          && (locale.hasLanguage() || locale.hasRegion())
          && (!(mConfiguration instanceof NestedConfiguration)
              || ((NestedConfiguration) mConfiguration).isOverridingLocale())) {
        icon = locale.getFlagImage();
      }

      if (icon != null) {
        int flagWidth = icon.getImageData().width;
        int flagHeight = icon.getImageData().height;
        labelLeft = Math.max(x + flagWidth / 2, labelLeft);
        gc.drawImage(icon, labelLeft - flagWidth / 2 - 1, labelTop);
        labelLeft += flagWidth / 2 + 1;
        gc.drawText(displayName, labelLeft, labelTop - (extent.y - flagHeight) / 2, true);
      } else {
        gc.drawText(displayName, labelLeft, labelTop, true);
      }

      labelTop += extent.y;
      titleHeight += fontHeight;
    }

    if (showFile && (mAlternateInput != null || mIncludedWithin != null)) {
      // Draw file flag, and parent folder name
      IFile file = mAlternateInput != null ? mAlternateInput : mIncludedWithin.getFile();
      String fileName = file.getParent().getName() + File.separator + file.getName();
      Point extent = gc.textExtent(fileName);
      Image icon = IconFactory.getInstance().getIcon("android_file"); // $NON-NLS-1$
      int flagWidth = icon.getImageData().width;
      int flagHeight = icon.getImageData().height;

      int labelLeft = Math.max(x, x + (width - extent.x - flagWidth - 1) / 2);

      gc.drawImage(icon, labelLeft, labelTop);

      gc.setForeground(gc.getDevice().getSystemColor(SWT.COLOR_GRAY));
      labelLeft += flagWidth + 1;
      labelTop -= (extent.y - flagHeight) / 2;
      gc.drawText(fileName, labelLeft, labelTop, true);

      titleHeight += Math.max(titleHeight, icon.getImageData().height);
    }

    gc.setClipping((Region) null);

    return titleHeight;
  }
  /**
   * Notifies that the preview's configuration has changed.
   *
   * @param flags the change flags, a bitmask corresponding to the {@code CHANGE_} constants in
   *     {@link ConfigurationClient}
   */
  public void configurationChanged(int flags) {
    if (!mVisible) {
      mDirty |= flags;
      return;
    }

    if ((flags & MASK_RENDERING) != 0) {
      mResourceResolver.clear();
      // Handle inheritance
      mConfiguration.syncFolderConfig();
      updateForkStatus();
      updateSize();
    }

    // Sanity check to make sure things are working correctly
    if (DEBUG) {
      RenderPreviewMode mode = mManager.getMode();
      if (mode == DEFAULT) {
        assert mConfiguration instanceof VaryingConfiguration;
        VaryingConfiguration config = (VaryingConfiguration) mConfiguration;
        int alternateFlags = config.getAlternateFlags();
        switch (alternateFlags) {
          case Configuration.CFG_DEVICE_STATE:
            {
              State configState = config.getDeviceState();
              State chooserState = mManager.getChooser().getConfiguration().getDeviceState();
              assert configState != null && chooserState != null;
              assert !configState.getName().equals(chooserState.getName())
                  : configState.toString() + ':' + chooserState;

              Device configDevice = config.getDevice();
              Device chooserDevice = mManager.getChooser().getConfiguration().getDevice();
              assert configDevice != null && chooserDevice != null;
              assert configDevice == chooserDevice : configDevice.toString() + ':' + chooserDevice;

              break;
            }
          case Configuration.CFG_DEVICE:
            {
              Device configDevice = config.getDevice();
              Device chooserDevice = mManager.getChooser().getConfiguration().getDevice();
              assert configDevice != null && chooserDevice != null;
              assert configDevice != chooserDevice : configDevice.toString() + ':' + chooserDevice;

              State configState = config.getDeviceState();
              State chooserState = mManager.getChooser().getConfiguration().getDeviceState();
              assert configState != null && chooserState != null;
              assert configState.getName().equals(chooserState.getName())
                  : configState.toString() + ':' + chooserState;

              break;
            }
          case Configuration.CFG_LOCALE:
            {
              Locale configLocale = config.getLocale();
              Locale chooserLocale = mManager.getChooser().getConfiguration().getLocale();
              assert configLocale != null && chooserLocale != null;
              assert configLocale != chooserLocale : configLocale.toString() + ':' + chooserLocale;
              break;
            }
          default:
            {
              // Some other type of override I didn't anticipate
              assert false : alternateFlags;
            }
        }
      }
    }

    mDirty = 0;
    mManager.scheduleRender(this);
  }