public class ActionHandlerPhotoFilter extends AbstractHandler {

  static final String COMMAND_ID = "command.net.tourbook.PhotoFilter"; // $NON-NLS-1$

  private static IPreferenceStore _prefStore = TourbookPlugin.getDefault().getPreferenceStore();

  private boolean _isAppPhotoFilterInitialized;

  public Object execute(final ExecutionEvent event) throws ExecutionException {

    final boolean isPhotoFilterActive = !HandlerUtil.toggleCommandState(event.getCommand());

    TourbookPlugin.setActivePhotoFilter(isPhotoFilterActive);

    // fire event that photo filter has changed
    _prefStore.setValue(ITourbookPreferences.APP_DATA_FILTER_IS_MODIFIED, Math.random());

    return null;
  }

  @Override
  public void setEnabled(final Object evaluationContext) {

    super.setEnabled(evaluationContext);

    if (_isAppPhotoFilterInitialized == false) {

      _isAppPhotoFilterInitialized = true;

      /*
       * initialize app photo filter, this is a hack because the whole app startup should be
       * sometimes be streamlined, it's more and more confusing
       */
      final Command command =
          ((ICommandService)
                  PlatformUI //
                      .getWorkbench()
                      .getService(ICommandService.class)) //
              .getCommand(ActionHandlerPhotoFilter.COMMAND_ID);

      final State state = command.getState(RegistryToggleState.STATE_ID);
      final Boolean isPhotoFilterActive = (Boolean) state.getValue();

      TourbookPlugin.setActivePhotoFilter(isPhotoFilterActive);
    }
  }
}
  @Override
  public void run() {

    // set the currently displayed map provider so that this mp will be selected in the pref page
    final IPreferenceStore prefStore = TourbookPlugin.getDefault().getPreferenceStore();

    prefStore.setValue( //
        IMappingPreferences.MAP_FACTORY_LAST_SELECTED_MAP_PROVIDER,
        _tourMapView.getMap().getMapProvider().getId());

    PreferencesUtil.createPreferenceDialogOn(
            Display.getCurrent().getActiveShell(),
            PrefPageMapProviders.PREF_PAGE_MAP_PROVIDER_ID,
            null,
            null)
        .open();
  }
  @Override
  public void start(final BundleContext context) throws Exception {

    super.start(context);

    _instance = this;
    _bundleContext = context;

    final Bundle bundle = context.getBundle();
    if (bundle instanceof AbstractBundle) {
      final AbstractBundle abstractBundle = (AbstractBundle) bundle;
      _version = abstractBundle.getVersion();
    }

    // log version that this info is easier accessable
    final Version version = TourbookPlugin.getDefault().getVersion();
    StatusUtil.log("AppVersion: " + version.toString()); // $NON-NLS-1$
  }
public class PrefPageAppearance extends PreferencePage implements IWorkbenchPreferencePage {

  public static final String ID = "net.tourbook.preferences.PrefPageAppearance"; // $NON-NLS-1$

  private final boolean _isOSX = net.tourbook.util.UI.IS_OSX;
  private final boolean _isLinux = net.tourbook.util.UI.IS_LINUX;

  private final IPreferenceStore _prefStore = TourbookPlugin.getDefault().getPreferenceStore();

  private boolean _isModified = false;

  /*
   * UI tools
   */
  private int _hintDefaultSpinnerWidth;
  private PixelConverter _pc;
  private SelectionAdapter _defaultSelectionAdapter;
  private MouseWheelListener _defaultMouseWheelListener;

  /*
   * UI controls
   */
  private Spinner _spinnerRecentTourTypes;
  private Spinner _spinnerRecentTags;
  private Button _chkMemMonitor;

  private Button _chkAutoOpenTagging;
  private Spinner _spinnerAutoOpenDelay;
  private Label _lblAutoTagDelay;
  private Label _lblAutoOpenMS;
  private Button _chkTaggingAnimation;

  public PrefPageAppearance() {
    //		noDefaultAndApplyButton();
  }

  @Override
  protected Control createContents(final Composite parent) {

    initUITools(parent);

    final Composite container = createUI(parent);

    restoreState();
    enableControls();

    return container;
  }

  private Composite createUI(final Composite parent) {

    final Composite container = new Composite(parent, SWT.NONE);
    GridDataFactory.fillDefaults().grab(true, false).applyTo(container);
    GridLayoutFactory.fillDefaults().spacing(5, 15).applyTo(container);
    {
      createUI10Tagging(container);
      createUI20RecentEntries(container);
      createUI30MemoryMonitor(container);
    }

    return container;
  }

  private void createUI10Tagging(final Composite parent) {

    final Group group = new Group(parent, SWT.NONE);
    GridDataFactory.fillDefaults().grab(true, false).applyTo(group);
    group.setText(Messages.Pref_Appearance_Group_Tagging);
    GridLayoutFactory.swtDefaults().numColumns(2).applyTo(group);
    {
      /*
       * number of recent tags
       */
      final Label label = new Label(group, NONE);
      label.setText(Messages.pref_appearance_number_of_recent_tags);
      label.setToolTipText(Messages.pref_appearance_number_of_recent_tags_tooltip);

      // spinner
      _spinnerRecentTags = new Spinner(group, SWT.BORDER);
      GridDataFactory.fillDefaults() //
          .hint(_hintDefaultSpinnerWidth, SWT.DEFAULT)
          .align(SWT.BEGINNING, SWT.CENTER)
          .applyTo(_spinnerRecentTags);
      _spinnerRecentTags.setToolTipText(Messages.pref_appearance_number_of_recent_tags_tooltip);
      _spinnerRecentTags.setMinimum(0);
      _spinnerRecentTags.setMaximum(9);
      _spinnerRecentTags.addSelectionListener(_defaultSelectionAdapter);
      _spinnerRecentTags.addMouseWheelListener(_defaultMouseWheelListener);

      /*
       * autoopen tagging
       */
      //				eclipse 3.7 supports this feature
      //				if (_isOSX) {
      //					// label: OSX is not supported, feature is not working
      //					final Label label = new Label(container, SWT.WRAP);
      //					GridDataFactory.fillDefaults().span(3, 1).applyTo(label);
      //					label.setText(Messages.Pref_Appearance_Label_NoOSXSupport);
      //				}
      _chkAutoOpenTagging = new Button(group, SWT.CHECK);
      GridDataFactory.fillDefaults().span(2, 1).applyTo(_chkAutoOpenTagging);
      _chkAutoOpenTagging.setText(Messages.Pref_Appearance_Check_AutoOpenTagging);
      _chkAutoOpenTagging.addSelectionListener(_defaultSelectionAdapter);
      _chkAutoOpenTagging.setToolTipText(Messages.Pref_Appearance_Label_AutoOpenTagging_Tooltip);

      final Composite autoTagContainer = new Composite(group, SWT.NONE);
      GridDataFactory.fillDefaults()
          .grab(false, false)
          .indent(16, 0)
          .span(2, 1)
          .applyTo(autoTagContainer);
      GridLayoutFactory.fillDefaults().numColumns(3).applyTo(autoTagContainer);
      {

        // label: delay
        _lblAutoTagDelay = new Label(autoTagContainer, SWT.NONE);
        _lblAutoTagDelay.setText(Messages.Pref_Appearance_Label_AutoOpenTaggingDelay);
        _lblAutoTagDelay.setToolTipText(Messages.Pref_Appearance_Label_AutoOpenTagging_Tooltip);

        // spinner
        _spinnerAutoOpenDelay = new Spinner(autoTagContainer, SWT.BORDER);
        GridDataFactory.fillDefaults() //
            .hint(_hintDefaultSpinnerWidth, SWT.DEFAULT)
            .align(SWT.BEGINNING, SWT.CENTER)
            .applyTo(_spinnerAutoOpenDelay);
        _spinnerAutoOpenDelay.setMinimum(0);
        _spinnerAutoOpenDelay.setMaximum(3000);
        _spinnerAutoOpenDelay.addSelectionListener(_defaultSelectionAdapter);
        _spinnerAutoOpenDelay.addMouseWheelListener(_defaultMouseWheelListener);

        // label: ms
        _lblAutoOpenMS = new Label(autoTagContainer, SWT.NONE);
        _lblAutoOpenMS.setText(UI.UNIT_LABEL_MS);

        // check: show animation
        _chkTaggingAnimation = new Button(autoTagContainer, SWT.CHECK);
        GridDataFactory.fillDefaults().span(3, 1).applyTo(_chkTaggingAnimation);
        _chkTaggingAnimation.setText(Messages.Pref_Appearance_Check_TaggingAnimation);
        _chkTaggingAnimation.addSelectionListener(_defaultSelectionAdapter);
      }
    }
  }

  private void createUI20RecentEntries(final Composite parent) {

    final Composite container = new Composite(parent, SWT.NONE);
    GridDataFactory.fillDefaults().grab(true, false).applyTo(container);
    GridLayoutFactory.fillDefaults().numColumns(2).applyTo(container);
    {

      /*
       * number of recent tour types
       */
      final Label label = new Label(container, NONE);
      label.setText(Messages.Pref_Appearance_NumberOfRecent_TourTypes);
      label.setToolTipText(Messages.Pref_Appearance_NumberOfRecent_TourTypes_Tooltip);

      // spinner
      _spinnerRecentTourTypes = new Spinner(container, SWT.BORDER);
      GridDataFactory.fillDefaults() //
          .hint(_hintDefaultSpinnerWidth, SWT.DEFAULT)
          .align(SWT.BEGINNING, SWT.CENTER)
          .applyTo(_spinnerRecentTourTypes);
      _spinnerRecentTourTypes.setToolTipText(
          Messages.Pref_Appearance_NumberOfRecent_TourTypes_Tooltip);
      _spinnerRecentTourTypes.setMinimum(0);
      _spinnerRecentTourTypes.setMaximum(9);
      _spinnerRecentTourTypes.addSelectionListener(_defaultSelectionAdapter);
      _spinnerRecentTourTypes.addMouseWheelListener(_defaultMouseWheelListener);
    }
  }

  /** memory monitor */
  private void createUI30MemoryMonitor(final Composite parent) {

    _chkMemMonitor = new Button(parent, SWT.CHECK);
    GridDataFactory.fillDefaults().indent(0, 10).applyTo(_chkMemMonitor);
    _chkMemMonitor.setText(Messages.pref_appearance_showMemoryMonitor);
  }

  private void enableControls() {

    final boolean isTagAutoOpen = _chkAutoOpenTagging.getSelection();
    final boolean isEnabled = true; // eclipse 3.7 supports this feature in OSX

    _chkAutoOpenTagging.setEnabled(isEnabled);
    _lblAutoOpenMS.setEnabled(isEnabled && isTagAutoOpen);
    _lblAutoTagDelay.setEnabled(isEnabled && isTagAutoOpen);
    _spinnerAutoOpenDelay.setEnabled(isEnabled && isTagAutoOpen);
    _chkTaggingAnimation.setEnabled(isEnabled && isTagAutoOpen);
  }

  @Override
  public void init(final IWorkbench workbench) {
    setPreferenceStore(_prefStore);
  }

  private void initUITools(final Composite parent) {

    _pc = new PixelConverter(parent);
    _hintDefaultSpinnerWidth =
        _isLinux ? SWT.DEFAULT : _pc.convertWidthInCharsToPixels(_isOSX ? 10 : 5);

    _defaultSelectionAdapter =
        new SelectionAdapter() {
          @Override
          public void widgetSelected(final SelectionEvent e) {
            onChangeProperty();
            enableControls();
          }
        };

    _defaultMouseWheelListener =
        new MouseWheelListener() {
          @Override
          public void mouseScrolled(final MouseEvent event) {
            UI.adjustSpinnerValueOnMouseScroll(event);
            onChangeProperty();
          }
        };
  }

  /** Property was changed, fire a property change event */
  private void onChangeProperty() {
    _isModified = true;
  }

  @Override
  protected void performApply() {

    saveState();

    super.performApply();
  }

