Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for UserQuestionException during reloads #7904

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions platform/openide.text/apichanges.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,20 @@
<apidef name="text">Text API</apidef>
</apidefs>
<changes>
<change id="DocumentOpenClose.ReloadAutomaticUserAnswers">
<api name="text"/>
<summary>DocumentFilter can block a reload, UserQuestionExceptions can be branded to true or false.</summary>
<version major="6" minor="96"/>
<date day="24" month="10" year="2024"/>
<author login="sdedic"/>
<compatibility addition="yes" binary="compatible" source="compatible"
semantic="compatible" deletion="no"
modification="no"/>
<description>
The implementation handles <code>UserQuestionException</code> during reload, which means a DocumentFilter
may block document reload. Support for automatic UserQuestionException handling was added as branding API
</description>
</change>
<change id="EditorCookie.Observable.PROP_RELOADING">
<api name="text"/>
<summary>Added EditorCookie.Observable.PROP_RELOADING and associated begin/end events</summary>
Expand Down
9 changes: 9 additions & 0 deletions platform/openide.text/arch.xml
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,15 @@ in methods
<code>org/netbeans/modules/openide/text/Bundle.properties</code>
to <code>yes</code> or <code>no</code> in a branding file in your application.
</api>
<api name="org.netbeans.modules.openide.text.UserQuestionAnswer" group="branding" type="export" category="devel">
Controls handling of UserQuestionExceptions thrown during document I/O by
<a href="@TOP@/org/openide/text/CloneableEditorSupport.html">CloneableEditorSupport</a>
Specific classes can be branded to result in
"yes" (reload without asking) or "no" (cancel the re/load operation). If unspecified or set to any other value, the
user will be asked the question (this is the default behaviour).
<p/>
The support is available from version 6.96
</api>
</answer>


Expand Down
3 changes: 1 addition & 2 deletions platform/openide.text/manifest.mf
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,4 @@ Manifest-Version: 1.0
OpenIDE-Module: org.openide.text
OpenIDE-Module-Localizing-Bundle: org/openide/text/Bundle.properties
AutoUpdate-Essential-Module: true
OpenIDE-Module-Specification-Version: 6.95

OpenIDE-Module-Specification-Version: 6.96
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,31 @@
*/
package org.netbeans.modules.openide.text;

import java.util.MissingResourceException;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.util.NbBundle;
import org.openide.util.UserQuestionException;

public final class AskEditorQuestions {
private AskEditorQuestions() {
}

public static Boolean askUserQuestion(UserQuestionException uqe) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A nit: it might be nicer to use a 3-constant enum instead of a Boolean. The enum could say YES, NO and ASK_USER, making the result more obvious.

String key = "UserQuestionAnswer_" + uqe.getClass().getName();
try {
String ask = NbBundle.getMessage(AskEditorQuestions.class, key); // NOI18N
if ("yes".equals(ask)) {
return true;
}
if ("no".equals(ask)) {
return false;
}
} catch (MissingResourceException ex) {
// expected
}
return null;
}

public static boolean askReloadDocument(String localizedMessage) {
String ask = NbBundle.getMessage(AskEditorQuestions.class, "ASK_OnReload"); // NOI18N
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,9 @@ private void atomicLockedRun() {
loadDoc.remove(0, loadDoc.getLength());
}
} catch (BadLocationException ex) {
if (ex.getCause() instanceof IOException) {
throw (IOException)ex.getCause();
}
LOG.log(Level.INFO, null, ex);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import java.io.IOException;
import javax.swing.text.StyledDocument;
import org.netbeans.modules.openide.text.AskEditorQuestions;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.util.Exceptions;
Expand All @@ -45,6 +46,29 @@ class UserQuestionExceptionHandler implements Runnable {
}

void runInEDT() {
Boolean shouldAsk = AskEditorQuestions.askUserQuestion(uqe);
// attempt to handle automatic responses synchronously:
if (Boolean.FALSE.equals(shouldAsk)) {
openRefused();
return;
} else if (Boolean.TRUE.equals(shouldAsk)) {
try {
uqe.confirmed();
uqe = null;
doc = openDocument();
opened(doc);
return;
} catch (UserQuestionException ex) {
// bad luck, go for EDT access.
uqe = ex;
} catch (IOException ex1) {
handleIOException(ex1);
return;
} catch (RuntimeException ex) {
handleRuntimeException(ex);
return;
}
}
Mutex.EVENT.readAccess(this);
}

Expand All @@ -60,9 +84,18 @@ boolean handleUserQuestionException() {
handleStart();
try {
while (true) {
NotifyDescriptor nd = new NotifyDescriptor.Confirmation(uqe.getLocalizedMessage(), NotifyDescriptor.YES_NO_OPTION);
nd.setOptions(new Object[]{NotifyDescriptor.YES_OPTION, NotifyDescriptor.NO_OPTION});
Object res = DialogDisplayer.getDefault().notify(nd);
Boolean shouldAsk = AskEditorQuestions.askUserQuestion(uqe);
Object res;
if (shouldAsk == null) {
NotifyDescriptor nd = new NotifyDescriptor.Confirmation(uqe.getLocalizedMessage(), NotifyDescriptor.YES_NO_OPTION);
nd.setOptions(new Object[]{NotifyDescriptor.YES_OPTION, NotifyDescriptor.NO_OPTION});
res = DialogDisplayer.getDefault().notify(nd);
} else if (Boolean.TRUE.equals(shouldAsk)) {
res = NotifyDescriptor.OK_OPTION;
} else {
res = NotifyDescriptor.NO_OPTION;
}

if (NotifyDescriptor.OK_OPTION.equals(res)) {
try {
uqe.confirmed();
Expand Down
Loading