mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
@AcceptNestedTransactions annotation and assert that project-modal dialogs can't be shown under write actions or transactions
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.application;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* Add this annotation to modal dialogs (DialogWrapper inheritors) shown from within transactions,
|
||||
* to allow nested transactions inside those dialogs.
|
||||
*
|
||||
* @see TransactionGuard#acceptNestedTransactions(TransactionKind...)
|
||||
* @since 146.*
|
||||
* @author peter
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface AcceptNestedTransactions {
|
||||
|
||||
/**
|
||||
* @return the kinds of transaction to allow inside the dialog
|
||||
*/
|
||||
TransactionKind.Common[] value();
|
||||
}
|
||||
@@ -60,7 +60,10 @@ import org.jetbrains.annotations.NotNull;
|
||||
*
|
||||
* Having said all that, it's still advisable that the transactions be as short as possible and preferably exclude any modal dialogs
|
||||
* for which transaction-ness is not critical. So a better overall strategy would be to either make the dialogs non-modal,
|
||||
* or at least make them and the code that shows them prepared for possible model changes while the dialog is shown.
|
||||
* or at least make them and the code that shows them prepared for possible model changes while the dialog is shown.<p/>
|
||||
*
|
||||
* Dialogs that have per-project modality must never be shown from a transaction, because this would disallow making changes in another
|
||||
* project: they'd be blocked by the running transaction.
|
||||
*
|
||||
* Q: I've got <b>"Write access is allowed from model transactions only"</b> exception, what do I do?<br/>
|
||||
* A: Add a transaction somewhere into the call stack, to the outermost callee where having read/write model consistency is needed.
|
||||
@@ -177,8 +180,10 @@ public abstract class TransactionGuard {
|
||||
/**
|
||||
* Allow incoming transactions of the specified kinds to be executed immediately, instead of being queued until the current transaction is finished.<p/>
|
||||
*
|
||||
* Example: outer transaction has shown a dialog with an editor, and typing into that editor (which requires a transaction for changing document)
|
||||
* should be allowed.
|
||||
* Example: outer transaction has shown a dialog with an editor, and typing into that editor (which requires a transaction for changing document).
|
||||
* should be allowed.<p/>
|
||||
*
|
||||
* For dialogs, consider using {@link AcceptNestedTransactions} annotation instead of explicit call to this method.
|
||||
* @param kinds kinds of transactions to allow
|
||||
* @return a token object for this session. Please call {@link AccessToken#finish()} (inside finally clause) when you don't want
|
||||
* nested transactions anymore.
|
||||
|
||||
@@ -18,8 +18,8 @@ package com.intellij.openapi.application;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
|
||||
/**
|
||||
* A kind of transaction used in {@link TransactionGuard#submitMergeableTransaction(TransactionKind, Runnable)}
|
||||
* and {@link TransactionGuard#acceptNestedTransactions(TransactionKind...)}.
|
||||
* A kind of transaction used in {@link TransactionGuard#submitMergeableTransaction(TransactionKind, Runnable)},
|
||||
* {@link TransactionGuard#acceptNestedTransactions(TransactionKind...)} and {@link AcceptNestedTransactions}.
|
||||
*/
|
||||
public interface TransactionKind {
|
||||
/**
|
||||
|
||||
@@ -24,9 +24,7 @@ import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.MnemonicHelper;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.actionSystem.ex.ActionUtil;
|
||||
import com.intellij.openapi.application.ApplicationInfo;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ModalityState;
|
||||
import com.intellij.openapi.application.*;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.help.HelpManager;
|
||||
import com.intellij.openapi.keymap.KeymapUtil;
|
||||
@@ -1641,6 +1639,16 @@ public abstract class DialogWrapper {
|
||||
|
||||
@NotNull
|
||||
private AsyncResult<Boolean> invokeShow() {
|
||||
Window window = myPeer.getWindow();
|
||||
if (window instanceof JDialog && ((JDialog)window).getModalityType() == Dialog.ModalityType.DOCUMENT_MODAL) {
|
||||
if (ApplicationManager.getApplication().isWriteAccessAllowed()) {
|
||||
LOG.error("Project-modal dialogs should not be shown under a write action.");
|
||||
}
|
||||
if (TransactionGuard.getInstance().isInsideTransaction()) {
|
||||
LOG.error("Project-modal dialogs should not be shown inside a transaction. See TransactionGuard documentation.");
|
||||
}
|
||||
}
|
||||
|
||||
final AsyncResult<Boolean> result = new AsyncResult<Boolean>();
|
||||
|
||||
ensureEventDispatchThread();
|
||||
@@ -1658,7 +1666,10 @@ public abstract class DialogWrapper {
|
||||
}
|
||||
});
|
||||
|
||||
myPeer.show();
|
||||
AcceptNestedTransactions anno = getClass().getAnnotation(AcceptNestedTransactions.class);
|
||||
try (AccessToken ignore = anno == null ? null : TransactionGuard.getInstance().acceptNestedTransactions((TransactionKind[])anno.value())) {
|
||||
myPeer.show();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user