  @Override
  protected void performDefaults() {

    _isModified = true;

    _spinnerRecentTags.setSelection( //
        _prefStore.getDefaultInt(ITourbookPreferences.APPEARANCE_NUMBER_OF_RECENT_TAGS));

    _spinnerRecentTourTypes.setSelection( //
        _prefStore.getDefaultInt(ITourbookPreferences.APPEARANCE_NUMBER_OF_RECENT_TOUR_TYPES));

    _chkAutoOpenTagging.setSelection(
        _prefStore.getDefaultBoolean(ITourbookPreferences.APPEARANCE_IS_TAGGING_AUTO_OPEN));
    _chkTaggingAnimation.setSelection(
        _prefStore.getDefaultBoolean(ITourbookPreferences.APPEARANCE_IS_TAGGING_ANIMATION));
    _spinnerAutoOpenDelay.setSelection(
        _prefStore.getDefaultInt(ITourbookPreferences.APPEARANCE_TAGGING_AUTO_OPEN_DELAY));

    _chkMemMonitor.setSelection(
        _prefStore.getDefaultBoolean(ITourbookPreferences.APPEARANCE_SHOW_MEMORY_MONITOR));

    super.performDefaults();

    // this do not work, I have no idea why, but with the apply button it works :-(
    //		fireModificationEvent();

    enableControls();
  }

  @Override
  public boolean performOk() {

    saveState();

    final boolean isShowMemoryOld =
        _prefStore.getBoolean(ITourbookPreferences.APPEARANCE_SHOW_MEMORY_MONITOR);

    final boolean isOK = super.performOk();

    final boolean isShowMemoryNew =
        _prefStore.getBoolean(ITourbookPreferences.APPEARANCE_SHOW_MEMORY_MONITOR);

    if (isOK && _isModified) {
      _isModified = false;
    }

    if (isShowMemoryNew != isShowMemoryOld) {
      if (MessageDialog.openQuestion(
          Display.getDefault().getActiveShell(),
          Messages.pref_appearance_showMemoryMonitor_title,
          Messages.pref_appearance_showMemoryMonitor_message)) {

        Display.getCurrent()
            .asyncExec(
                new Runnable() {
                  @Override
                  public void run() {
                    PlatformUI.getWorkbench().restart();
                  }
                });
      }
    }

    return isOK;
  }

  private void restoreState() {

    _spinnerRecentTags.setSelection( //
        _prefStore.getInt(ITourbookPreferences.APPEARANCE_NUMBER_OF_RECENT_TAGS));

    _spinnerRecentTourTypes.setSelection( //
        _prefStore.getInt(ITourbookPreferences.APPEARANCE_NUMBER_OF_RECENT_TOUR_TYPES));

    _chkAutoOpenTagging.setSelection(
        _prefStore.getBoolean(ITourbookPreferences.APPEARANCE_IS_TAGGING_AUTO_OPEN));
    _chkTaggingAnimation.setSelection(
        _prefStore.getBoolean(ITourbookPreferences.APPEARANCE_IS_TAGGING_ANIMATION));
    _spinnerAutoOpenDelay.setSelection(
        _prefStore.getInt(ITourbookPreferences.APPEARANCE_TAGGING_AUTO_OPEN_DELAY));

    _chkMemMonitor.setSelection(
        _prefStore.getBoolean(ITourbookPreferences.APPEARANCE_SHOW_MEMORY_MONITOR));
  }

  private void saveState() {

    _prefStore.setValue( //
        ITourbookPreferences.APPEARANCE_NUMBER_OF_RECENT_TAGS, _spinnerRecentTags.getSelection());

    _prefStore.setValue(
        ITourbookPreferences.APPEARANCE_NUMBER_OF_RECENT_TOUR_TYPES,
        _spinnerRecentTourTypes.getSelection());

    _prefStore.setValue(
        ITourbookPreferences.APPEARANCE_IS_TAGGING_AUTO_OPEN, _chkAutoOpenTagging.getSelection());
    _prefStore.setValue(
        ITourbookPreferences.APPEARANCE_IS_TAGGING_ANIMATION, _chkTaggingAnimation.getSelection());
    _prefStore.setValue(
        ITourbookPreferences.APPEARANCE_TAGGING_AUTO_OPEN_DELAY,
        _spinnerAutoOpenDelay.getSelection());

    _prefStore.setValue(
        ITourbookPreferences.APPEARANCE_SHOW_MEMORY_MONITOR, _chkMemMonitor.getSelection());
  }
}
public class SmoothingAlgorithmJamet implements ISmoothingAlgorithm {

  private static final int MAX_TAU = 5000;

  private final IPreferenceStore _prefStore = TourbookPlugin.getDefault().getPreferenceStore();

  private final boolean _isOSX = net.tourbook.common.UI.IS_OSX;
  private final boolean _isLinux = net.tourbook.common.UI.IS_LINUX;

  private int _hintDefaultSpinnerWidth;

  private SmoothingUI _smoothingUI;

  private SelectionAdapter _selectionListener;
  private MouseWheelListener _spinnerMouseWheelListener;

  private boolean _isUpdateUI;

  /*
   * UI resources
   */
  private PixelConverter _pc;

  private Image _imageAltitude =
      TourbookPlugin.getImageDescriptor( //
              Messages.Image__graph_altitude)
          .createImage();
  private Image _imageGradient =
      TourbookPlugin.getImageDescriptor( //
              Messages.Image__graph_gradient)
          .createImage();
  private Image _imagePulse =
      TourbookPlugin.getImageDescriptor( //
              Messages.Image__graph_heartbeat)
          .createImage();
  private Image _imageSpeed =
      TourbookPlugin.getImageDescriptor( //
              Messages.Image__graph_speed)
          .createImage();

  /*
   * UI controls
   */
  private FormToolkit _tk;

  private Button _chkIsSynchSmoothing;
  private Button _chkIsAltitudeSmoothing;
  private Button _chkIsPulseSmoothing;
  private Spinner _spinnerGradientTau;
  private Spinner _spinnerPulseTau;
  private Spinner _spinnerSpeedTau;
  private Spinner _spinnerRepeatedSmoothing;
  private Spinner _spinnerRepeatedTau;
  private Spinner _spinnerLastUsed;

  private Label _lblRepeatedSmoothing;
  private Label _lblRepeatedTau;

  private CLabel _iconSpeed;
  private CLabel _iconPulse;
  private CLabel _iconGradient;
  private CLabel _iconAltitude;

  public SmoothingAlgorithmJamet() {}

  @Override
  public Composite createUI(
      final SmoothingUI smoothingUI, final Composite parent, final boolean isShowDescription) {

    _smoothingUI = smoothingUI;

    initUI(parent);

    final Composite container = _tk.createComposite(parent);
    GridDataFactory.fillDefaults().grab(true, true).applyTo(container);
    GridLayoutFactory.fillDefaults().spacing(5, 5).numColumns(3).applyTo(container);
    //		container.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_BLUE));
    {
      createUI10Tau(container);
      createUI20SmoothSpeed(container);
      createUI22SmoothGradient(container);
      createUI24SmoothPulse(container);
      createUI26SmoothAltitude(container);
      createUI30Iterations(container);

      createUI50Actions(container);
    }

    restoreState();
    enableControls();

    return container;
  }

  private void createUI10Tau(final Composite parent) {

    final Label label = _tk.createLabel(parent, Messages.TourChart_Smoothing_Label_TauParameter);
    GridDataFactory.fillDefaults().span(3, 1).grab(false, false).applyTo(label);
  }

  private void createUI20SmoothSpeed(final Composite parent) {

    /*
     * image: speed
     */
    _iconSpeed = new CLabel(parent, SWT.NONE);
    GridDataFactory.fillDefaults().indent(16, 0).applyTo(_iconSpeed);
    _iconSpeed.setBackground(_tk.getColors().getBackground());
    _iconSpeed.setImage(_imageSpeed);

    /*
     * label: smooth speed
     */
    final Label label = _tk.createLabel(parent, Messages.TourChart_Smoothing_Label_SpeedSmoothing);
    GridDataFactory.fillDefaults() //
        .align(SWT.FILL, SWT.CENTER)
        .applyTo(label);
    label.setToolTipText(Messages.TourChart_Smoothing_Label_SpeedSmoothing_Tooltip);

    /*
     * spinner: tau
     */
    _spinnerSpeedTau = new Spinner(parent, SWT.BORDER);
    GridDataFactory.fillDefaults() //
        .align(SWT.BEGINNING, SWT.FILL)
        .applyTo(_spinnerSpeedTau);
    _spinnerSpeedTau.setDigits(1);
    _spinnerSpeedTau.setMinimum(1);
    _spinnerSpeedTau.setMaximum(MAX_TAU);
    _spinnerSpeedTau.addSelectionListener(_selectionListener);
    _spinnerSpeedTau.addMouseWheelListener(_spinnerMouseWheelListener);
  }

  private void createUI22SmoothGradient(final Composite parent) {

    /*
     * image: gradient
     */
    _iconGradient = new CLabel(parent, SWT.NONE);
    GridDataFactory.fillDefaults().indent(16, 0).applyTo(_iconGradient);
    _iconGradient.setBackground(_tk.getColors().getBackground());
    _iconGradient.setImage(_imageGradient);

    /*
     * label: smooth gradient
     */
    final Label label =
        _tk.createLabel(parent, Messages.TourChart_Smoothing_Label_GradientSmoothing, SWT.CHECK);
    GridDataFactory.fillDefaults() //
        .align(SWT.FILL, SWT.CENTER)
        .applyTo(label);
    label.setToolTipText(Messages.TourChart_Smoothing_Label_GradientSmoothing_Tooltip);

    /*
     * spinner: gradient tau
     */
    _spinnerGradientTau = new Spinner(parent, SWT.BORDER);
    GridDataFactory.fillDefaults() //
        .align(SWT.BEGINNING, SWT.FILL)
        .applyTo(_spinnerGradientTau);
    _spinnerGradientTau.setDigits(1);
    _spinnerGradientTau.setMinimum(1);
    _spinnerGradientTau.setMaximum(MAX_TAU);
    _spinnerGradientTau.addSelectionListener(_selectionListener);
    _spinnerGradientTau.addMouseWheelListener(_spinnerMouseWheelListener);
  }

  private void createUI24SmoothPulse(final Composite parent) {

    /*
     * image: pulse
     */
    _iconPulse = new CLabel(parent, SWT.NONE);
    GridDataFactory.fillDefaults().indent(16, 0).applyTo(_iconPulse);
    _iconPulse.setBackground(_tk.getColors().getBackground());
    _iconPulse.setImage(_imagePulse);

    /*
     * checkbox: smooth speed
     */
    _chkIsPulseSmoothing =
        _tk.createButton(parent, Messages.TourChart_Smoothing_Checkbox_IsPulseSmoothing, SWT.CHECK);
    GridDataFactory.fillDefaults() //
        .align(SWT.FILL, SWT.CENTER)
        .applyTo(_chkIsPulseSmoothing);
    _chkIsPulseSmoothing.addSelectionListener(_selectionListener);
    _chkIsPulseSmoothing.setToolTipText(
        Messages.TourChart_Smoothing_Checkbox_IsPulseSmoothing_Tooltip);

    /*
     * spinner: speed tau
     */
    _spinnerPulseTau = new Spinner(parent, SWT.BORDER);
    GridDataFactory.fillDefaults() //
        .align(SWT.BEGINNING, SWT.FILL)
        .applyTo(_spinnerPulseTau);
    _spinnerPulseTau.setDigits(1);
    _spinnerPulseTau.setMinimum(1);
    _spinnerPulseTau.setMaximum(MAX_TAU);
    _spinnerPulseTau.addSelectionListener(_selectionListener);
    _spinnerPulseTau.addMouseWheelListener(_spinnerMouseWheelListener);
  }

  private void createUI26SmoothAltitude(final Composite parent) {

    /*
     * image: altitude
     */
    _iconAltitude = new CLabel(parent, SWT.NONE);
    GridDataFactory.fillDefaults().indent(16, 0).applyTo(_iconAltitude);
    _iconAltitude.setBackground(_tk.getColors().getBackground());
    _iconAltitude.setImage(_imageAltitude);

    /*
     * checkbox: smooth altitude
     */
    _chkIsAltitudeSmoothing =
        _tk.createButton(
            parent, Messages.TourChart_Smoothing_Checkbox_IsAltitudeSmoothing, SWT.CHECK);
    GridDataFactory.fillDefaults() //
        .align(SWT.FILL, SWT.CENTER)
        .span(2, 1)
        .applyTo(_chkIsAltitudeSmoothing);
    _chkIsAltitudeSmoothing.setToolTipText(
        Messages.TourChart_Smoothing_Checkbox_IsAltitudeSmoothing_Tooltip);
    _chkIsAltitudeSmoothing.addSelectionListener(_selectionListener);
  }

