/* (non-Javadoc)
   * @see org.eclipse.ui.texteditor.AbstractDocumentProvider#doSaveDocument(org.eclipse.core.runtime.IProgressMonitor, java.lang.Object, org.eclipse.jface.text.IDocument, boolean)
   * tau 21.03.2005
   */
  protected void doSaveDocument(
      IProgressMonitor monitor, Object element, IDocument document, boolean overwrite)
      throws CoreException {

    if (element instanceof IFileEditorInput) {
      doSaveFileResource(monitor, element, document, overwrite);
    } else if (element instanceof IAdaptable) {
      // reuses code from TextFileDocumentProvider to handle external files (195615)
      // TODO consider converting the super class to TextFileDocumentProvider
      IAdaptable adaptable = (IAdaptable) element;

      ITextFileBufferManager manager = FileBuffers.getTextFileBufferManager();
      ITextFileBuffer fileBuffer = null;
      LocationKind locationKind = null;

      ILocationProvider provider =
          (ILocationProvider) adaptable.getAdapter(ILocationProvider.class);
      if (provider instanceof ILocationProviderExtension) {
        URI uri = ((ILocationProviderExtension) provider).getURI(element);
        if (ResourcesPlugin.getWorkspace().getRoot().findFilesForLocationURI(uri).length == 0) {
          IFileStore fileStore = EFS.getStore(uri);
          manager.connectFileStore(fileStore, getProgressMonitor());
          fileBuffer = manager.getFileStoreTextFileBuffer(fileStore);
        }
      }
      if (fileBuffer == null && provider != null) {
        IPath location = provider.getPath(element);
        if (location != null) {
          locationKind = LocationKind.NORMALIZE;
          manager.connect(location, locationKind, getProgressMonitor());
          fileBuffer = manager.getTextFileBuffer(location, locationKind);
        }
      }

      if (fileBuffer != null) {
        fileBuffer.getDocument().set(document.get());
        fileBuffer.commit(null, true);
      }
    }

    // tau 21.03.05
    // First attempt show Message Connection through SQLScrapbookEditorInput
    if (element instanceof SQLScrapbookEditorInput)
      ((SQLScrapbookEditorInput) element).showMessageConnection();
    // Second attempt show Message Connection through sqlEditor
    IEditorPart editor =
        PlatformUI.getWorkbench()
            .getActiveWorkbenchWindow()
            .getActivePage()
            .findEditor((IEditorInput) element);
    if ((editor != null) && (editor instanceof SQLEditor)) {
      ((SQLEditor) editor).refreshConnectionStatus();
    }
  }
 public static IDocument getDocFromFile(IFile file) {
   IPath path = file.getFullPath();
   ITextFileBufferManager mgr = FileBuffers.getTextFileBufferManager();
   try {
     mgr.connect(path, LocationKind.IFILE, null);
   } catch (CoreException e) {
     e.printStackTrace();
     return null;
   }
   ITextFileBuffer buf = mgr.getTextFileBuffer(path, LocationKind.IFILE);
   return buf.getDocument();
 }
  public void testSingleNonUIThreadUpdatesToEditorDocument() throws Exception {
    IFile file = getOrCreateFile(PROJECT_NAME + "/" + "testBackgroundChanges.xml");
    ITextFileBufferManager textFileBufferManager = FileBuffers.getTextFileBufferManager();
    textFileBufferManager.connect(
        file.getFullPath(), LocationKind.IFILE, new NullProgressMonitor());

    ITextFileBuffer textFileBuffer =
        textFileBufferManager.getTextFileBuffer(file.getFullPath(), LocationKind.IFILE);
    final IDocument document = textFileBuffer.getDocument();
    document.replace(0, 0, "<?xml encoding=\"UTF-8\" version=\"1.0\"?>\n");
    textFileBuffer.commit(new NullProgressMonitor(), true);

    String testText = document.get() + "<c/><b/><a/>";
    final int end = document.getLength();
    IWorkbenchPage activePage =
        PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
    IEditorPart openedEditor = IDE.openEditor(activePage, file);

    final boolean state[] = new boolean[] {false};
    Job changer =
        new Job("text changer") {
          protected IStatus run(IProgressMonitor monitor) {
            try {
              document.replace(end, 0, "<a/>");
              document.replace(end, 0, "<b/>");
              document.replace(end, 0, "<c/>");
            } catch (Exception e) {
              return new Status(IStatus.ERROR, SSEUIPlugin.ID, e.getMessage());
            } finally {
              state[0] = true;
            }
            return Status.OK_STATUS;
          }
        };
    changer.setUser(true);
    changer.setSystem(false);
    changer.schedule();

    while (!state[0]) {
      openedEditor.getSite().getShell().getDisplay().readAndDispatch();
    }

    String finalText = document.get();
    textFileBuffer.commit(new NullProgressMonitor(), true);
    textFileBufferManager.disconnect(
        file.getFullPath(), LocationKind.IFILE, new NullProgressMonitor());
    activePage.closeEditor(openedEditor, false);
    assertEquals("Non-UI changes did not apply", testText, finalText);
  }
 /**
  * Adds the specified tag to the source member defined by the member name and signature
  *
  * @param unit
  * @param membername
  * @param signature
  * @param tagname
  * @param remove
  * @throws CoreException
  * @throws MalformedTreeException
  * @throws BadLocationException
  */
 private void updateTagInSource(
     ICompilationUnit unit, String membername, String signature, String tagname, boolean remove)
     throws CoreException, MalformedTreeException, BadLocationException {
   ASTParser parser = ASTParser.newParser(AST.JLS4);
   parser.setSource(unit);
   CompilationUnit cunit = (CompilationUnit) parser.createAST(new NullProgressMonitor());
   assertNotNull("the ast compilation unit cannot be null", cunit);
   cunit.recordModifications();
   ASTRewrite rewrite = ASTRewrite.create(cunit.getAST());
   cunit.accept(new SourceChangeVisitor(membername, signature, tagname, remove, rewrite));
   ITextFileBufferManager bm = FileBuffers.getTextFileBufferManager();
   IPath path = cunit.getJavaElement().getPath();
   try {
     bm.connect(path, LocationKind.IFILE, null);
     ITextFileBuffer tfb = bm.getTextFileBuffer(path, LocationKind.IFILE);
     IDocument document = tfb.getDocument();
     TextEdit edits = rewrite.rewriteAST(document, null);
     edits.apply(document);
     tfb.commit(new NullProgressMonitor(), true);
   } finally {
     bm.disconnect(path, LocationKind.IFILE, null);
   }
 }
  public void run(ISelection selection) {

    String errorTitle = CompareMessages.AddFromHistory_title;
    String errorMessage = CompareMessages.AddFromHistory_internalErrorMessage;
    Shell shell = getShell();

    ICompilationUnit cu = null;
    IParent parent = null;
    IMember input = null;

    // analyze selection
    if (selection.isEmpty()) {
      // no selection: we try to use the editor's input
      JavaEditor editor = getEditor();
      if (editor != null) {
        IEditorInput editorInput = editor.getEditorInput();
        IWorkingCopyManager manager = JavaPlugin.getDefault().getWorkingCopyManager();
        if (manager != null) {
          cu = manager.getWorkingCopy(editorInput);
          parent = cu;
        }
      }
    } else {
      input = getEditionElement(selection);
      if (input != null) {
        cu = input.getCompilationUnit();
        parent = input;
        input = null;

      } else {
        if (selection instanceof IStructuredSelection) {
          Object o = ((IStructuredSelection) selection).getFirstElement();
          if (o instanceof ICompilationUnit) {
            cu = (ICompilationUnit) o;
            parent = cu;
          }
        }
      }
    }

    if (parent == null || cu == null) {
      String invalidSelectionMessage = CompareMessages.AddFromHistory_invalidSelectionMessage;
      MessageDialog.openInformation(shell, errorTitle, invalidSelectionMessage);
      return;
    }

    IFile file = getFile(parent);
    if (file == null) {
      MessageDialog.openError(shell, errorTitle, errorMessage);
      return;
    }

    boolean inEditor = beingEdited(file);

    IStatus status = Resources.makeCommittable(file, shell);
    if (!status.isOK()) {
      return;
    }

    // get the document where to insert the text
    IPath path = file.getFullPath();
    ITextFileBufferManager bufferManager = FileBuffers.getTextFileBufferManager();
    ITextFileBuffer textFileBuffer = null;
    try {
      bufferManager.connect(path, LocationKind.IFILE, null);
      textFileBuffer = bufferManager.getTextFileBuffer(path, LocationKind.IFILE);
      IDocument document = textFileBuffer.getDocument();

      // configure EditionSelectionDialog and let user select an edition
      ITypedElement target = new JavaTextBufferNode(file, document, inEditor);
      ITypedElement[] editions = buildEditions(target, file);

      ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_NAME);
      EditionSelectionDialog d = new EditionSelectionDialog(shell, bundle);
      d.setAddMode(true);
      d.setHelpContextId(IJavaHelpContextIds.ADD_ELEMENT_FROM_HISTORY_DIALOG);
      ITypedElement selected = d.selectEdition(target, editions, parent);
      if (selected == null) return; // user cancel

      ICompilationUnit cu2 = cu;
      if (parent instanceof IMember) cu2 = ((IMember) parent).getCompilationUnit();

      CompilationUnit root = parsePartialCompilationUnit(cu2);
      ASTRewrite rewriter = ASTRewrite.create(root.getAST());

      ITypedElement[] results = d.getSelection();
      for (int i = 0; i < results.length; i++) {

        // create an AST node
        ASTNode newNode =
            createASTNode(
                rewriter,
                results[i],
                TextUtilities.getDefaultLineDelimiter(document),
                cu.getJavaProject());
        if (newNode == null) {
          MessageDialog.openError(shell, errorTitle, errorMessage);
          return;
        }

        // now determine where to put the new node
        if (newNode instanceof PackageDeclaration) {
          rewriter.set(root, CompilationUnit.PACKAGE_PROPERTY, newNode, null);

        } else if (newNode instanceof ImportDeclaration) {
          ListRewrite lw = rewriter.getListRewrite(root, CompilationUnit.IMPORTS_PROPERTY);
          lw.insertFirst(newNode, null);

        } else { // class, interface, enum, annotation, method, field

          if (parent instanceof ICompilationUnit) { // top level
            ListRewrite lw = rewriter.getListRewrite(root, CompilationUnit.TYPES_PROPERTY);
            int index = ASTNodes.getInsertionIndex((BodyDeclaration) newNode, root.types());
            lw.insertAt(newNode, index, null);

          } else if (parent instanceof IType) {
            ASTNode declaration = getBodyContainer(root, (IType) parent);
            if (declaration instanceof TypeDeclaration
                || declaration instanceof AnnotationTypeDeclaration) {
              List container = ASTNodes.getBodyDeclarations(declaration);
              int index = ASTNodes.getInsertionIndex((BodyDeclaration) newNode, container);
              ListRewrite lw =
                  rewriter.getListRewrite(
                      declaration, ASTNodes.getBodyDeclarationsProperty(declaration));
              lw.insertAt(newNode, index, null);
            } else if (declaration instanceof EnumDeclaration) {
              List container = ((EnumDeclaration) declaration).enumConstants();
              int index = ASTNodes.getInsertionIndex((FieldDeclaration) newNode, container);
              ListRewrite lw =
                  rewriter.getListRewrite(declaration, EnumDeclaration.ENUM_CONSTANTS_PROPERTY);
              lw.insertAt(newNode, index, null);
            }
          } else {
            JavaPlugin.logErrorMessage(
                "JavaAddElementFromHistoryImpl: unknown container " + parent); // $NON-NLS-1$
          }
        }
      }

      Map options = null;
      IJavaProject javaProject = cu2.getJavaProject();
      if (javaProject != null) options = javaProject.getOptions(true);
      applyChanges(rewriter, document, textFileBuffer, shell, inEditor, options);

    } catch (InvocationTargetException ex) {
      ExceptionHandler.handle(ex, shell, errorTitle, errorMessage);

    } catch (InterruptedException ex) {
      // shouldn't be called because is not cancelable
      Assert.isTrue(false);

    } catch (CoreException ex) {
      ExceptionHandler.handle(ex, shell, errorTitle, errorMessage);

    } finally {
      try {
        if (textFileBuffer != null) bufferManager.disconnect(path, LocationKind.IFILE, null);
      } catch (CoreException e) {
        JavaPlugin.log(e);
      }
    }
  }
  /**
   * Note: This test takes a while to run, but it's testing scalability after all.
   *
   * @throws Exception
   */
  public void testManyNonUIThreadsUpdatingEditorDocument() throws Exception {
    final int numberOfJobs = 30;
    /** 15 minute timeout before we stop waiting for the change jobs to complete */
    long timeout = 15 * 60 * 1000;

    long startTime = System.currentTimeMillis();
    IFile file = getOrCreateFile(PROJECT_NAME + "/" + "testManyBackgroundChanges.xml");
    ITextFileBufferManager textFileBufferManager = FileBuffers.getTextFileBufferManager();
    textFileBufferManager.connect(
        file.getFullPath(), LocationKind.IFILE, new NullProgressMonitor());

    ITextFileBuffer textFileBuffer =
        textFileBufferManager.getTextFileBuffer(file.getFullPath(), LocationKind.IFILE);
    final IDocument document = textFileBuffer.getDocument();
    document.replace(0, 0, "<?xml encoding=\"UTF-8\" version=\"1.0\"?>\n");
    textFileBuffer.commit(new NullProgressMonitor(), true);

    final int insertionPoint = document.getLength();
    final char names[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
    // numberOfJobs Jobs, inserting 26 tags, each 4 characters long
    int expectedLength = insertionPoint + numberOfJobs * 4 * names.length;
    IWorkbenchPage activePage =
        PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
    activePage.showView(IPageLayout.ID_PROGRESS_VIEW);
    IEditorPart openedEditor = IDE.openEditor(activePage, file);

    final int finished[] = new int[] {numberOfJobs};
    Job changers[] = new Job[numberOfJobs];
    for (int i = 0; i < changers.length; i++) {
      changers[i] =
          new Job("Text Changer " + Integer.toString(i)) {
            protected IStatus run(IProgressMonitor monitor) {
              try {
                for (int j = 0; j < names.length; j++) {
                  document.replace(insertionPoint + 4 * j, 0, "<" + names[j] + "/>");
                }
              } catch (Exception e) {
                return new Status(IStatus.ERROR, SSEUIPlugin.ID, e.getMessage());
              } finally {
                finished[0]--;
              }
              return Status.OK_STATUS;
            }
          };
      changers[i].setUser(true);
      changers[i].setSystem(false);
    }
    for (int i = 0; i < changers.length; i++) {
      changers[i].schedule();
    }

    long runtime = 0;
    while (finished[0] > 0 && (runtime = System.currentTimeMillis()) - startTime < timeout) {
      openedEditor.getSite().getShell().getDisplay().readAndDispatch();
    }
    assertTrue("Test timed out: (" + timeout + " was allowed)", runtime - startTime < timeout);

    int finalLength = document.getLength();
    textFileBuffer.commit(new NullProgressMonitor(), true);
    textFileBufferManager.disconnect(
        file.getFullPath(), LocationKind.IFILE, new NullProgressMonitor());
    activePage.closeEditor(openedEditor, false);
    assertEquals("Some non-UI changes did not apply", expectedLength, finalLength);
  }
  private static TextFileChange[] generateModelEdits(
      final ModelModification modification, final IProgressMonitor monitor, boolean performEdits) {
    ArrayList edits = new ArrayList();
    // create own model, attach listeners and grab text edits
    ITextFileBufferManager manager = FileBuffers.getTextFileBufferManager();
    IFile[] files;
    if (modification.isFullBundleModification()) {
      files = new IFile[2];
      files[F_Bi] = modification.getManifestFile();
      files[F_Xi] = modification.getXMLFile();
    } else {
      files = new IFile[] {modification.getFile()};
    }
    // need to monitor number of successful buffer connections for disconnection purposes
    // @see } finally { statement
    int sc = 0;
    try {
      ITextFileBuffer[] buffers = new ITextFileBuffer[files.length];
      IDocument[] documents = new IDocument[files.length];
      for (int i = 0; i < files.length; i++) {
        if (files[i] == null || !files[i].exists()) continue;
        manager.connect(files[i].getFullPath(), LocationKind.NORMALIZE, monitor);
        sc++;
        buffers[i] = manager.getTextFileBuffer(files[i].getFullPath(), LocationKind.NORMALIZE);
        if (performEdits && buffers[i].isDirty()) buffers[i].commit(monitor, true);
        documents[i] = buffers[i].getDocument();
      }

      IBaseModel editModel;
      if (modification.isFullBundleModification())
        editModel = prepareBundlePluginModel(files, documents, !performEdits);
      else editModel = prepareAbstractEditingModel(files[0], documents[0], !performEdits);

      modification.modifyModel(editModel, monitor);

      IModelTextChangeListener[] listeners = gatherListeners(editModel);
      for (int i = 0; i < listeners.length; i++) {
        if (listeners[i] == null) continue;
        TextEdit[] currentEdits = listeners[i].getTextOperations();
        if (currentEdits.length > 0) {
          MultiTextEdit multi = new MultiTextEdit();
          multi.addChildren(currentEdits);
          if (performEdits) {
            multi.apply(documents[i]);
            buffers[i].commit(monitor, true);
          }
          TextFileChange change = new TextFileChange(files[i].getName(), files[i]);
          change.setEdit(multi);
          // If the edits were performed right away (performEdits == true) then
          // all the names are null and we don't need the granular detail anyway.
          if (!performEdits) {
            for (int j = 0; j < currentEdits.length; j++) {
              String name = listeners[i].getReadableName(currentEdits[j]);
              if (name != null) change.addTextEditGroup(new TextEditGroup(name, currentEdits[j]));
            }
          }
          // save the file after the change applied
          change.setSaveMode(TextFileChange.FORCE_SAVE);
          setChangeTextType(change, files[i]);
          edits.add(change);
        }
      }
    } catch (CoreException e) {
      PDEPlugin.log(e);
    } catch (MalformedTreeException e) {
      PDEPlugin.log(e);
    } catch (BadLocationException e) {
      PDEPlugin.log(e);
    } finally {
      // don't want to over-disconnect in case we ran into an exception during connections
      // dc <= sc stops this from happening
      int dc = 0;
      for (int i = 0; i < files.length && dc <= sc; i++) {
        if (files[i] == null || !files[i].exists()) continue;
        try {
          manager.disconnect(files[i].getFullPath(), LocationKind.NORMALIZE, monitor);
          dc++;
        } catch (CoreException e) {
          PDEPlugin.log(e);
        }
      }
    }
    return (TextFileChange[]) edits.toArray(new TextFileChange[edits.size()]);
  }