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

Merged
merged 1 commit into from
Jan 15, 2025
Merged
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,48 @@
*/
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 {
public enum QuestionResult {
/**
* The implementation should ask the user. The default, if no
* value is present in the resource bundle.
*/
ASK_USER,

/**
* Assume yes, do not ask the user, proceed immediately.
*/
YES,

/**
* Assume no, do not ask the user, proceed immediately.
*/
NO,
}
private AskEditorQuestions() {
}

public static QuestionResult askUserQuestion(UserQuestionException uqe) {
String key = "UserQuestionAnswer_" + uqe.getClass().getName();
try {
String ask = NbBundle.getMessage(AskEditorQuestions.class, key); // NOI18N
if ("yes".equals(ask)) {
return QuestionResult.YES;
}
if ("no".equals(ask)) {
return QuestionResult.NO;
}
} catch (MissingResourceException ex) {
// expected
}
return QuestionResult.ASK_USER;
}

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() {
AskEditorQuestions.QuestionResult shouldAsk = AskEditorQuestions.askUserQuestion(uqe);
// attempt to handle automatic responses synchronously:
if (AskEditorQuestions.QuestionResult.NO == shouldAsk) {
openRefused();
return;
} else if (AskEditorQuestions.QuestionResult.YES == 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);
AskEditorQuestions.QuestionResult shouldAsk = AskEditorQuestions.askUserQuestion(uqe);
Object res;
if (AskEditorQuestions.QuestionResult.ASK_USER == shouldAsk) {
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 (AskEditorQuestions.QuestionResult.YES == shouldAsk) {
res = NotifyDescriptor.OK_OPTION;
} else {
res = NotifyDescriptor.NO_OPTION;
}

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