  private void createUI30Iterations(final Composite parent) {

    /*
     * sync smoothing
     */
    {
      _chkIsSynchSmoothing =
          _tk.createButton(
              parent, Messages.TourChart_Smoothing_Checkbox_IsSyncSmoothing, SWT.CHECK);
      GridDataFactory.fillDefaults() //
          .align(SWT.FILL, SWT.CENTER)
          .span(3, 1)
          .indent(0, 10)
          .applyTo(_chkIsSynchSmoothing);
      _chkIsSynchSmoothing.setToolTipText(
          Messages.TourChart_Smoothing_Checkbox_IsSyncSmoothing_Tooltip);
      _chkIsSynchSmoothing.addSelectionListener(_selectionListener);
    }

    /*
     * repeated smoothing
     */
    {
      _lblRepeatedSmoothing =
          _tk.createLabel(parent, Messages.TourChart_Smoothing_Label_RepeatedSmoothing);
      GridDataFactory.fillDefaults() //
          .align(SWT.FILL, SWT.CENTER)
          .span(2, 1)
          .indent(0, 10)
          .applyTo(_lblRepeatedSmoothing);
      _lblRepeatedSmoothing.setToolTipText(
          Messages.TourChart_Smoothing_Label_RepeatedSmoothing_Tooltip);

      /*
       * spinner: repeated smoothing
       */
      _spinnerRepeatedSmoothing = new Spinner(parent, SWT.BORDER);
      GridDataFactory.fillDefaults() //
          .align(SWT.BEGINNING, SWT.FILL)
          .indent(0, 10)
          .hint(_hintDefaultSpinnerWidth, SWT.DEFAULT)
          .applyTo(_spinnerRepeatedSmoothing);
      _spinnerRepeatedSmoothing.setMinimum(0);
      _spinnerRepeatedSmoothing.setMaximum(10);
      _spinnerRepeatedSmoothing.addSelectionListener(_selectionListener);
      _spinnerRepeatedSmoothing.addMouseWheelListener(_spinnerMouseWheelListener);
    }

    /*
     * repeated tau
     */
    {
      _lblRepeatedTau = _tk.createLabel(parent, Messages.TourChart_Smoothing_Label_RepeatedTau);
      GridDataFactory.fillDefaults() //
          .align(SWT.FILL, SWT.CENTER)
          .span(2, 1)
          .applyTo(_lblRepeatedTau);
      _lblRepeatedTau.setToolTipText(Messages.TourChart_Smoothing_Label_RepeatedTau_Tooltip);

      /*
       * spinner: repeated tau
       */
      _spinnerRepeatedTau = new Spinner(parent, SWT.BORDER);
      GridDataFactory.fillDefaults() //
          .align(SWT.BEGINNING, SWT.FILL)
          .hint(_hintDefaultSpinnerWidth, SWT.DEFAULT)
          .applyTo(_spinnerRepeatedTau);
      _spinnerRepeatedTau.setDigits(1);
      _spinnerRepeatedTau.setMinimum(1);
      _spinnerRepeatedTau.setMaximum(10);
      _spinnerRepeatedTau.addSelectionListener(_selectionListener);
      _spinnerRepeatedTau.addMouseWheelListener(_spinnerMouseWheelListener);
    }
  }

  private void createUI50Actions(final Composite parent) {

    final Composite container = _tk.createComposite(parent);
    GridDataFactory.fillDefaults().grab(true, true).span(3, 1).applyTo(container);
    GridLayoutFactory.fillDefaults().numColumns(1).applyTo(container);
    //		container.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_YELLOW));
    {
      /*
       * button: compute smoothing values for all tours
       */
      final Button btnComputValues =
          _tk.createButton(container, Messages.Compute_Smoothing_Button_ForAllTours, SWT.NONE);
      GridDataFactory.fillDefaults()
          .align(SWT.BEGINNING, SWT.FILL)
          .indent(0, 10)
          .applyTo(btnComputValues);
      btnComputValues.setToolTipText(Messages.Compute_Smoothing_Button_ForAllTours_Tooltip);
      btnComputValues.addSelectionListener(
          new SelectionAdapter() {
            @Override
            public void widgetSelected(final SelectionEvent e) {
              _smoothingUI.computeSmoothingForAllTours();
            }
          });

      /*
       * link: restore defaults
       */
      Link link = new Link(container, SWT.NONE);
      GridDataFactory.fillDefaults() //
          .align(SWT.FILL, SWT.END)
          .grab(false, true)
          .applyTo(link);
      link.setText(Messages.App_Link_RestoreDefaultValues);
      link.setEnabled(true);
      link.addSelectionListener(
          new SelectionAdapter() {
            @Override
            public void widgetSelected(final SelectionEvent e) {
              performDefaults(true);
            }
          });
      _tk.adapt(link, true, true);

      /*
       * link: break time
       */
      link = new Link(container, SWT.NONE);
      GridDataFactory.fillDefaults() //
          .align(SWT.FILL, SWT.END)
          .applyTo(link);
      link.setText(Messages.TourChart_Smoothing_Link_PrefBreakTime);
      link.setEnabled(true);
      link.addSelectionListener(
          new SelectionAdapter() {
            @Override
            public void widgetSelected(final SelectionEvent e) {
              PreferencesUtil.createPreferenceDialogOn(
                      parent.getShell(),
                      PrefPageComputedValues.ID,
                      null,
                      PrefPageComputedValues.TAB_FOLDER_BREAK_TIME)
                  .open();
            }
          });
      _tk.adapt(link, true, true);

      /*
       * link: smoothing online documentation
       */
      link = new Link(container, SWT.NONE);
      GridDataFactory.fillDefaults() //
          .align(SWT.FILL, SWT.END)
          .applyTo(link);
      link.setText(Messages.TourChart_Smoothing_Link_SmoothingOnlineDocumentation);
      link.setEnabled(true);
      link.addSelectionListener(
          new SelectionAdapter() {
            @Override
            public void widgetSelected(final SelectionEvent e) {
              WEB.openUrl(
                  //
                  // the url MUST be splitted otherwise the messages editor will truncate the url
                  //
                  Messages.External_Link_MyTourbook
                      + Messages.External_Link_MyTourbook_TourChartSmoothing);
            }
          });
      _tk.adapt(link, true, true);
    }
  }

  @Override
  public void dispose() {

    Util.disposeResource(_imageAltitude);
    Util.disposeResource(_imageGradient);
    Util.disposeResource(_imagePulse);
    Util.disposeResource(_imageSpeed);

    _tk.dispose();
  }

  private void enableControls() {

    final boolean isRepeated = _spinnerRepeatedSmoothing.getSelection() != 0;

    _lblRepeatedTau.setEnabled(isRepeated);

    _spinnerPulseTau.setEnabled(_chkIsPulseSmoothing.getSelection());
    _spinnerRepeatedTau.setEnabled(isRepeated);
  }

  private void initUI(final Composite parent) {

    _pc = new PixelConverter(parent);
    _hintDefaultSpinnerWidth =
        _isLinux ? SWT.DEFAULT : _pc.convertWidthInCharsToPixels(_isOSX ? 10 : 5);

    _tk = new FormToolkit(parent.getDisplay());

    _selectionListener =
        new SelectionAdapter() {
          @Override
          public void widgetSelected(final SelectionEvent e) {
            if (_isUpdateUI) {
              return;
            }
            onModifySmoothing(e.widget, true);
          }
        };

    _spinnerMouseWheelListener =
        new MouseWheelListener() {
          @Override
          public void mouseScrolled(final MouseEvent event) {
            Util.adjustSpinnerValueOnMouseScroll(event);
            if (_isUpdateUI) {
              return;
            }
            onModifySmoothing(event.widget, true);
          }
        };
  }

  private void onModifySmoothing(final Widget widget, final boolean isFireModifications) {

    updateSyncedSlider(widget);

    enableControls();

    saveState();

    if (isFireModifications) {

      // delete cached data that the smoothed data series are recreated when displayed
      TourManager.getInstance().removeAllToursFromCache();

      // fire unique event for all changes
      TourManager.fireEvent(TourEventId.TOUR_CHART_PROPERTY_IS_MODIFIED);
    }
  }

  @Override
  public void performDefaults(final boolean isFireModifications) {

    _isUpdateUI = true;
    {
      _chkIsSynchSmoothing.setSelection( //
          _prefStore.getDefaultBoolean(
              ITourbookPreferences.GRAPH_JAMET_SMOOTHING_IS_SYNCH_SMOOTHING));

      // repeated smoothing
      _spinnerRepeatedSmoothing.setSelection( //
          _prefStore.getDefaultInt(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_REPEATED_SMOOTHING));
      _spinnerRepeatedTau.setSelection( //
          (int)
              (_prefStore.getDefaultDouble(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_REPEATED_TAU)
                  * 10));

      // altitude
      _chkIsAltitudeSmoothing.setSelection( //
          _prefStore.getDefaultBoolean(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_IS_ALTITUDE));

      // gradient
      _spinnerGradientTau.setSelection( //
          (int)
              (_prefStore.getDefaultDouble(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_GRADIENT_TAU)
                  * 10));

      // pulse
      _chkIsPulseSmoothing.setSelection( //
          _prefStore.getDefaultBoolean(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_IS_PULSE));
      _spinnerPulseTau.setSelection(
          (int)
              (_prefStore.getDefaultDouble(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_PULSE_TAU)
                  * 10));

      // speed
      _spinnerSpeedTau.setSelection( //
          (int)
              (_prefStore.getDefaultDouble(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_SPEED_TAU)
                  * 10));
    }
    _isUpdateUI = false;

    onModifySmoothing(null, isFireModifications);
  }

  private void restoreState() {

    _isUpdateUI = true;
    {
      _chkIsSynchSmoothing.setSelection( //
          _prefStore.getBoolean(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_IS_SYNCH_SMOOTHING));

      // repeated smoothing
      _spinnerRepeatedSmoothing.setSelection( //
          _prefStore.getInt(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_REPEATED_SMOOTHING));
      _spinnerRepeatedTau.setSelection( //
          (int)
              (_prefStore.getDouble(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_REPEATED_TAU) * 10));

      // altitude
      _chkIsAltitudeSmoothing.setSelection( //
          _prefStore.getBoolean(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_IS_ALTITUDE));

      // gradient
      _spinnerGradientTau.setSelection( //
          (int)
              (_prefStore.getDouble(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_GRADIENT_TAU) * 10));

      // pulse
      _chkIsPulseSmoothing.setSelection( //
          _prefStore.getBoolean(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_IS_PULSE));
      _spinnerPulseTau.setSelection( //
          (int) (_prefStore.getDouble(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_PULSE_TAU) * 10));

      // speed
      _spinnerSpeedTau.setSelection( //
          (int) (_prefStore.getDouble(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_SPEED_TAU) * 10));
    }
    _isUpdateUI = false;
  }

  private void saveState() {

    _prefStore.setValue(
        ITourbookPreferences.GRAPH_JAMET_SMOOTHING_IS_SYNCH_SMOOTHING, //
        _chkIsSynchSmoothing.getSelection());

    // repeated smoothing
    _prefStore.setValue(
        ITourbookPreferences.GRAPH_JAMET_SMOOTHING_REPEATED_SMOOTHING, //
        _spinnerRepeatedSmoothing.getSelection());
    _prefStore.setValue(
        ITourbookPreferences.GRAPH_JAMET_SMOOTHING_REPEATED_TAU, //
        _spinnerRepeatedTau.getSelection() / 10.0);

    // altitude
    _prefStore.setValue(
        ITourbookPreferences.GRAPH_JAMET_SMOOTHING_IS_ALTITUDE, //
        _chkIsAltitudeSmoothing.getSelection());

    // gradient
    _prefStore.setValue(
        ITourbookPreferences.GRAPH_JAMET_SMOOTHING_GRADIENT_TAU, //
        _spinnerGradientTau.getSelection() / 10.0);

    // pulse
    _prefStore.setValue(
        ITourbookPreferences.GRAPH_JAMET_SMOOTHING_IS_PULSE, //
        _chkIsPulseSmoothing.getSelection());
    _prefStore.setValue(
        ITourbookPreferences.GRAPH_JAMET_SMOOTHING_PULSE_TAU, //
        _spinnerPulseTau.getSelection() / 10.0);

    // speed smoothing
    _prefStore.setValue(
        ITourbookPreferences.GRAPH_JAMET_SMOOTHING_SPEED_TAU, //
        _spinnerSpeedTau.getSelection() / 10.0);
  }

