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);
      }
    }
  }
  @Override
  public boolean close() {

    _offlineManager.stopLoading();

    MP.removeTileListener(this);

    super.close();

    return true;
  }
  /** 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);
    }
  }
  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);
  }
  @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();
          }
        });
  }
  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);
  }
  /**
   * @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 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);
  }
  @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);
            }
          }
        });
  }