@Override public void contentsChanged(VirtualFileEvent event) { if (event.isFromSave()) return; final VirtualFile file = event.getFile(); final Document document = getCachedDocument(file); if (document == null) { myMultiCaster.fileWithNoDocumentChanged(file); return; } if (isBinaryWithDecompiler(file)) { myMultiCaster.fileWithNoDocumentChanged( file); // This will generate PSI event at FileManagerImpl } long documentStamp = document.getModificationStamp(); long oldFileStamp = event.getOldModificationStamp(); if (documentStamp != oldFileStamp) { LOG.info("reload from disk?"); LOG.info(" documentStamp:" + documentStamp); LOG.info(" oldFileStamp:" + oldFileStamp); if (file.isValid() && askReloadFromDisk(file, document)) { reloadFromDisk(document); } } else { reloadFromDisk(document); } }
private void doSaveDocument(@NotNull final Document document) throws IOException, SaveVetoException { VirtualFile file = getFile(document); if (file == null || file instanceof LightVirtualFile || file.isValid() && !isFileModified(file)) { removeFromUnsaved(document); return; } if (file.isValid() && needsRefresh(file)) { file.refresh(false, false); if (!myUnsavedDocuments.contains(document)) return; } for (FileDocumentSynchronizationVetoer vetoer : Extensions.getExtensions(FileDocumentSynchronizationVetoer.EP_NAME)) { if (!vetoer.maySaveDocument(document)) { throw new SaveVetoException(); } } final AccessToken token = ApplicationManager.getApplication().acquireWriteActionLock(getClass()); try { doSaveDocumentInWriteAction(document, file); } finally { token.finish(); } }
@Override public void reloadFiles(final VirtualFile... files) { for (VirtualFile file : files) { if (file.exists()) { final Document doc = getCachedDocument(file); if (doc != null) { reloadFromDisk(doc); } } } }
private static boolean isSaveNeeded(@NotNull Document document, @NotNull VirtualFile file) throws IOException { if (file.getFileType().isBinary() || document.getTextLength() > 1000 * 1000) { // don't compare if the file is too big return true; } byte[] bytes = file.contentsToByteArray(); CharSequence loaded = LoadTextUtil.getTextByBinaryPresentation(bytes, file, false, false); return !Comparing.equal(document.getCharsSequence(), loaded); }
@Override public boolean requestWriting(@NotNull Document document, Project project) { final VirtualFile file = getInstance().getFile(document); if (project != null && file != null && file.isValid()) { return !file.getFileType().isBinary() && ReadonlyStatusHandler.ensureFilesWritable(project, file); } if (document.isWritable()) { return true; } document.fireReadOnlyModificationAttempt(); return false; }
@Override @Nullable public Document getCachedDocument(@NotNull VirtualFile file) { Reference<Document> reference = file.getUserData(DOCUMENT_KEY); Document document = reference == null ? null : reference.get(); if (document != null && isBinaryWithoutDecompiler(file)) { file.putUserData(DOCUMENT_KEY, null); document.putUserData(FILE_KEY, null); return null; } return document; }
@Override public boolean isFileModified(@NotNull VirtualFile file) { final Document doc = getCachedDocument(file); return doc != null && isDocumentUnsaved(doc) && doc.getModificationStamp() != file.getModificationStamp(); }
protected boolean askReloadFromDisk(final VirtualFile file, final Document document) { ApplicationManager.getApplication().assertIsDispatchThread(); if (!isDocumentUnsaved(document)) return true; String message = UIBundle.message("file.cache.conflict.message.text", file.getPresentableUrl()); if (ApplicationManager.getApplication().isUnitTestMode()) throw new RuntimeException(message); final DialogBuilder builder = new DialogBuilder((Project) null); builder.setCenterPanel(new JLabel(message, Messages.getQuestionIcon(), SwingConstants.CENTER)); builder.addOkAction().setText(UIBundle.message("file.cache.conflict.load.fs.changes.button")); builder .addCancelAction() .setText(UIBundle.message("file.cache.conflict.keep.memory.changes.button")); builder.addAction( new AbstractAction(UIBundle.message("file.cache.conflict.show.difference.button")) { @Override public void actionPerformed(ActionEvent e) { String title = UIBundle.message( "file.cache.conflict.for.file.dialog.title", file.getPresentableUrl()); final ProjectEx project = (ProjectEx) ProjectLocator.getInstance().guessProjectForFile(file); SimpleDiffRequest request = new SimpleDiffRequest(project, title); FileType fileType = file.getFileType(); String fsContent = LoadTextUtil.loadText(file).toString(); request.setContents( new SimpleContent(fsContent, fileType), new DocumentContent(project, document, fileType)); request.setContentTitles( UIBundle.message("file.cache.conflict.diff.content.file.system.content"), UIBundle.message("file.cache.conflict.diff.content.memory.content")); DialogBuilder diffBuilder = new DialogBuilder(project); DiffPanelImpl diffPanel = (DiffPanelImpl) DiffManager.getInstance() .createDiffPanel(diffBuilder.getWindow(), project, diffBuilder, null); diffPanel.getOptions().setShowSourcePolicy(DiffPanelOptions.ShowSourcePolicy.DONT_SHOW); diffBuilder.setCenterPanel(diffPanel.getComponent()); diffBuilder.setDimensionServiceKey("FileDocumentManager.FileCacheConflict"); diffPanel.setDiffRequest(request); diffBuilder .addOkAction() .setText(UIBundle.message("file.cache.conflict.save.changes.button")); diffBuilder.addCancelAction(); diffBuilder.setTitle(title); if (diffBuilder.show() == DialogWrapper.OK_EXIT_CODE) { builder.getDialogWrapper().close(DialogWrapper.CANCEL_EXIT_CODE); } } }); builder.setTitle(UIBundle.message("file.cache.conflict.dialog.title")); builder.setButtonsAlignment(SwingConstants.CENTER); builder.setHelpId("reference.dialogs.fileCacheConflict"); return builder.show() == 0; }
public static void registerDocument( @NotNull final Document document, @NotNull VirtualFile virtualFile) { synchronized (lock) { virtualFile.putUserData( DOCUMENT_KEY, new SoftReference<Document>(document) { @Override public Document get() { return document; } }); document.putUserData(FILE_KEY, virtualFile); } }
private void doSaveDocumentInWriteAction(@NotNull Document document, @NotNull VirtualFile file) throws IOException { if (!file.isValid()) { removeFromUnsaved(document); return; } if (!file.equals(getFile(document))) { registerDocument(document, file); } if (!isSaveNeeded(document, file)) { if (document instanceof DocumentEx) { ((DocumentEx) document).setModificationStamp(file.getModificationStamp()); } removeFromUnsaved(document); updateModifiedProperty(file); return; } myMultiCaster.beforeDocumentSaving(document); LOG.assertTrue(file.isValid()); String text = document.getText(); String lineSeparator = getLineSeparator(document, file); if (!lineSeparator.equals("\n")) { text = StringUtil.convertLineSeparators(text, lineSeparator); } Project project = ProjectLocator.getInstance().guessProjectForFile(file); LoadTextUtil.write(project, file, this, text, document.getModificationStamp()); myUnsavedDocuments.remove(document); LOG.assertTrue(!myUnsavedDocuments.contains(document)); myTrailingSpacesStripper.clearLineModificationFlags(document); }
@Override @Nullable public Document getDocument(@NotNull final VirtualFile file) { DocumentEx document = (DocumentEx) getCachedDocument(file); if (document == null) { if (file.isDirectory() || isBinaryWithoutDecompiler(file) || SingleRootFileViewProvider.isTooLargeForContentLoading(file)) { return null; } final CharSequence text = LoadTextUtil.loadText(file); synchronized (lock) { document = (DocumentEx) getCachedDocument(file); if (document != null) return document; // Double checking document = (DocumentEx) createDocument(text); document.setModificationStamp(file.getModificationStamp()); final FileType fileType = file.getFileType(); document.setReadOnly(!file.isWritable() || fileType.isBinary()); file.putUserData(DOCUMENT_KEY, new WeakReference<Document>(document)); document.putUserData(FILE_KEY, file); if (!(file instanceof LightVirtualFile || file.getFileSystem() instanceof DummyFileSystem)) { document.addDocumentListener( new DocumentAdapter() { @Override public void documentChanged(DocumentEvent e) { final Document document = e.getDocument(); myUnsavedDocuments.add(document); final Runnable currentCommand = CommandProcessor.getInstance().getCurrentCommand(); Project project = currentCommand == null ? null : CommandProcessor.getInstance().getCurrentCommandProject(); String lineSeparator = CodeStyleFacade.getInstance(project).getLineSeparator(); document.putUserData(LINE_SEPARATOR_KEY, lineSeparator); // avoid documents piling up during batch processing if (areTooManyDocumentsInTheQueue(myUnsavedDocuments)) { saveAllDocumentsLater(); } } }); } } myMultiCaster.fileContentLoaded(file, document); } return document; }
private static boolean isBinaryWithoutDecompiler(VirtualFile file) { final FileType ft = file.getFileType(); return ft.isBinary() && BinaryFileTypeDecompilers.INSTANCE.forFileType(ft) == null; }
private static boolean needsRefresh(final VirtualFile file) { final VirtualFileSystem fs = file.getFileSystem(); return fs instanceof NewVirtualFileSystem && file.getTimeStamp() != ((NewVirtualFileSystem) fs).getTimeStamp(file); }