  private void updateSyncedSlider(final Widget widget) {

    if (widget == null) {
      return;
    }

    int synchValue = -1;

    if (widget == _chkIsSynchSmoothing
        && _chkIsSynchSmoothing.getSelection()
        && _spinnerLastUsed != null) {

      // synch is checked, set spinner to the last used values, when available

      synchValue = _spinnerLastUsed.getSelection();

    } else {

      if (widget == _spinnerGradientTau) {

        synchValue = _spinnerGradientTau.getSelection();
        _spinnerLastUsed = _spinnerGradientTau;

      } else if (widget == _spinnerPulseTau) {

        synchValue = _spinnerPulseTau.getSelection();
        _spinnerLastUsed = _spinnerPulseTau;

      } else if (widget == _spinnerSpeedTau) {

        synchValue = _spinnerSpeedTau.getSelection();
        _spinnerLastUsed = _spinnerSpeedTau;
      }
    }

    // set last used spinner if existing
    if (_chkIsSynchSmoothing.getSelection() == false) {
      // no synching
      return;
    }

    if (synchValue != -1) {
      _isUpdateUI = true;
      {
        _spinnerGradientTau.setSelection(synchValue);
        _spinnerPulseTau.setSelection(synchValue);
        _spinnerSpeedTau.setSelection(synchValue);
      }
      _isUpdateUI = false;
    }
  }

