public void recalculate() {
   myApplianceManager.reset();
   myStorage.removeAll();
   myDeferredFoldRegions.clear();
   myEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
   myApplianceManager.recalculateIfNecessary();
 }
  public SoftWrapModelImpl(@NotNull EditorImpl editor) {
    myEditor = editor;
    myStorage = new SoftWrapsStorage();
    myPainter = new CompositeSoftWrapPainter(editor);
    myEditorTextRepresentationHelper = new DefaultEditorTextRepresentationHelper(editor);
    myDataMapper = new CachingSoftWrapDataMapper(editor, myStorage);
    myApplianceManager = new SoftWrapApplianceManager(myStorage, editor, myPainter, myDataMapper);
    myVisualSizeManager = new SoftWrapAwareVisualSizeManager(myPainter);

    myApplianceManager.addListener(myVisualSizeManager);
    myApplianceManager.addListener(
        new SoftWrapAwareDocumentParsingListenerAdapter() {
          @Override
          public void recalculationEnds() {
            for (SoftWrapChangeListener listener : mySoftWrapListeners) {
              listener.recalculationEnds();
            }
          }
        });
    myUseSoftWraps = areSoftWrapsEnabledInEditor();
    myEditor.getColorsScheme().getFontPreferences().copyTo(myFontPreferences);

    editor.addPropertyChangeListener(this, this);

    myApplianceManager.addListener(myDataMapper);
  }
 /**
  * We know that there are problems with incremental soft wraps cache update at the moment. Hence,
  * we may implement full cache reconstruction when the problem is encountered in order to avoid
  * customer annoyance.
  *
  * <p>However, the problems still should be fixed, hence, we report them only if dedicated flag is
  * set.
  *
  * <p>Current method encapsulates the logic mentioned above.
  *
  * @param task command object that which execution may trigger incremental update of update soft
  *     wraps cache
  */
 @SuppressWarnings({"UseOfArchaicSystemPropertyAccessors"})
 private void executeSafely(SoftWrapAwareTask task) {
   try {
     task.run(true);
   } catch (Throwable e) {
     if (Boolean.getBoolean(DEBUG_PROPERTY_NAME)
         || ApplicationManager.getApplication().isUnitTestMode()) {
       String info = myEditor.dumpState();
       LOG.error(
           String.format("Unexpected exception occurred during performing '%s'", task), e, info);
     }
     myEditor.getFoldingModel().rebuild();
     myDataMapper.release();
     myApplianceManager.reset();
     myStorage.removeAll();
     myApplianceManager.recalculateIfNecessary();
     try {
       task.run(true);
     } catch (Throwable e1) {
       String info = myEditor.dumpState();
       LOG.error(
           String.format("Can't perform %s even with complete soft wraps cache re-parsing", task),
           e1,
           info);
       myEditor.getSettings().setUseSoftWraps(false);
       task.run(false);
     }
   }
 }
  /**
   * Configures given editor to wrap at given width, assuming characters are of given width
   *
   * @return whether any actual wraps of editor contents were created as a result of turning on soft
   *     wraps
   */
  @TestOnly
  public static boolean configureSoftWraps(
      Editor editor, final int visibleWidth, final int charWidthInPixels) {
    editor.getSettings().setUseSoftWraps(true);
    SoftWrapModelImpl model = (SoftWrapModelImpl) editor.getSoftWrapModel();
    model.setSoftWrapPainter(
        new SoftWrapPainter() {
          @Override
          public int paint(
              @NotNull Graphics g,
              @NotNull SoftWrapDrawingType drawingType,
              int x,
              int y,
              int lineHeight) {
            return charWidthInPixels;
          }

          @Override
          public int getDrawingHorizontalOffset(
              @NotNull Graphics g,
              @NotNull SoftWrapDrawingType drawingType,
              int x,
              int y,
              int lineHeight) {
            return charWidthInPixels;
          }

          @Override
          public int getMinDrawingWidth(@NotNull SoftWrapDrawingType drawingType) {
            return charWidthInPixels;
          }

          @Override
          public boolean canUse() {
            return true;
          }

          @Override
          public void reinit() {}
        });
    model.reinitSettings();

    SoftWrapApplianceManager applianceManager = model.getApplianceManager();
    applianceManager.setWidthProvider(
        new SoftWrapApplianceManager.VisibleAreaWidthProvider() {
          @Override
          public int getVisibleAreaWidth() {
            return visibleWidth;
          }
        });
    model.setEditorTextRepresentationHelper(
        new DefaultEditorTextRepresentationHelper(editor) {
          @Override
          public int charWidth(char c, int fontType) {
            return charWidthInPixels;
          }
        });
    applianceManager.registerSoftWrapIfNecessary();
    return !model.getRegisteredSoftWraps().isEmpty();
  }
 /**
  * We know that there are problems with incremental soft wraps cache update at the moment. Hence,
  * we may implement full cache reconstruction when the problem is encountered in order to avoid
  * customer annoyance.
  *
  * <p>However, the problems still should be fixed, hence, we report them only if dedicated flag is
  * set.
  *
  * <p>Current method encapsulates the logic mentioned above.
  *
  * @param task command object that which execution may trigger incremental update of update soft
  *     wraps cache
  */
 @SuppressWarnings({"UseOfArchaicSystemPropertyAccessors"})
 private void executeSafely(SoftWrapAwareTask task) {
   try {
     task.run(true);
   } catch (Throwable e) {
     if (Boolean.getBoolean(DEBUG_PROPERTY_NAME)) {
       LOG.error(
           String.format(
               "Unexpected exception occurred during performing '%s'. Current soft wraps cache: %n"
                   + "%s%nFold regions: %s",
               task, myDataMapper, Arrays.toString(myEditor.getFoldingModel().fetchTopLevel())),
           e);
     }
     myEditor.getFoldingModel().rebuild();
     myDataMapper.release();
     myApplianceManager.reset();
     myStorage.removeAll();
     try {
       task.run(true);
     } catch (Throwable e1) {
       LOG.error(
           String.format(
               "Can't perform %s even with complete soft wraps cache re-parsing. Current soft wraps cache: %n"
                   + "%s. Document:%n%s%nFold regions: %s",
               task,
               myDataMapper,
               myEditor.getDocument().getText(),
               Arrays.toString(myEditor.getFoldingModel().fetchTopLevel())),
           e1);
       myEditor.getSettings().setUseSoftWraps(false);
       task.run(false);
     }
   }
 }
  /**
   * Encapsulates preparations for performing document dimension mapping (e.g. visual to logical
   * position) and answers if soft wraps-aware processing should be used (e.g. there is no need to
   * consider soft wraps if user configured them not to be used).
   *
   * @return <code>true</code> if soft wraps-aware processing should be used; <code>false</code>
   *     otherwise
   */
  private boolean prepareToMapping() {
    boolean useSoftWraps =
        myActive <= 0 && isSoftWrappingEnabled() && myEditor.getDocument().getTextLength() > 0;

    if (!useSoftWraps) {
      return false;
    }

    if (myDirty) {
      myApplianceManager.reset();
      myDeferredFoldRegions.clear();
      myDirty = false;
    }

    return myApplianceManager.recalculateIfNecessary();
  }
 @Override
 public void release() {
   myDataMapper.release();
   myApplianceManager.release();
   myStorage.removeAll();
   myDeferredFoldRegions.clear();
 }
 @NotNull
 @Override
 public String dumpState() {
   return String.format(
       "appliance manager state: %s; soft wraps mapping info: %s",
       myApplianceManager.dumpState(), myDataMapper.dumpState());
 }
  /**
   * Called on editor settings change. Current model is expected to drop all cached information
   * about the settings if any.
   */
  public void reinitSettings() {
    boolean softWrapsUsedBefore = myUseSoftWraps;
    myUseSoftWraps = areSoftWrapsEnabledInEditor();

    int tabWidthBefore = myTabWidth;
    myTabWidth = EditorUtil.getTabSize(myEditor);

    boolean fontsChanged = false;
    if (!myFontPreferences.equals(myEditor.getColorsScheme().getFontPreferences())
        && myEditorTextRepresentationHelper instanceof DefaultEditorTextRepresentationHelper) {
      fontsChanged = true;
      myEditor.getColorsScheme().getFontPreferences().copyTo(myFontPreferences);
      ((DefaultEditorTextRepresentationHelper) myEditorTextRepresentationHelper)
          .clearSymbolWidthCache();
      myPainter.reinit();
    }

    if ((myUseSoftWraps ^ softWrapsUsedBefore)
        || (tabWidthBefore >= 0 && myTabWidth != tabWidthBefore)
        || fontsChanged) {
      myApplianceManager.reset();
      myDeferredFoldRegions.clear();
      myStorage.removeAll();
      myEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
    }
  }
  /**
   * Encapsulates preparations for performing document dimension mapping (e.g. visual to logical
   * position) and answers if soft wraps-aware processing should be used (e.g. there is no need to
   * consider soft wraps if user configured them not to be used).
   *
   * @return <code>true</code> if soft wraps-aware processing should be used; <code>false</code>
   *     otherwise
   */
  private boolean prepareToMapping() {
    if (myUpdateInProgress
        || myBulkUpdateInProgress
        || myActive > 0
        || !isSoftWrappingEnabled()
        || myEditor.getDocument().getTextLength() <= 0) {
      return false;
    }

    if (myDirty) {
      myApplianceManager.reset();
      myDeferredFoldRegions.clear();
      myDirty = false;
    }

    return myApplianceManager.recalculateIfNecessary();
  }
 @Override
 public void documentChanged(DocumentEvent event) {
   if (myBulkUpdateInProgress) {
     return;
   }
   myUpdateInProgress = false;
   if (!isSoftWrappingEnabled()) {
     return;
   }
   myApplianceManager.documentChanged(event);
 }
 @Override
 public void beforeDocumentChange(DocumentEvent event) {
   if (myBulkUpdateInProgress) {
     return;
   }
   myUpdateInProgress = true;
   if (!isSoftWrappingEnabled()) {
     myDirty = true;
     return;
   }
   myApplianceManager.beforeDocumentChange(event);
 }
  /**
   * Callback method that is expected to be invoked before editor painting.
   *
   * <p>It's primary purpose is to recalculate soft wraps at least for the painted area if
   * necessary.
   */
  public void registerSoftWrapsIfNecessary() {
    if (!isSoftWrappingEnabled()) {
      return;
    }

    myActive++;
    try {
      myApplianceManager.registerSoftWrapIfNecessary();
    } finally {
      myActive--;
    }
  }
 @Override
 public void moveTextHappened(int start, int end, int base) {
   if (myBulkUpdateInProgress) {
     return;
   }
   if (!isSoftWrappingEnabled()) {
     myDirty = true;
     return;
   }
   myApplianceManager.recalculate(
       Arrays.asList(new TextRange(start, end), new TextRange(base, base + end - start)));
 }
 public SoftWrapModelImpl(
     @NotNull final EditorEx editor,
     @NotNull SoftWrapsStorage storage,
     @NotNull SoftWrapPainter painter,
     @NotNull EditorTextRepresentationHelper representationHelper) {
   this(
       editor,
       storage,
       painter,
       representationHelper,
       new CachingSoftWrapDataMapper(editor, storage, representationHelper));
   myApplianceManager.addListener(myDataMapper);
 }
 /**
  * Called on editor settings change. Current model is expected to drop all cached information
  * about the settings if any.
  */
 public void reinitSettings() {
   boolean softWrapsUsedBefore = myUseSoftWraps;
   EditorSettings settings = myEditor.getSettings();
   myUseSoftWraps = settings.isUseSoftWraps();
   if (myUseSoftWraps && (!softWrapsUsedBefore || settings.getAdditionalColumnsCount() > 0)) {
     myApplianceManager.reset();
     myDeferredFoldRegions.clear();
     myAdditionalColumnsCount = settings.getAdditionalColumnsCount();
     settings.setAdditionalColumnsCount(0);
     myEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
   } else if (!myUseSoftWraps && softWrapsUsedBefore) {
     settings.setAdditionalColumnsCount(myAdditionalColumnsCount);
     myEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
   }
 }
  public SoftWrapModelImpl(
      @NotNull EditorEx editor,
      @NotNull SoftWrapsStorage storage,
      @NotNull SoftWrapPainter painter,
      @NotNull SoftWrapApplianceManager applianceManager,
      @NotNull CachingSoftWrapDataMapper dataMapper) {
    myEditor = editor;
    myStorage = storage;
    myPainter = painter;
    myApplianceManager = applianceManager;
    myDataMapper = dataMapper;
    myFoldBasedApplianceStrategy = new SoftWrapFoldBasedApplianceStrategy(editor);
    myVisualSizeManager = new SoftWrapAwareVisualSizeManager(painter);

    myDocumentListeners.add(myApplianceManager);
    myFoldListeners.add(myApplianceManager);
    applianceManager.addListener(myVisualSizeManager);
    EditorSettings settings = myEditor.getSettings();
    myAdditionalColumnsCount = settings.getAdditionalColumnsCount();
    myUseSoftWraps = settings.isUseSoftWraps();

    editor.addPropertyChangeListener(this);
  }
 public void recalculate() {
   myApplianceManager.reset();
   myStorage.removeAll();
   myDeferredFoldRegions.clear();
   myApplianceManager.recalculateIfNecessary();
 }
 @TestOnly
 public void setEditorTextRepresentationHelper(
     EditorTextRepresentationHelper editorTextRepresentationHelper) {
   myEditorTextRepresentationHelper = editorTextRepresentationHelper;
   myApplianceManager.reset();
 }
 @TestOnly
 public void setSoftWrapPainter(SoftWrapPainter painter) {
   myPainter = painter;
   myApplianceManager.setSoftWrapPainter(painter);
   myVisualSizeManager.setSoftWrapPainter(painter);
 }