diff --git a/platform/diff-api/src/com/intellij/ide/diff/BackgroundOperatingDiffElement.java b/platform/diff-api/src/com/intellij/ide/diff/AsyncDiffElement.java similarity index 62% rename from platform/diff-api/src/com/intellij/ide/diff/BackgroundOperatingDiffElement.java rename to platform/diff-api/src/com/intellij/ide/diff/AsyncDiffElement.java index a6a28360f654..7cbde1b3e70f 100644 --- a/platform/diff-api/src/com/intellij/ide/diff/BackgroundOperatingDiffElement.java +++ b/platform/diff-api/src/com/intellij/ide/diff/AsyncDiffElement.java @@ -15,20 +15,21 @@ */ package com.intellij.ide.diff; -import com.intellij.openapi.util.Ref; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.concurrency.Promise; /** * @author lene * Date: 18.10.11 */ -public interface BackgroundOperatingDiffElement { +public interface AsyncDiffElement { - void copyTo(DiffElement container, - Ref errorMessage, - Ref diffElement, - Runnable onFinish, - DiffElement target, - String relativePath); + @NotNull + Promise copyToAsync(@NotNull DiffElement container, + @Nullable DiffElement target, + @NotNull String relativePath); - void delete(Ref errorMessage, Runnable onFinish); + @NotNull + Promise deleteAsync(); } diff --git a/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffPanel.java b/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffPanel.java index 67f2d1712607..1dfa189b2039 100644 --- a/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffPanel.java +++ b/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffPanel.java @@ -255,7 +255,7 @@ public class DirDiffPanel implements Disposable, DataProvider { } }); loadingPanel.add(myComponent, BorderLayout.CENTER); - myTable.putClientProperty(myModel.DECORATOR, loadingPanel); + UIUtil.putClientProperty(myTable, DirDiffTableModel.DECORATOR_KEY, loadingPanel); myTable.addComponentListener(new ComponentAdapter() { @Override public void componentShown(ComponentEvent e) { @@ -286,12 +286,12 @@ public class DirDiffPanel implements Disposable, DataProvider { myModel.addModelListener(new DirDiffModelListener() { @Override public void updateStarted() { - myFilter.setEnabled(false); + UIUtil.setEnabled(myFilter, false, true); } @Override public void updateFinished() { - myFilter.setEnabled(true); + UIUtil.setEnabled(myFilter, true, true); } }); myFilter.getTextEditor().setColumns(10); diff --git a/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffTableModel.java b/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffTableModel.java index 87b82469a3e9..b5d072709729 100644 --- a/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffTableModel.java +++ b/platform/diff-impl/src/com/intellij/openapi/diff/impl/dir/DirDiffTableModel.java @@ -37,7 +37,7 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.popup.Balloon; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsBundle; import com.intellij.openapi.vfs.VirtualFile; @@ -48,6 +48,7 @@ import com.intellij.ui.table.JBTable; import com.intellij.util.TimeoutUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.StatusText; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -66,33 +67,36 @@ import java.util.concurrent.atomic.AtomicReference; */ public class DirDiffTableModel extends AbstractTableModel implements DirDiffModel, Disposable { private static final Logger LOG = Logger.getInstance(DirDiffTableModel.class); + + public static final Key DECORATOR_KEY = Key.create("DIFF_TABLE_DECORATOR"); public static final String COLUMN_NAME = "Name"; public static final String COLUMN_SIZE = "Size"; public static final String COLUMN_DATE = "Date"; + public static final String EMPTY_STRING = StringUtil.repeatSymbol(' ', 50); + private final Project myProject; private final DirDiffSettings mySettings; - private DiffElement mySrc; - private DiffElement myTrg; + + private DiffElement mySource; + private DiffElement myTarget; private DTree myTree; private final List myElements = new ArrayList<>(); private final AtomicBoolean myUpdating = new AtomicBoolean(false); private JBTable myTable; - public String DECORATOR = "DIFF_TABLE_DECORATOR"; - public final AtomicReference text = new AtomicReference<>(prepareText("")); + private final AtomicReference text = new AtomicReference<>(prepareText("")); private Updater myUpdater; private List myListeners = ContainerUtil.createLockFreeCopyOnWriteList(); private TableSelectionConfig mySelectionConfig; - private String myStatus = null; - public static final String EMPTY_STRING = " "; + private DirDiffPanel myPanel; private volatile boolean myDisposed; - public DirDiffTableModel(@NotNull Project project, DiffElement src, DiffElement trg, DirDiffSettings settings) { + public DirDiffTableModel(@NotNull Project project, DiffElement source, DiffElement target, DirDiffSettings settings) { UsageTrigger.trigger("diff.DirDiffTableModel"); myProject = project; mySettings = settings; - mySrc = src; - myTrg = trg; + mySource = source; + myTarget = target; } public void stopUpdating() { @@ -173,7 +177,7 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode } public boolean isOperationsEnabled() { - return !myDisposed && mySrc.isOperationsEnabled() && myTrg.isOperationsEnabled(); + return !myDisposed && mySource.isOperationsEnabled() && myTarget.isOperationsEnabled(); } public List getElements() { @@ -214,13 +218,14 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode myListeners.add(listener); } - public void reloadModel(final boolean userForcedRefresh) { + public void reloadModel(boolean userForcedRefresh) { + fireUpdateStarted(); myUpdating.set(true); myTable.getEmptyText().setText(StatusText.DEFAULT_EMPTY_TEXT); - final JBLoadingPanel loadingPanel = getLoadingPanel(); + JBLoadingPanel loadingPanel = getLoadingPanel(); loadingPanel.startLoading(); - final ModalityState modalityState = ModalityState.current(); + ModalityState modalityState = ModalityState.current(); ApplicationManager.getApplication().executeOnPooledThread(() -> { EmptyProgressIndicator indicator = new EmptyProgressIndicator(modalityState); @@ -231,20 +236,21 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode myUpdater.start(); text.set("Loading..."); myTree = new DTree(null, "", true); - mySrc.refresh(userForcedRefresh); - myTrg.refresh(userForcedRefresh); - scan(mySrc, myTree, true); - scan(myTrg, myTree, false); + mySource.refresh(userForcedRefresh); + myTarget.refresh(userForcedRefresh); + scan(mySource, myTree, true); + scan(myTarget, myTree, false); } - catch (final IOException e) { + catch (IOException e) { LOG.warn(e); reportException(VcsBundle.message("refresh.failed.message", StringUtil.decapitalize(e.getLocalizedMessage()))); } finally { if (myTree != null) { - myTree.setSource(mySrc); - myTree.setTarget(myTrg); + myTree.setSource(mySource); + myTree.setTarget(myTarget); myTree.update(mySettings); + ApplicationManager.getApplication().invokeLater(this::fireUpdateFinished, ModalityState.any()); applySettings(); } } @@ -257,19 +263,20 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode myUpdating.set(true); try { + fireUpdateStarted(); myTree = new DTree(null, "", true); - mySrc.refresh(true); - myTrg.refresh(true); - scan(mySrc, myTree, true); - scan(myTrg, myTree, false); + mySource.refresh(true); + myTarget.refresh(true); + scan(mySource, myTree, true); + scan(myTarget, myTree, false); } catch (final IOException e) { LOG.warn(e); reportException(VcsBundle.message("refresh.failed.message", StringUtil.decapitalize(e.getLocalizedMessage()))); } finally { - myTree.setSource(mySrc); - myTree.setTarget(myTrg); + myTree.setSource(mySource); + myTree.setTarget(myTarget); myTree.update(mySettings); ArrayList elements = new ArrayList<>(); @@ -278,10 +285,12 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode myElements.addAll(elements); myUpdating.set(false); + fireUpdateFinished(); } } - private void reportException(final String htmlContent) { + private void reportException(@Nullable String htmlContent) { + if (myDisposed || htmlContent == null) return; Runnable balloonShower = () -> { Balloon balloon = JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(htmlContent, MessageType.WARNING, null). setShowCallout(false).setHideOnClickOutside(true).setHideOnAction(true).setHideOnFrameResize(true).setHideOnKeyOutside(true). @@ -292,17 +301,17 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode balloon.show(point, Balloon.Position.below); Disposer.register(myProject != null ? myProject : ApplicationManager.getApplication(), balloon); }; - ApplicationManager.getApplication().invokeLater(balloonShower, o -> !(myProject == null || myProject.isDefault()) && ((!myProject.isOpen()) || myProject.isDisposed()) - ); + ApplicationManager.getApplication().invokeLater(balloonShower, o -> + myProject != null && !myProject.isDefault() && !myProject.isOpen()); } private JBLoadingPanel getLoadingPanel() { - return (JBLoadingPanel)myTable.getClientProperty(DECORATOR); + return UIUtil.getClientProperty(myTable, DECORATOR_KEY); } public void applySettings() { - if (! myUpdating.get()) myUpdating.set(true); - final JBLoadingPanel loadingPanel = getLoadingPanel(); + if (!myUpdating.get()) myUpdating.set(true); + JBLoadingPanel loadingPanel = getLoadingPanel(); if (!loadingPanel.isLoading()) { loadingPanel.startLoading(); if (myUpdater == null) { @@ -310,13 +319,13 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode myUpdater.start(); } } - final Application app = ApplicationManager.getApplication(); + Application app = ApplicationManager.getApplication(); app.executeOnPooledThread(() -> { if (myDisposed) return; myTree.updateVisibility(mySettings); - final ArrayList elements = new ArrayList<>(); + ArrayList elements = new ArrayList<>(); fillElements(myTree, elements); - final Runnable uiThread = () -> { + Runnable uiThread = () -> { if (myDisposed) return; clear(); myElements.addAll(elements); @@ -328,14 +337,16 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode } if (mySelectionConfig == null) { selectFirstRow(); - } else { + } + else { mySelectionConfig.restore(); } myPanel.update(true); }; if (myProject == null || myProject.isDefault()) { SwingUtilities.invokeLater(uiThread); - } else { + } + else { app.invokeLater(uiThread, ModalityState.any()); } }); @@ -407,13 +418,13 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode public String getTitle() { if (myDisposed) return "Diff"; - if (mySrc instanceof VirtualFileDiffElement && - myTrg instanceof VirtualFileDiffElement) { - VirtualFile srcFile = ((VirtualFileDiffElement)mySrc).getValue(); - VirtualFile trgFile = ((VirtualFileDiffElement)myTrg).getValue(); + if (mySource instanceof VirtualFileDiffElement && + myTarget instanceof VirtualFileDiffElement) { + VirtualFile srcFile = ((VirtualFileDiffElement)mySource).getValue(); + VirtualFile trgFile = ((VirtualFileDiffElement)myTarget).getValue(); return DiffRequestFactory.getInstance().getTitle(srcFile, trgFile); } - return IdeBundle.message("diff.dialog.title", mySrc.getPresentablePath(), myTrg.getPresentablePath()); + return IdeBundle.message("diff.dialog.title", mySource.getPresentablePath(), myTarget.getPresentablePath()); } @Nullable @@ -422,19 +433,19 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode } public DiffElement getSourceDir() { - return mySrc; + return mySource; } public DiffElement getTargetDir() { - return myTrg; + return myTarget; } public void setSourceDir(DiffElement src) { - mySrc = src; + mySource = src; } public void setTargetDir(DiffElement trg) { - myTrg = trg; + myTarget = trg; } @Override @@ -570,8 +581,8 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode myDisposed = true; myListeners.clear(); myElements.clear(); - mySrc = null; - myTrg = null; + mySource = null; + myTarget = null; myTree = null; } @@ -580,33 +591,27 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode } public void performCopyTo(final DirDiffElementImpl element) { - final DiffElement source = element.getSource(); + DiffElement source = element.getSource(); if (source != null) { - final String path = element.getParentNode().getPath(); + String path = element.getParentNode().getPath(); - if (source instanceof BackgroundOperatingDiffElement) { - final Ref errorMessage = new Ref<>(); - final Ref diff = new Ref<>(); - Runnable onFinish = () -> { - ApplicationManager.getApplication().assertIsDispatchThread(); - if (!myDisposed) { - DiffElement newElement = diff.get(); + if (source instanceof AsyncDiffElement) { + ((AsyncDiffElement)source).copyToAsync(myTarget, element.getTarget(), path) + .rejected(error -> reportException(error == null ? null : error.getMessage())) + .done(newElement -> { + ApplicationManager.getApplication().assertIsDispatchThread(); + if (myDisposed) return; if (newElement == null && element.getTarget() != null) { final int row = myElements.indexOf(element); element.updateTargetData(); fireTableRowsUpdated(row, row); } refreshElementAfterCopyTo(newElement, element); - if (!errorMessage.isNull()) { - reportException(errorMessage.get()); - } - } - }; - ((BackgroundOperatingDiffElement)source).copyTo(myTrg, errorMessage, diff, onFinish, element.getTarget(), path); + }); } else { WriteAction.run(() -> { - final DiffElement diffElement = source.copyTo(myTrg, path); + DiffElement diffElement = source.copyTo(myTarget, path); refreshElementAfterCopyTo(diffElement, element); }); } @@ -615,11 +620,11 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode private void refreshElementAfterCopyTo(DiffElement newElement, DirDiffElementImpl element) { if (newElement != null) { - final DTree node = element.getNode(); + DTree node = element.getNode(); node.setType(DiffType.EQUAL); node.setTarget(newElement); - final int row = myElements.indexOf(element); + int row = myElements.indexOf(element); if (getSettings().showEqual) { element.updateSourceFromTarget(newElement); fireTableRowsUpdated(row, row); @@ -630,28 +635,23 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode } } - public void performCopyFrom(final DirDiffElementImpl element) { - final DiffElement target = element.getTarget(); + public void performCopyFrom(@NotNull DirDiffElementImpl element) { + DiffElement target = element.getTarget(); if (target != null) { - final String path = element.getParentNode().getPath(); + String path = element.getParentNode().getPath(); - if (target instanceof BackgroundOperatingDiffElement) { - final Ref errorMessage = new Ref<>(); - final Ref diff = new Ref<>(); - Runnable onFinish = () -> { - ApplicationManager.getApplication().assertIsDispatchThread(); - if (!myDisposed) { - refreshElementAfterCopyFrom(element, diff.get()); - if (!errorMessage.isNull()) { - reportException(errorMessage.get()); - } - } - }; - ((BackgroundOperatingDiffElement)target).copyTo(mySrc, errorMessage, diff, onFinish, element.getSource(), path); + if (target instanceof AsyncDiffElement) { + ((AsyncDiffElement)target).copyToAsync(mySource, element.getSource(), path) + .rejected(error -> reportException(error == null ? null : error.getMessage())) + .done(newElement -> { + if (myDisposed) return; + ApplicationManager.getApplication().assertIsDispatchThread(); + refreshElementAfterCopyFrom(element, newElement); + }); } else { WriteAction.run(() -> { - final DiffElement diffElement = target.copyTo(mySrc, path); + DiffElement diffElement = target.copyTo(mySource, path); refreshElementAfterCopyFrom(element, diffElement); }); } @@ -686,63 +686,38 @@ public class DirDiffTableModel extends AbstractTableModel implements DirDiffMode myElements.remove(row); int start = row; - if (row > 0 && row == myElements.size() && myElements.get(row - 1).isSeparator()) { - final DirDiffElementImpl el = myElements.get(row - 1); + if (row > 0 && row == myElements.size() && myElements.get(row - 1).isSeparator() || + row != myElements.size() && myElements.get(row).isSeparator() && row > 0 && myElements.get(row - 1).isSeparator()) { + DirDiffElementImpl el = myElements.get(row - 1); if (removeFromTree) { el.getParentNode().remove(el.getNode()); } myElements.remove(row - 1); start = row - 1; - } - else if (row != myElements.size() && myElements.get(row).isSeparator() && row > 0 && myElements.get(row - 1).isSeparator()) { - final DirDiffElementImpl el = myElements.get(row - 1); - if (removeFromTree) { - el.getParentNode().remove(el.getNode()); - } - myElements.remove(row - 1); - start = row - 1; - } - fireTableRowsDeleted(start, row); } + fireTableRowsDeleted(start, row); + } } - public void performDelete(final DirDiffElementImpl element) { - final DiffElement source = element.getSource(); - final DiffElement target = element.getTarget(); + public void performDelete(@NotNull DirDiffElementImpl element) { + DiffElement source = element.getSource(); + DiffElement target = element.getTarget(); LOG.assertTrue(source == null || target == null); - if (source instanceof BackgroundOperatingDiffElement || target instanceof BackgroundOperatingDiffElement) { - final Ref errorMessage = new Ref<>(); - Runnable onFinish = () -> { - if (!myDisposed) { - if (!errorMessage.isNull()) { - reportException(errorMessage.get()); + if (source instanceof AsyncDiffElement || target instanceof AsyncDiffElement) { + ((AsyncDiffElement)(source != null ? source : target)).deleteAsync() + .rejected(error -> reportException(error != null ? error.getMessage() : null)) + .done(result -> { + if (!myDisposed && myElements.indexOf(element) != -1) { + removeElement(element, true); } - else { - if (myElements.indexOf(element) != -1) { - removeElement(element, true); - } - } - } - }; - if (source != null) { - ((BackgroundOperatingDiffElement)source).delete(errorMessage, onFinish); - } - else { - ((BackgroundOperatingDiffElement)target).delete(errorMessage, onFinish); - } + }); } else { if (myElements.indexOf(element) != -1) { removeElement(element, true); } - WriteAction.run(() -> { - if (source != null) { - source.delete(); - } - if (target != null) { - target.delete(); - } - }); + WriteAction.run( + () -> (source != null ? source : target).delete()); } }