  @Override
  public void updateUIFromPrefStore() {
    restoreState();
    enableControls();
  }
}
  @Override
  public void initializeDefaultPreferences() {

    final IPreferenceStore store = TourbookPlugin.getDefault().getPreferenceStore();

    /*
     * system
     */
    store.setDefault(ITourbookPreferences.TOUR_CACHE_SIZE, 500);

    /*
     * tour database, default is embedded
     */
    store.setDefault(ITourbookPreferences.TOUR_DATABASE_IS_DERBY_EMBEDDED, true);

    /*
     * regional settings
     */

    // disabled since version 11.7
    store.setDefault(ITourbookPreferences.MEASUREMENT_SYSTEM_SHOW_IN_UI, false);

    store.setDefault(
        ITourbookPreferences.MEASUREMENT_SYSTEM_DISTANCE,
        ITourbookPreferences.MEASUREMENT_SYSTEM_DISTANCE_KM);
    store.setDefault(
        ITourbookPreferences.MEASUREMENT_SYSTEM_ALTITUDE,
        ITourbookPreferences.MEASUREMENT_SYSTEM_ALTITUDE_M);
    store.setDefault(
        ITourbookPreferences.MEASUREMENT_SYSTEM_TEMPERATURE,
        ITourbookPreferences.MEASUREMENT_SYSTEM_TEMPERATURE_C);
    store.setDefault(
        ITourbookPreferences.MEASUREMENT_SYSTEM_ENERGY,
        ITourbookPreferences.MEASUREMENT_SYSTEM_ENERGY_JOULE);

    store.setDefault(ITourbookPreferences.REGIONAL_USE_CUSTOM_DECIMAL_FORMAT, false);
    store.setDefault(ITourbookPreferences.REGIONAL_DECIMAL_SEPARATOR, "."); // $NON-NLS-1$
    store.setDefault(ITourbookPreferences.REGIONAL_GROUP_SEPARATOR, "'"); // $NON-NLS-1$

    /*
     * Statistics
     */
    store.setDefault(ITourbookPreferences.STAT_ALTITUDE_LOW_VALUE, 0);
    store.setDefault(ITourbookPreferences.STAT_ALTITUDE_INTERVAL, 250);
    store.setDefault(ITourbookPreferences.STAT_ALTITUDE_NUMBERS, 21);

    store.setDefault(ITourbookPreferences.STAT_DISTANCE_LOW_VALUE, 0);
    store.setDefault(ITourbookPreferences.STAT_DISTANCE_INTERVAL, 10);
    store.setDefault(ITourbookPreferences.STAT_DISTANCE_NUMBERS, 21);

    store.setDefault(ITourbookPreferences.STAT_DURATION_LOW_VALUE, 0);
    store.setDefault(ITourbookPreferences.STAT_DURATION_INTERVAL, 60);
    store.setDefault(ITourbookPreferences.STAT_DURATION_NUMBERS, 12);

    store.setDefault(ITourbookPreferences.STAT_DAY_IS_SHOW_ALTITUDE, true);
    store.setDefault(ITourbookPreferences.STAT_DAY_IS_SHOW_AVG_PACE, true);
    store.setDefault(ITourbookPreferences.STAT_DAY_IS_SHOW_AVG_SPEED, true);
    store.setDefault(ITourbookPreferences.STAT_DAY_IS_SHOW_DISTANCE, true);
    store.setDefault(ITourbookPreferences.STAT_DAY_IS_SHOW_DURATION, true);

    /*
     * Graph preferences
     */
    store.setDefault(ITourbookPreferences.GRAPH_PREF_PAGE_IS_TOUR_CHART_LIVE_UPDATE, true);
    store.setDefault(
        ITourbookPreferences.GRAPH_VISIBLE, Integer.toString(TourManager.GRAPH_ALTITUDE));
    store.setDefault(ITourbookPreferences.GRAPH_IS_GRAPH_OVERLAPPED, false);

    final String separator = StringToArrayConverter.STRING_SEPARATOR;

    store.setDefault(
        ITourbookPreferences.GRAPH_ALL,
        (Integer.toString(TourManager.GRAPH_ALTITUDE) + separator)
            + (Integer.toString(TourManager.GRAPH_PULSE) + separator)
            + (Integer.toString(TourManager.GRAPH_SPEED) + separator)
            + (Integer.toString(TourManager.GRAPH_PACE) + separator)
            + (Integer.toString(TourManager.GRAPH_TEMPERATURE) + separator)
            + (Integer.toString(TourManager.GRAPH_CADENCE) + separator)
            + (Integer.toString(TourManager.GRAPH_GEARS) + separator)
            + (Integer.toString(TourManager.GRAPH_ALTIMETER) + separator)
            + (Integer.toString(TourManager.GRAPH_GRADIENT) + separator)
            + Integer.toString(TourManager.GRAPH_POWER));

    // HR zone backbround
    store.setDefault(ITourbookPreferences.GRAPH_IS_HR_ZONE_BACKGROUND_VISIBLE, false);
    store.setDefault(
        ITourbookPreferences.GRAPH_HR_ZONE_STYLE, TourChart.ACTION_ID_HR_ZONE_STYLE_GRAPH_TOP);

    store.setDefault(ITourbookPreferences.GRAPH_ANTIALIASING, true);
    store.setDefault(ITourbookPreferences.GRAPH_TRANSPARENCY_LINE, 0xFF);
    store.setDefault(ITourbookPreferences.GRAPH_TRANSPARENCY_FILLING, 0x80);

    // chart/tour segment alternate color
    store.setDefault(ITourbookPreferences.GRAPH_IS_SEGMENT_ALTERNATE_COLOR, false);
    PreferenceConverter.setDefault(
        store, ITourbookPreferences.GRAPH_SEGMENT_ALTERNATE_COLOR, new RGB(0xf5, 0xf5, 0xf5));

    // tour segmenter chart value font
    final FontData[] segmenterDefaultFontData = Display.getDefault().getSystemFont().getFontData();
    segmenterDefaultFontData[0].setHeight(8);
    PreferenceConverter.setDefault(
        store, ITourbookPreferences.TOUR_SEGMENTER_CHART_VALUE_FONT, segmenterDefaultFontData);

    // show breaktime values
    store.setDefault(ITourbookPreferences.GRAPH_IS_BREAKTIME_VALUES_VISIBLE, true);

    // tour marker
    store.setDefault(ITourbookPreferences.GRAPH_IS_MARKER_VISIBLE, true);
    store.setDefault(ITourbookPreferences.GRAPH_MARKER_HOVER_SIZE, 4);
    store.setDefault(ITourbookPreferences.GRAPH_MARKER_LABEL_OFFSET, 2);
    store.setDefault(
        ITourbookPreferences.GRAPH_MARKER_LABEL_TEMP_POSITION,
        TourMarker.LABEL_POS_HORIZONTAL_ABOVE_GRAPH_CENTERED);
    store.setDefault(ITourbookPreferences.GRAPH_MARKER_POINT_SIZE, 2);
    store.setDefault(ITourbookPreferences.GRAPH_MARKER_SIGN_IMAGE_SIZE, 50); // in DLU
    store.setDefault(ITourbookPreferences.GRAPH_MARKER_IS_DRAW_WITH_DEFAULT_COLOR, true);
    store.setDefault(ITourbookPreferences.GRAPH_MARKER_IS_SHOW_ABSOLUTE_VALUES, false);
    store.setDefault(ITourbookPreferences.GRAPH_MARKER_IS_SHOW_HIDDEN_MARKER, false);
    store.setDefault(ITourbookPreferences.GRAPH_MARKER_IS_SHOW_ONLY_WITH_DESCRIPTION, false);
    store.setDefault(ITourbookPreferences.GRAPH_MARKER_IS_SHOW_LABEL_TEMP_POSITION, false);
    store.setDefault(ITourbookPreferences.GRAPH_MARKER_IS_SHOW_MARKER_LABEL, true);
    store.setDefault(ITourbookPreferences.GRAPH_MARKER_IS_SHOW_MARKER_POINT, true);
    store.setDefault(ITourbookPreferences.GRAPH_MARKER_IS_SHOW_MARKER_TOOLTIP, true);
    store.setDefault(ITourbookPreferences.GRAPH_MARKER_IS_SHOW_SIGN_IMAGE, true);
    store.setDefault(
        ITourbookPreferences.GRAPH_MARKER_TOOLTIP_POSITION,
        ChartMarkerToolTip.DEFAULT_TOOLTIP_POSITION);

    PreferenceConverter.setDefault(
        store, ITourbookPreferences.GRAPH_MARKER_COLOR_DEFAULT, new RGB(0x60, 0x60, 0x60));
    PreferenceConverter.setDefault(
        store, ITourbookPreferences.GRAPH_MARKER_COLOR_DEVICE, new RGB(0xff, 0x0, 0x80));
    PreferenceConverter.setDefault(
        store, ITourbookPreferences.GRAPH_MARKER_COLOR_HIDDEN, new RGB(0x24, 0x9C, 0xFF));

    // tour info
    store.setDefault(ITourbookPreferences.GRAPH_TOUR_INFO_IS_VISIBLE, true);
    store.setDefault(ITourbookPreferences.GRAPH_TOUR_INFO_IS_TITLE_VISIBLE, true);
    store.setDefault(ITourbookPreferences.GRAPH_TOUR_INFO_IS_TOOLTIP_VISIBLE, true);
    store.setDefault(ITourbookPreferences.GRAPH_TOUR_INFO_IS_TOUR_SEPARATOR_VISIBLE, true);
    store.setDefault(ITourbookPreferences.GRAPH_TOUR_INFO_TOOLTIP_DELAY, 200);

    // is photo visible
    store.setDefault(ITourbookPreferences.GRAPH_IS_TOUR_PHOTO_VISIBLE, true);
    store.setDefault(ITourbookPreferences.GRAPH_IS_TOUR_PHOTO_TOOLTIP_VISIBLE, true);

    // define which unit is shown on the x-axis
    store.setDefault(ITourbookPreferences.GRAPH_X_AXIS, TourManager.X_AXIS_DISTANCE);

    // mouse modus: zoom tour chart
    store.setDefault(ITourbookPreferences.GRAPH_MOUSE_MODE, Chart.MOUSE_MODE_ZOOM);

    // move sliders to border when zoomed
    store.setDefault(ITourbookPreferences.GRAPH_MOVE_SLIDERS_WHEN_ZOOMED, false);

    // graph grid
    store.setDefault(ITourbookPreferences.CHART_GRID_VERTICAL_DISTANCE, 80);
    store.setDefault(ITourbookPreferences.CHART_GRID_HORIZONTAL_DISTANCE, 80);
    store.setDefault(ITourbookPreferences.CHART_GRID_IS_SHOW_HORIZONTAL_GRIDLINES, false);
    store.setDefault(ITourbookPreferences.CHART_GRID_IS_SHOW_VERTICAL_GRIDLINES, false);

    /*
     * Min/Max values
     */
    store.setDefault(ITourbookPreferences.GRAPH_IS_MIN_MAX_ENABLED, true);

    store.setDefault(ITourbookPreferences.GRAPH_ALTIMETER_IS_MIN_ENABLED, true);
    store.setDefault(ITourbookPreferences.GRAPH_ALTIMETER_IS_MAX_ENABLED, true);
    store.setDefault(ITourbookPreferences.GRAPH_ALTIMETER_MIN_VALUE, 0);
    store.setDefault(ITourbookPreferences.GRAPH_ALTIMETER_MAX_VALUE, 1500);

    store.setDefault(ITourbookPreferences.GRAPH_ALTITUDE_IS_MIN_ENABLED, false);
    store.setDefault(ITourbookPreferences.GRAPH_ALTITUDE_IS_MAX_ENABLED, false);
    store.setDefault(ITourbookPreferences.GRAPH_ALTITUDE_MIN_VALUE, 0);
    store.setDefault(ITourbookPreferences.GRAPH_ALTITUDE_MAX_VALUE, 3000);

    store.setDefault(ITourbookPreferences.GRAPH_CADENCE_IS_MIN_ENABLED, false);
    store.setDefault(ITourbookPreferences.GRAPH_CADENCE_IS_MAX_ENABLED, false);
    store.setDefault(ITourbookPreferences.GRAPH_CADENCE_MIN_VALUE, 50);
    store.setDefault(ITourbookPreferences.GRAPH_CADENCE_MAX_VALUE, 100);

    store.setDefault(ITourbookPreferences.GRAPH_GRADIENT_IS_MIN_ENABLED, true);
    store.setDefault(ITourbookPreferences.GRAPH_GRADIENT_IS_MAX_ENABLED, true);
    store.setDefault(ITourbookPreferences.GRAPH_GRADIENT_MIN_VALUE, -20);
    store.setDefault(ITourbookPreferences.GRAPH_GRADIENT_MAX_VALUE, 20);

    store.setDefault(ITourbookPreferences.GRAPH_PACE_IS_MIN_ENABLED, true);
    store.setDefault(ITourbookPreferences.GRAPH_PACE_IS_MAX_ENABLED, true);
    store.setDefault(ITourbookPreferences.GRAPH_PACE_MIN_VALUE, 1);
    store.setDefault(ITourbookPreferences.GRAPH_PACE_MAX_VALUE, 6);

    store.setDefault(ITourbookPreferences.GRAPH_SPEED_IS_MIN_ENABLED, true);
    store.setDefault(ITourbookPreferences.GRAPH_SPEED_IS_MAX_ENABLED, true);
    store.setDefault(ITourbookPreferences.GRAPH_SPEED_MIN_VALUE, 5);
    store.setDefault(ITourbookPreferences.GRAPH_SPEED_MAX_VALUE, 150);

    store.setDefault(ITourbookPreferences.GRAPH_POWER_IS_MIN_ENABLED, true);
    store.setDefault(ITourbookPreferences.GRAPH_POWER_IS_MAX_ENABLED, true);
    store.setDefault(ITourbookPreferences.GRAPH_POWER_MIN_VALUE, 100);
    store.setDefault(ITourbookPreferences.GRAPH_POWER_MAX_VALUE, 400);

    store.setDefault(ITourbookPreferences.GRAPH_PULSE_IS_MIN_ENABLED, false);
    store.setDefault(ITourbookPreferences.GRAPH_PULSE_IS_MAX_ENABLED, false);
    store.setDefault(ITourbookPreferences.GRAPH_PULSE_MIN_VALUE, 50);
    store.setDefault(ITourbookPreferences.GRAPH_PULSE_MAX_VALUE, 200);

    store.setDefault(ITourbookPreferences.GRAPH_TEMPERATURE_IS_MIN_ENABLED, false);
    store.setDefault(ITourbookPreferences.GRAPH_TEMPERATURE_IS_MAX_ENABLED, false);
    store.setDefault(ITourbookPreferences.GRAPH_TEMPERATURE_MIN_VALUE, -50);
    store.setDefault(ITourbookPreferences.GRAPH_TEMPERATURE_MAX_VALUE, 50);

    // value point tool tip
    store.setDefault(ITourbookPreferences.VALUE_POINT_TOOL_TIP_IS_VISIBLE, true);

    /*
     * graph smoothing
     */
    // algorithm
    store.setDefault(
        ITourbookPreferences.GRAPH_SMOOTHING_SMOOTHING_ALGORITHM,
        ISmoothingAlgorithm.SMOOTHING_ALGORITHM_JAMET);

    store.setDefault(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_REPEATED_SMOOTHING, 1);
    store.setDefault(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_REPEATED_TAU, 1.0);
    store.setDefault(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_IS_SYNCH_SMOOTHING, true);

    // altitude
    store.setDefault(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_IS_ALTITUDE, false);

    // gradient
    store.setDefault(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_GRADIENT_TAU, 10.0);

    // pulse
    store.setDefault(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_IS_PULSE, false);
    store.setDefault(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_PULSE_TAU, 10.0);

    // speed
    store.setDefault(ITourbookPreferences.GRAPH_JAMET_SMOOTHING_SPEED_TAU, 10.0);

    /*
     * view colors
     */
    PreferenceConverter.setDefault(
        store, ITourbookPreferences.VIEW_LAYOUT_COLOR_CATEGORY, new RGB(0xF2, 0x5B, 0x00));
    PreferenceConverter.setDefault(
        store, ITourbookPreferences.VIEW_LAYOUT_COLOR_TITLE, new RGB(0x00, 0x6F, 0xDD));
    PreferenceConverter.setDefault(
        store, ITourbookPreferences.VIEW_LAYOUT_COLOR_SUB, new RGB(0xF2, 0x5B, 0x00));
    PreferenceConverter.setDefault(
        store, ITourbookPreferences.VIEW_LAYOUT_COLOR_SUB_SUB, new RGB(0x00, 0x6F, 0xDD));
    PreferenceConverter.setDefault(
        store, ITourbookPreferences.VIEW_LAYOUT_COLOR_TOUR, new RGB(0x00, 0x00, 0x00));
    PreferenceConverter.setDefault(
        store, ITourbookPreferences.VIEW_LAYOUT_COLOR_BG_HISTORY_TOUR, new RGB(0xFC, 0xFF, 0xE3));

    /*
     * Display formats
     */

    store.setDefault(ITourbookPreferences.VIEW_LAYOUT_DISPLAY_LINES, false);

    /*
     * map
     */
    store.setDefault(
        ITourbookPreferences.MAP_LAYOUT_PLOT_TYPE, PrefPageMap2Appearance.DEFAULT_PLOT_TYPE);
    store.setDefault(ITourbookPreferences.MAP_LAYOUT_SYMBOL_WIDTH, 6);
    store.setDefault(ITourbookPreferences.MAP_LAYOUT_PAINT_WITH_BORDER, true);
    store.setDefault(ITourbookPreferences.MAP_LAYOUT_BORDER_WIDTH, 1);
    store.setDefault(ITourbookPreferences.MAP_LAYOUT_BORDER_DIMM_VALUE, 80); // 0...100

    PreferenceConverter.setDefault(
        store, ITourbookPreferences.MAP_LAYOUT_BORDER_COLOR, new RGB(0x50, 0x50, 0x50));
    PreferenceConverter.setDefault(
        store, ITourbookPreferences.MAP_LAYOUT_MAP_DIMM_COLOR, new RGB(0x00, 0x00, 0x00));
    store.setDefault(
        ITourbookPreferences.MAP_LAYOUT_TOUR_PAINT_METHOD,
        PrefPageMap2Appearance.TOUR_PAINT_METHOD_SIMPLE);
    store.setDefault(ITourbookPreferences.MAP_LAYOUT_LIVE_UPDATE, true);

    /*
     * tour data editor
     */
    store.setDefault(ITourbookPreferences.TOUR_EDITOR_DESCRIPTION_HEIGHT, 3);

    /*
     * general appearance
     */
    store.setDefault(ITourbookPreferences.APPEARANCE_NUMBER_OF_RECENT_TOUR_TYPES, 3);
    store.setDefault(ITourbookPreferences.APPEARANCE_NUMBER_OF_RECENT_TAGS, 3);
    store.setDefault(ITourbookPreferences.APPEARANCE_SHOW_TOUR_TYPE_CONTEXT_MENU, true);

    // heap is not displayed by default since version 11.7
    store.setDefault(ITourbookPreferences.APPEARANCE_SHOW_MEMORY_MONITOR, false);

    store.setDefault(ITourbookPreferences.APPEARANCE_IS_TAGGING_AUTO_OPEN, true);
    store.setDefault(ITourbookPreferences.APPEARANCE_IS_TAGGING_ANIMATION, true);
    store.setDefault(ITourbookPreferences.APPEARANCE_TAGGING_AUTO_OPEN_DELAY, 500);

    /*
     * merge tour dialog
     */
    store.setDefault(ITourbookPreferences.MERGE_TOUR_GRAPH_X_AXIS, TourManager.X_AXIS_DISTANCE);
    store.setDefault(ITourbookPreferences.MERGE_TOUR_PREVIEW_CHART, false);
    store.setDefault(ITourbookPreferences.MERGE_TOUR_ALTITUDE_DIFF_SCALING, false);
    store.setDefault(ITourbookPreferences.MERGE_TOUR_SYNC_START_TIME, true);

    // save actions
    store.setDefault(ITourbookPreferences.MERGE_TOUR_MERGE_GRAPH_ALTITUDE, false);
    store.setDefault(ITourbookPreferences.MERGE_TOUR_MERGE_GRAPH_PULSE, false);
    store.setDefault(ITourbookPreferences.MERGE_TOUR_MERGE_GRAPH_TEMPERATURE, false);
    store.setDefault(ITourbookPreferences.MERGE_TOUR_MERGE_GRAPH_CADENCE, false);

    store.setDefault(ITourbookPreferences.MERGE_TOUR_ADJUST_START_ALTITUDE, false);
    store.setDefault(ITourbookPreferences.MERGE_TOUR_LINEAR_INTERPOLATION, false);

    store.setDefault(ITourbookPreferences.MERGE_TOUR_SET_TOUR_TYPE, false);
    store.setDefault(
        ITourbookPreferences.MERGE_TOUR_SET_TOUR_TYPE_ID, TourDatabase.ENTITY_IS_NOT_SAVED);

    /*
     * computed values
     */

    // speed minimum time slice value in seconds
    store.setDefault(ITourbookPreferences.APP_DATA_SPEED_MIN_TIMESLICE_VALUE, 10);

    /*
     * break time using metric values
     */
    store.setDefault(
        ITourbookPreferences.BREAK_TIME_METHOD2,
        BreakTimeTool.BREAK_TIME_METHOD_BY_AVG_SLICE_SPEED);

    // minimum speed for a break, default is 1.0 km/h to respect walking in the mountains
    store.setDefault(ITourbookPreferences.BREAK_TIME_MIN_AVG_SPEED_AS, 1.0f);
    store.setDefault(ITourbookPreferences.BREAK_TIME_MIN_SLICE_SPEED_AS, 1.0f);
    store.setDefault(ITourbookPreferences.BREAK_TIME_MIN_SLICE_TIME_AS, 2);

    // minimum speed for a break, default is 1.0 km/h to respect walking in the mountains
    store.setDefault(ITourbookPreferences.BREAK_TIME_MIN_SLICE_SPEED, 1.0f);
    store.setDefault(ITourbookPreferences.BREAK_TIME_MIN_AVG_SPEED, 1.0f);

    // break time, default is 3.6 km/h (20 m in 20 sec)
    store.setDefault(ITourbookPreferences.BREAK_TIME_SHORTEST_TIME, 20);
    store.setDefault(ITourbookPreferences.BREAK_TIME_MAX_DISTANCE, 20.0f);
    store.setDefault(ITourbookPreferences.BREAK_TIME_SLICE_DIFF, 5); // 5 minutes

    // DP tolerance when computing altitude up/down
    store.setDefault(ITourbookPreferences.COMPUTED_ALTITUDE_DP_TOLERANCE, 7.0f);

    /*
     * view column tooltip
     */
    store.setDefault(ITourbookPreferences.VIEW_TOOLTIP_COLLATED_COLLATION, true);
    store.setDefault(ITourbookPreferences.VIEW_TOOLTIP_COLLATED_TIME, true);
    store.setDefault(ITourbookPreferences.VIEW_TOOLTIP_COLLATED_TITLE, true);
    store.setDefault(ITourbookPreferences.VIEW_TOOLTIP_COLLATED_TAGS, true);
    store.setDefault(ITourbookPreferences.VIEW_TOOLTIP_COLLATED_WEEKDAY, true);

    store.setDefault(ITourbookPreferences.VIEW_TOOLTIP_TOURBOOK_DATE, true);
    store.setDefault(ITourbookPreferences.VIEW_TOOLTIP_TOURBOOK_TIME, true);
    store.setDefault(ITourbookPreferences.VIEW_TOOLTIP_TOURBOOK_TITLE, true);
    store.setDefault(ITourbookPreferences.VIEW_TOOLTIP_TOURBOOK_TAGS, true);
    store.setDefault(ITourbookPreferences.VIEW_TOOLTIP_TOURBOOK_WEEKDAY, true);

    store.setDefault(ITourbookPreferences.VIEW_TOOLTIP_TAGGING_TAG, true);
    store.setDefault(ITourbookPreferences.VIEW_TOOLTIP_TAGGING_TITLE, true);
    store.setDefault(ITourbookPreferences.VIEW_TOOLTIP_TAGGING_TAGS, true);

    store.setDefault(ITourbookPreferences.VIEW_TOOLTIP_TOURCATALOG_REFTOUR, true);
    store.setDefault(ITourbookPreferences.VIEW_TOOLTIP_TOURCATALOG_TITLE, true);
    store.setDefault(ITourbookPreferences.VIEW_TOOLTIP_TOURCATALOG_TAGS, true);

    store.setDefault(ITourbookPreferences.VIEW_TOOLTIP_TOURIMPORT_DATE, true);
    store.setDefault(ITourbookPreferences.VIEW_TOOLTIP_TOURIMPORT_TIME, true);
    store.setDefault(ITourbookPreferences.VIEW_TOOLTIP_TOURIMPORT_TITLE, true);
    store.setDefault(ITourbookPreferences.VIEW_TOOLTIP_TOURIMPORT_TAGS, true);

    /*
     * view actions
     */
    store.setDefault(
        ITourbookPreferences.VIEW_DOUBLE_CLICK_ACTIONS,
        PrefPageViews.VIEW_DOUBLE_CLICK_ACTION_QUICK_EDIT);

    /*
     * Pref page: Map3 color
     */
    store.setDefault(ITourbookPreferences.MAP3_IS_COLOR_SELECTOR_DISPLAYED, true);
    store.setDefault(ITourbookPreferences.MAP3_NUMBER_OF_COLOR_SELECTORS, 10);

    /*
     * Tour import
     */
    store.setDefault(ITourbookPreferences.IMPORT_IS_NEW_UI, false);

    /*
     * Adjust temperature
     */
    store.setDefault(
        ITourbookPreferences.ADJUST_TEMPERATURE_AVG_TEMPERATURE,
        EasyConfig.TEMPERATURE_AVG_TEMPERATURE_DEFAULT);
    store.setDefault(
        ITourbookPreferences.ADJUST_TEMPERATURE_DURATION_TIME,
        EasyConfig.TEMPERATURE_ADJUSTMENT_DURATION_DEFAULT);

    /*
     * Heart rate variability
     */
    store.setDefault(ITourbookPreferences.HRV_OPTIONS_2X_ERROR_TOLERANCE, 20); // milliseconds
    store.setDefault(ITourbookPreferences.HRV_OPTIONS_IS_FIX_2X_ERROR, false);

    /*
     * Time zone
     */
    store.setDefault(
        ITourbookPreferences.DIALOG_SET_TIME_ZONE_ACTION,
        DialogSetTimeZone.TIME_ZONE_ACTION_SET_FROM_LIST);
    store.setDefault(
        ITourbookPreferences.DIALOG_SET_TIME_ZONE_SELECTED_ZONE_ID,
        TimeTools.getDefaultTimeZoneId());

    // SET_FORMATTING_ON
  }
