/**
  * 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);
     }
   }
 }
  public void onContentChangedIn(EditorSource source) {
    myDiffUpdater.contentRemoved(source);
    final EditorEx editor = source.getEditor();
    if (myIsHorizontal && source.getSide() == FragmentSide.SIDE1 && editor != null) {
      editor.setVerticalScrollbarOrientation(EditorEx.VERTICAL_SCROLLBAR_LEFT);
    }
    DiffSideView viewSide = getSideView(source.getSide());
    viewSide.setEditorSource(getProject(), source);
    Disposer.dispose(myScrollSupport);
    if (editor == null) {
      if (!myDisposed) {
        rediff();
      }
      return;
    }

    final MouseListener mouseListener =
        PopupHandler.installUnknownPopupHandler(
            editor.getContentComponent(),
            new MergeActionGroup(this, source.getSide()),
            ActionManager.getInstance());
    myDiffUpdater.contentAdded(source);
    editor.getSettings().setLineNumbersShown(true);
    editor.getSettings().setFoldingOutlineShown(false);
    editor.getFoldingModel().setFoldingEnabled(false);
    ((EditorMarkupModel) editor.getMarkupModel()).setErrorStripeVisible(true);

    Editor editor1 = getEditor(FragmentSide.SIDE1);
    Editor editor2 = getEditor(FragmentSide.SIDE2);
    if (editor1 != null && editor2 != null && myIsSyncScroll) {
      myScrollSupport.install(new EditingSides[] {this});
    }

    final VisibleAreaListener visibleAreaListener = mySplitter.getVisibleAreaListener();
    final ScrollingModel scrollingModel = editor.getScrollingModel();
    if (visibleAreaListener != null) {
      scrollingModel.addVisibleAreaListener(visibleAreaListener);
      scrollingModel.addVisibleAreaListener(myVisibleAreaListener);
    }
    myFontSizeSynchronizer.synchronize(editor);
    source.addDisposable(
        new Disposable() {
          public void dispose() {
            myFontSizeSynchronizer.stopSynchronize(editor);
          }
        });
    source.addDisposable(
        new Disposable() {
          public void dispose() {
            if (visibleAreaListener != null) {
              scrollingModel.removeVisibleAreaListener(visibleAreaListener);
              scrollingModel.removeVisibleAreaListener(myVisibleAreaListener);
            }
            editor.getContentComponent().removeMouseListener(mouseListener);
          }
        });
  }
 /** @return total number of soft wrap-introduced new visual lines */
 public int getSoftWrapsIntroducedLinesNumber() {
   if (!isSoftWrappingEnabled()) {
     return 0;
   }
   int result = 0;
   FoldingModel foldingModel = myEditor.getFoldingModel();
   for (SoftWrap softWrap : myStorage.getSoftWraps()) {
     if (!foldingModel.isOffsetCollapsed(softWrap.getStart())) {
       result++; // Assuming that soft wrap has single line feed all the time
     }
   }
   return result;
 }
  @Override
  public boolean isVisible(SoftWrap softWrap) {
    FoldingModel foldingModel = myEditor.getFoldingModel();
    int start = softWrap.getStart();
    if (foldingModel.isOffsetCollapsed(start)) {
      return false;
    }

    // There is a possible case that soft wrap and collapsed folding region share the same offset,
    // i.e. soft wrap is represented
    // before the folding. We need to return 'true' in such situation. Hence, we check if offset
    // just before the soft wrap
    // is collapsed as well.
    return start <= 0 || !foldingModel.isOffsetCollapsed(start - 1);
  }
  private EditorFragmentComponent(
      EditorEx editor, int startLine, int endLine, boolean showFolding, boolean showGutter) {
    Document doc = editor.getDocument();
    final int endOffset =
        endLine < doc.getLineCount() ? doc.getLineEndOffset(endLine) : doc.getTextLength();
    int textWidth =
        Math.min(
            editor.getMaxWidthInRange(doc.getLineStartOffset(startLine), endOffset),
            ScreenUtil.getScreenRectangle(1, 1).width);
    LOG.assertTrue(
        textWidth > 0,
        "TextWidth: " + textWidth + "; startLine:" + startLine + "; endLine:" + endLine + ";");

    FoldingModelEx foldingModel = editor.getFoldingModel();
    boolean isFoldingEnabled = foldingModel.isFoldingEnabled();
    if (!showFolding) {
      foldingModel.setFoldingEnabled(false);
    }

    Point p1 = editor.logicalPositionToXY(new LogicalPosition(startLine, 0));
    Point p2 = editor.logicalPositionToXY(new LogicalPosition(Math.max(endLine, startLine + 1), 0));
    int y1 = p1.y;
    int y2 = p2.y;
    int height = y2 - y1 == 0 ? editor.getLineHeight() : y2 - y1;
    LOG.assertTrue(
        height > 0,
        "Height: "
            + height
            + "; startLine:"
            + startLine
            + "; endLine:"
            + endLine
            + "; p1:"
            + p1
            + "; p2:"
            + p2);

    int savedScrollOffset = editor.getScrollingModel().getHorizontalScrollOffset();
    if (savedScrollOffset > 0) {
      editor.stopOptimizedScrolling();
      editor.getScrollingModel().scrollHorizontally(0);
    }

    final Image textImage = new BufferedImage(textWidth, height, BufferedImage.TYPE_INT_RGB);
    Graphics textGraphics = textImage.getGraphics();

    final JComponent rowHeader;
    final Image markersImage;
    if (showGutter) {
      rowHeader = editor.getGutterComponentEx();
      markersImage =
          new BufferedImage(Math.max(1, rowHeader.getWidth()), height, BufferedImage.TYPE_INT_RGB);
      Graphics markerGraphics = markersImage.getGraphics();

      markerGraphics.translate(0, -y1);
      markerGraphics.setClip(0, y1, rowHeader.getWidth(), height);
      markerGraphics.setColor(getBackgroundColor(editor));
      markerGraphics.fillRect(0, y1, rowHeader.getWidth(), height);
      rowHeader.paint(markerGraphics);
    } else {
      rowHeader = null;
      markersImage = null;
    }

    textGraphics.translate(0, -y1);
    textGraphics.setClip(0, y1, textWidth, height);
    final boolean wasVisible = editor.setCaretVisible(false);
    editor.setPurePaintingMode(true);
    try {
      editor.getContentComponent().paint(textGraphics);
    } finally {
      editor.setPurePaintingMode(false);
    }
    if (wasVisible) {
      editor.setCaretVisible(true);
    }

    if (!showFolding) {
      foldingModel.setFoldingEnabled(isFoldingEnabled);
    }

    if (savedScrollOffset > 0) {
      editor.stopOptimizedScrolling();
      editor.getScrollingModel().scrollHorizontally(savedScrollOffset);
    }

    JComponent component =
        new JComponent() {
          public Dimension getPreferredSize() {
            return new Dimension(
                textImage.getWidth(null) + (markersImage == null ? 0 : markersImage.getWidth(null)),
                textImage.getHeight(null));
          }

          protected void paintComponent(Graphics graphics) {
            if (markersImage != null) {
              graphics.drawImage(markersImage, 0, 0, null);
              graphics.drawImage(textImage, rowHeader.getWidth(), 0, null);
            } else {
              graphics.drawImage(textImage, 0, 0, null);
            }
          }
        };

    setLayout(new BorderLayout());
    add(component);

    final Color borderColor =
        editor.getColorsScheme().getColor(EditorColors.SELECTED_TEARLINE_COLOR);

    Border outsideBorder = BorderFactory.createLineBorder(borderColor, 1);
    Border insideBorder = BorderFactory.createEmptyBorder(2, 2, 2, 2);
    setBorder(BorderFactory.createCompoundBorder(outsideBorder, insideBorder));
  }