private void linkedModeLeft() {
    fgActiveLinkedMode = null;
    if (fInfoPopup != null) {
      fInfoPopup.close();
    }

    ISourceViewer viewer = fEditor.getViewer();
    if (viewer instanceof IEditingSupportRegistry) {
      IEditingSupportRegistry registry = (IEditingSupportRegistry) viewer;
      registry.unregister(fFocusEditingSupport);
    }
  }
 private void restoreFullSelection() {
   if (fOriginalSelection.y != 0) {
     int originalOffset = fOriginalSelection.x;
     LinkedPosition[] positions = fLinkedPositionGroup.getPositions();
     for (int i = 0; i < positions.length; i++) {
       LinkedPosition position = positions[i];
       if (!position.isDeleted() && position.includes(originalOffset)) {
         fEditor.getViewer().setSelectedRange(position.offset, position.length);
         return;
       }
     }
   }
 }
  private Point computeWordStart() {
    ITextSelection selection = (ITextSelection) fEditor.getSelectionProvider().getSelection();
    IRegion textRegion =
        DartWordFinder.findWord(fEditor.getViewer().getDocument(), selection.getOffset());
    if (textRegion == null) {
      return null;
    }

    IRegion widgetRegion = modelRange2WidgetRange(textRegion);
    if (widgetRegion == null) {
      return null;
    }

    int start = widgetRegion.getOffset();

    StyledText styledText = fEditor.getViewer().getTextWidget();
    Point result = styledText.getLocationAtOffset(start);
    result.y += styledText.getLineHeight(start);

    if (!styledText.getClientArea().contains(result)) {
      return null;
    }
    return result;
  }
  private IRegion modelRange2WidgetRange(IRegion region) {
    ISourceViewer viewer = fEditor.getViewer();
    if (viewer instanceof ITextViewerExtension5) {
      ITextViewerExtension5 extension = (ITextViewerExtension5) viewer;
      return extension.modelRange2WidgetRange(region);
    }

    IRegion visibleRegion = viewer.getVisibleRegion();
    int start = region.getOffset() - visibleRegion.getOffset();
    int end = start + region.getLength();
    if (end > visibleRegion.getLength()) {
      end = visibleRegion.getLength();
    }

    return new Region(start, end - start);
  }
  private RenameSupport undoAndCreateRenameSupport(String newName) throws CoreException {
    // Assumption: the linked mode model should be shut down by now.

    final ISourceViewer viewer = fEditor.getViewer();

    try {
      if (!fOriginalName.equals(newName)) {
        IWorkbenchWindow workbenchWindow = fEditor.getSite().getWorkbenchWindow();
        // undo
        workbenchWindow.run(
            false,
            true,
            new IRunnableWithProgress() {
              @Override
              public void run(IProgressMonitor monitor)
                  throws InvocationTargetException, InterruptedException {
                if (viewer instanceof ITextViewerExtension6) {
                  IUndoManager undoManager = ((ITextViewerExtension6) viewer).getUndoManager();
                  if (undoManager instanceof IUndoManagerExtension) {
                    IUndoManagerExtension undoManagerExtension =
                        (IUndoManagerExtension) undoManager;
                    IUndoContext undoContext = undoManagerExtension.getUndoContext();
                    IOperationHistory operationHistory =
                        OperationHistoryFactory.getOperationHistory();
                    while (undoManager.undoable()) {
                      if (fStartingUndoOperation != null
                          && fStartingUndoOperation.equals(
                              operationHistory.getUndoOperation(undoContext))) {
                        return;
                      }
                      undoManager.undo();
                    }
                  }
                }
              }
            });
        // wait for analysis
        IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
        progressService.busyCursorWhile(
            new IRunnableWithProgress() {
              @Override
              public void run(IProgressMonitor monitor)
                  throws InvocationTargetException, InterruptedException {
                monitor.beginTask("Waiting for background analysis...", IProgressMonitor.UNKNOWN);
                try {
                  RefactoringUtils.waitResolvedCompilationUnit(fEditor, monitor);
                  RefactoringUtils.waitReadyForRefactoring(monitor);
                } finally {
                  monitor.done();
                }
              }
            });
        // by some reason "busyCursorWhile" looses focus, so restore it
        fEditor.setFocus();
        // get new Element, after background build finished
        prepareElement();
        if (fDartElement == null) {
          return null;
        }
      }
    } catch (InvocationTargetException e) {
      throw new CoreException(
          new Status(
              IStatus.ERROR,
              DartToolsPlugin.getPluginId(),
              ReorgMessages.RenameLinkedMode_error_saving_editor,
              e));
    } catch (InterruptedException e) {
      // canceling is OK
      return null;
    }

    viewer.setSelectedRange(fOriginalSelection.x, fOriginalSelection.y);

    if (newName.length() == 0) {
      return null;
    }

    return RenameSupport.create(fDartElement, newName);
  }
  void doRename(boolean showPreview) {
    cancel();

    Image image = null;
    Label label = null;

    fShowPreview |= showPreview;
    try {
      ISourceViewer viewer = fEditor.getViewer();
      if (viewer instanceof SourceViewer) {
        SourceViewer sourceViewer = (SourceViewer) viewer;
        Control viewerControl = sourceViewer.getControl();
        if (viewerControl instanceof Composite) {
          Composite composite = (Composite) viewerControl;
          Display display = composite.getDisplay();

          // Flush pending redraw requests:
          while (!display.isDisposed() && display.readAndDispatch()) {}

          // Copy editor area:
          GC gc = new GC(composite);
          Point size;
          try {
            size = composite.getSize();
            image = new Image(gc.getDevice(), size.x, size.y);
            gc.copyArea(image, 0, 0);
          } finally {
            gc.dispose();
            gc = null;
          }

          // Persist editor area while executing refactoring:
          label = new Label(composite, SWT.NONE);
          label.setImage(image);
          label.setBounds(0, 0, size.x, size.y);
          label.moveAbove(null);
        }
      }

      String newName = fNamePosition.getContent();
      if (fOriginalName.equals(newName)) {
        return;
      }
      RenameSupport renameSupport = undoAndCreateRenameSupport(newName);
      if (renameSupport == null) {
        return;
      }

      Shell shell = fEditor.getSite().getShell();
      if (renameSupport.hasUnresolvedNameReferences()) {
        fShowPreview = true;
      }
      boolean executed;
      if (fShowPreview) { // could have been updated by undoAndCreateRenameSupport(..)
        executed = renameSupport.openDialog(shell, true);
      } else {
        renameSupport.perform(shell, fEditor.getSite().getWorkbenchWindow());
        executed = true;
      }
      if (executed) {
        restoreFullSelection();
      }
    } catch (CoreException ex) {
      DartToolsPlugin.log(ex);
    } catch (InterruptedException ex) {
      // canceling is OK -> redo text changes in that case?
    } catch (InvocationTargetException ex) {
      DartToolsPlugin.log(ex);
    } catch (BadLocationException e) {
      DartToolsPlugin.log(e);
    } finally {
      if (label != null) {
        label.dispose();
      }
      if (image != null) {
        image.dispose();
      }
    }
  }
  public void start() {
    if (getActiveLinkedMode() != null) {
      // for safety; should already be handled in RenameDartElementAction
      fgActiveLinkedMode.startFullDialog();
      return;
    }

    ISourceViewer viewer = fEditor.getViewer();
    IDocument document = viewer.getDocument();
    fOriginalSelection = viewer.getSelectedRange();
    int offset = fOriginalSelection.x;

    try {
      fLinkedPositionGroup = new LinkedPositionGroup();
      prepareElement();
      if (fDartElement == null) {
        return;
      }

      if (viewer instanceof ITextViewerExtension6) {
        IUndoManager undoManager = ((ITextViewerExtension6) viewer).getUndoManager();
        if (undoManager instanceof IUndoManagerExtension) {
          IUndoManagerExtension undoManagerExtension = (IUndoManagerExtension) undoManager;
          IUndoContext undoContext = undoManagerExtension.getUndoContext();
          IOperationHistory operationHistory = OperationHistoryFactory.getOperationHistory();
          fStartingUndoOperation = operationHistory.getUndoOperation(undoContext);
        }
      }

      fOriginalName = nameNode.getName();
      final int pos = nameNode.getOffset();
      final List<ASTNode> sameNodes = Lists.newArrayList();
      nameNode
          .getRoot()
          .accept(
              new RecursiveASTVisitor<Void>() {
                @Override
                public Void visitSimpleIdentifier(SimpleIdentifier node) {
                  Element element = node.getElement();
                  element = getCanonicalElement(element);
                  if (Objects.equal(element, fDartElement)) {
                    sameNodes.add(node);
                  }
                  return super.visitSimpleIdentifier(node);
                }
              });

      // TODO: copied from LinkedNamesAssistProposal#apply(..):
      // sort for iteration order, starting with the node @ offset
      Collections.sort(
          sameNodes,
          new Comparator<ASTNode>() {
            @Override
            public int compare(ASTNode o1, ASTNode o2) {
              return rank(o1) - rank(o2);
            }

            /**
             * Returns the absolute rank of an <code>ASTNode</code>. Nodes preceding <code>pos
             * </code> are ranked last.
             *
             * @param node the node to compute the rank for
             * @return the rank of the node with respect to the invocation offset
             */
            private int rank(ASTNode node) {
              int relativeRank = node.getOffset() + node.getLength() - pos;
              if (relativeRank < 0) {
                return Integer.MAX_VALUE + relativeRank;
              } else {
                return relativeRank;
              }
            }
          });
      for (int i = 0; i < sameNodes.size(); i++) {
        ASTNode elem = sameNodes.get(i);
        LinkedPosition linkedPosition =
            new LinkedPosition(document, elem.getOffset(), elem.getLength(), i);
        if (i == 0) {
          fNamePosition = linkedPosition;
        }
        fLinkedPositionGroup.addPosition(linkedPosition);
      }

      fLinkedModeModel = new LinkedModeModel();
      fLinkedModeModel.addGroup(fLinkedPositionGroup);
      fLinkedModeModel.forceInstall();
      fLinkedModeModel.addLinkingListener(new EditorHighlightingSynchronizer(fEditor));
      fLinkedModeModel.addLinkingListener(new EditorSynchronizer());

      LinkedModeUI ui = new EditorLinkedModeUI(fLinkedModeModel, viewer);
      ui.setExitPosition(viewer, offset, 0, Integer.MAX_VALUE);
      ui.setExitPolicy(new ExitPolicy(document));
      ui.enter();

      viewer.setSelectedRange(
          fOriginalSelection.x,
          fOriginalSelection.y); // by default, full word is selected; restore original selection

      if (viewer instanceof IEditingSupportRegistry) {
        IEditingSupportRegistry registry = (IEditingSupportRegistry) viewer;
        registry.register(fFocusEditingSupport);
      }

      openSecondaryPopup();
      //			startAnimation();
      fgActiveLinkedMode = this;

    } catch (BadLocationException e) {
      DartToolsPlugin.log(e);
    }
  }
 protected Point computeMenuLocation(StyledText text) {
   if (fEditor == null || text != fEditor.getViewer().getTextWidget()) {
     return null;
   }
   return computeWordStart();
 }