public class DialogManageOfflineImages extends TitleAreaDialog implements ITileListener {

  private final IPreferenceStore _prefStore = TourbookPlugin.getDefault().getPreferenceStore();

  private final IDialogSettings _state =
      TourbookPlugin.getDefault()
          .getDialogSettingsSection("DialogManageOfflineImages"); // $NON-NLS-1$

  private final OfflineLoadManager _offlineManager = OfflineLoadManager.getInstance();

  private MP _selectedMp;
  private MPProfile _mpProfile;
  private final int _mapZoomLevel;

  private final Point _offlineWorldStart;
  private final Point _offlineWorldEnd;

  private Combo _comboMapProvider;
  private Combo _comboTargetZoom;
  private ProgressBar _progbarQueue;
  private Text _txtQueue;
  private Button _btnDownload;
  private Button _btnRefreshParts;
  private Button _btnStop;
  private Button _btnDeleteAll;
  private Button _btnDeletePart;

  private int[] _targetZoomLevels;
  private ArrayList<MP> _allMapProviders;

  private TableViewer _partViewer;
  private final ArrayList<PartMP> _partMapProvider = new ArrayList<PartMP>();
  private int _validMapZoomLevel;

  private Image _imageRefresh;

  private final int[] _updateCounter = new int[] {0};
  private int _maxQueue;

  private final Display _display;

  private final NumberFormat _nf = NumberFormat.getInstance();

  {
    _nf.setMinimumFractionDigits(1);
    _nf.setMaximumFractionDigits(1);
  }

  class PartMP {

    MP partMp;
    int missingImages;
    int existingImages;

    public PartMP(final MP partMp) {
      this.partMp = partMp;
    }

    @Override
    public String toString() {

      final StringBuilder sb = new StringBuilder();
      sb.append(partMp);
      sb.append("\tmissing:"); // $NON-NLS-1$
      sb.append(missingImages);
      sb.append("\texisting:"); // $NON-NLS-1$
      sb.append(existingImages);

      return sb.toString();
    }
  }

  class PartViewerContentProvicer implements IStructuredContentProvider {

    @Override
    public void dispose() {}

    @Override
    public Object[] getElements(final Object inputElement) {
      return _partMapProvider.toArray();
    }

    @Override
    public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) {}
  }

  public DialogManageOfflineImages(
      final Shell parentShell,
      final MP mp,
      final Point offlineWorldStart,
      final Point offlineWorldEnd,
      final int mapZoomLevel) {

    super(parentShell);

    _selectedMp = mp;
    _mapZoomLevel = mapZoomLevel;

    _offlineWorldStart = offlineWorldStart;
    _offlineWorldEnd = offlineWorldEnd;

    _display = Display.getCurrent();

    // make dialog resizable
    setShellStyle(getShellStyle() | SWT.RESIZE);
  }

  @Override
  public boolean close() {

    _offlineManager.stopLoading();

    MP.removeTileListener(this);

    super.close();

    return true;
  }

  @Override
  protected void configureShell(final Shell shell) {

    super.configureShell(shell);

    shell.setText(Messages.Dialog_OfflineArea_Title);
  }

  @Override
  public void create() {

    getMapProviders();

    super.create();

    setTitle(Messages.Dialog_OfflineArea_Title);
    setMessage(Messages.Dialog_OfflineArea_Message);

    MP.addTileListener(this);

    // disable all controls
    enableControls(false);

    _display.asyncExec(
        new Runnable() {
          @Override
          public void run() {
            initOfflineManager();
            _comboTargetZoom.setFocus();
          }
        });
  }

  @Override
  protected void createButtonsForButtonBar(final Composite parent) {

    // create close button
    createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CLOSE_LABEL, false);
  }

  @Override
  protected Control createDialogArea(final Composite parent) {

    final Composite container = (Composite) super.createDialogArea(parent);

    _imageRefresh = TourbookPlugin.getImageDescriptor(Messages.Image__Refresh).createImage();

    // create ui
    createUI(container);

    initUI();

    parent.addDisposeListener(
        new DisposeListener() {
          @Override
          public void widgetDisposed(final DisposeEvent e) {
            _imageRefresh.dispose();
          }
        });

    return container;
  }

  private void createUI(final Composite parent) {

    final Composite container = new Composite(parent, SWT.NONE);
    GridDataFactory.fillDefaults().grab(true, true).applyTo(container);
    GridLayoutFactory.swtDefaults().numColumns(2).applyTo(container);
    {
      final Composite innerContainer = new Composite(container, SWT.NONE);
      GridDataFactory.fillDefaults().grab(true, true).span(2, 1).applyTo(innerContainer);
      GridLayoutFactory.fillDefaults().numColumns(2).applyTo(innerContainer);
      {
        createUI10LeftPart(innerContainer);
        createUI30Actions(innerContainer);
      }
    }

    // set download as default button
    parent.getShell().setDefaultButton(_btnDownload);
  }

  private void createUI10LeftPart(final Composite parent) {

    Label label;
    final PixelConverter pc = new PixelConverter(parent);

    final Composite container = new Composite(parent, SWT.NONE);
    GridDataFactory.fillDefaults().grab(true, true).applyTo(container);
    GridLayoutFactory.fillDefaults().numColumns(2).applyTo(container);
    //		container.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_GREEN));
    {
      /*
       * target zoom level
       */
      label = new Label(container, SWT.NONE);
      label.setText(Messages.Dialog_OfflineArea_Label_ZoomLevel);

      // combo: zoom level
      _comboTargetZoom = new Combo(container, SWT.READ_ONLY);
      _comboTargetZoom.setVisibleItemCount(20);
      _comboTargetZoom.addSelectionListener(
          new SelectionAdapter() {
            @Override
            public void widgetSelected(final SelectionEvent e) {

              getOfflineImageState();

              // focus was disabled, reset focus
              _comboTargetZoom.setFocus();
            }
          });

      /*
       * map provider
       */
      label = new Label(container, SWT.NONE);
      label.setText(Messages.Dialog_OfflineArea_Label_MapProvider);

      // combo: zoom level
      _comboMapProvider = new Combo(container, SWT.READ_ONLY);
      GridDataFactory.fillDefaults() //
          .hint(pc.convertWidthInCharsToPixels(60), SWT.DEFAULT)
          .applyTo(_comboMapProvider);
      _comboMapProvider.setVisibleItemCount(30);
      _comboMapProvider.addSelectionListener(
          new SelectionAdapter() {
            @Override
            public void widgetSelected(final SelectionEvent e) {
              onSelectMapProvider();
            }
          });

      /*
       * profile parts
       */
      label = new Label(container, SWT.NONE);
      label.setText(Messages.Dialog_OfflineArea_Label_ProfileParts);
      GridDataFactory.fillDefaults().align(SWT.BEGINNING, SWT.FILL).applyTo(label);

      createUI20PartViewer(container);

      /*
       * queue
       */
      label = new Label(container, SWT.NONE);
      label.setText(Messages.Dialog_OfflineArea_Label_Queue);

      final Composite progContainer = new Composite(container, SWT.NONE);
      GridDataFactory.fillDefaults().grab(true, false).applyTo(progContainer);
      GridLayoutFactory.fillDefaults().numColumns(2).applyTo(progContainer);
      //			progContainer.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_BLUE));
      {
        /*
         * progress bar
         */
        _progbarQueue = new ProgressBar(progContainer, SWT.HORIZONTAL | SWT.SMOOTH);
        GridDataFactory.fillDefaults().grab(true, false).applyTo(_progbarQueue);

        /*
         * text: queue
         */
        _txtQueue = new Text(progContainer, SWT.READ_ONLY | SWT.TRAIL | SWT.BORDER);
        GridDataFactory.fillDefaults() //
            .align(SWT.END, SWT.FILL)
            .hint(pc.convertWidthInCharsToPixels(20), SWT.DEFAULT)
            .applyTo(_txtQueue);
        _txtQueue.setBackground(_display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
      }
    }
  }

  private void createUI20PartViewer(final Composite parent) {

    final PixelConverter pixelConverter = new PixelConverter(parent);

    final TableColumnLayout tableLayout = new TableColumnLayout();
    final Composite layoutContainer = new Composite(parent, SWT.NONE);
    layoutContainer.setLayout(tableLayout);

    GridDataFactory.fillDefaults() //
        .grab(true, true)
        .hint(SWT.DEFAULT, pixelConverter.convertHeightInCharsToPixels(13))
        .applyTo(layoutContainer);

    /*
     * create table
     */
    final Table table = new Table(layoutContainer, SWT.FULL_SELECTION | SWT.BORDER);

    table.setLayout(new TableLayout());
    table.setHeaderVisible(true);
    table.setLinesVisible(true);

    _partViewer = new TableViewer(table);

    /*
     * create columns
     */
    TableViewerColumn tvc;
    TableColumn tvcColumn;

    // column: map provider
    tvc = new TableViewerColumn(_partViewer, SWT.LEAD);
    tvcColumn = tvc.getColumn();
    tvcColumn.setText(Messages.Dialog_OfflineArea_Column_MapProvider);
    tvc.setLabelProvider(
        new CellLabelProvider() {
          @Override
          public void update(final ViewerCell cell) {
            final PartMP partMp = (PartMP) cell.getElement();
            cell.setText(partMp.partMp.getName());
          }
        });
    tableLayout.setColumnData(tvcColumn, new ColumnWeightData(100));

    // column: existing images
    tvc = new TableViewerColumn(_partViewer, SWT.TRAIL);
    tvcColumn = tvc.getColumn();
    tvcColumn.setText(Messages.Dialog_OfflineArea_Column_ExistingImages);
    tvcColumn.setToolTipText(Messages.Dialog_OfflineArea_Column_ExistingImages_Tooltip);
    tvc.setLabelProvider(
        new CellLabelProvider() {
          @Override
          public void update(final ViewerCell cell) {
            final PartMP partMp = (PartMP) cell.getElement();
            cell.setText(Integer.toString(partMp.existingImages));
          }
        });
    tableLayout.setColumnData(
        tvcColumn, new ColumnPixelData(pixelConverter.convertWidthInCharsToPixels(12), true));

    // column: missing images
    tvc = new TableViewerColumn(_partViewer, SWT.TRAIL);
    tvcColumn = tvc.getColumn();
    tvcColumn.setText(Messages.Dialog_OfflineArea_Column_MissingImages);
    tvcColumn.setToolTipText(Messages.Dialog_OfflineArea_Column_MissingImages_Tooltip);
    tvc.setLabelProvider(
        new CellLabelProvider() {
          @Override
          public void update(final ViewerCell cell) {
            final PartMP partMp = (PartMP) cell.getElement();
            cell.setText(Integer.toString(partMp.missingImages));
          }
        });
    tableLayout.setColumnData(
        tvcColumn, new ColumnPixelData(pixelConverter.convertWidthInCharsToPixels(12), true));

    /*
     * create table viewer
     */

    _partViewer.setContentProvider(new PartViewerContentProvicer());

    _partViewer.addSelectionChangedListener(
        new ISelectionChangedListener() {
          @Override
          public void selectionChanged(final SelectionChangedEvent event) {
            final StructuredSelection selection = (StructuredSelection) event.getSelection();
            if (selection != null) {
              enableControls(true);
            }
          }
        });
  }

  private void createUI30Actions(final Composite parent) {

    final Composite container = new Composite(parent, SWT.NONE);
    GridDataFactory.fillDefaults().applyTo(container);
    GridLayoutFactory.fillDefaults().spacing(5, 5).applyTo(container);
    //		container.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_BLUE));
    {
      /*
       * button: start loading
       */
      _btnDownload = new Button(container, SWT.NONE);
      GridDataFactory.fillDefaults().grab(true, false).applyTo(_btnDownload);
      _btnDownload.setText(Messages.Dialog_OfflineArea_Button_Download);
      _btnDownload.setToolTipText(Messages.Dialog_OfflineArea_Button_Download_Tooltip);
      _btnDownload.addSelectionListener(
          new SelectionAdapter() {

            @Override
            public void widgetDefaultSelected(final SelectionEvent e) {
              onSelectDownload();
            }

            @Override
            public void widgetSelected(final SelectionEvent e) {
              onSelectDownload();
            }
          });

      /*
       * button: refresh parts
       */
      _btnRefreshParts = new Button(container, SWT.NONE);
      GridDataFactory.fillDefaults().grab(true, false).applyTo(_btnRefreshParts);
      _btnRefreshParts.setText(Messages.Dialog_OfflineArea_Button_RefreshParts);
      _btnRefreshParts.setToolTipText(Messages.Dialog_OfflineArea_Button_RefreshParts_Tooltip);
      _btnRefreshParts.setImage(_imageRefresh);
      _btnRefreshParts.addSelectionListener(
          new SelectionAdapter() {
            @Override
            public void widgetSelected(final SelectionEvent e) {
              getOfflineImageState();
            }
          });

      /*
       * button: stop
       */
      _btnStop = new Button(container, SWT.NONE);
      GridDataFactory.fillDefaults().grab(true, false).applyTo(_btnStop);
      _btnStop.setText(Messages.Dialog_OfflineArea_Button_StopDownloading);
      _btnStop.addSelectionListener(
          new SelectionAdapter() {

            @Override
            public void widgetSelected(final SelectionEvent e) {
              _offlineManager.stopLoading();
              _txtQueue.setText(UI.EMPTY_STRING);
              getOfflineImageState();
            }
          });

      /*
       * button: delete all images
       */
      _btnDeleteAll = new Button(container, SWT.NONE);
      GridDataFactory.fillDefaults().grab(true, false).applyTo(_btnDeleteAll);
      _btnDeleteAll.setText(Messages.Dialog_OfflineArea_Button_DeleteAll);
      _btnDeleteAll.setToolTipText(Messages.Dialog_OfflineArea_Button_DeleteAll_Tooltip);
      _btnDeleteAll.addSelectionListener(
          new SelectionAdapter() {

            @Override
            public void widgetSelected(final SelectionEvent e) {
              onSelectDelete(null);
            }
          });

      /*
       * button: delete part images
       */
      _btnDeletePart = new Button(container, SWT.NONE);
      GridDataFactory.fillDefaults().grab(true, false).applyTo(_btnDeletePart);
      _btnDeletePart.setText(Messages.Dialog_OfflineArea_Button_DeletePart);
      _btnDeletePart.setToolTipText(Messages.Dialog_OfflineArea_Button_DeletePart_Tooltip);
      _btnDeletePart.addSelectionListener(
          new SelectionAdapter() {

            @Override
            public void widgetSelected(final SelectionEvent e) {
              onSelectDelete(((StructuredSelection) _partViewer.getSelection()).getFirstElement());
            }
          });
    }
  }

  private void deleteOfflineImages(final MP selectedPartMp) {

    if (OfflineLoadManager.isLoading()) {
      return;
    }

    enableControls(false);

    final int selectedZoomLevel = _targetZoomLevels[_comboTargetZoom.getSelectionIndex()];

    final int tileSize = _selectedMp.getTileSize();

    final int worldStartX = _offlineWorldStart.x;
    final int worldStartY = _offlineWorldStart.y;
    final int worldEndX = _offlineWorldEnd.x;
    final int worldEndY = _offlineWorldEnd.y;

    for (final PartMP partMp : _partMapProvider) {

      final MP offlineMp = partMp.partMp;

      /*
       * check if only one part should be deleted, all will be deleted when the selectedPartMP
       * is null
       */
      //			if (selectedPartMp != null && offlineMp != selectedPartMp) {
      if (selectedPartMp != null) {

        // mp is set --> only 1 mp will be deleted

        if (_mpProfile == null) {

          if (selectedPartMp != offlineMp) {
            // delete only the selected mp offline images
            continue;
          }
        } else {

          // a mp profile is available in the mp list

          if (_mpProfile == offlineMp) {

            // delete also the mp profile offline images !!!

          } else {

            if (selectedPartMp != offlineMp) {
              continue;
            }
          }
        }
      }

      double worldX1 = Math.min(worldStartX, worldEndX);
      double worldX2 = Math.max(worldStartX, worldEndX);
      double worldY1 = Math.min(worldStartY, worldEndY);
      double worldY2 = Math.max(worldStartY, worldEndY);

      for (int zoomLevel = _validMapZoomLevel; zoomLevel <= selectedZoomLevel; zoomLevel++) {

        final int maxMapTileSize = _selectedMp.getMapTileSize(zoomLevel).width;

        final int areaPixelWidth = (int) (worldX2 - worldX1);
        final int areaPixelHeight = (int) (worldY2 - worldY1);

        final int numTileWidth = (int) Math.ceil((double) areaPixelWidth / (double) tileSize);
        final int numTileHeight = (int) Math.ceil((double) areaPixelHeight / (double) tileSize);

        int tilePosMinX = (int) Math.floor(worldX1 / tileSize);
        int tilePosMinY = (int) Math.floor(worldY1 / tileSize);
        int tilePosMaxX = tilePosMinX + numTileWidth;
        int tilePosMaxY = tilePosMinY + numTileHeight;

        // ensure tiles are within the map
        tilePosMinX = Math.max(0, tilePosMinX);
        tilePosMinY = Math.max(0, tilePosMinY);
        tilePosMaxX = Math.min(tilePosMaxX, maxMapTileSize);
        tilePosMaxY = Math.min(tilePosMaxY, maxMapTileSize);

        for (int tilePosX = tilePosMinX; tilePosX <= tilePosMaxX; tilePosX++) {
          for (int tilePosY = tilePosMinY; tilePosY <= tilePosMaxY; tilePosY++) {

            // create offline tile
            final Tile offlineTile = new Tile(offlineMp, zoomLevel, tilePosX, tilePosY, null);
            offlineTile.setBoundingBoxEPSG4326();
            offlineMp.doPostCreation(offlineTile);

            _offlineManager.deleteOfflineImage(offlineMp, offlineTile);
          }
        }

        // set next zoom level, zoom into the map
        worldX1 *= 2;
        worldX2 *= 2;
        worldY1 *= 2;
        worldY2 *= 2;
      }
    }

    getOfflineImageState();

    // reset states
    tileEvent(TileEventId.TILE_RESET_QUEUES, null);
  }

  private void enableControls(final boolean canBeEnabled) {

    final boolean isLoading = OfflineLoadManager.isLoading();
    final boolean isPartSelected = _partViewer.getSelection().isEmpty() == false;

    _comboTargetZoom.setEnabled(canBeEnabled && isLoading == false);
    _comboMapProvider.setEnabled(canBeEnabled);

    _btnDownload.setEnabled(canBeEnabled && isLoading == false);
    _btnStop.setEnabled(canBeEnabled && isLoading);

    _btnRefreshParts.setEnabled(canBeEnabled && isLoading == false);
    _btnDeleteAll.setEnabled(canBeEnabled && isLoading == false);
    _btnDeletePart.setEnabled(canBeEnabled && isLoading == false && isPartSelected);
  }

  @Override
  protected IDialogSettings getDialogBoundsSettings() {

    // keep window size and position
    return _state;
    //		return null;
  }

  /**
   * @return update the map providers with information from the pref store, the customized order and
   *     the toggle status
   */
  private void getMapProviders() {

    final List<MP> allMapProviders = MapProviderManager.getInstance().getAllMapProviders(true);

    // get sorted map providers from the pref store
    final String[] storedProviderIds =
        StringToArrayConverter.convertStringToArray( //
            _prefStore.getString(IMappingPreferences.MAP_PROVIDER_SORT_ORDER));

    final ArrayList<MP> mapProviders = new ArrayList<MP>();
    final ArrayList<String> validMpIds = new ArrayList<String>();

    // set all map provider which are in the pref store
    for (final String storeMpId : storedProviderIds) {

      /*
       * ensure that a map provider is unique and not duplicated, this happend during
       * debugging
       */
      boolean ignoreMP = false;
      for (final MP mp : mapProviders) {
        if (mp.getId().equalsIgnoreCase(storeMpId)) {
          ignoreMP = true;
          break;
        }
      }
      if (ignoreMP) {
        continue;
      }

      // find the stored map provider in the available map providers
      for (final MP mp : allMapProviders) {
        if (mp.getId().equalsIgnoreCase(storeMpId)) {
          mapProviders.add(mp);
          validMpIds.add(mp.getId());
          break;
        }
      }
    }

    // make sure that all available map providers are in the list
    for (final MP mp : allMapProviders) {
      if (!mapProviders.contains(mp)) {
        mapProviders.add(mp);
      }
    }

    /*
     * save valid mp id's
     */
    _prefStore.setValue(
        IMappingPreferences.MAP_PROVIDER_SORT_ORDER, //
        StringToArrayConverter.convertArrayToString( //
            validMpIds.toArray(new String[validMpIds.size()])));

    /*
     * set status if the map provider can be toggled with the map provider button
     */
    final String[] toggleIds =
        StringToArrayConverter.convertStringToArray( //
            _prefStore.getString(IMappingPreferences.MAP_PROVIDER_TOGGLE_LIST));

    for (final MP mp : allMapProviders) {

      final String mpId = mp.getId();

      for (final String toggleId : toggleIds) {
        if (mpId.equals(toggleId)) {
          mp.setCanBeToggled(true);
          break;
        }
      }
    }

    _allMapProviders = mapProviders;
  }

  private void getOfflineImageState() {

    if (OfflineLoadManager.isLoading()) {
      return;
    }

    enableControls(false);

    getOfflineMapProviders();

    BusyIndicator.showWhile(
        _display,
        new Runnable() {
          @Override
          public void run() {

            final int selectedZoomLevel = _targetZoomLevels[_comboTargetZoom.getSelectionIndex()];

            final int tileSize = _selectedMp.getTileSize();

            final int worldStartX = _offlineWorldStart.x;
            final int worldStartY = _offlineWorldStart.y;
            final int worldEndX = _offlineWorldEnd.x;
            final int worldEndY = _offlineWorldEnd.y;

            for (final PartMP partMp : _partMapProvider) {

              final MP offlineMp = partMp.partMp;

              double worldX1 = Math.min(worldStartX, worldEndX);
              double worldX2 = Math.max(worldStartX, worldEndX);
              double worldY1 = Math.min(worldStartY, worldEndY);
              double worldY2 = Math.max(worldStartY, worldEndY);

              for (int zoomLevel = _validMapZoomLevel;
                  zoomLevel <= selectedZoomLevel;
                  zoomLevel++) {

                final int maxMapTileSize = offlineMp.getMapTileSize(zoomLevel).width;

                final int areaPixelWidth = (int) (worldX2 - worldX1);
                final int areaPixelHeight = (int) (worldY2 - worldY1);

                final int numTileWidth =
                    (int) Math.ceil((double) areaPixelWidth / (double) tileSize);
                final int numTileHeight =
                    (int) Math.ceil((double) areaPixelHeight / (double) tileSize);

                int tilePosMinX = (int) Math.floor(worldX1 / tileSize);
                int tilePosMinY = (int) Math.floor(worldY1 / tileSize);
                int tilePosMaxX = tilePosMinX + numTileWidth;
                int tilePosMaxY = tilePosMinY + numTileHeight;

                // ensure tiles are within the map
                tilePosMinX = Math.max(0, tilePosMinX);
                tilePosMinY = Math.max(0, tilePosMinY);
                tilePosMaxX = Math.min(tilePosMaxX, maxMapTileSize);
                tilePosMaxY = Math.min(tilePosMaxY, maxMapTileSize);

                for (int tilePosX = tilePosMinX; tilePosX <= tilePosMaxX; tilePosX++) {
                  for (int tilePosY = tilePosMinY; tilePosY <= tilePosMaxY; tilePosY++) {

                    // create offline tile
                    final Tile offlineTile =
                        new Tile(offlineMp, zoomLevel, tilePosX, tilePosY, null);
                    offlineTile.setBoundingBoxEPSG4326();
                    offlineMp.doPostCreation(offlineTile);

                    final boolean isAvailable =
                        _offlineManager.isOfflineImageAvailable(offlineMp, offlineTile);

                    if (isAvailable) {
                      partMp.existingImages++;
                    } else {
                      partMp.missingImages++;
                    }
                  }
                }

                // zoom into the map
                worldX1 *= 2;
                worldX2 *= 2;
                worldY1 *= 2;
                worldY2 *= 2;
              }
            }
          }
        });

    // update part viewer
    _partViewer.setInput(new Object());

    // deselect all
    _partViewer.setSelection(null);

    //		// reset queue
    //		_txtQueue.setText(UI.EMPTY_STRING);

    enableControls(true);
  }

  /**
   * creates the list {@link #_partMapProvider} which contains all map providers which should be
   * loaded/deleted/checked
   */
  private void getOfflineMapProviders() {

    // get map providers including
    _partMapProvider.clear();
    _partMapProvider.add(new PartMP(_selectedMp));

    // add all visible mp's which a profile mp contains
    if (_selectedMp instanceof MPProfile) {

      _mpProfile = (MPProfile) _selectedMp;

      final MPProfile mpProfile = (MPProfile) _selectedMp;
      for (final MPWrapper mpWrapper : mpProfile.getAllWrappers()) {
        if (mpWrapper.isDisplayedInMap()) {
          _partMapProvider.add(new PartMP(mpWrapper.getMP()));
        }
      }
    }
  }

  private void initOfflineManager() {

    if (_offlineManager.initialize(_selectedMp)) {

      getOfflineImageState();

      enableControls(true);

    } else {

      // disable controls

      enableControls(false);
    }
  }

  private void initUI() {

    updateZoomLevels();

    // select first zoom level which is the minimum zoom
    _comboTargetZoom.select(0);

    // fill mp combo
    int mpCounter = 0;
    int mpIndex = 0;
    for (final MP mp : _allMapProviders) {
      _comboMapProvider.add(mp.getName());

      if (mp.equals(_selectedMp)) {
        mpIndex = mpCounter;
      }

      mpCounter++;
    }
    // select map provider which is displayed in the map
    _comboMapProvider.select(mpIndex);

    enableControls(true);
  }

  private void loadOfflineImages() {

    if (OfflineLoadManager.isLoading()) {
      return;
    }

    final int selectedZoomLevel = _targetZoomLevels[_comboTargetZoom.getSelectionIndex()];

    final int tileSize = _selectedMp.getTileSize();

    final int worldStartX = _offlineWorldStart.x;
    final int worldStartY = _offlineWorldStart.y;
    final int worldEndX = _offlineWorldEnd.x;
    final int worldEndY = _offlineWorldEnd.y;

    double worldX1 = Math.min(worldStartX, worldEndX);
    double worldX2 = Math.max(worldStartX, worldEndX);
    double worldY1 = Math.min(worldStartY, worldEndY);
    double worldY2 = Math.max(worldStartY, worldEndY);

    for (int zoomLevel = _validMapZoomLevel; zoomLevel <= selectedZoomLevel; zoomLevel++) {

      final int maxMapTileSize = _selectedMp.getMapTileSize(zoomLevel).width;

      final int areaPixelWidth = (int) (worldX2 - worldX1);
      final int areaPixelHeight = (int) (worldY2 - worldY1);

      final int numTileWidth = (int) Math.ceil((double) areaPixelWidth / (double) tileSize);
      final int numTileHeight = (int) Math.ceil((double) areaPixelHeight / (double) tileSize);

      int tilePosMinX = (int) Math.floor(worldX1 / tileSize);
      int tilePosMinY = (int) Math.floor(worldY1 / tileSize);
      int tilePosMaxX = tilePosMinX + numTileWidth;
      int tilePosMaxY = tilePosMinY + numTileHeight;

      // ensure tiles are within the map
      tilePosMinX = Math.max(0, tilePosMinX);
      tilePosMinY = Math.max(0, tilePosMinY);
      tilePosMaxX = Math.min(tilePosMaxX, maxMapTileSize);
      tilePosMaxY = Math.min(tilePosMaxY, maxMapTileSize);

      for (int tilePosX = tilePosMinX; tilePosX <= tilePosMaxX; tilePosX++) {
        for (int tilePosY = tilePosMinY; tilePosY <= tilePosMaxY; tilePosY++) {

          // create offline tile
          final Tile offlineTile = new Tile(_selectedMp, zoomLevel, tilePosX, tilePosY, null);
          offlineTile.setBoundingBoxEPSG4326();
          _selectedMp.doPostCreation(offlineTile);

          _offlineManager.addOfflineTile(_selectedMp, offlineTile);
        }
      }

      // set next zoom level, zoom into the map
      worldX1 *= 2;
      worldX2 *= 2;
      worldY1 *= 2;
      worldY2 *= 2;
    }

    // initialize progress bar
    _maxQueue = MP.getTileWaitingQueue().size();
    _progbarQueue.setMaximum(_maxQueue);
  }

  @Override
  protected void okPressed() {

    super.okPressed();
  }

  private void onSelectDelete(final Object selectedPart) {

    if (selectedPart instanceof PartMP) {

      final MP selectedPartMp = ((PartMP) selectedPart).partMp;

      if (MessageDialog.openConfirm(
          _display.getActiveShell(),
          Messages.Dialog_OfflineArea_ConfirmDelete_Title,
          NLS.bind(
              Messages.Dialog_OfflineArea_ConfirmDeletePart_Message, selectedPartMp.getName()))) {

        deleteOfflineImages(selectedPartMp);
      }

    } else {

      if (MessageDialog.openConfirm(
          _display.getActiveShell(),
          Messages.Dialog_OfflineArea_ConfirmDelete_Title,
          Messages.Dialog_OfflineArea_ConfirmDeleteAll_Message)) {

        deleteOfflineImages(null);
      }
    }
  }

  private void onSelectDownload() {

    loadOfflineImages();
    enableControls(true);
  }

  private void onSelectMapProvider() {

    _selectedMp = _allMapProviders.get(_comboMapProvider.getSelectionIndex());

    updateZoomLevels();

    initOfflineManager();

    _comboMapProvider.setFocus();
  }

  @Override
  public void tileEvent(final TileEventId tileEventId, final Tile tile) {

    final int tileWaitingQueueSize = MP.getTileWaitingQueue().size();

    _updateCounter[0]++;

    _display.asyncExec(
        new Runnable() {

          final int _runnableUpdateCounter = _updateCounter[0];

          public void run() {

            // check if a new runnable was created
            if (_runnableUpdateCounter != _updateCounter[0]) {
              // a new runnable was created
              return;
            }

            // check if widgets are disposed
            if (_comboMapProvider.isDisposed()) {
              return;
            }

            final float progress = _maxQueue - tileWaitingQueueSize;
            final float percent = _maxQueue == 0 ? 0 : progress * 100 / _maxQueue;

            final StringBuilder sb = new StringBuilder();
            sb.append(Integer.toString(tileWaitingQueueSize));
            sb.append(UI.DASH_WITH_SPACE);
            sb.append(_nf.format(percent));
            sb.append('%');

            _progbarQueue.setSelection((int) progress);
            _txtQueue.setText(sb.toString());

            /*
             * update state when all images are downloaded, it's possible that not all images
             * are downloaded when queue size is 0
             */
            if (tileWaitingQueueSize == 0) {

              final UIJob uiJob = new UIJob(_display, "update offline state") { // $NON-NLS-1$

                    final int _uiJobUpdateCounter = _updateCounter[0];

                    @Override
                    public IStatus runInUIThread(final IProgressMonitor monitor) {

                      // check if a new runnable was created
                      if (_uiJobUpdateCounter != _updateCounter[0]) {
                        // a new runnable was created
                        return Status.OK_STATUS;
                      }

                      getOfflineImageState();
                      enableControls(true);

                      _comboTargetZoom.setFocus();

                      return Status.OK_STATUS;
                    }
                  };
              uiJob.setSystem(true);
              uiJob.schedule(200);
            }
          }
        });
  }

  /** update zoom levels for the selected mp */
  private void updateZoomLevels() {

    // get selected zoom level
    final int selectedIndex = _comboTargetZoom.getSelectionIndex();
    int selectedZoomLevel = -1;
    if (selectedIndex != -1 && _targetZoomLevels != null) {
      selectedZoomLevel = _targetZoomLevels[selectedIndex];
    }

    /*
     * get valid zoom levels
     */
    _validMapZoomLevel = _mapZoomLevel;
    final int mapMaxZoom = _selectedMp.getMaxZoomLevel();

    // check if the map zoom level is higher than the available mp zoom levels
    if (_mapZoomLevel > mapMaxZoom) {
      _validMapZoomLevel = mapMaxZoom;
    } else {
      _validMapZoomLevel = _mapZoomLevel;
    }

    _targetZoomLevels = new int[mapMaxZoom - _validMapZoomLevel + 1];

    int zoomIndex = 0;
    for (int zoomLevel = _validMapZoomLevel; zoomLevel <= mapMaxZoom; zoomLevel++) {
      _targetZoomLevels[zoomIndex++] = zoomLevel;
    }

    // fill zoom combo
    _comboTargetZoom.removeAll();
    int reselectedZoomLevelIndex = -1;
    zoomIndex = 0;
    for (final int zoomLevel : _targetZoomLevels) {

      _comboTargetZoom.add(Integer.toString(zoomLevel + 1));

      if (selectedZoomLevel != -1 && zoomLevel == selectedZoomLevel) {
        reselectedZoomLevelIndex = zoomIndex;
      }

      zoomIndex++;
    }

    // reselect zoom level
    if (reselectedZoomLevelIndex == -1) {
      // old zoom level is not available, select first zoom level
      _comboTargetZoom.select(0);
    } else {
      _comboTargetZoom.select(reselectedZoomLevelIndex);
    }
  }
}
 /**
  * This is a shortcut for {@link TourbookPlugin#getDefault()#getPreferenceStore()}
  *
  * @return
  */
 public static IPreferenceStore getPrefStore() {
   return TourbookPlugin.getDefault().getPreferenceStore();
 }