From 5440c61536259f9d4d4ac9c9bcfeedd1186f61ae Mon Sep 17 00:00:00 2001 From: Alicia Appelhagen Date: Fri, 10 Mar 2023 13:03:26 +0100 Subject: [PATCH 01/95] Create closed child goal for SMT applications --- key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java | 5 +++++ key.core/src/main/java/de/uka/ilkd/key/proof/Proof.java | 4 ++-- key.core/src/main/java/de/uka/ilkd/key/smt/RuleAppSMT.java | 4 ++-- .../java/de/uka/ilkd/key/gui/actions/GoalBackAction.java | 4 ++-- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java b/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java index ee4e56f80fb..0fb22357082 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java @@ -13,6 +13,7 @@ import de.uka.ilkd.key.rule.*; import de.uka.ilkd.key.rule.inst.SVInstantiations; import de.uka.ilkd.key.rule.merge.MergeRule; +import de.uka.ilkd.key.smt.RuleAppSMT; import de.uka.ilkd.key.strategy.AutomatedRuleApplicationManager; import de.uka.ilkd.key.strategy.QueueRuleApplicationManager; import de.uka.ilkd.key.strategy.Strategy; @@ -629,6 +630,10 @@ public ImmutableList apply(final RuleApp ruleApp) { if (ruleApp instanceof TacletApp && ((TacletApp) ruleApp).taclet().closeGoal()) // the first new goal is the one to be closed proof.closeGoal(goalList.head()); + if (ruleApp instanceof RuleAppSMT) { + // the first new goal is the one to be closed + proof.closeGoal(goalList.head()); + } } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/Proof.java b/key.core/src/main/java/de/uka/ilkd/key/proof/Proof.java index 59270febb43..4cc7d45bdea 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/Proof.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/Proof.java @@ -517,8 +517,7 @@ public void replace(Goal oldGoal, ImmutableList newGoals) { /** - * Add the given constraint to the closure constraint of the given goal, i.e. the given goal is - * closed if p_c is satisfied. + * Close the given goals and all goals in the subtree below it. * * @param goalToClose the goal to close. */ @@ -530,6 +529,7 @@ public void closeGoal(Goal goalToClose) { Iterator it = closedSubtree.leavesIterator(); Goal goal; + // close all goals below the given goalToClose while (it.hasNext()) { goal = getGoal(it.next()); if (goal != null) { diff --git a/key.core/src/main/java/de/uka/ilkd/key/smt/RuleAppSMT.java b/key.core/src/main/java/de/uka/ilkd/key/smt/RuleAppSMT.java index 688ec7e7ff4..b6b47397fce 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/smt/RuleAppSMT.java +++ b/key.core/src/main/java/de/uka/ilkd/key/smt/RuleAppSMT.java @@ -27,7 +27,7 @@ public class RuleAppSMT extends AbstractBuiltInRuleApp { } private RuleAppSMT(SMTRule rule, PosInOccurrence pio, ImmutableList ifInsts, - String title) { + String title) { super(rule, pio, ifInsts); this.title = title; } @@ -95,7 +95,7 @@ public boolean isAxiomJustification() { // RuleAppSMT app = (RuleAppSMT) ruleApp; // goal.node().getNodeInfo().setBranchLabel(app.getTitle()); - ImmutableList newGoals = goal.split(0); + ImmutableList newGoals = goal.split(1); return newGoals; } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalBackAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalBackAction.java index ae59dd53313..7cc59504b5e 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalBackAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalBackAction.java @@ -20,8 +20,8 @@ /** * This action is one part of the previous UndoLastStepAction: It undoes the last rule application - * on the currently selected branch. It now also works on closed branches if not the flag - * "--no-pruning-closed" is set (to save memory). + * on the currently selected branch. It now also works on closed branches if the flag + * "--no-pruning-closed" is not set (to save memory). * * The action is enabled if: 1. the proof is not empty (just the root node exists) and 2. either * pruning of closed branches is enabled or the selected node is open From 0728cfe83f3617ae6dc271877c74e78a98a380ab Mon Sep 17 00:00:00 2001 From: Alicia Appelhagen Date: Fri, 10 Mar 2023 13:05:07 +0100 Subject: [PATCH 02/95] Rename RuleAppSMT for consistency --- .../ilkd/key/macros/scripts/SMTCommand.java | 2 +- .../main/java/de/uka/ilkd/key/proof/Goal.java | 4 ++-- .../de/uka/ilkd/key/proof/Statistics.java | 3 ++- .../proof/io/IntermediateProofReplayer.java | 6 ++--- .../smt/{RuleAppSMT.java => SMTRuleApp.java} | 24 +++++++++---------- .../uka/ilkd/key/gui/smt/SolverListener.java | 2 +- 6 files changed, 21 insertions(+), 20 deletions(-) rename key.core/src/main/java/de/uka/ilkd/key/smt/{RuleAppSMT.java => SMTRuleApp.java} (81%) diff --git a/key.core/src/main/java/de/uka/ilkd/key/macros/scripts/SMTCommand.java b/key.core/src/main/java/de/uka/ilkd/key/macros/scripts/SMTCommand.java index 4dfbc49d52a..e66f6d71946 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/macros/scripts/SMTCommand.java +++ b/key.core/src/main/java/de/uka/ilkd/key/macros/scripts/SMTCommand.java @@ -79,7 +79,7 @@ private void runSMT(SMTCommandArguments args, SolverTypeCollection su, Goal goal for (SMTProblem problem : probList) { SMTSolverResult finalResult = problem.getFinalResult(); if (finalResult.isValid() == ThreeValuedTruth.VALID) { - IBuiltInRuleApp app = RuleAppSMT.rule.createApp(null).setTitle(args.solver); + IBuiltInRuleApp app = SMTRuleApp.rule.createApp(null).setTitle(args.solver); problem.getGoal().apply(app); } System.err.println("SMT Runtime, goal " + goal.node().serialNr() + ": " diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java b/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java index 0fb22357082..e702c92ba31 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java @@ -13,7 +13,7 @@ import de.uka.ilkd.key.rule.*; import de.uka.ilkd.key.rule.inst.SVInstantiations; import de.uka.ilkd.key.rule.merge.MergeRule; -import de.uka.ilkd.key.smt.RuleAppSMT; +import de.uka.ilkd.key.smt.SMTRuleApp; import de.uka.ilkd.key.strategy.AutomatedRuleApplicationManager; import de.uka.ilkd.key.strategy.QueueRuleApplicationManager; import de.uka.ilkd.key.strategy.Strategy; @@ -630,7 +630,7 @@ public ImmutableList apply(final RuleApp ruleApp) { if (ruleApp instanceof TacletApp && ((TacletApp) ruleApp).taclet().closeGoal()) // the first new goal is the one to be closed proof.closeGoal(goalList.head()); - if (ruleApp instanceof RuleAppSMT) { + if (ruleApp instanceof SMTRuleApp) { // the first new goal is the one to be closed proof.closeGoal(goalList.head()); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/Statistics.java b/key.core/src/main/java/de/uka/ilkd/key/proof/Statistics.java index 35a4eeb7911..d9455199a9c 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/Statistics.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/Statistics.java @@ -15,6 +15,7 @@ import de.uka.ilkd.key.rule.TacletApp; import de.uka.ilkd.key.rule.UseDependencyContractApp; import de.uka.ilkd.key.rule.merge.MergeRuleBuiltInRuleApp; +import de.uka.ilkd.key.smt.SMTRuleApp; import de.uka.ilkd.key.util.EnhancedStringBuffer; import de.uka.ilkd.key.util.Pair; @@ -236,7 +237,7 @@ private void changeOnNode(final Node node, if (ruleApp instanceof de.uka.ilkd.key.rule.OneStepSimplifierRuleApp) { oss++; ossCaptured += tmpOssCaptured(ruleApp); - } else if (ruleApp instanceof de.uka.ilkd.key.smt.RuleAppSMT) { + } else if (ruleApp instanceof SMTRuleApp) { smt++; } else if (ruleApp instanceof UseDependencyContractApp) { dep++; diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/io/IntermediateProofReplayer.java b/key.core/src/main/java/de/uka/ilkd/key/proof/io/IntermediateProofReplayer.java index d08078b93cf..39064c5f368 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/io/IntermediateProofReplayer.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/io/IntermediateProofReplayer.java @@ -25,7 +25,7 @@ import de.uka.ilkd.key.rule.merge.procedures.MergeWithPredicateAbstractionFactory; import de.uka.ilkd.key.settings.DefaultSMTSettings; import de.uka.ilkd.key.settings.ProofIndependentSettings; -import de.uka.ilkd.key.smt.RuleAppSMT; +import de.uka.ilkd.key.smt.SMTRuleApp; import de.uka.ilkd.key.smt.SMTProblem; import de.uka.ilkd.key.smt.SMTSolverResult.ThreeValuedTruth; import de.uka.ilkd.key.smt.SolverLauncher; @@ -547,7 +547,7 @@ private IBuiltInRuleApp constructBuiltinApp(BuiltInAppIntermediate currInterm, G } } - if (RuleAppSMT.rule.name().toString().equals(ruleName)) { + if (SMTRuleApp.rule.name().toString().equals(ruleName)) { boolean error = false; final SMTProblem smtProblem = new SMTProblem(currGoal); try { @@ -569,7 +569,7 @@ private IBuiltInRuleApp constructBuiltinApp(BuiltInAppIntermediate currInterm, G status = "Your proof has been loaded, but SMT solvers have not been run"; throw new SkipSMTRuleException(); } else { - return RuleAppSMT.rule.createApp(null, proof.getServices()); + return SMTRuleApp.rule.createApp(null, proof.getServices()); } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/smt/RuleAppSMT.java b/key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java similarity index 81% rename from key.core/src/main/java/de/uka/ilkd/key/smt/RuleAppSMT.java rename to key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java index b6b47397fce..6eb02e631fa 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/smt/RuleAppSMT.java +++ b/key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java @@ -16,29 +16,29 @@ * The rule application that is used when a goal is closed by means of an external solver. So far it * stores the rule that that has been used and a title containing some information for the user. */ -public class RuleAppSMT extends AbstractBuiltInRuleApp { +public class SMTRuleApp extends AbstractBuiltInRuleApp { public final static SMTRule rule = new SMTRule(); private final String title; - RuleAppSMT(SMTRule rule, PosInOccurrence pio) { + SMTRuleApp(SMTRule rule, PosInOccurrence pio) { this(rule, pio, null, "SMT Rule App"); } - private RuleAppSMT(SMTRule rule, PosInOccurrence pio, ImmutableList ifInsts, + private SMTRuleApp(SMTRule rule, PosInOccurrence pio, ImmutableList ifInsts, String title) { super(rule, pio, ifInsts); this.title = title; } - private RuleAppSMT(SMTRule rule, String title) { + private SMTRuleApp(SMTRule rule, String title) { super(rule, null); this.title = title; } - public RuleAppSMT replacePos(PosInOccurrence newPos) { + public SMTRuleApp replacePos(PosInOccurrence newPos) { return this; } @@ -65,13 +65,13 @@ public BuiltInRule rule() { public static class SMTRule implements BuiltInRule { public static final Name name = new Name("SMTRule"); - public RuleAppSMT createApp(PosInOccurrence pos) { + public SMTRuleApp createApp(PosInOccurrence pos) { return createApp(pos, null); } @Override - public RuleAppSMT createApp(PosInOccurrence pos, TermServices services) { - return new RuleAppSMT(this, pos); + public SMTRuleApp createApp(PosInOccurrence pos, TermServices services) { + return new SMTRuleApp(this, pos); } @@ -124,18 +124,18 @@ public Name name() { } - public RuleAppSMT setTitle(String title) { - return new RuleAppSMT(rule, title); + public SMTRuleApp setTitle(String title) { + return new SMTRuleApp(rule, title); } @Override - public RuleAppSMT setIfInsts(ImmutableList ifInsts) { + public SMTRuleApp setIfInsts(ImmutableList ifInsts) { setMutable(ifInsts); return this; } @Override - public RuleAppSMT tryToInstantiate(Goal goal) { + public SMTRuleApp tryToInstantiate(Goal goal) { return this; } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java index 688d6a18fb1..fcdb3593ee2 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java @@ -215,7 +215,7 @@ private void applyResults() { for (SMTProblem problem : smtProblems) { if (problem.getFinalResult().isValid() == ThreeValuedTruth.VALID) { IBuiltInRuleApp app = - RuleAppSMT.rule.createApp(null).setTitle(getTitle(problem)); + SMTRuleApp.rule.createApp(null).setTitle(getTitle(problem)); problem.getGoal().apply(app); } } From b22dd92a874d6280fe74c5dfd7a95dad8f89f7c1 Mon Sep 17 00:00:00 2001 From: Alicia Appelhagen Date: Fri, 17 Mar 2023 07:08:24 +0100 Subject: [PATCH 03/95] Dispose of ProgessDialog to avoid applying SMT twice via double-click --- .../src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java index fcdb3593ee2..1a2f498f98f 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java @@ -308,7 +308,8 @@ private void discardEvent(final SolverLauncher launcher) { private void applyEvent(final SolverLauncher launcher) { launcher.stop(); applyResults(); - progressDialog.setVisible(false); + //progressDialog.setVisible(false); + progressDialog.dispose(); } @Override From 532a3a7e6e2b7e258d54811323ef243dbf7bc963 Mon Sep 17 00:00:00 2001 From: Alicia Appelhagen Date: Tue, 4 Apr 2023 15:58:44 +0200 Subject: [PATCH 04/95] Always dispose of ProgressDialog instead of hiding it --- .../main/java/de/uka/ilkd/key/gui/smt/SolverListener.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java index 90539e7c219..3e12a0e4580 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java @@ -286,13 +286,16 @@ private void stopEvent(final SolverLauncher launcher) { private void discardEvent(final SolverLauncher launcher) { launcher.stop(); - progressDialog.setVisible(false); + progressDialog.dispose(); } private void applyEvent(final SolverLauncher launcher) { launcher.stop(); applyResults(); - //progressDialog.setVisible(false); + /* Previously, the progressDialog was only made invisible which enabled users to + click the apply button more than once, each time creating a new SMT goal. + Disposing of the dialog is fine as it is created anew each time a SolverLauncher + is started anyway (see #launcherStarted(), #prepareDialog()). */ progressDialog.dispose(); } From cd5ad5636fc5da15d927c56c30a122461a9cbb90 Mon Sep 17 00:00:00 2001 From: Alicia Appelhagen Date: Fri, 21 Apr 2023 06:14:43 +0200 Subject: [PATCH 05/95] Add all top level formulas to ifInsts of SMTRuleAp when instantiating on a goal --- .../ilkd/key/macros/scripts/SMTCommand.java | 8 +++- .../java/de/uka/ilkd/key/smt/SMTRuleApp.java | 48 +++++++++++++++---- .../useractions/ProofSMTApplyUserAction.java | 9 +++- 3 files changed, 52 insertions(+), 13 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/macros/scripts/SMTCommand.java b/key.core/src/main/java/de/uka/ilkd/key/macros/scripts/SMTCommand.java index 62b73bbb2ae..7db772b9de0 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/macros/scripts/SMTCommand.java +++ b/key.core/src/main/java/de/uka/ilkd/key/macros/scripts/SMTCommand.java @@ -2,6 +2,9 @@ import java.util.*; +import de.uka.ilkd.key.logic.PosInOccurrence; +import de.uka.ilkd.key.logic.PosInTerm; +import de.uka.ilkd.key.logic.SequentFormula; import de.uka.ilkd.key.macros.scripts.meta.Option; import de.uka.ilkd.key.macros.scripts.meta.ValueInjector; import de.uka.ilkd.key.proof.Goal; @@ -85,7 +88,10 @@ private void runSMT(SMTCommandArguments args, SolverTypeCollection su, Goal goal for (SMTProblem problem : probList) { SMTSolverResult finalResult = problem.getFinalResult(); if (finalResult.isValid() == ThreeValuedTruth.VALID) { - IBuiltInRuleApp app = SMTRuleApp.rule.createApp(null).setTitle(args.solver); + SequentFormula formula = problem.getSequent().getFormulabyNr(0); + IBuiltInRuleApp app = SMTRuleApp.rule.createApp(null) + .tryToInstantiate(problem.getGoal()) + .setTitle(args.solver); problem.getGoal().apply(app); } LOGGER.info("Finished run on goal " + goal.node().serialNr() + " in " diff --git a/key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java b/key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java index 51bd38e23dd..9b5ea73cf50 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java @@ -1,9 +1,7 @@ package de.uka.ilkd.key.smt; import de.uka.ilkd.key.java.Services; -import de.uka.ilkd.key.logic.Name; -import de.uka.ilkd.key.logic.PosInOccurrence; -import de.uka.ilkd.key.logic.TermServices; +import de.uka.ilkd.key.logic.*; import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.rule.AbstractBuiltInRuleApp; import de.uka.ilkd.key.rule.BuiltInRule; @@ -11,6 +9,9 @@ import org.key_project.util.collection.ImmutableList; +import java.util.ArrayList; +import java.util.List; + /** * The rule application that is used when a goal is closed by means of an external solver. So far it * stores the rule that that has been used and a title containing some information for the user. @@ -20,7 +21,11 @@ public class SMTRuleApp extends AbstractBuiltInRuleApp { public final static SMTRule rule = new SMTRule(); private final String title; - + /** + * Create a new rule app without ifInsts (will be null). + * @param rule the SMTRule to apply + * @param pio the pos in term to apply the rule on + */ SMTRuleApp(SMTRule rule, PosInOccurrence pio) { this(rule, pio, null, "SMT Rule App"); } @@ -31,14 +36,13 @@ private SMTRuleApp(SMTRule rule, PosInOccurrence pio, ImmutableListruleApp + * @param services the Services with the necessary information about the java programs + * @param ruleApp the rule application to be executed + * @return a list with an identical goal as the given goal + */ @Override public ImmutableList apply(Goal goal, Services services, RuleApp ruleApp) { if (goal.proof().getInitConfig().getJustifInfo().getJustification(rule) == null) { @@ -118,7 +129,7 @@ public Name name() { } public SMTRuleApp setTitle(String title) { - return new SMTRuleApp(rule, title); + return new SMTRuleApp(rule, pio, ifInsts, title); } @Override @@ -127,9 +138,26 @@ public SMTRuleApp setIfInsts(ImmutableList ifInsts) { return this; } + /** + * Create a new RuleApp with the same pio (in this case, that will probably be null as the + * SMT rule is applied to the complete sequent) as this one. + * Add all top level formulas of the goal + * to the RuleApp's ifInsts. + * @param goal the goal to instantiate the current RuleApp on + * @return a new RuleApp with the same pio and all top level formulas of the goal as ifInsts + */ @Override public SMTRuleApp tryToInstantiate(Goal goal) { - return this; + SMTRuleApp app = rule.createApp(pio); + Sequent seq = goal.sequent(); + List ifInsts = new ArrayList<>(); + for (SequentFormula ante : seq.antecedent()) { + ifInsts.add(new PosInOccurrence(ante, PosInTerm.getTopLevel(), true)); + } + for (SequentFormula succ : seq.succedent()) { + ifInsts.add(new PosInOccurrence(succ, PosInTerm.getTopLevel(), false)); + } + return app.setIfInsts(ImmutableList.fromList(ifInsts)); } } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/useractions/ProofSMTApplyUserAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/useractions/ProofSMTApplyUserAction.java index 69ca04f1bcc..94878f5d653 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/useractions/ProofSMTApplyUserAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/useractions/ProofSMTApplyUserAction.java @@ -5,6 +5,9 @@ import java.util.Iterator; import de.uka.ilkd.key.core.KeYMediator; +import de.uka.ilkd.key.logic.PosInOccurrence; +import de.uka.ilkd.key.logic.PosInTerm; +import de.uka.ilkd.key.logic.SequentFormula; import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Node; import de.uka.ilkd.key.proof.Proof; @@ -53,8 +56,10 @@ public String name() { protected void apply() { for (SMTProblem problem : smtProblems) { if (problem.getFinalResult().isValid() == SMTSolverResult.ThreeValuedTruth.VALID) { - IBuiltInRuleApp app = - SMTRuleApp.rule.createApp(null).setTitle(getTitle(problem)); + SequentFormula formula = problem.getSequent().getFormulabyNr(1); + IBuiltInRuleApp app = SMTRuleApp.rule.createApp(null) + .tryToInstantiate(problem.getGoal()) + .setTitle(getTitle(problem)); goalsClosed.add(problem.getGoal().node()); problem.getGoal().apply(app); } From 49b9e8faa9e450df8cc1eb68d5b6e20507ba09f1 Mon Sep 17 00:00:00 2001 From: Alexander Weigl Date: Sat, 22 Jul 2023 01:23:00 +0200 Subject: [PATCH 06/95] fixate bash as shell for dlsmt.sh --- .github/workflows/tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index dabcff72fd9..5b578c65d7a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -95,6 +95,8 @@ jobs: - name: Install SMT-Solvers run: .github/dlsmt.sh + shell: bash + - name: "Running tests: ${{ matrix.test }}" uses: gradle/gradle-build-action@v2.4.2 From 70b6b0dcccacdb02231974a5841b0825c6d48700 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Sat, 22 Jul 2023 11:32:37 +0200 Subject: [PATCH 07/95] Fix division by zero and NPE in proof tree search --- .../uka/ilkd/key/gui/prooftree/ProofTreeSearchBar.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeSearchBar.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeSearchBar.java index de63ce022ca..f167a1f7535 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeSearchBar.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeSearchBar.java @@ -32,6 +32,9 @@ public void setVisible(boolean vis) { public void searchNext() { fillCache(); + if (cache.isEmpty()) { + return; // no results to switch to + } startRow = currentRow + 1; startRow %= cache.size(); search(searchField.getText(), Position.Bias.Forward); @@ -39,6 +42,9 @@ public void searchNext() { public void searchPrevious() { fillCache(); + if (cache.isEmpty()) { + return; // no results to switch to + } startRow = currentRow - 1; startRow %= cache.size(); search(searchField.getText(), Position.Bias.Backward); @@ -98,7 +104,8 @@ private void addNodeToCache(GUIAbstractTreeNode node) { private void fillCache() { if (cache == null) { cache = new ArrayList<>(); - if (this.proofTreeView.delegateModel.getRoot() != null) { + if (this.proofTreeView.delegateModel != null + && this.proofTreeView.delegateModel.getRoot() != null) { addNodeToCache((GUIAbstractTreeNode) this.proofTreeView.delegateModel.getRoot()); fillCacheHelp((GUIBranchNode) this.proofTreeView.delegateModel.getRoot()); } From 8b266fe6fdcc8ad924072c9180379dcb4935ab74 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Sat, 22 Jul 2023 11:45:47 +0200 Subject: [PATCH 08/95] Fix that navigation was active without proof --- .../gui/actions/GoalSelectAboveAction.java | 8 ++--- .../gui/actions/GoalSelectBelowAction.java | 10 ++---- .../key/gui/actions/MainWindowAction.java | 33 +++++++++++++++++-- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalSelectAboveAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalSelectAboveAction.java index f1c737a110c..9ac268eb7f4 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalSelectAboveAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalSelectAboveAction.java @@ -7,23 +7,21 @@ import de.uka.ilkd.key.gui.fonticons.IconFactory; /** + * Action to select the next goal above in the proof tree. */ public final class GoalSelectAboveAction extends MainWindowAction { - /** - * - */ private static final long serialVersionUID = 4574670781882014092L; /** - * Creates a new GoalBackAction. + * Creates the new action. * * @param mainWindow the main window this action belongs to * @param longName true iff long names (including the name of the rule to undo) shall be * displayed (e.g. in menu items) */ public GoalSelectAboveAction(MainWindow mainWindow) { - super(mainWindow); + super(mainWindow, true); setAcceleratorLetter(KeyEvent.VK_K); setName("Select Goal Above"); setIcon(IconFactory.selectGoalAbove(MainWindow.TOOLBAR_ICON_SIZE)); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalSelectBelowAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalSelectBelowAction.java index aba46f051dc..e655ae4708b 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalSelectBelowAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalSelectBelowAction.java @@ -7,23 +7,19 @@ import de.uka.ilkd.key.gui.fonticons.IconFactory; /** + * Action to select the next goal below in the proof tree. */ public final class GoalSelectBelowAction extends MainWindowAction { - /** - * - */ private static final long serialVersionUID = 4574670781882014092L; /** - * Creates a new GoalBackAction. + * Creates the new action. * * @param mainWindow the main window this action belongs to - * @param longName true iff long names (including the name of the rule to undo) shall be - * displayed (e.g. in menu items) */ public GoalSelectBelowAction(MainWindow mainWindow) { - super(mainWindow); + super(mainWindow, true); setAcceleratorLetter(KeyEvent.VK_J); setName("Select Goal Below"); setIcon(IconFactory.selectGoalBelow(MainWindow.TOOLBAR_ICON_SIZE)); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/MainWindowAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/MainWindowAction.java index 81c6b38525c..aeef2f84e21 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/MainWindowAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/MainWindowAction.java @@ -1,8 +1,12 @@ package de.uka.ilkd.key.gui.actions; +import java.util.ArrayList; +import java.util.Collection; import javax.swing.*; import de.uka.ilkd.key.core.KeYMediator; +import de.uka.ilkd.key.core.KeYSelectionEvent; +import de.uka.ilkd.key.core.KeYSelectionListener; import de.uka.ilkd.key.gui.MainWindow; import de.uka.ilkd.key.gui.keyshortcuts.KeyStrokeManager; @@ -12,11 +16,11 @@ * {@link KeyStrokeManager}. */ public abstract class MainWindowAction extends KeyAction { - /** - * - */ private static final long serialVersionUID = -6611537258325987383L; + private static final MainWindowActionSelectionListener LISTENER = + new MainWindowActionSelectionListener(); + protected final MainWindow mainWindow; protected MainWindowAction(MainWindow mainWindow) { @@ -26,6 +30,14 @@ protected MainWindowAction(MainWindow mainWindow) { KeyStrokeManager.registerAction(this); } + protected MainWindowAction(MainWindow mainWindow, boolean onlyActiveWhenProofAvailable) { + this(mainWindow); + if (onlyActiveWhenProofAvailable) { + LISTENER.actions.add(this); + this.setEnabled(getMediator().getSelectionModel().getSelectedProof() != null); + } + } + protected void setAcceleratorLetter(int letter) { setAcceleratorKey(KeyStroke.getKeyStroke(letter, SHORTCUT_KEY_MASK)); } @@ -41,4 +53,19 @@ protected void setAcceleratorKey(KeyStroke keyStroke) { protected KeYMediator getMediator() { return mainWindow.getMediator(); } + + private static final class MainWindowActionSelectionListener implements KeYSelectionListener { + private final Collection actions = new ArrayList<>(); + + @Override + public void selectedNodeChanged(KeYSelectionEvent e) { + var enable = e.getSource().getSelectedProof() != null; + actions.forEach(a -> a.setEnabled(enable)); + } + + @Override + public void selectedProofChanged(KeYSelectionEvent e) { + selectedNodeChanged(e); + } + } } From 4406916f0f73538253795518a4d4c00be81c0178 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Sat, 22 Jul 2023 11:50:06 +0200 Subject: [PATCH 09/95] Fix test case generation dialog not centered --- .../src/main/java/de/uka/ilkd/key/gui/testgen/TGInfoDialog.java | 1 - .../java/de/uka/ilkd/key/gui/testgen/TestGenerationAction.java | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/TGInfoDialog.java b/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/TGInfoDialog.java index 245ad756352..d9d9d0d11f8 100644 --- a/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/TGInfoDialog.java +++ b/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/TGInfoDialog.java @@ -100,7 +100,6 @@ public TGInfoDialog(Window owner) { setTitle("Test Suite Generation"); setSize(1000, 700); setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); - setLocationRelativeTo(MainWindow.getInstance()); setLayout(new BorderLayout()); final JScrollPane scrollpane = new JScrollPane(textArea); diff --git a/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/TestGenerationAction.java b/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/TestGenerationAction.java index fc2464b6693..24d2d3bef44 100644 --- a/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/TestGenerationAction.java +++ b/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/TestGenerationAction.java @@ -39,6 +39,7 @@ public TestGenerationAction(MainWindow mainWindow) { public void actionPerformed(ActionEvent e) { TGInfoDialog dlg = new TGInfoDialog(mainWindow); dlg.setVisible(true); + dlg.setLocationRelativeTo(mainWindow); } From 98b1475808fbd401b94e6dccc4b5fed8b5101a3f Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Sat, 22 Jul 2023 11:57:00 +0200 Subject: [PATCH 10/95] Make sure UI is usable after any exception --- key.ui/src/main/java/de/uka/ilkd/key/gui/IssueDialog.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/IssueDialog.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/IssueDialog.java index 2a9afc727af..a27c60df996 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/IssueDialog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/IssueDialog.java @@ -19,6 +19,7 @@ import javax.swing.text.html.HTML; import javax.swing.text.html.HTMLDocument; +import de.uka.ilkd.key.core.KeYMediator; import de.uka.ilkd.key.gui.actions.EditSourceFileAction; import de.uka.ilkd.key.gui.actions.SendFeedbackAction; import de.uka.ilkd.key.gui.configuration.Config; @@ -551,6 +552,9 @@ private JPanel createSourcePanel(Font font) { * @param exception the exception to display */ public static void showExceptionDialog(Window parent, Throwable exception) { + // make sure UI is usable after any exception + MainWindow.getInstance().getMediator().startInterface(true); + Set msg = Collections.singleton(extractMessage(exception)); IssueDialog dlg = new IssueDialog(parent, "Parser Error", msg, true, exception); dlg.setVisible(true); From 322e22593ced545fbee3bce3f0d5a7a4c008b771 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Sat, 22 Jul 2023 12:04:34 +0200 Subject: [PATCH 11/95] Make sure UI is active after loading PO --- .../java/de/uka/ilkd/key/gui/ProofManagementDialog.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/ProofManagementDialog.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/ProofManagementDialog.java index cf653b9255a..59748802905 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/ProofManagementDialog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/ProofManagementDialog.java @@ -476,7 +476,6 @@ private void findOrStartProof(@Nonnull Contract contract) { env = ui.createProofEnvironmentAndRegisterProof(po, pl, initConfig); } else { env.registerProof(po, pl); - } } catch (ProofInputException exc) { IssueDialog.showExceptionDialog(MainWindow.getInstance(), exc); @@ -485,6 +484,11 @@ private void findOrStartProof(@Nonnull Contract contract) { mediator.setProof(proof); } startedProof = true; + // starting another proof will not execute the ProblemLoader again, + // so we have to activate the UI here + if (initConfig.getServices().getSpecificationRepository().getAllProofs().size() > 1) { + mediator.startInterface(true); + } } private void updateStartButton() { From a7bfac502e253cb3ea239e87bf3bfd754be5cb93 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Sat, 22 Jul 2023 12:07:46 +0200 Subject: [PATCH 12/95] Make sure SMT dialog is centered --- .../src/main/java/de/uka/ilkd/key/gui/smt/ProgressDialog.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/ProgressDialog.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/ProgressDialog.java index 45ce5e35d21..ca8f36c196a 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/ProgressDialog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/ProgressDialog.java @@ -89,7 +89,6 @@ public ProgressDialog(ProgressModel model, ProgressDialogListener listener, table.getTableHeader().setReorderingAllowed(false); table.setModel(model, titles); this.listener = listener; - setLocationRelativeTo(MainWindow.getInstance()); if (counterexample) { this.setTitle("SMT Counterexample Search"); } else { @@ -126,6 +125,8 @@ public ProgressDialog(ProgressModel model, ProgressDialogListener listener, constraints.insets.bottom = 5; contentPane.add(buttonBox, constraints); this.pack(); + // always set the location last, otherwise it is not centered! + setLocationRelativeTo(MainWindow.getInstance()); } public void setProgress(int value) { From 9b48e483ba5a7aabe84d8058bf86e97a0af4149a Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Sat, 22 Jul 2023 12:12:46 +0200 Subject: [PATCH 13/95] Center heatmap options dialog --- .../src/main/java/de/uka/ilkd/key/gui/HeatmapOptionsDialog.java | 1 + 1 file changed, 1 insertion(+) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/HeatmapOptionsDialog.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/HeatmapOptionsDialog.java index dbeea424c25..17d90432e74 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/HeatmapOptionsDialog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/HeatmapOptionsDialog.java @@ -163,6 +163,7 @@ public HeatmapOptionsDialog() { pack(); setAlwaysOnTop(true); setResizable(false); + setLocationRelativeTo(MainWindow.getInstance()); } /** From ec24ae596eb2efdd9328fe55d30395d0e7ab98a0 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Sat, 22 Jul 2023 12:14:27 +0200 Subject: [PATCH 14/95] Make sure taclet load dialog is centered --- .../ilkd/key/gui/lemmatagenerator/LoadUserTacletsDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/lemmatagenerator/LoadUserTacletsDialog.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/lemmatagenerator/LoadUserTacletsDialog.java index 49fdaf6d911..0351f172397 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/lemmatagenerator/LoadUserTacletsDialog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/lemmatagenerator/LoadUserTacletsDialog.java @@ -263,9 +263,9 @@ private JDialog getHelpWindow() { textArea.setEditable(false); helpWindow.getContentPane().add(new JScrollPane(textArea)); helpWindow.setMinimumSize(new Dimension(400, 200)); - helpWindow.setLocationRelativeTo(MainWindow.getInstance()); helpWindow.setTitle("Help"); helpWindow.pack(); + helpWindow.setLocationRelativeTo(MainWindow.getInstance()); } return helpWindow; From 0e9189b3b78dc4a47c06b93d0958596880de8af9 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Sat, 22 Jul 2023 12:26:19 +0200 Subject: [PATCH 15/95] Log all exceptions --- .../src/main/java/de/uka/ilkd/key/gui/IssueDialog.java | 2 +- .../main/java/de/uka/ilkd/key/gui/ProofMacroWorker.java | 1 + .../java/de/uka/ilkd/key/gui/ProofManagementDialog.java | 5 +++++ .../main/java/de/uka/ilkd/key/gui/ProofScriptWorker.java | 1 + .../java/de/uka/ilkd/key/gui/ProofSelectionDialog.java | 5 +++++ .../de/uka/ilkd/key/gui/TacletMatchCompletionDialog.java | 1 + .../de/uka/ilkd/key/gui/WindowUserInterfaceControl.java | 1 + .../uka/ilkd/key/gui/actions/LemmaGenerationAction.java | 9 +++++++++ .../ilkd/key/gui/actions/ProofScriptFromFileAction.java | 5 +++++ .../de/uka/ilkd/key/gui/actions/SendFeedbackAction.java | 2 ++ .../actions/ExceptionFailureNotificationDialog.java | 6 ++++++ .../key/gui/plugins/caching/ReferenceSearchDialog.java | 6 ++++++ .../java/de/uka/ilkd/key/gui/smt/ProgressDialog.java | 7 +++++++ .../uka/ilkd/key/gui/testgen/CounterExampleAction.java | 5 +++++ 14 files changed, 55 insertions(+), 1 deletion(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/IssueDialog.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/IssueDialog.java index a27c60df996..94a2898b027 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/IssueDialog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/IssueDialog.java @@ -19,7 +19,6 @@ import javax.swing.text.html.HTML; import javax.swing.text.html.HTMLDocument; -import de.uka.ilkd.key.core.KeYMediator; import de.uka.ilkd.key.gui.actions.EditSourceFileAction; import de.uka.ilkd.key.gui.actions.SendFeedbackAction; import de.uka.ilkd.key.gui.configuration.Config; @@ -547,6 +546,7 @@ private JPanel createSourcePanel(Font font) { /** * Shows the dialog with a single exception. The stacktrace is extracted and can optionally be * shown in the dialog. + * Important: make sure to also log the exception before showing the dialog! * * @param parent the parent of the dialog (will be blocked) * @param exception the exception to display diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/ProofMacroWorker.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/ProofMacroWorker.java index daaf1a32c91..8f7f413a826 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/ProofMacroWorker.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/ProofMacroWorker.java @@ -118,6 +118,7 @@ protected void done() { if (!isCancelled() && exception != null) { // user cancelled task is fine, we do not // report this // This should actually never happen. + LOGGER.error("", exception); IssueDialog.showExceptionDialog(MainWindow.getInstance(), exception); } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/ProofManagementDialog.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/ProofManagementDialog.java index 59748802905..9effcd984c2 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/ProofManagementDialog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/ProofManagementDialog.java @@ -44,9 +44,13 @@ import org.key_project.util.collection.DefaultImmutableSet; import org.key_project.util.collection.ImmutableSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public final class ProofManagementDialog extends JDialog { private static final long serialVersionUID = 3543411893273433386L; + private static final Logger LOGGER = LoggerFactory.getLogger(ProofManagementDialog.class); /** * The contracts are stored by name of the {@link KeYJavaType}, method name, and contract name @@ -478,6 +482,7 @@ private void findOrStartProof(@Nonnull Contract contract) { env.registerProof(po, pl); } } catch (ProofInputException exc) { + LOGGER.error("", exc); IssueDialog.showExceptionDialog(MainWindow.getInstance(), exc); } } else { diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/ProofScriptWorker.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/ProofScriptWorker.java index ef71a3230c6..eaed97d7a42 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/ProofScriptWorker.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/ProofScriptWorker.java @@ -170,6 +170,7 @@ public void done() { } catch (CancellationException ex) { LOGGER.info("Scripting was cancelled."); } catch (Throwable ex) { + LOGGER.error("", ex); IssueDialog.showExceptionDialog(MainWindow.getInstance(), ex); } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/ProofSelectionDialog.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/ProofSelectionDialog.java index bc732d4521d..0a427a7eb0e 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/ProofSelectionDialog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/ProofSelectionDialog.java @@ -14,6 +14,9 @@ import javax.swing.*; import javax.swing.border.TitledBorder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * This dialog allows the user to select the proof to load from a proof bundle. * @@ -22,6 +25,7 @@ public final class ProofSelectionDialog extends JDialog { private static final long serialVersionUID = -586107341789859969L; + private static final Logger LOGGER = LoggerFactory.getLogger(ProofSelectionDialog.class); /** * Regex for identifiers (class, method), which catches for example "java.lang.Object", @@ -203,6 +207,7 @@ private static Path showDialog(Path bundlePath) { dialog.setVisible(true); proofPath = dialog.proofToLoad; } catch (IOException exc) { + LOGGER.error("", exc); IssueDialog.showExceptionDialog(MainWindow.getInstance(), exc); } return proofPath; diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/TacletMatchCompletionDialog.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/TacletMatchCompletionDialog.java index 4de95d9f3a4..2eee26ddf36 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/TacletMatchCompletionDialog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/TacletMatchCompletionDialog.java @@ -321,6 +321,7 @@ public void actionPerformed(ActionEvent e) { errorPositionKnown(exc.getMessage(), ex.getPosition().line(), ex.getPosition().column(), ex.inIfSequent()); } + LOGGER.error("", exc); IssueDialog.showExceptionDialog(TacletMatchCompletionDialog.this, exc); return; } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/WindowUserInterfaceControl.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/WindowUserInterfaceControl.java index dd5e384ab8f..cc17f13a3a6 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/WindowUserInterfaceControl.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/WindowUserInterfaceControl.java @@ -194,6 +194,7 @@ public void taskFinished(TaskFinishedInfo info) { resetStatus(this); Throwable result = (Throwable) info.getResult(); if (info.getResult() != null) { + LOGGER.error("", result); IssueDialog.showExceptionDialog(mainWindow, result); } else if (getMediator().getUI().isSaveOnly()) { mainWindow.displayResults("Finished Saving!"); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/LemmaGenerationAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/LemmaGenerationAction.java index 42ee7069843..a0fc83ef3ff 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/LemmaGenerationAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/LemmaGenerationAction.java @@ -25,7 +25,12 @@ import org.key_project.util.collection.ImmutableList; import org.key_project.util.collection.ImmutableSet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public abstract class LemmaGenerationAction extends MainWindowAction { + private static final Logger LOGGER = LoggerFactory.getLogger(LemmaGenerationAction.class); + public enum Mode { ProveUserDefinedTaclets, ProveKeYTaclets, ProveAndAddUserDefinedTaclets } @@ -53,6 +58,7 @@ public LemmaGenerationAction(MainWindow mainWindow) { abstract protected boolean proofIsRequired(); protected final void handleException(Throwable exception) { + LOGGER.error("", exception); IssueDialog.showExceptionDialog(mainWindow, exception); } @@ -134,6 +140,7 @@ protected void loadTaclets() { LoaderListener listener = new AbstractLoaderListener(mainWindow) { @Override public void doStopped(Throwable exception) { + LOGGER.error("", exception); IssueDialog.showExceptionDialog(ProveKeYTaclets.this.mainWindow, exception); } @@ -213,6 +220,7 @@ protected void loadTaclets() { LoaderListener listener = new AbstractLoaderListener(mainWindow) { @Override public void doStopped(Throwable exception) { + LOGGER.error("", exception); IssueDialog.showExceptionDialog(ProveUserDefinedTaclets.this.mainWindow, exception); } @@ -287,6 +295,7 @@ protected void loadTaclets() { LoaderListener listener = new AbstractLoaderListener(mainWindow) { @Override public void doStopped(Throwable exception) { + LOGGER.error("", exception); IssueDialog.showExceptionDialog(ProveAndAddTaclets.this.mainWindow, exception); } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ProofScriptFromFileAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ProofScriptFromFileAction.java index 7c85129edd1..e2aede274fb 100755 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ProofScriptFromFileAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ProofScriptFromFileAction.java @@ -11,6 +11,9 @@ import de.uka.ilkd.key.gui.ProofScriptWorker; import de.uka.ilkd.key.proof.Proof; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * The Class ProofScriptFromFileAction. * @@ -18,6 +21,7 @@ */ public class ProofScriptFromFileAction extends AbstractAction { private static final long serialVersionUID = -3181592516055470032L; + private static final Logger LOGGER = LoggerFactory.getLogger(ProofScriptFromFileAction.class); private final KeYMediator mediator; @@ -66,6 +70,7 @@ public void actionPerformed(ActionEvent e) { psw.execute(); } } catch (Exception ex) { + LOGGER.error("", ex); IssueDialog.showExceptionDialog(MainWindow.getInstance(), ex); } } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SendFeedbackAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SendFeedbackAction.java index 72116827dca..7290c18d0dd 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SendFeedbackAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SendFeedbackAction.java @@ -356,6 +356,7 @@ public String getDescription() { + "e-mail to " + FEEDBACK_RECIPIENT + ".", jfc.getSelectedFile())); } } catch (Exception e) { + LOGGER.error("", e); IssueDialog.showExceptionDialog(parent, e); } } @@ -399,6 +400,7 @@ private void sendReport(String message) { } } catch (Exception e) { + LOGGER.error("", e); IssueDialog.showExceptionDialog(parent, e); } } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/notification/actions/ExceptionFailureNotificationDialog.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/notification/actions/ExceptionFailureNotificationDialog.java index e285be36bbb..662363ceb43 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/notification/actions/ExceptionFailureNotificationDialog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/notification/actions/ExceptionFailureNotificationDialog.java @@ -7,7 +7,12 @@ import de.uka.ilkd.key.gui.notification.events.ExceptionFailureEvent; import de.uka.ilkd.key.gui.notification.events.NotificationEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class ExceptionFailureNotificationDialog extends ShowDisplayPane { + private static final Logger LOGGER = + LoggerFactory.getLogger(ExceptionFailureNotificationDialog.class); public ExceptionFailureNotificationDialog(Frame parentComponent) { super(parentComponent); @@ -18,6 +23,7 @@ public boolean execute(NotificationEvent event) { if (event instanceof ExceptionFailureEvent) { ExceptionFailureEvent ev = (ExceptionFailureEvent) event; setMessage(ev.getErrorMessage()); + LOGGER.error(ev.getErrorMessage(), ev.getException()); IssueDialog.showExceptionDialog(parentComponent, ev.getException()); } else { setMessage("An unknown error has occured." + event); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/ReferenceSearchDialog.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/ReferenceSearchDialog.java index d37782cb47e..fdaca1743cb 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/ReferenceSearchDialog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/ReferenceSearchDialog.java @@ -10,6 +10,9 @@ import org.key_project.util.java.SwingUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Dialog showing reference search information. * @@ -18,6 +21,8 @@ public class ReferenceSearchDialog extends JDialog { private static final long serialVersionUID = 1L; + private static final Logger LOGGER = LoggerFactory.getLogger(ReferenceSearchDialog.class); + /** * The table of reference search results. */ @@ -107,6 +112,7 @@ private JButton getApplyButton() { listener.copyButtonClicked(this); } catch (Exception exception) { // There may be exceptions during rule application that should not be lost. + LOGGER.error("", exception); IssueDialog.showExceptionDialog(ReferenceSearchDialog.this, exception); } }); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/ProgressDialog.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/ProgressDialog.java index ca8f36c196a..24f814c9841 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/ProgressDialog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/ProgressDialog.java @@ -17,12 +17,17 @@ import org.key_project.util.java.SwingUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Dialog showing launched SMT processes and results. */ public class ProgressDialog extends JDialog { private static final long serialVersionUID = 1L; + private static final Logger LOGGER = LoggerFactory.getLogger(ProgressDialog.class); + private final ProgressTable table; /** * Button to apply the results of running the SMT solver. @@ -152,6 +157,7 @@ private JButton getFocusButton() { try { listener.focusButtonClicked(); } catch (Exception exception) { + LOGGER.error("", exception); // There may be exceptions during rule application that should not be lost. IssueDialog.showExceptionDialog(ProgressDialog.this, exception); } @@ -171,6 +177,7 @@ private JButton getApplyButton() { listener.applyButtonClicked(); } catch (Exception exception) { // There may be exceptions during rule application that should not be lost. + LOGGER.error("", exception); IssueDialog.showExceptionDialog(ProgressDialog.this, exception); } }); diff --git a/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/CounterExampleAction.java b/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/CounterExampleAction.java index 8ff28d48f4f..c2417b013e5 100644 --- a/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/CounterExampleAction.java +++ b/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/CounterExampleAction.java @@ -24,8 +24,12 @@ import de.uka.ilkd.key.smt.counterexample.AbstractCounterExampleGenerator; import de.uka.ilkd.key.smt.counterexample.AbstractSideProofCounterExampleGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class CounterExampleAction extends MainWindowAction { private static final long serialVersionUID = -1931682474791981751L; + private static final Logger LOGGER = LoggerFactory.getLogger(CounterExampleAction.class); private static final String NAME = "Search for Counterexample"; private static final String TOOLTIP = "Search for a counterexample for the selected goal"; @@ -106,6 +110,7 @@ public void actionPerformed(ActionEvent e) { getMediator().addInterruptedListener(worker); worker.execute(); } catch (Exception exc) { + LOGGER.error("", exc); IssueDialog.showExceptionDialog(mainWindow, exc); } } From d8d299099f0d7cb78e91d729e32a568b0e940d32 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Sat, 22 Jul 2023 12:28:49 +0200 Subject: [PATCH 16/95] Make sure taclet load dialog is centered 2.0 --- .../ilkd/key/gui/lemmatagenerator/LoadUserTacletsDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/lemmatagenerator/LoadUserTacletsDialog.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/lemmatagenerator/LoadUserTacletsDialog.java index 0351f172397..834679e6d5f 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/lemmatagenerator/LoadUserTacletsDialog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/lemmatagenerator/LoadUserTacletsDialog.java @@ -448,8 +448,8 @@ private JDialog getDialog() { buttonPane.add(Box.createHorizontalStrut(5)); buttonPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); pane.add(buttonPane); - dialog.setLocationRelativeTo(MainWindow.getInstance()); dialog.pack(); + dialog.setLocationRelativeTo(MainWindow.getInstance()); } return dialog; } From 3d73e59bd6ba8a8a15fb36f93aa193d3d7bd65d3 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Sat, 22 Jul 2023 12:42:19 +0200 Subject: [PATCH 17/95] New UI testing facility --- .../gui/keyshortcuts/KeyStrokeManager.java | 10 + .../org/key_project/util/java/SwingUtil.java | 149 +++++++++++++ .../java/de/uka/ilkd/key/gui/ChaosMonkey.java | 195 ++++++++++++++++++ .../org/key_project/util/java/SwingUtil.java | 57 ----- 4 files changed, 354 insertions(+), 57 deletions(-) create mode 100644 key.ui/src/main/java/org/key_project/util/java/SwingUtil.java create mode 100644 key.ui/src/test/java/de/uka/ilkd/key/gui/ChaosMonkey.java delete mode 100644 key.util/src/main/java/org/key_project/util/java/SwingUtil.java diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeManager.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeManager.java index b7fedd992a1..94dc623fcaa 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeManager.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeManager.java @@ -3,6 +3,7 @@ import java.awt.*; import java.awt.event.KeyEvent; import java.lang.ref.WeakReference; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import javax.swing.*; @@ -160,4 +161,13 @@ private static int getShortcutMask() { return 0; } } + + /** + * Get all the managed actions. + * + * @return all actions + */ + public static Collection> getAllActions() { + return actions.values(); + } } diff --git a/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java b/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java new file mode 100644 index 00000000000..a84008585a4 --- /dev/null +++ b/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java @@ -0,0 +1,149 @@ +package org.key_project.util.java; + + +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.swing.*; + +/** + * Utilities for working with Swing. + * + * @author Arne Keller + */ +public final class SwingUtil { + private SwingUtil() { + } + + /** + * Find a component of the specified class in the container. + * This will search the view hierarchy recursively. + * + * @param container container to search in + * @param classToFind class to look for + * @return the object if found, otherwise null + * @param class of the component + */ + public static T findComponent(Container container, Class classToFind) { + for (int i = 0; i < container.getComponentCount(); i++) { + var c = container.getComponent(i); + if (c.getClass().equals(classToFind)) { + return (T) c; + } else if (c instanceof Container) { + var f = findComponent((Container) c, classToFind); + if (f != null) { + return f; + } + } + } + return null; + } + + /** + * Find all components of the specified class in the container. + * This will search the view hierarchy recursively and is limited + * to visible elements. + * + * @param container container to search in + * @param classToFind class to look for + * @return the object(s) if found (may be empty) + * @param class of the component + */ + public static List findAllComponents(Container container, Class classToFind) { + List l = new ArrayList<>(); + for (int i = 0; i < container.getComponentCount(); i++) { + var c = container.getComponent(i); + if (!c.isVisible()) { + continue; + } + + if (classToFind.isAssignableFrom(c.getClass())) { + l.add((T) c); + } else if (c instanceof Container) { + var f = findAllComponents((Container) c, classToFind); + l.addAll(f); + } + if (c instanceof JMenu) { + var queue = new HashSet(); + queue.add((JMenu) c); + while (!queue.isEmpty()) { + var newQ = new HashSet(); + for (var menu : queue) { + for (int j = 0; j < menu.getItemCount(); j++) { + var item = menu.getItem(j); + if (item == null) { + continue; + } + if (item instanceof JMenu) { + newQ.add((JMenu) item); + } + if (classToFind.isAssignableFrom(item.getClass())) { + l.add((T) item); + } + } + } + queue = newQ; + } + } + } + return l; + } + + public static Collection getAllOpenWindows() { + var l = new HashSet(); + + Set q = new HashSet<>(); + q.addAll(Arrays.asList(Window.getWindows())); + q.addAll(Arrays.asList(Window.getOwnerlessWindows())); + while (!q.isEmpty()) { + var newQ = new HashSet(); + + for (var window : q) { + if (l.contains(window)) { + continue; + } + l.add(window); + newQ.addAll(Arrays.asList(window.getOwnedWindows())); + } + q = newQ; + } + + return l; + } + + public static List getPopups() { + MenuSelectionManager msm = MenuSelectionManager.defaultManager(); + MenuElement[] p = msm.getSelectedPath(); + + List list = new ArrayList<>(); + for (MenuElement element : p) { + if (element instanceof JPopupMenu) { + list.add((JPopupMenu) element); + } + } + return list; + } + + /** + * Create a scroll pane around the given table. + * It will always have vertical and horizontal scroll bars. + * + * @param table the table + * @return the scroll pane + */ + public static JScrollPane createScrollPane(JTable table) { + var scrollPane = new JScrollPane(table, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, + ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); + + Dimension dim = new Dimension(table.getPreferredSize()); + dim.width += (Integer) UIManager.get("ScrollBar.width") + 2; + dim.height = scrollPane.getPreferredSize().height; + scrollPane.setPreferredSize(dim); + + return scrollPane; + } +} diff --git a/key.ui/src/test/java/de/uka/ilkd/key/gui/ChaosMonkey.java b/key.ui/src/test/java/de/uka/ilkd/key/gui/ChaosMonkey.java new file mode 100644 index 00000000000..f7af28bcf43 --- /dev/null +++ b/key.ui/src/test/java/de/uka/ilkd/key/gui/ChaosMonkey.java @@ -0,0 +1,195 @@ +package de.uka.ilkd.key.gui; + +import java.awt.event.ActionEvent; +import java.awt.event.WindowEvent; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Random; +import java.util.Set; +import javax.swing.*; + +import de.uka.ilkd.key.core.KeYMediator; +import de.uka.ilkd.key.core.Main; +import de.uka.ilkd.key.gui.actions.EditMostRecentFileAction; +import de.uka.ilkd.key.gui.actions.KeYProjectHomepageAction; +import de.uka.ilkd.key.gui.actions.LemmaGenerationAction; +import de.uka.ilkd.key.gui.keyshortcuts.KeyStrokeManager; +import de.uka.ilkd.key.settings.ProofIndependentSettings; + +import org.key_project.util.java.SwingUtil; + +import bibliothek.gui.dock.dockable.AbstractDockable; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Random testing of the UI. Will click random buttons and perform random actions. + * + * @author Arne Keller + */ +final class ChaosMonkey { + + private static final Logger LOGGER = LoggerFactory.getLogger(ChaosMonkey.class); + + private static final Set BANNED_ACTIONS = + Set.of("Open the last opened file with the default external editor", "Show log"); + private static final Set> BANNED_KEY_ACTIONS = + Set.of(LemmaGenerationAction.ProveKeYTaclets.class, + KeYProjectHomepageAction.class, + EditMostRecentFileAction.class, + LogView.OpenLogExternalAction.class); + /** + * Actions that should not be done, specified by class name. + * Use this if the action is a private class! + */ + private static final Set BANNED_KEY_ACTIONS_BY_CLASS_NAME = Set.of( + "de.uka.ilkd.key.gui.help.HelpFacade$OpenHelpAction"); + + private static boolean detectedError = false; + + @Test + @Disabled + void clickAllTheButtons() { + new Thread(ChaosMonkey::click, "ChaosMonkey").start(); + + ProofIndependentSettings.DEFAULT_INSTANCE.getViewSettings() + .setShowLoadExamplesDialog(false); + + Main.main( + "--examples ../key.ui/examples ../key.ui/examples/firstTouch/01-Agatha/project.key" + .split(" ")); + MainWindow mw = MainWindow.getInstance(); + mw.setSize(800, 600); + mw.setLocation(0, 0); + + try { + while (true) { + Thread.sleep(100000); + } + } catch (InterruptedException e) { + } + } + + static void click() { + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + return; + } + MainWindow mw = MainWindow.getInstance(); + KeYMediator mediator = mw.getMediator(); + Random rand = new Random(); + try { + while (!detectedError) { + // wait for automode to finish + mediator.getUI().getProofControl().waitWhileAutoMode(); + + // close any dialogs and popup menus + var windows = SwingUtil.getAllOpenWindows(); + for (var window : windows) { + if (window instanceof MainWindow || !window.isVisible()) { + continue; + } + String title = window instanceof JDialog ? ((JDialog) window).getTitle() + : window.getClass().toString(); + LOGGER.info("closing: {}", title); + SwingUtilities.invokeLater(() -> { + window.dispatchEvent(new WindowEvent(window, WindowEvent.WINDOW_CLOSING)); + }); + Thread.sleep(500); + } + var popups = SwingUtil.getPopups(); + for (var popup : popups) { + LOGGER.info("hiding popup menu"); + popup.setVisible(false); + Thread.sleep(250); + } + + // now, find a random button to press >:) + var buttons = SwingUtil.findAllComponents(MainWindow.getInstance(), JButton.class); + var actions = new ArrayList<>(); + actions.addAll(buttons); + actions.addAll(KeyStrokeManager.getAllActions()); + var foundButton = false; + LOGGER.info("monkey chooses from {} buttons and actions ...", actions.size()); + for (int i = 0; i < 100; i++) { + int actionIdx = rand.nextInt(actions.size()); + var action = actions.get(actionIdx); + if (action instanceof JButton) { + JButton button = (JButton) action; + // only enabled buttons + // (the "Show log" button is broken in test cases) + if (!button.isEnabled() || (button.getToolTipText() != null + && BANNED_ACTIONS.contains(button.getToolTipText()))) { + continue; + } + LOGGER.info("monkey clicks on {} {} {}", button.getClass(), + button.getName(), button.getToolTipText()); + var hierarchy = new ArrayList<>(); + var container = button.getParent(); + while (container != null) { + hierarchy.add(container); + container = container.getParent(); + } + for (var x : hierarchy) { + if (x instanceof AbstractDockable) { + AbstractDockable c = (AbstractDockable) x; + LOGGER.info(" {}", c.getTitleText()); + } else { + LOGGER.info(" {}", x); + } + } + SwingUtilities.invokeLater(() -> { + try { + button.doClick(); + } catch (Exception e) { + LOGGER.error("detected uncaught exception ", e); + detectedError = true; + } + }); + foundButton = true; + break; + } else if (action instanceof WeakReference) { + WeakReference a = (WeakReference) action; + Action keyAction = a.get(); + if (keyAction == null + || !keyAction.isEnabled() + || BANNED_KEY_ACTIONS.contains(keyAction.getClass()) + || BANNED_KEY_ACTIONS_BY_CLASS_NAME + .contains(keyAction.getClass().getName())) { + continue; + } + LOGGER.info("performing action {}", keyAction); + SwingUtilities.invokeLater(() -> { + try { + Object source = keyAction; + var menuItems = SwingUtil.findAllComponents(mw, JMenuItem.class); + for (var menuItem : menuItems) { + if (menuItem.getAction() == keyAction) { + source = menuItem; + break; + } + } + keyAction.actionPerformed(new ActionEvent(source, 0, "")); + } catch (Exception e) { + LOGGER.error("detected uncaught exception ", e); + detectedError = true; + } + }); + foundButton = true; + break; + } + } + if (!foundButton) { + LOGGER.error("chaos monkey failed to find an enabled button!"); + break; + } + Thread.sleep(1000); + } + } catch (Exception e) { + LOGGER.error("chaos monkey failed (in unexpected way)! ", e); + } + } +} diff --git a/key.util/src/main/java/org/key_project/util/java/SwingUtil.java b/key.util/src/main/java/org/key_project/util/java/SwingUtil.java deleted file mode 100644 index 8e2c3560782..00000000000 --- a/key.util/src/main/java/org/key_project/util/java/SwingUtil.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.key_project.util.java; - -import java.awt.*; -import javax.swing.*; - -/** - * Utilities for working with Swing. - * - * @author Arne Keller - */ -public final class SwingUtil { - private SwingUtil() { - } - - /** - * Find a component of the specified class in the container. - * This will search recursively. - * - * @param container container to search in - * @param classToFind class to look for - * @return the object if found, otherwise null - * @param class of the component - */ - public static T findComponent(Container container, Class classToFind) { - for (int i = 0; i < container.getComponentCount(); i++) { - var c = container.getComponent(i); - if (c.getClass().equals(classToFind)) { - return (T) c; - } else if (c instanceof Container) { - var f = findComponent((Container) c, classToFind); - if (f != null) { - return f; - } - } - } - return null; - } - - /** - * Create a scroll pane around the given table. - * It will always have vertical and horizontal scroll bars. - * - * @param table the table - * @return the scroll pane - */ - public static JScrollPane createScrollPane(JTable table) { - var scrollPane = new JScrollPane(table, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, - ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); - - Dimension dim = new Dimension(table.getPreferredSize()); - dim.width += (Integer) UIManager.get("ScrollBar.width") + 2; - dim.height = scrollPane.getPreferredSize().height; - scrollPane.setPreferredSize(dim); - - return scrollPane; - } -} From 59a670320d72475968614fdde66814b2ed3de874 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Sat, 22 Jul 2023 13:42:45 +0200 Subject: [PATCH 18/95] Make sure proof caching button is active on time --- .../ilkd/key/gui/plugins/caching/CachingExtension.java | 9 +++++++-- .../key/gui/plugins/caching/ReferenceSearchButton.java | 9 +++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java index 6ce2a336f10..67ba9b9d8a8 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java @@ -69,6 +69,7 @@ public class CachingExtension * Proofs tracked for automatic reference search. */ private final Set trackedProofs = new HashSet<>(); + private ReferenceSearchButton referenceSearchButton; @Override public void selectedProofChanged(KeYSelectionEvent e) { @@ -156,7 +157,8 @@ public List getContextActions(@Nonnull KeYMediator mediator, @Override public List getStatusLineComponents() { - return List.of(new ReferenceSearchButton(mediator)); + referenceSearchButton = new ReferenceSearchButton(mediator); + return List.of(referenceSearchButton); } @Override @@ -263,7 +265,7 @@ public void proofDisposed(ProofDisposedEvent e) { * * @author Arne Keller */ - static class CloseByReference extends KeyAction { + private final class CloseByReference extends KeyAction { /** * The mediator. */ @@ -311,6 +313,9 @@ public void actionPerformed(ActionEvent e) { mismatches.add(n.serialNr()); } } + if (!nodes.isEmpty()) { + referenceSearchButton.updateState(nodes.get(0).proof()); + } if (!mismatches.isEmpty()) { JOptionPane.showMessageDialog((JComponent) e.getSource(), "No matching branch found for node(s) " + Arrays.toString(mismatches.toArray()), diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/ReferenceSearchButton.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/ReferenceSearchButton.java index ecd65c5cce1..3e2ff836483 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/ReferenceSearchButton.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/ReferenceSearchButton.java @@ -69,6 +69,15 @@ public void actionPerformed(ActionEvent e) { @Override public void selectedNodeChanged(KeYSelectionEvent e) { Proof p = e.getSource().getSelectedProof(); + updateState(p); + } + + /** + * Update the UI state of this button. + * + * @param p the currently selected proof + */ + public void updateState(Proof p) { if (p == null) { setText("Proof Caching"); setForeground(null); From 3f8f088dddcfed66432830db2f5ce4ab97e6a6b4 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Sat, 22 Jul 2023 13:46:47 +0200 Subject: [PATCH 19/95] Make sure proof caching dialog displays right goal --- .../plugins/caching/ReferenceSearchTable.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/ReferenceSearchTable.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/ReferenceSearchTable.java index 17eb2b81aa9..b0781ff1f4f 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/ReferenceSearchTable.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/ReferenceSearchTable.java @@ -3,6 +3,7 @@ import java.awt.*; import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; import javax.swing.*; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; @@ -24,9 +25,9 @@ class ReferenceSearchTable extends JTable implements TableModel { */ private final KeYMediator mediator; /** - * List of open goals in the selected proof. + * List of open and closed goals in the selected proof. */ - private final List openGoals; + private final List goals; /** * Construct a new table. @@ -36,8 +37,10 @@ class ReferenceSearchTable extends JTable implements TableModel { */ public ReferenceSearchTable(Proof proof, KeYMediator mediator) { this.setModel(this); - this.openGoals = proof.openGoals().toList(); - Collections.reverse(this.openGoals); + this.goals = proof.allGoals().stream() + .filter(g -> !g.node().isClosed() || g.node().lookup(ClosedBy.class) != null) + .collect(Collectors.toList()); + Collections.reverse(this.goals); this.mediator = mediator; getColumnModel().getColumn(1).setMinWidth(200); } @@ -60,7 +63,7 @@ public void removeTableModelListener(TableModelListener l) { @Override public int getRowCount() { - return openGoals.size(); + return goals.size(); } @Override @@ -88,9 +91,9 @@ public Class getColumnClass(int column) { @Override public Object getValueAt(int row, int column) { if (column == 0) { - return String.valueOf(openGoals.get(row).node().serialNr()); + return String.valueOf(goals.get(row).node().serialNr()); } else { - Goal g = openGoals.get(row); + Goal g = goals.get(row); ClosedBy c = g.node().lookup(ClosedBy.class); if (c == null) { return "no reference found"; From 9b81e26892066b515d52270e99368dac49d19682 Mon Sep 17 00:00:00 2001 From: Alexander Weigl Date: Sat, 22 Jul 2023 14:09:19 +0200 Subject: [PATCH 20/95] fixing/testing macos --- .github/dlsmt.sh | 2 +- .github/workflows/tests_winmac.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/dlsmt.sh b/.github/dlsmt.sh index 511e4b0aac1..f31e72d6522 100755 --- a/.github/dlsmt.sh +++ b/.github/dlsmt.sh @@ -1,4 +1,4 @@ -#!/usr/bin/sh +#!/usr/bin/bash ## Weigl's little helper to download SMT-solvers. # SPDX-License-Identifier: GPL-2.0-or-later diff --git a/.github/workflows/tests_winmac.yml b/.github/workflows/tests_winmac.yml index 389f5abebe1..fea3b5fa318 100644 --- a/.github/workflows/tests_winmac.yml +++ b/.github/workflows/tests_winmac.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macos-latest] + os: [macos-latest] # ubuntu-latest, windows-latest java: [11, 17] continue-on-error: true runs-on: ${{ matrix.os }} @@ -52,7 +52,7 @@ jobs: fail-fast: false matrix: test: [testProveRules, testRunAllFunProofs, testRunAllInfProofs] - os: [ ubuntu-latest, windows-latest, macos-latest ] + os: [ macos-latest ] # ubuntu-latest, windows-latest, java: [11,17] runs-on: ${{ matrix.os }} steps: From acab92f96b147cc93a9780bbd0ab8e772fb65b91 Mon Sep 17 00:00:00 2001 From: Alexander Weigl Date: Sat, 22 Jul 2023 14:16:26 +0200 Subject: [PATCH 21/95] exclude jacocoReports from artifacts (saves roughly 15MB) --- .github/workflows/tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5b578c65d7a..b790b082bef 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -63,6 +63,8 @@ jobs: path: | **/build/test-results/*/*.xml **/build/reports/ + !jacocoTestReport.xml + - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v3 From e7dcc14adf06aa2b63d31b1243c3a58cf7f6bca1 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Sat, 22 Jul 2023 14:18:50 +0200 Subject: [PATCH 22/95] Make sure proof file is recorded for non-Java proofs --- key.core/src/main/java/de/uka/ilkd/key/proof/Proof.java | 9 +++++++++ .../de/uka/ilkd/key/proof/init/KeYUserProblemFile.java | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/Proof.java b/key.core/src/main/java/de/uka/ilkd/key/proof/Proof.java index fd641d10982..0912e334ca8 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/Proof.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/Proof.java @@ -237,6 +237,15 @@ private Proof(String name, Sequent problem, TacletIndex rules, BuiltInRuleIndex } } + public Proof(String name, Term problem, String header, InitConfig initConfig, File proofFile) { + this(name, + Sequent.createSuccSequent( + Semisequent.EMPTY_SEMISEQUENT.insert(0, new SequentFormula(problem)).semisequent()), + initConfig.createTacletIndex(), initConfig.createBuiltInRuleIndex(), initConfig); + problemHeader = header; + this.proofFile = proofFile; + } + public Proof(String name, Term problem, String header, InitConfig initConfig) { this(name, Sequent.createSuccSequent( diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/init/KeYUserProblemFile.java b/key.core/src/main/java/de/uka/ilkd/key/proof/init/KeYUserProblemFile.java index 24f41d5ac50..3b6e1192616 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/init/KeYUserProblemFile.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/init/KeYUserProblemFile.java @@ -162,7 +162,8 @@ public ProofAggregate getPO() throws ProofInputException { ProofSettings settings = getPreferences(); initConfig.setSettings(settings); return ProofAggregate.createProofAggregate( - new Proof(name, problemTerm, getParseContext().getProblemHeader() + "\n", initConfig), + new Proof(name, problemTerm, getParseContext().getProblemHeader() + "\n", initConfig, + file.file()), name); } From d03f59956f056a14c487bb1cdc22934b52d8f1f6 Mon Sep 17 00:00:00 2001 From: Alexander Weigl Date: Sat, 22 Jul 2023 14:45:44 +0200 Subject: [PATCH 23/95] Update dlsmt.sh --- .github/dlsmt.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/dlsmt.sh b/.github/dlsmt.sh index f31e72d6522..049cb4a5261 100755 --- a/.github/dlsmt.sh +++ b/.github/dlsmt.sh @@ -1,4 +1,4 @@ -#!/usr/bin/bash +# No shebang! ## Weigl's little helper to download SMT-solvers. # SPDX-License-Identifier: GPL-2.0-or-later From 2a3f271d8b520426a561588ceb0df105e7f6b916 Mon Sep 17 00:00:00 2001 From: Alexander Weigl Date: Sat, 22 Jul 2023 15:42:43 +0200 Subject: [PATCH 24/95] activate all operating systems --- .github/workflows/tests.yml | 2 +- .github/workflows/tests_winmac.yml | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b790b082bef..ef657be2e08 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -63,7 +63,7 @@ jobs: path: | **/build/test-results/*/*.xml **/build/reports/ - !jacocoTestReport.xml + !**/jacocoTestReport.xml - name: Upload coverage reports to Codecov diff --git a/.github/workflows/tests_winmac.yml b/.github/workflows/tests_winmac.yml index fea3b5fa318..7a9ce23b229 100644 --- a/.github/workflows/tests_winmac.yml +++ b/.github/workflows/tests_winmac.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - os: [macos-latest] # ubuntu-latest, windows-latest + os: [macos-latest, ubuntu-latest, windows-latest] java: [11, 17] continue-on-error: true runs-on: ${{ matrix.os }} @@ -40,9 +40,8 @@ jobs: path: | **/build/test-results/*/*.xml **/build/reports/ - - - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v3 + !**/jacocoTestReport.xml + integration-tests: env: @@ -52,7 +51,7 @@ jobs: fail-fast: false matrix: test: [testProveRules, testRunAllFunProofs, testRunAllInfProofs] - os: [ macos-latest ] # ubuntu-latest, windows-latest, + os: [ macos-latest, ubuntu-latest, windows-latest ] java: [11,17] runs-on: ${{ matrix.os }} steps: @@ -87,3 +86,5 @@ jobs: **/build/test-results/*/*.xml key.core/build/reports/runallproofs/* **/build/reports/ + !**/jacocoTestReport.xml + From 84ed5582d4e5caf055dde291d051efc45a71efc0 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Sat, 22 Jul 2023 14:19:20 +0200 Subject: [PATCH 25/95] Ensure proof caching checks user lemmas --- .../proof/reference/ReferenceSearcher.java | 30 ++++++++++-- .../java/de/uka/ilkd/key/rule/Taclet.java | 8 +++- .../reference/TestReferenceSearcher.java | 46 +++++++++++++++++++ .../testcase/proofCaching/proofWithRule.proof | 23 ++++++++++ .../proofCaching/proofWithoutRule.proof | 15 ++++++ 5 files changed, 117 insertions(+), 5 deletions(-) create mode 100644 key.core/src/test/resources/testcase/proofCaching/proofWithRule.proof create mode 100644 key.core/src/test/resources/testcase/proofCaching/proofWithoutRule.proof diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/reference/ReferenceSearcher.java b/key.core/src/main/java/de/uka/ilkd/key/proof/reference/ReferenceSearcher.java index 4d3da4e3b43..3d43b1354dd 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/reference/ReferenceSearcher.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/reference/ReferenceSearcher.java @@ -14,6 +14,7 @@ import de.uka.ilkd.key.logic.Term; import de.uka.ilkd.key.proof.Node; import de.uka.ilkd.key.proof.Proof; +import de.uka.ilkd.key.rule.NoPosTacletApp; import de.uka.ilkd.key.rule.merge.CloseAfterMerge; /** @@ -39,12 +40,35 @@ public static ClosedBy findPreviousProof(DefaultListModel previousProofs, if (!suitableForCloseByReference(newNode)) { return null; } - DefaultListModel proofs = previousProofs; - for (int i = 0; i < proofs.size(); i++) { - Proof p = proofs.get(i); + for (int i = 0; i < previousProofs.size(); i++) { + Proof p = previousProofs.get(i); if (p == newNode.proof()) { continue; // doesn't make sense } + // conservative check: all user-defined rules in a previous proof + // have to also be available in the new proof + var proofFile = p.getProofFile() != null ? p.getProofFile().toString() : "////"; + var tacletIndex = p.allGoals().head().ruleAppIndex().tacletIndex(); + var newTacletIndex = newNode.proof().allGoals().head().ruleAppIndex().tacletIndex(); + Set newTaclets = null; + var tacletsOk = true; + for (var taclet : tacletIndex.allNoPosTacletApps().stream() + .filter(x -> x.taclet().getOrigin() != null + && x.taclet().getOrigin().contains(proofFile)) + .collect(Collectors.toList())) { + if (newTaclets == null) { + newTaclets = newTacletIndex.allNoPosTacletApps(); + } + if (newTaclets.stream().noneMatch(newTaclet -> Objects + .equals(taclet.taclet().toString(), newTaclet.taclet().toString()))) { + tacletsOk = false; + break; + } + } + if (!tacletsOk) { + continue; + } + // only search in compatible proofs if (!p.getSettings().getChoiceSettings() .equals(newNode.proof().getSettings().getChoiceSettings())) { diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/Taclet.java b/key.core/src/main/java/de/uka/ilkd/key/rule/Taclet.java index 4d366d44873..c3d2634defc 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/Taclet.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/Taclet.java @@ -1003,9 +1003,13 @@ public TacletExecutor getExecutor() { @Override @Nullable - public String getOrigin() { return origin; } + public String getOrigin() { + return origin; + } - public void setOrigin(@Nullable String origin) { this.origin = origin; } + public void setOrigin(@Nullable String origin) { + this.origin = origin; + } public void setAddedBy(Node addedBy) { this.addedBy = addedBy; diff --git a/key.core/src/test/java/de/uka/ilkd/key/proof/reference/TestReferenceSearcher.java b/key.core/src/test/java/de/uka/ilkd/key/proof/reference/TestReferenceSearcher.java index 14b4989a7cb..65d4eea0cd3 100644 --- a/key.core/src/test/java/de/uka/ilkd/key/proof/reference/TestReferenceSearcher.java +++ b/key.core/src/test/java/de/uka/ilkd/key/proof/reference/TestReferenceSearcher.java @@ -79,4 +79,50 @@ void testFindsReferenceInSameProof() throws Exception { p.dispose(); p2.dispose(); } + + @Test + void checksUserLemmas() throws Exception { + GeneralSettings.noPruningClosed = false; + // Test scenario: + // Proof 1 uses a user-defined lemma. + // Proof 2 does not. + // Reference searcher should not find proof 1 when considering proof 2. + + KeYEnvironment env = + KeYEnvironment.load(new File(testCaseDirectory, + "proofCaching/proofWithRule.proof")); + Proof p = env.getLoadedProof(); + KeYEnvironment env2 = + KeYEnvironment.load(new File(testCaseDirectory, + "proofCaching/proofWithoutRule.proof")); + Proof p2 = env2.getLoadedProof(); + KeYEnvironment env3 = + KeYEnvironment.load(new File(testCaseDirectory, + "proofCaching/proofWithRule.proof")); + Proof p3 = env3.getLoadedProof(); + + DefaultListModel previousProofs = new DefaultListModel<>(); + previousProofs.addElement(p); + DefaultListModel newProof = new DefaultListModel<>(); + newProof.addElement(p2); + + p2.pruneProof(p2.root()); + + assertTrue(ReferenceSearcher.suitableForCloseByReference(p2.root())); + ClosedBy c = ReferenceSearcher.findPreviousProof(previousProofs, p2.root()); + assertNull(c); + + // check that result is found if the user taclet is available + p3.pruneProof(p3.root()); + assertTrue(ReferenceSearcher.suitableForCloseByReference(p3.root())); + c = ReferenceSearcher.findPreviousProof(previousProofs, p3.root()); + assertNotNull(c); + assertEquals(0, c.getNode().serialNr()); + assertEquals(p, c.getProof()); + + GeneralSettings.noPruningClosed = true; + p.dispose(); + p2.dispose(); + p3.dispose(); + } } diff --git a/key.core/src/test/resources/testcase/proofCaching/proofWithRule.proof b/key.core/src/test/resources/testcase/proofCaching/proofWithRule.proof new file mode 100644 index 00000000000..1c12a8e83c9 --- /dev/null +++ b/key.core/src/test/resources/testcase/proofCaching/proofWithRule.proof @@ -0,0 +1,23 @@ +\rules { + + \lemma + two_plus_two_is_four { + \find(2 + 2 = 4) + \sameUpdateLevel + \replacewith(true) + }; + } +\problem { +add(Z(2(#)), Z(2(#))) = Z(4(#)) +} + +\proof { +(keyLog "0" (keyUser "arne" ) (keyVersion "3b3afbd3c459d500948aebed1347d8d52aa969d6")) + +(autoModeTime "0") + +(branch "dummy ID" +(rule "two_plus_two_is_four" (formula "1") (userinteraction)) +(rule "closeTrue" (formula "1") (userinteraction)) +) +} diff --git a/key.core/src/test/resources/testcase/proofCaching/proofWithoutRule.proof b/key.core/src/test/resources/testcase/proofCaching/proofWithoutRule.proof new file mode 100644 index 00000000000..307063856b3 --- /dev/null +++ b/key.core/src/test/resources/testcase/proofCaching/proofWithoutRule.proof @@ -0,0 +1,15 @@ +\problem { +add(Z(2(#)), Z(2(#))) = Z(4(#)) +} + +\proof { +(keyLog "0" (keyUser "arne" ) (keyVersion "3b3afbd3c459d500948aebed1347d8d52aa969d6")) + +(autoModeTime "17") + +(branch "dummy ID" +(rule "add_literals" (formula "1") (term "0")) + (builtin "One Step Simplification" (formula "1")) +(rule "closeTrue" (formula "1")) +) +} From 2945ec43238021a53e6e800e0d1ba207ed97c8b6 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Sat, 22 Jul 2023 14:33:59 +0200 Subject: [PATCH 26/95] Test: ensure full exception stack trace is printed --- key.core/src/test/resources/logback.xml | 2 +- key.ui/src/test/resources/logback.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/key.core/src/test/resources/logback.xml b/key.core/src/test/resources/logback.xml index c96e3c9f3f3..1a1b90c6f79 100644 --- a/key.core/src/test/resources/logback.xml +++ b/key.core/src/test/resources/logback.xml @@ -6,7 +6,7 @@ key.log false - %-10relative %-5level %-15thread %-25logger{5} %msg %ex{short}%n + %-10relative %-5level %-15thread %-25logger{5} %msg %ex%n diff --git a/key.ui/src/test/resources/logback.xml b/key.ui/src/test/resources/logback.xml index 875e9e091de..eefd443474d 100644 --- a/key.ui/src/test/resources/logback.xml +++ b/key.ui/src/test/resources/logback.xml @@ -4,11 +4,11 @@ key.log false - %-10relative %-5level %-15thread %-25logger{5} %msg %ex{short}%n + %-10relative %-5level %-15thread %-25logger{5} %msg %ex%n - \ No newline at end of file + From af73403658ccd846157d410da775e4ee7c9881c8 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Sat, 22 Jul 2023 14:44:05 +0200 Subject: [PATCH 27/95] Bug fix in selection history --- .../src/main/java/de/uka/ilkd/key/gui/SelectionHistory.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/SelectionHistory.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/SelectionHistory.java index 6eaf41deeb7..f5b944d0249 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/SelectionHistory.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/SelectionHistory.java @@ -118,9 +118,10 @@ public Node nextNode() { while (previous != null && (previous.proof().isDisposed() || !previous.proof().find(previous) || previous == currentSelection)) { - previous = selectionHistoryForward.removeLast(); + previous = !selectionHistoryForward.isEmpty() ? selectionHistoryForward.removeLast() + : null; } - // this is a query method, re-instantiate previous state + // this is a query method (modulo fixing up the history), re-instantiate previous state if (previous != null) { selectionHistoryForward.addLast(previous); } From 929f2887629e6636a2d868de476f56ea76c21852 Mon Sep 17 00:00:00 2001 From: Alexander Weigl Date: Sun, 23 Jul 2023 14:29:04 +0200 Subject: [PATCH 28/95] Store test results for each operating system separately --- .github/workflows/tests_winmac.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests_winmac.yml b/.github/workflows/tests_winmac.yml index 7a9ce23b229..ad2a88b4f30 100644 --- a/.github/workflows/tests_winmac.yml +++ b/.github/workflows/tests_winmac.yml @@ -81,7 +81,7 @@ jobs: uses: actions/upload-artifact@v3.1.1 if: success() || failure() # run this step even if previous step failed with: - name: test-results + name: test-results-${{ matrix.os }} path: | **/build/test-results/*/*.xml key.core/build/reports/runallproofs/* From bec7d6ac9154ecf4c1b84bbfffaec048080db85d Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Mon, 24 Jul 2023 10:05:02 +0200 Subject: [PATCH 29/95] UI test: allow interaction with dockables --- .../src/main/java/org/key_project/util/java/SwingUtil.java | 7 +++++-- key.ui/src/test/java/de/uka/ilkd/key/gui/ChaosMonkey.java | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java b/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java index a84008585a4..56a16c6efb2 100644 --- a/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java +++ b/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java @@ -10,6 +10,8 @@ import java.util.Set; import javax.swing.*; +import bibliothek.gui.dock.themes.basic.BasicDockableDisplayer; + /** * Utilities for working with Swing. * @@ -46,7 +48,7 @@ public static T findComponent(Container container, Class classToFind) { /** * Find all components of the specified class in the container. * This will search the view hierarchy recursively and is limited - * to visible elements. + * to "visible" elements (on screen or on visible tab). * * @param container container to search in * @param classToFind class to look for @@ -57,7 +59,8 @@ public static List findAllComponents(Container container, Class classT List l = new ArrayList<>(); for (int i = 0; i < container.getComponentCount(); i++) { var c = container.getComponent(i); - if (!c.isVisible()) { + // if the docking container is visible, we consider all tabs in the search + if (!c.isVisible() && !(c instanceof BasicDockableDisplayer)) { continue; } diff --git a/key.ui/src/test/java/de/uka/ilkd/key/gui/ChaosMonkey.java b/key.ui/src/test/java/de/uka/ilkd/key/gui/ChaosMonkey.java index f7af28bcf43..59be4c650f6 100644 --- a/key.ui/src/test/java/de/uka/ilkd/key/gui/ChaosMonkey.java +++ b/key.ui/src/test/java/de/uka/ilkd/key/gui/ChaosMonkey.java @@ -73,6 +73,8 @@ void clickAllTheButtons() { } static void click() { + // wishlist: + // - interaction with dialogs/popup menus besides closing them try { Thread.sleep(3000); } catch (InterruptedException e) { From 87339a9d639e94c1f57269ec7dbce054aebc39d8 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Mon, 24 Jul 2023 10:08:47 +0200 Subject: [PATCH 30/95] Do not read settings if file does not exist --- .../src/main/java/de/uka/ilkd/key/settings/ProofSettings.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/key.core/src/main/java/de/uka/ilkd/key/settings/ProofSettings.java b/key.core/src/main/java/de/uka/ilkd/key/settings/ProofSettings.java index 66d3a29c790..b86340dac0d 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/settings/ProofSettings.java +++ b/key.core/src/main/java/de/uka/ilkd/key/settings/ProofSettings.java @@ -175,6 +175,9 @@ public void loadSettingsFromStream(Reader in) { * Loads the the former settings from configuration file. */ public void loadSettings() { + if (!PROVER_CONFIG_FILE.exists()) { + return; + } try (FileReader in = new FileReader(PROVER_CONFIG_FILE, StandardCharsets.UTF_8)) { if (Boolean.getBoolean(PathConfig.DISREGARD_SETTINGS_PROPERTY)) { LOGGER.warn("The settings in {} are *not* read.", PROVER_CONFIG_FILE); From 4cb61ceaef1685b63487488103f16ec8151459dc Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Mon, 24 Jul 2023 10:09:42 +0200 Subject: [PATCH 31/95] Fix recent files not saving without ~/.key --- .../de/uka/ilkd/key/gui/RecentFileMenu.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/RecentFileMenu.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/RecentFileMenu.java index a44133ca10d..d0aaf43716a 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/RecentFileMenu.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/RecentFileMenu.java @@ -242,17 +242,20 @@ public String getMostRecent() { */ public void store(String filename) { File localRecentFiles = new File(filename); - - Properties p = new Properties(); - try (FileInputStream fin = new FileInputStream(localRecentFiles); - FileOutputStream fout = new FileOutputStream(localRecentFiles)) { + localRecentFiles.getParentFile().mkdirs(); + try { // creates a new file if it does not exist yet localRecentFiles.createNewFile(); - p.load(fin); - store(p); - p.store(fout, "recent files"); + + Properties p = new Properties(); + try (FileInputStream fin = new FileInputStream(localRecentFiles); + FileOutputStream fout = new FileOutputStream(localRecentFiles)) { + p.load(fin); + store(p); + p.store(fout, "recent files"); + } } catch (IOException ex) { - LOGGER.info("Could not write recent files list", ex); + LOGGER.info("Could not write recent files list ", ex); } } From f19d91c24c4f4213b33d74f2be73b2b7d6945fc4 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Mon, 24 Jul 2023 10:14:00 +0200 Subject: [PATCH 32/95] Apply global font factor setting on startup --- key.ui/src/main/java/de/uka/ilkd/key/gui/MainWindow.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/MainWindow.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/MainWindow.java index 62915893971..019181df058 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/MainWindow.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/MainWindow.java @@ -45,6 +45,7 @@ import de.uka.ilkd.key.gui.plugins.action_history.ActionHistoryExtension; import de.uka.ilkd.key.gui.proofdiff.ProofDiffFrame; import de.uka.ilkd.key.gui.prooftree.ProofTreeView; +import de.uka.ilkd.key.gui.settings.FontSizeFacade; import de.uka.ilkd.key.gui.settings.SettingsManager; import de.uka.ilkd.key.gui.smt.DropdownSelectionButton; import de.uka.ilkd.key.gui.sourceview.SourceViewFrame; @@ -58,6 +59,7 @@ import de.uka.ilkd.key.rule.RuleApp; import de.uka.ilkd.key.settings.GeneralSettings; import de.uka.ilkd.key.settings.ProofIndependentSettings; +import de.uka.ilkd.key.settings.ViewSettings; import de.uka.ilkd.key.smt.SolverTypeCollection; import de.uka.ilkd.key.smt.solvertypes.SolverType; import de.uka.ilkd.key.ui.AbstractMediatorUserInterfaceControl; @@ -287,6 +289,9 @@ private MainWindow() { mediator = getMainWindowMediator(userInterface); KeYGuiExtensionFacade.getStartupExtensions().forEach(it -> it.preInit(this, mediator)); + ViewSettings vs = ProofIndependentSettings.DEFAULT_INSTANCE.getViewSettings(); + FontSizeFacade.resizeFonts(vs.getUIFontSizeFactor()); + termLabelMenu = new TermLabelMenu(this); currentGoalView = new CurrentGoalView(this); emptySequent = new EmptySequent(this); From 501eb68f0c301dbd48349b368345d1b7c34c9ca1 Mon Sep 17 00:00:00 2001 From: Wolfram Pfeifer Date: Mon, 24 Jul 2023 12:40:29 +0200 Subject: [PATCH 33/95] renamed SMTRuleApp back to RuleAppSMT to allow for easier merge --- .../ilkd/key/macros/scripts/SMTCommand.java | 4 +-- .../main/java/de/uka/ilkd/key/proof/Goal.java | 4 +-- .../de/uka/ilkd/key/proof/Statistics.java | 4 +-- .../proof/io/IntermediateProofReplayer.java | 6 ++-- .../smt/{SMTRuleApp.java => RuleAppSMT.java} | 28 +++++++++---------- .../useractions/ProofSMTApplyUserAction.java | 6 ++-- .../slicing/DependencyTracker.java | 4 +-- .../slicing/SlicingProofReplayer.java | 6 ++-- .../slicing/analysis/DependencyAnalyzer.java | 4 +-- .../key_project/slicing/EndToEndTests.java | 4 +-- 10 files changed, 33 insertions(+), 37 deletions(-) rename key.core/src/main/java/de/uka/ilkd/key/smt/{SMTRuleApp.java => RuleAppSMT.java} (84%) diff --git a/key.core/src/main/java/de/uka/ilkd/key/macros/scripts/SMTCommand.java b/key.core/src/main/java/de/uka/ilkd/key/macros/scripts/SMTCommand.java index 7db772b9de0..24c9ad8cfed 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/macros/scripts/SMTCommand.java +++ b/key.core/src/main/java/de/uka/ilkd/key/macros/scripts/SMTCommand.java @@ -2,8 +2,6 @@ import java.util.*; -import de.uka.ilkd.key.logic.PosInOccurrence; -import de.uka.ilkd.key.logic.PosInTerm; import de.uka.ilkd.key.logic.SequentFormula; import de.uka.ilkd.key.macros.scripts.meta.Option; import de.uka.ilkd.key.macros.scripts.meta.ValueInjector; @@ -89,7 +87,7 @@ private void runSMT(SMTCommandArguments args, SolverTypeCollection su, Goal goal SMTSolverResult finalResult = problem.getFinalResult(); if (finalResult.isValid() == ThreeValuedTruth.VALID) { SequentFormula formula = problem.getSequent().getFormulabyNr(0); - IBuiltInRuleApp app = SMTRuleApp.rule.createApp(null) + IBuiltInRuleApp app = RuleAppSMT.rule.createApp(null) .tryToInstantiate(problem.getGoal()) .setTitle(args.solver); problem.getGoal().apply(app); diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java b/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java index 57fcd25ef53..5e73ddfc83a 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java @@ -20,7 +20,7 @@ import de.uka.ilkd.key.rule.*; import de.uka.ilkd.key.rule.inst.SVInstantiations; import de.uka.ilkd.key.rule.merge.MergeRule; -import de.uka.ilkd.key.smt.SMTRuleApp; +import de.uka.ilkd.key.smt.RuleAppSMT; import de.uka.ilkd.key.strategy.AutomatedRuleApplicationManager; import de.uka.ilkd.key.strategy.QueueRuleApplicationManager; import de.uka.ilkd.key.strategy.Strategy; @@ -636,7 +636,7 @@ public ImmutableList apply(final RuleApp ruleApp) { // the first new goal is the one to be closed proof.closeGoal(goalList.head()); } - if (ruleApp instanceof SMTRuleApp) { + if (ruleApp instanceof RuleAppSMT) { // the first new goal is the one to be closed proof.closeGoal(goalList.head()); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/Statistics.java b/key.core/src/main/java/de/uka/ilkd/key/proof/Statistics.java index 8f5613c16f7..c3b3cd579de 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/Statistics.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/Statistics.java @@ -10,7 +10,7 @@ import de.uka.ilkd.key.rule.*; import de.uka.ilkd.key.rule.OneStepSimplifier.Protocol; import de.uka.ilkd.key.rule.merge.MergeRuleBuiltInRuleApp; -import de.uka.ilkd.key.smt.SMTRuleApp; +import de.uka.ilkd.key.smt.RuleAppSMT; import de.uka.ilkd.key.util.EnhancedStringBuffer; import de.uka.ilkd.key.util.Pair; @@ -232,7 +232,7 @@ private void changeOnNode(final Node node, if (ruleApp instanceof de.uka.ilkd.key.rule.OneStepSimplifierRuleApp) { oss++; ossCaptured += tmpOssCaptured(ruleApp); - } else if (ruleApp instanceof SMTRuleApp) { + } else if (ruleApp instanceof RuleAppSMT) { smt++; } else if (ruleApp instanceof UseDependencyContractApp) { dep++; diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/io/IntermediateProofReplayer.java b/key.core/src/main/java/de/uka/ilkd/key/proof/io/IntermediateProofReplayer.java index 4627850edd7..1b59f5d35e4 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/io/IntermediateProofReplayer.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/io/IntermediateProofReplayer.java @@ -39,7 +39,7 @@ import de.uka.ilkd.key.rule.merge.procedures.MergeWithPredicateAbstractionFactory; import de.uka.ilkd.key.settings.DefaultSMTSettings; import de.uka.ilkd.key.settings.ProofIndependentSettings; -import de.uka.ilkd.key.smt.SMTRuleApp; +import de.uka.ilkd.key.smt.RuleAppSMT; import de.uka.ilkd.key.smt.SMTProblem; import de.uka.ilkd.key.smt.SMTSolverResult.ThreeValuedTruth; import de.uka.ilkd.key.smt.SolverLauncher; @@ -559,7 +559,7 @@ private IBuiltInRuleApp constructBuiltinApp(BuiltInAppIntermediate currInterm, G } } - if (SMTRuleApp.rule.name().toString().equals(ruleName)) { + if (RuleAppSMT.rule.name().toString().equals(ruleName)) { boolean error = false; final SMTProblem smtProblem = new SMTProblem(currGoal); try { @@ -581,7 +581,7 @@ private IBuiltInRuleApp constructBuiltinApp(BuiltInAppIntermediate currInterm, G status = SMT_NOT_RUN; throw new SkipSMTRuleException(); } else { - return SMTRuleApp.rule.createApp(null, proof.getServices()); + return RuleAppSMT.rule.createApp(null, proof.getServices()); } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java b/key.core/src/main/java/de/uka/ilkd/key/smt/RuleAppSMT.java similarity index 84% rename from key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java rename to key.core/src/main/java/de/uka/ilkd/key/smt/RuleAppSMT.java index 9b5ea73cf50..2c629948e96 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/smt/RuleAppSMT.java @@ -16,7 +16,7 @@ * The rule application that is used when a goal is closed by means of an external solver. So far it * stores the rule that that has been used and a title containing some information for the user. */ -public class SMTRuleApp extends AbstractBuiltInRuleApp { +public class RuleAppSMT extends AbstractBuiltInRuleApp { public final static SMTRule rule = new SMTRule(); private final String title; @@ -26,23 +26,23 @@ public class SMTRuleApp extends AbstractBuiltInRuleApp { * @param rule the SMTRule to apply * @param pio the pos in term to apply the rule on */ - SMTRuleApp(SMTRule rule, PosInOccurrence pio) { + RuleAppSMT(SMTRule rule, PosInOccurrence pio) { this(rule, pio, null, "SMT Rule App"); } - private SMTRuleApp(SMTRule rule, PosInOccurrence pio, ImmutableList ifInsts, + private RuleAppSMT(SMTRule rule, PosInOccurrence pio, ImmutableList ifInsts, String title) { super(rule, pio, ifInsts); this.title = title; } - private SMTRuleApp(SMTRule rule, String title) { + private RuleAppSMT(SMTRule rule, String title) { super(rule, null); this.title = title; } - public SMTRuleApp replacePos(PosInOccurrence newPos) { - return new SMTRuleApp(rule, newPos, ifInsts, title); + public RuleAppSMT replacePos(PosInOccurrence newPos) { + return new RuleAppSMT(rule, newPos, ifInsts, title); } @Override @@ -67,13 +67,13 @@ public BuiltInRule rule() { public static class SMTRule implements BuiltInRule { public static final Name name = new Name("SMTRule"); - public SMTRuleApp createApp(PosInOccurrence pos) { + public RuleAppSMT createApp(PosInOccurrence pos) { return createApp(pos, null); } @Override - public SMTRuleApp createApp(PosInOccurrence pos, TermServices services) { - return new SMTRuleApp(this, pos); + public RuleAppSMT createApp(PosInOccurrence pos, TermServices services) { + return new RuleAppSMT(this, pos); } @@ -128,12 +128,12 @@ public Name name() { } - public SMTRuleApp setTitle(String title) { - return new SMTRuleApp(rule, pio, ifInsts, title); + public RuleAppSMT setTitle(String title) { + return new RuleAppSMT(rule, pio, ifInsts, title); } @Override - public SMTRuleApp setIfInsts(ImmutableList ifInsts) { + public RuleAppSMT setIfInsts(ImmutableList ifInsts) { setMutable(ifInsts); return this; } @@ -147,8 +147,8 @@ public SMTRuleApp setIfInsts(ImmutableList ifInsts) { * @return a new RuleApp with the same pio and all top level formulas of the goal as ifInsts */ @Override - public SMTRuleApp tryToInstantiate(Goal goal) { - SMTRuleApp app = rule.createApp(pio); + public RuleAppSMT tryToInstantiate(Goal goal) { + RuleAppSMT app = rule.createApp(pio); Sequent seq = goal.sequent(); List ifInsts = new ArrayList<>(); for (SequentFormula ante : seq.antecedent()) { diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/useractions/ProofSMTApplyUserAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/useractions/ProofSMTApplyUserAction.java index 94878f5d653..83844cb4f03 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/useractions/ProofSMTApplyUserAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/useractions/ProofSMTApplyUserAction.java @@ -5,15 +5,13 @@ import java.util.Iterator; import de.uka.ilkd.key.core.KeYMediator; -import de.uka.ilkd.key.logic.PosInOccurrence; -import de.uka.ilkd.key.logic.PosInTerm; import de.uka.ilkd.key.logic.SequentFormula; import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Node; import de.uka.ilkd.key.proof.Proof; import de.uka.ilkd.key.rule.IBuiltInRuleApp; import de.uka.ilkd.key.smt.SMTProblem; -import de.uka.ilkd.key.smt.SMTRuleApp; +import de.uka.ilkd.key.smt.RuleAppSMT; import de.uka.ilkd.key.smt.SMTSolver; import de.uka.ilkd.key.smt.SMTSolverResult; @@ -57,7 +55,7 @@ protected void apply() { for (SMTProblem problem : smtProblems) { if (problem.getFinalResult().isValid() == SMTSolverResult.ThreeValuedTruth.VALID) { SequentFormula formula = problem.getSequent().getFormulabyNr(1); - IBuiltInRuleApp app = SMTRuleApp.rule.createApp(null) + IBuiltInRuleApp app = RuleAppSMT.rule.createApp(null) .tryToInstantiate(problem.getGoal()) .setTitle(getTitle(problem)); goalsClosed.add(problem.getGoal().node()); diff --git a/keyext.slicing/src/main/java/org/key_project/slicing/DependencyTracker.java b/keyext.slicing/src/main/java/org/key_project/slicing/DependencyTracker.java index ccc589fd6c1..dc84541317f 100644 --- a/keyext.slicing/src/main/java/org/key_project/slicing/DependencyTracker.java +++ b/keyext.slicing/src/main/java/org/key_project/slicing/DependencyTracker.java @@ -34,7 +34,7 @@ import de.uka.ilkd.key.rule.TacletApp; import de.uka.ilkd.key.rule.merge.CloseAfterMergeRuleBuiltInRuleApp; import de.uka.ilkd.key.rule.merge.MergeRuleBuiltInRuleApp; -import de.uka.ilkd.key.smt.SMTRuleApp; +import de.uka.ilkd.key.smt.RuleAppSMT; import de.uka.ilkd.key.util.Pair; import org.key_project.slicing.analysis.AnalysisResults; @@ -153,7 +153,7 @@ public static Set ifInstsOfRuleApp(RuleApp ruleApp, Node node) // SMT application: add all formulas as inputs if (ruleApp instanceof MergeRuleBuiltInRuleApp || ruleApp instanceof CloseAfterMergeRuleBuiltInRuleApp - || ruleApp instanceof SMTRuleApp) { + || ruleApp instanceof RuleAppSMT) { node.sequent().antecedent().iterator().forEachRemaining( it -> inputs.add(new PosInOccurrence(it, PosInTerm.getTopLevel(), true))); node.sequent().succedent().iterator().forEachRemaining( diff --git a/keyext.slicing/src/main/java/org/key_project/slicing/SlicingProofReplayer.java b/keyext.slicing/src/main/java/org/key_project/slicing/SlicingProofReplayer.java index c6e9bb78580..83c555070eb 100644 --- a/keyext.slicing/src/main/java/org/key_project/slicing/SlicingProofReplayer.java +++ b/keyext.slicing/src/main/java/org/key_project/slicing/SlicingProofReplayer.java @@ -47,7 +47,7 @@ import de.uka.ilkd.key.rule.UseDependencyContractRule; import de.uka.ilkd.key.rule.UseOperationContractRule; import de.uka.ilkd.key.rule.inst.SVInstantiations; -import de.uka.ilkd.key.smt.SMTRuleApp; +import de.uka.ilkd.key.smt.RuleAppSMT; import de.uka.ilkd.key.speclang.Contract; import de.uka.ilkd.key.speclang.OperationContract; import de.uka.ilkd.key.util.MiscTools; @@ -389,8 +389,8 @@ private IBuiltInRuleApp constructBuiltinApp(Node originalStep, Goal currGoal) builtinIfInsts = builtinIfInsts.append(newFormula); } - if (SMTRuleApp.rule.displayName().equals(ruleName)) { - return SMTRuleApp.rule.createApp(null, proof.getServices()); + if (RuleAppSMT.rule.displayName().equals(ruleName)) { + return RuleAppSMT.rule.createApp(null, proof.getServices()); } IBuiltInRuleApp ourApp = null; diff --git a/keyext.slicing/src/main/java/org/key_project/slicing/analysis/DependencyAnalyzer.java b/keyext.slicing/src/main/java/org/key_project/slicing/analysis/DependencyAnalyzer.java index 717c0a8c14d..472b1ffd9d8 100644 --- a/keyext.slicing/src/main/java/org/key_project/slicing/analysis/DependencyAnalyzer.java +++ b/keyext.slicing/src/main/java/org/key_project/slicing/analysis/DependencyAnalyzer.java @@ -31,7 +31,7 @@ import de.uka.ilkd.key.rule.merge.CloseAfterMergeRuleBuiltInRuleApp; import de.uka.ilkd.key.rule.merge.MergeRuleBuiltInRuleApp; import de.uka.ilkd.key.settings.GeneralSettings; -import de.uka.ilkd.key.smt.SMTRuleApp; +import de.uka.ilkd.key.smt.RuleAppSMT; import de.uka.ilkd.key.util.Pair; import org.key_project.slicing.DependencyNodeData; @@ -222,7 +222,7 @@ public AnalysisResults analyze() { executionTime.start(STATISTICS); int steps = proof.countNodes() - proof.closedGoals().size() + (int) proof.closedGoals() - .stream().filter(it -> it.node().getAppliedRuleApp() instanceof SMTRuleApp) + .stream().filter(it -> it.node().getAppliedRuleApp() instanceof RuleAppSMT) .count(); // gather statistics on useful/useless rules RuleStatistics rules = getRuleStatistics(); diff --git a/keyext.slicing/src/test/java/org/key_project/slicing/EndToEndTests.java b/keyext.slicing/src/test/java/org/key_project/slicing/EndToEndTests.java index af70acd38a7..9de73be267e 100644 --- a/keyext.slicing/src/test/java/org/key_project/slicing/EndToEndTests.java +++ b/keyext.slicing/src/test/java/org/key_project/slicing/EndToEndTests.java @@ -14,7 +14,7 @@ import de.uka.ilkd.key.proof.init.JavaProfile; import de.uka.ilkd.key.settings.GeneralSettings; import de.uka.ilkd.key.settings.ProofIndependentSettings; -import de.uka.ilkd.key.smt.SMTRuleApp; +import de.uka.ilkd.key.smt.RuleAppSMT; import de.uka.ilkd.key.util.Pair; import org.key_project.slicing.analysis.AnalysisResults; @@ -281,7 +281,7 @@ private Pair sliceProofFullFilename(File proofFile, int expectedTot assertEquals(expectedInSlice + slicedProof.closedGoals().size() - slicedProof.closedGoals().stream() - .filter(x -> x.node().getAppliedRuleApp() instanceof SMTRuleApp) + .filter(x -> x.node().getAppliedRuleApp() instanceof RuleAppSMT) .count(), slicedProof.countNodes()); From 48d5da65a54a96fb95ab274d1a1b280fada14727 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Mon, 24 Jul 2023 12:48:20 +0200 Subject: [PATCH 34/95] Fix filters applying on proof tree menu open --- .../ProofTreeSettingsMenuFactory.java | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeSettingsMenuFactory.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeSettingsMenuFactory.java index 81784e6e0d5..a04baa361a1 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeSettingsMenuFactory.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeSettingsMenuFactory.java @@ -54,16 +54,14 @@ private static CButton createExpandAll(ProofTreeView view) { } private static CCheckBox createFilter(ProofTreeView view, ProofTreeViewFilter filter) { - CCheckBox check = new CCheckBox() { - @Override - protected void changed() { - final boolean selected = isSelected(); - setEnabled(view.setFilter(filter, selected)); - } - }; + CCheckBox check = new ProofTreeSettingsCheckBox(); check.setText(filter.name()); check.setEnabled(view.delegateModel != null); check.setSelected(filter.isActive()); + // add the selection listener *after* setting the initial value + // (to avoid re-applying the filter) + check.intern().addSelectableListener( + (component, selected) -> check.setEnabled(view.setFilter(filter, check.isSelected()))); return check; } @@ -132,4 +130,17 @@ protected void changed() { check.setSelected(MainWindow.getInstance().isShowTacletInfo()); return check; } + + /** + * The checkbox used in the proof tree settings. + * + * @author Arne Keller + */ + private static class ProofTreeSettingsCheckBox extends CCheckBox { + @Override + protected void changed() { + // intentionally empty, a listener is added in the menu factory + } + } + } From 4a4e337175a3f446242577694ea092eafd6ba6b2 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Mon, 24 Jul 2023 13:07:05 +0200 Subject: [PATCH 35/95] Restore proof tree expansion state after filtering --- .../ilkd/key/gui/prooftree/ProofTreeView.java | 11 +++++ .../org/key_project/util/java/SwingUtil.java | 43 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java index e09f8339590..de29197fab8 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java @@ -38,6 +38,7 @@ import org.key_project.util.collection.ImmutableList; import org.key_project.util.collection.ImmutableSLList; +import org.key_project.util.java.SwingUtil; import bibliothek.gui.dock.common.action.CAction; import org.slf4j.Logger; @@ -678,6 +679,10 @@ public boolean setFilter(ProofTreeViewFilter filter, boolean selected) { return false; } + // Save expansion state to restore. + List rowsToExpand = new ArrayList<>(expansionState); + + final TreePath branch; final Node invokedNode; if (selectedPath.getLastPathComponent() instanceof GUIProofTreeNode) { @@ -741,6 +746,12 @@ public boolean setFilter(ProofTreeViewFilter filter, boolean selected) { delegateView.setSelectionPath(tp); } } + + // Expand previously visible rows. + for (TreePath tp : rowsToExpand) { + TreePath newTp = SwingUtil.findPathInNewTree(delegateView, tp); + delegateView.expandPath(newTp); + } return true; } diff --git a/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java b/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java index 56a16c6efb2..8f6b98f24c8 100644 --- a/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java +++ b/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Set; import javax.swing.*; +import javax.swing.tree.TreePath; import bibliothek.gui.dock.themes.basic.BasicDockableDisplayer; @@ -149,4 +150,46 @@ public static JScrollPane createScrollPane(JTable table) { return scrollPane; } + + /** + * Try to find a tree path after updating the nodes of a {@link JTree}. + * This will compare nodes by their string representation. + * + * @param tree the tree to search + * @param tp the tree path + * @return a tree path or null + */ + public static TreePath findPathInNewTree(JTree tree, TreePath tp) { + TreePath root = tree.getPathForRow(0); + Object last = root.getLastPathComponent(); + int pathIndex = 0; + if (!last.toString().equals(tp.getPathComponent(pathIndex).toString())) { + return null; + } + pathIndex++; + TreePath newPath = root; + if (tp.getPathCount() == 1) { + return newPath; + } + while (true) { + int c = tree.getModel().getChildCount(last); + boolean found = false; + for (int i = 0; i < c; i++) { + var child = tree.getModel().getChild(last, i); + if (child.toString().equals(tp.getPathComponent(pathIndex).toString())) { + last = child; + newPath = newPath.pathByAddingChild(last); + pathIndex++; + if (pathIndex == tp.getPathCount()) { + return newPath; + } + found = true; + break; + } + } + if (!found) { + return null; + } + } + } } From 21ffd666d110689b3be0203eeed0b7fd95ca829c Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Mon, 24 Jul 2023 17:55:11 +0200 Subject: [PATCH 36/95] Optimize expansion state restore Co-Authored-By: Julian Wiesler --- .../ilkd/key/gui/prooftree/ProofTreeView.java | 8 +++- .../org/key_project/util/java/SwingUtil.java | 43 ------------------- 2 files changed, 6 insertions(+), 45 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java index de29197fab8..955ec83c5b0 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java @@ -38,7 +38,6 @@ import org.key_project.util.collection.ImmutableList; import org.key_project.util.collection.ImmutableSLList; -import org.key_project.util.java.SwingUtil; import bibliothek.gui.dock.common.action.CAction; import org.slf4j.Logger; @@ -749,7 +748,12 @@ public boolean setFilter(ProofTreeViewFilter filter, boolean selected) { // Expand previously visible rows. for (TreePath tp : rowsToExpand) { - TreePath newTp = SwingUtil.findPathInNewTree(delegateView, tp); + TreePath newTp = delegateView.getPathForRow(0); + for (int i = 1; i < tp.getPathCount(); i++) { + Node n = ((GUIBranchNode) tp.getPathComponent(i)).getNode(); + newTp = newTp.pathByAddingChild( + delegateModel.getBranchNode(n, n.getNodeInfo().getBranchLabel())); + } delegateView.expandPath(newTp); } return true; diff --git a/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java b/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java index 8f6b98f24c8..56a16c6efb2 100644 --- a/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java +++ b/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java @@ -9,7 +9,6 @@ import java.util.List; import java.util.Set; import javax.swing.*; -import javax.swing.tree.TreePath; import bibliothek.gui.dock.themes.basic.BasicDockableDisplayer; @@ -150,46 +149,4 @@ public static JScrollPane createScrollPane(JTable table) { return scrollPane; } - - /** - * Try to find a tree path after updating the nodes of a {@link JTree}. - * This will compare nodes by their string representation. - * - * @param tree the tree to search - * @param tp the tree path - * @return a tree path or null - */ - public static TreePath findPathInNewTree(JTree tree, TreePath tp) { - TreePath root = tree.getPathForRow(0); - Object last = root.getLastPathComponent(); - int pathIndex = 0; - if (!last.toString().equals(tp.getPathComponent(pathIndex).toString())) { - return null; - } - pathIndex++; - TreePath newPath = root; - if (tp.getPathCount() == 1) { - return newPath; - } - while (true) { - int c = tree.getModel().getChildCount(last); - boolean found = false; - for (int i = 0; i < c; i++) { - var child = tree.getModel().getChild(last, i); - if (child.toString().equals(tp.getPathComponent(pathIndex).toString())) { - last = child; - newPath = newPath.pathByAddingChild(last); - pathIndex++; - if (pathIndex == tp.getPathCount()) { - return newPath; - } - found = true; - break; - } - } - if (!found) { - return null; - } - } - } } From 200309b6f2756c895cc0c29bccb6f1420d4f2956 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Mon, 24 Jul 2023 18:11:04 +0200 Subject: [PATCH 37/95] UI test: also click menu items --- .../java/de/uka/ilkd/key/gui/ChaosMonkey.java | 46 +++++++++++++++---- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/key.ui/src/test/java/de/uka/ilkd/key/gui/ChaosMonkey.java b/key.ui/src/test/java/de/uka/ilkd/key/gui/ChaosMonkey.java index 59be4c650f6..a5035d43d12 100644 --- a/key.ui/src/test/java/de/uka/ilkd/key/gui/ChaosMonkey.java +++ b/key.ui/src/test/java/de/uka/ilkd/key/gui/ChaosMonkey.java @@ -2,10 +2,12 @@ import java.awt.event.ActionEvent; import java.awt.event.WindowEvent; -import java.lang.ref.WeakReference; +import java.lang.ref.Reference; import java.util.ArrayList; +import java.util.Objects; import java.util.Random; import java.util.Set; +import java.util.stream.Collectors; import javax.swing.*; import de.uka.ilkd.key.core.KeYMediator; @@ -19,7 +21,6 @@ import org.key_project.util.java.SwingUtil; import bibliothek.gui.dock.dockable.AbstractDockable; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,7 +51,6 @@ final class ChaosMonkey { private static boolean detectedError = false; @Test - @Disabled void clickAllTheButtons() { new Thread(ChaosMonkey::click, "ChaosMonkey").start(); @@ -111,11 +111,26 @@ static void click() { // now, find a random button to press >:) var buttons = SwingUtil.findAllComponents(MainWindow.getInstance(), JButton.class); + var keyActions = KeyStrokeManager.getAllActions() + .stream().map(Reference::get).filter(Objects::nonNull) + .collect(Collectors.toSet()); + var allMenuItems = + SwingUtil.findAllComponents(MainWindow.getInstance(), JMenuItem.class); var actions = new ArrayList<>(); actions.addAll(buttons); - actions.addAll(KeyStrokeManager.getAllActions()); + actions.addAll(keyActions); + for (var menuItem : allMenuItems) { + if (menuItem.getAction() != null && keyActions.contains(menuItem.getAction())) { + continue; + } + if (!menuItem.isEnabled() || (menuItem instanceof JMenu)) { + continue; + } + actions.add(menuItem); + } var foundButton = false; - LOGGER.info("monkey chooses from {} buttons and actions ...", actions.size()); + LOGGER.info("monkey chooses from {} buttons, actions and menu items ...", + actions.size()); for (int i = 0; i < 100; i++) { int actionIdx = rand.nextInt(actions.size()); var action = actions.get(actionIdx); @@ -153,11 +168,9 @@ static void click() { }); foundButton = true; break; - } else if (action instanceof WeakReference) { - WeakReference a = (WeakReference) action; - Action keyAction = a.get(); - if (keyAction == null - || !keyAction.isEnabled() + } else if (action instanceof Action) { + Action keyAction = (Action) action; + if (!keyAction.isEnabled() || BANNED_KEY_ACTIONS.contains(keyAction.getClass()) || BANNED_KEY_ACTIONS_BY_CLASS_NAME .contains(keyAction.getClass().getName())) { @@ -182,6 +195,19 @@ static void click() { }); foundButton = true; break; + } else if (action instanceof JMenuItem) { + var menuItem = (JMenuItem) action; + LOGGER.info("performing menu item {}", menuItem.getText()); + SwingUtilities.invokeLater(() -> { + try { + menuItem.doClick(50); + } catch (Exception e) { + LOGGER.error("detected uncaught exception ", e); + detectedError = true; + } + }); + foundButton = true; + break; } } if (!foundButton) { From 9eb843762853a079feabc19f96da9af1c51672bd Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Tue, 25 Jul 2023 09:28:56 +0200 Subject: [PATCH 38/95] Fix watchdog preventing JVM exit --- key.ui/src/main/java/de/uka/ilkd/key/core/Watchdog.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/core/Watchdog.java b/key.ui/src/main/java/de/uka/ilkd/key/core/Watchdog.java index 5249c1752ba..b64ad30f68b 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/core/Watchdog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/core/Watchdog.java @@ -35,7 +35,11 @@ private Watchdog() { * Start the watchdog in a background thread. */ public static void start() { - new Thread(Watchdog::run, "Watchdog").start(); + var thread = new Thread(Watchdog::run, "Watchdog"); + // mark as daemon + // (only relevant for startup exception, where this thread would prevent the JVM exiting) + thread.setDaemon(true); + thread.start(); } private static void run() { From 04aee0cc652d846c83d0dc325e802c0c3d49c23a Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Tue, 25 Jul 2023 09:29:08 +0200 Subject: [PATCH 39/95] Fix proof tree font update --- .../main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java | 1 + 1 file changed, 1 insertion(+) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java index 955ec83c5b0..83277f4d973 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java @@ -325,6 +325,7 @@ private void setProofTreeFont() { // set row height before changing the font (since the latter repaints the component) delegateView.setRowHeight(rowHeight); + renderer.setFont(myFont); delegateView.setFont(myFont); } else { LOGGER.debug("KEY-PROOF_TREE_FONT not available, use standard font."); From 3ccdb7f578db3fd54294cbda7569fcf72e82ef8a Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Tue, 25 Jul 2023 13:36:28 +0200 Subject: [PATCH 40/95] Fixes a NullPointerException when the configuration files for the "Recent Files" feature is not yet created We must ensure to create the "recentFiles" configuration file before passing the File object to an InputStream. --- .../src/main/java/de/uka/ilkd/key/gui/RecentFileMenu.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/RecentFileMenu.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/RecentFileMenu.java index a44133ca10d..819a75ce040 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/RecentFileMenu.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/RecentFileMenu.java @@ -242,12 +242,16 @@ public String getMostRecent() { */ public void store(String filename) { File localRecentFiles = new File(filename); + // creates a new file if it does not exist yet + try { + localRecentFiles.createNewFile(); + } catch (IOException e) { + LOGGER.info("Could not create or access recent files", e); + } Properties p = new Properties(); try (FileInputStream fin = new FileInputStream(localRecentFiles); FileOutputStream fout = new FileOutputStream(localRecentFiles)) { - // creates a new file if it does not exist yet - localRecentFiles.createNewFile(); p.load(fin); store(p); p.store(fout, "recent files"); From c628a78d84b00f805a715a42b25e53a80326ebeb Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Tue, 25 Jul 2023 16:56:48 +0200 Subject: [PATCH 41/95] Improve behavior if file cannot be created --- key.ui/src/main/java/de/uka/ilkd/key/gui/RecentFileMenu.java | 1 + 1 file changed, 1 insertion(+) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/RecentFileMenu.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/RecentFileMenu.java index 819a75ce040..538bf4f2e03 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/RecentFileMenu.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/RecentFileMenu.java @@ -247,6 +247,7 @@ public void store(String filename) { localRecentFiles.createNewFile(); } catch (IOException e) { LOGGER.info("Could not create or access recent files", e); + return; } Properties p = new Properties(); From 90c7632ea921e56dd625c13663352f537f48417b Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Tue, 25 Jul 2023 17:51:06 +0200 Subject: [PATCH 42/95] Fix exceptions when abandoning a running prover --- .../uka/ilkd/key/prover/impl/DefaultTaskFinishedInfo.java | 3 +++ .../de/uka/ilkd/key/gui/WindowUserInterfaceControl.java | 2 +- .../java/de/uka/ilkd/key/gui/actions/AbandonTaskAction.java | 4 ++++ .../key/gui/notification/events/GeneralFailureEvent.java | 2 ++ .../uka/ilkd/key/gui/plugins/caching/CachingExtension.java | 2 +- .../java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java | 6 +++++- .../main/java/de/uka/ilkd/key/ui/MediatorProofControl.java | 6 ++++-- 7 files changed, 20 insertions(+), 5 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/prover/impl/DefaultTaskFinishedInfo.java b/key.core/src/main/java/de/uka/ilkd/key/prover/impl/DefaultTaskFinishedInfo.java index babe9065a31..974cb0f1fb8 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/prover/impl/DefaultTaskFinishedInfo.java +++ b/key.core/src/main/java/de/uka/ilkd/key/prover/impl/DefaultTaskFinishedInfo.java @@ -70,6 +70,9 @@ public Proof getProof() { // display message for the status bar @Override public String toString() { + if (proof.isDisposed()) { + return "Proof disposed"; + } if (appliedRules != 0) { StringBuilder message = new StringBuilder(); String timeString = (timeInMillis / 1000) + "." + ((timeInMillis % 1000) / 100); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/WindowUserInterfaceControl.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/WindowUserInterfaceControl.java index cc17f13a3a6..b6ea9cd3fd4 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/WindowUserInterfaceControl.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/WindowUserInterfaceControl.java @@ -156,7 +156,7 @@ public void taskFinished(TaskFinishedInfo info) { ApplyStrategyInfo result = (ApplyStrategyInfo) info.getResult(); Proof proof = info.getProof(); - if (proof != null && !proof.closed() + if (proof != null && !proof.isDisposed() && !proof.closed() && mainWindow.getMediator().getSelectedProof() == proof) { Goal g = result.nonCloseableGoal(); if (g == null) { diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/AbandonTaskAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/AbandonTaskAction.java index 5c2c6dee159..d2ff95a41b7 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/AbandonTaskAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/AbandonTaskAction.java @@ -32,6 +32,10 @@ public AbandonTaskAction(MainWindow mainWindow, Proof proof) { public synchronized void actionPerformed(ActionEvent e) { boolean removalConfirmed = getMediator().getUI().confirmTaskRemoval("Are you sure?"); if (removalConfirmed) { + // abandon proof that is currently in auto mode: first stop auto mode + if (getMediator().isInAutoMode()) { + getMediator().getUI().getProofControl().stopAutoMode(); + } if (proof == null) { getMediator().getSelectedProof().dispose(); } else { diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/notification/events/GeneralFailureEvent.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/notification/events/GeneralFailureEvent.java index 584f5852bc5..1595ad968b4 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/notification/events/GeneralFailureEvent.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/notification/events/GeneralFailureEvent.java @@ -9,8 +9,10 @@ * A notification event caused by a general unexpected failure (usually caused by a bug of the * system) * + * @deprecated use {@link de.uka.ilkd.key.gui.IssueDialog} * @author bubel */ +@Deprecated public class GeneralFailureEvent extends NotificationEvent { private String errorMessage = "Unknown Error."; diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java index 67ba9b9d8a8..3077e23a9c8 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java @@ -183,7 +183,7 @@ public void taskFinished(TaskFinishedInfo info) { return; // try close macro was running, no need to do anything here } Proof p = info.getProof(); - if (p == null || p.closed() || !(info.getSource() instanceof ApplyStrategy + if (p == null || p.isDisposed() || p.closed() || !(info.getSource() instanceof ApplyStrategy || info.getSource() instanceof ProofMacro)) { return; } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java index 83277f4d973..00915a25c5b 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java @@ -937,6 +937,10 @@ public void valueChanged(TreeSelectionEvent e) { GUIAbstractTreeNode treeNode = ((GUIAbstractTreeNode) e.getNewLeadSelectionPath().getLastPathComponent()); + if (treeNode.getNode().proof().isDisposed()) { + setProof(null); + return; + } if (treeNode instanceof GUIBranchNode) { selectBranchNode((GUIBranchNode) treeNode); } else { @@ -1226,7 +1230,7 @@ private void renderOneStepSimplification(Style style, GUIOneStepChildTreeNode no @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { - if (proof == null || !(value instanceof GUIAbstractTreeNode)) { + if (proof == null || proof.isDisposed() || !(value instanceof GUIAbstractTreeNode)) { // print dummy tree return super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/ui/MediatorProofControl.java b/key.ui/src/main/java/de/uka/ilkd/key/ui/MediatorProofControl.java index d5975630dd8..48862d5bb39 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/ui/MediatorProofControl.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/ui/MediatorProofControl.java @@ -9,6 +9,8 @@ import de.uka.ilkd.key.control.AbstractProofControl; import de.uka.ilkd.key.control.ProofControl; import de.uka.ilkd.key.core.KeYMediator; +import de.uka.ilkd.key.gui.IssueDialog; +import de.uka.ilkd.key.gui.MainWindow; import de.uka.ilkd.key.gui.ProofMacroWorker; import de.uka.ilkd.key.gui.notification.events.GeneralFailureEvent; import de.uka.ilkd.key.gui.notification.events.GeneralInformationEvent; @@ -205,8 +207,8 @@ protected void emitInteractiveAutoMode(List initialGoals, Proof proof, } private void notifyException(final Exception exception) { - ui.notify(new GeneralFailureEvent( - "An exception occurred during" + " strategy execution.\n Exception:" + exception)); + LOGGER.error("exception during strategy ", exception); + IssueDialog.showExceptionDialog(MainWindow.getInstance(), exception); } @Override From 627914610d41086d8b88385db5569969213942fd Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Tue, 25 Jul 2023 18:03:15 +0200 Subject: [PATCH 43/95] Fix UI deadlock See #1117 --- .../java/de/uka/ilkd/key/gui/WindowUserInterfaceControl.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/WindowUserInterfaceControl.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/WindowUserInterfaceControl.java index b6ea9cd3fd4..c01a0431999 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/WindowUserInterfaceControl.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/WindowUserInterfaceControl.java @@ -149,6 +149,11 @@ public void resetStatus(Object sender) { @Override public void taskFinished(TaskFinishedInfo info) { super.taskFinished(info); + // ensure all UI modifying operations are done on the UI thread + SwingUtilities.invokeLater(() -> taskFinishedInternal(info)); + } + + private void taskFinishedInternal(TaskFinishedInfo info) { if (info != null && info.getSource() instanceof ProverCore) { if (!isAtLeastOneMacroRunning()) { resetStatus(this); From 66f2d6c42045c7785f2c3c32ebb2c5196c02f55d Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Wed, 26 Jul 2023 08:58:05 +0200 Subject: [PATCH 44/95] Fix font factor issue in menu bar --- .../ilkd/key/gui/settings/FontSizeFacade.java | 19 ++++++++------- .../ilkd/key/gui/settings/SettingsDialog.java | 8 +++++++ .../org/key_project/util/java/SwingUtil.java | 24 +++++++++++++++++++ 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/FontSizeFacade.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/FontSizeFacade.java index 36b38be4187..a7536df4add 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/FontSizeFacade.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/FontSizeFacade.java @@ -5,6 +5,10 @@ import java.util.Map; import javax.swing.*; +import de.uka.ilkd.key.gui.MainWindow; + +import org.key_project.util.java.SwingUtil; + /** * @author Alexander Weigl * @version 1 (10.05.19) @@ -22,14 +26,14 @@ public class FontSizeFacade { "Slider.font", "Spinner.font", "TabbedPane.font", "TabbedPane.smallFont", "Table.font", "TableHeader.font", "TextArea.font", "TextField.font", "TextPane.font", "TitledBorder.font", "ToggleButton.font", "ToolBar.font", "ToolTip.font", "Tree.font", "Viewport.font" }; - private static final Map originalFontSize = new HashMap<>(); + private static final Map originalFontSize = new HashMap<>(); private static double currentFactor = 1; public static void saveCurrentFontSizes() { for (String k : KEYS) { Font f = UIManager.getDefaults().getFont(k); if (f != null) { - originalFontSize.put(k, f.getSize()); + originalFontSize.put(k, (float) f.getSize()); } } } @@ -56,14 +60,13 @@ public static void resizeFonts(double factor) { } }); - // redraw all frames - for (Window w : Window.getWindows()) { - SwingUtilities.updateComponentTreeUI(w); - } + // for some reason, the menu bar does not update its font on its own + SwingUtil.setFont(MainWindow.getInstance().getJMenuBar(), + UIManager.getDefaults().getFont("Menu.font")); - for (Window w : Dialog.getWindows()) { + // redraw all frames and dialogs + for (Window w : Window.getWindows()) { SwingUtilities.updateComponentTreeUI(w); } - } } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/SettingsDialog.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/SettingsDialog.java index 5cc0a631498..24ee00bef2b 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/SettingsDialog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/SettingsDialog.java @@ -11,6 +11,9 @@ import de.uka.ilkd.key.gui.MainWindow; import de.uka.ilkd.key.gui.actions.KeyAction; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * The settings dialog. * @@ -20,6 +23,8 @@ */ public class SettingsDialog extends JDialog { private static final long serialVersionUID = -3204453471778351602L; + private static final Logger LOGGER = LoggerFactory.getLogger(SettingsDialog.class); + private final MainWindow mainWindow; private final SettingsUi ui; private final Action actionCancel = new CancelAction(); @@ -86,6 +91,9 @@ private void apply(List providers, List exceptions) private boolean showErrors(List apply) { if (!apply.isEmpty()) { + for (Exception e : apply) { + LOGGER.error("", e); + } String msg = apply.stream().map(Throwable::getMessage) .collect(Collectors.joining("
", "", "")); JOptionPane.showMessageDialog(this, msg, "Error in Settings", diff --git a/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java b/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java index 56a16c6efb2..c6c51f86734 100644 --- a/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java +++ b/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java @@ -149,4 +149,28 @@ public static JScrollPane createScrollPane(JTable table) { return scrollPane; } + + /** + * Set the provided font on the component and recursively on all children components. + * + * @param component the component + * @param font the font + */ + public static void setFont(JComponent component, Font font) { + component.setFont(font); + for (int i = 0; i < component.getComponentCount(); i++) { + Component c = component.getComponent(i); + if (c == null) { + continue; + } + c.setFont(font); + if (c instanceof JComponent) { + setFont((JComponent) c, font); + } + } + // JMenu hides its entries in the popup menu + if (component instanceof JMenu && ((JMenu) component).getPopupMenu() != null) { + setFont(((JMenu) component).getPopupMenu(), font); + } + } } From 9f8055c123d41a19f117b4cf0ac6aa349ee82950 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Wed, 26 Jul 2023 13:43:25 +0200 Subject: [PATCH 45/95] Show errors in auto mode in issue dialog --- .../main/java/de/uka/ilkd/key/ui/MediatorProofControl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/ui/MediatorProofControl.java b/key.ui/src/main/java/de/uka/ilkd/key/ui/MediatorProofControl.java index 48862d5bb39..1ca0b5be905 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/ui/MediatorProofControl.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/ui/MediatorProofControl.java @@ -198,6 +198,10 @@ protected void done() { ui.getMediator().startInterface(true); emitInteractiveAutoMode(initialGoals, proof, info); + + if (info.getException() != null) { + notifyException(info.getException()); + } } } @@ -206,7 +210,7 @@ protected void emitInteractiveAutoMode(List initialGoals, Proof proof, interactionListeners.forEach((l) -> l.runAutoMode(initialGoals, proof, info)); } - private void notifyException(final Exception exception) { + private void notifyException(final Throwable exception) { LOGGER.error("exception during strategy ", exception); IssueDialog.showExceptionDialog(MainWindow.getInstance(), exception); } From 60d16086b886e7fed82c6b81e44143ad9538b771 Mon Sep 17 00:00:00 2001 From: Florian Lanzinger Date: Wed, 26 Jul 2023 14:10:21 +0200 Subject: [PATCH 46/95] Always use Metal as default Look and Feel --- .../uka/ilkd/key/gui/settings/StandardUISettings.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/StandardUISettings.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/StandardUISettings.java index 669ddc06f70..d61434ab0cd 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/StandardUISettings.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/StandardUISettings.java @@ -28,12 +28,12 @@ public class StandardUISettings extends SettingsPanel implements SettingsProvide /** * Labels for the selectable look and feels. Must be kept in sync with {@link #LAF_CLASSES}. */ - private static final List LAF_LABELS = new ArrayList<>(List.of("System")); + private static final List LAF_LABELS = new ArrayList<>(List.of("Metal")); /** * Classnames corresponding to the labels in {@link #LAF_LABELS}. */ private static final List LAF_CLASSES = - new ArrayList<>(List.of(UIManager.getSystemLookAndFeelClassName())); + new ArrayList<>(List.of(UIManager.getCrossPlatformLookAndFeelClassName())); private final JComboBox lookAndFeel; private final JSpinner spFontSizeGlobal; @@ -60,8 +60,10 @@ public StandardUISettings() { // load all available look and feels if (LAF_LABELS.size() == 1) { for (UIManager.LookAndFeelInfo it : UIManager.getInstalledLookAndFeels()) { - LAF_LABELS.add(it.getName()); - LAF_CLASSES.add(it.getClassName()); + if (!LAF_LABELS.contains(it.getName())) { + LAF_LABELS.add(it.getName()); + LAF_CLASSES.add(it.getClassName()); + } } } From 4114738d2fcb32a2631cb162be922176bd45b39d Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Wed, 26 Jul 2023 14:26:25 +0200 Subject: [PATCH 47/95] Fix enabling actions on proof load --- .../de/uka/ilkd/key/gui/actions/MainWindowAction.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/MainWindowAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/MainWindowAction.java index aeef2f84e21..40206950333 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/MainWindowAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/MainWindowAction.java @@ -33,7 +33,7 @@ protected MainWindowAction(MainWindow mainWindow) { protected MainWindowAction(MainWindow mainWindow, boolean onlyActiveWhenProofAvailable) { this(mainWindow); if (onlyActiveWhenProofAvailable) { - LISTENER.actions.add(this); + LISTENER.addAction(this); this.setEnabled(getMediator().getSelectionModel().getSelectedProof() != null); } } @@ -57,6 +57,13 @@ protected KeYMediator getMediator() { private static final class MainWindowActionSelectionListener implements KeYSelectionListener { private final Collection actions = new ArrayList<>(); + private void addAction(MainWindowAction action) { + if (actions.isEmpty()) { + action.getMediator().addKeYSelectionListener(this); + } + actions.add(action); + } + @Override public void selectedNodeChanged(KeYSelectionEvent e) { var enable = e.getSource().getSelectedProof() != null; From 33703a7ab57f4406d7246670f22ebc5d199040b5 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Wed, 26 Jul 2023 14:57:32 +0200 Subject: [PATCH 48/95] Sort SMT solvers alphabetically This way, Z3_FP won't be at the top and selected by default --- key.core/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/key.core/build.gradle b/key.core/build.gradle index 52050ae6914..d93135c0c0b 100644 --- a/key.core/build.gradle +++ b/key.core/build.gradle @@ -100,6 +100,7 @@ task generateSolverPropsList { list.add(file.name) } }) + list.sort() if (!file("$outputDir/$pack/solvers.txt").exists()) { String files = '' for (String propsFile : list) { From 7f075dca8a7bbbd6bfd8f0750adf65a15f5193fb Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Wed, 26 Jul 2023 15:08:04 +0200 Subject: [PATCH 49/95] Make goal select/below actually do what they say --- .../gui/actions/GoalSelectAboveAction.java | 2 - .../ilkd/key/gui/prooftree/ProofTreeView.java | 62 ++++++++++++++++--- 2 files changed, 53 insertions(+), 11 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalSelectAboveAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalSelectAboveAction.java index 9ac268eb7f4..2ffe2b3578c 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalSelectAboveAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalSelectAboveAction.java @@ -17,8 +17,6 @@ public final class GoalSelectAboveAction extends MainWindowAction { * Creates the new action. * * @param mainWindow the main window this action belongs to - * @param longName true iff long names (including the name of the rule to undo) shall be - * displayed (e.g. in menu items) */ public GoalSelectAboveAction(MainWindow mainWindow) { super(mainWindow, true); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java index 00915a25c5b..f2157f220bc 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java @@ -393,21 +393,65 @@ private void unregister() { mediator.removeGUIListener(guiListener); } + /** + * Select the next goal above the currently selected node. + * + * @return whether such a goal was found + */ public boolean selectAbove() { - return selectRelative(+1); + TreePath path = delegateView.getSelectionPath(); + if (path == null) { + return false; + } + int row = delegateView.getRowForPath(path); + row--; + while (delegateView.getPathForRow(row) != null) { + TreePath tp = delegateView.getPathForRow(row); + var treeNode = (GUIAbstractTreeNode) tp.getLastPathComponent(); + if (treeNode instanceof GUIBranchNode && treeNode.getNode().parent() != null + && treeNode.getNode().parent().childrenCount() > 1 + && !delegateView.isExpanded(tp)) { + int prevRows = delegateView.getRowCount(); + delegateView.expandPath(tp); + int newRows = delegateView.getRowCount(); + // search must continue at the end of the just expanded branch! + row += (newRows - prevRows); + continue; + } + if (treeNode.getNode().leaf()) { + mediator.getSelectionModel().setSelectedNode(treeNode.getNode()); + return true; + } + row--; + } + return false; } + /** + * Select the next goal below the currently selected node. + * + * @return whether such a goal was found + */ public boolean selectBelow() { - return selectRelative(-1); - } - - private boolean selectRelative(int i) { TreePath path = delegateView.getSelectionPath(); + if (path == null) { + return false; + } int row = delegateView.getRowForPath(path); - TreePath newPath = delegateView.getPathForRow(row - i); - if (newPath != null) { - delegateView.setSelectionPath(newPath); - return true; + row++; + while (delegateView.getPathForRow(row) != null) { + TreePath tp = delegateView.getPathForRow(row); + var treeNode = (GUIAbstractTreeNode) tp.getLastPathComponent(); + if (treeNode instanceof GUIBranchNode && treeNode.getNode().parent() != null + && treeNode.getNode().parent().childrenCount() > 1 + && !delegateView.isExpanded(tp)) { + delegateView.expandPath(tp); + } + if (treeNode.getNode().leaf()) { + mediator.getSelectionModel().setSelectedNode(treeNode.getNode()); + return true; + } + row++; } return false; } From dc10b51bd4c3e7bfb4d63d3f1fb276a370b2adc8 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Wed, 26 Jul 2023 15:12:46 +0200 Subject: [PATCH 50/95] Extract examples when needed Regression from 854bbe21c16373d03e46fa953c08e6c0adb832b2 --- .../main/java/de/uka/ilkd/key/core/Main.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/core/Main.java b/key.ui/src/main/java/de/uka/ilkd/key/core/Main.java index f2387302fd5..9861ae8e15c 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/core/Main.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/core/Main.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; +import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -542,9 +543,42 @@ private static AbstractMediatorUserInterfaceControl createUserInterface( public static void ensureExamplesAvailable() { File examplesDir = getExamplesDir() == null ? ExampleChooser.lookForExamples() : new File(getExamplesDir()); + if (!examplesDir.exists()) { + examplesDir = setupExamples(); + } setExamplesDir(examplesDir.getAbsolutePath()); } + private static File setupExamples() { + try { + URL examplesURL = Main.class.getResource("/examples.zip"); + if (examplesURL == null) { + throw new IOException("Missing examples.zip in resources"); + } + + File tempDir = createTempDirectory(); + + if (tempDir != null) { + IOUtil.extractZip(examplesURL.openStream(), tempDir.toPath()); + } + return tempDir; + } catch (IOException e) { + LOGGER.warn("Error setting up examples", e); + return null; + } + } + + + private static File createTempDirectory() throws IOException { + final File tempDir = File.createTempFile("keyheap-examples-", null); + tempDir.delete(); + if (!tempDir.mkdir()) { + return null; + } + Runtime.getRuntime().addShutdownHook(new Thread(() -> IOUtil.delete(tempDir))); + return tempDir; + } + private static void evaluateLemmataOptions(CommandLine options) { LemmataAutoModeOptions opt; From fc02e4379ffc1700df7d1253d4d70b3ba99bc868 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Wed, 26 Jul 2023 15:25:14 +0200 Subject: [PATCH 51/95] Update email in license --- LICENSE.TXT | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE.TXT b/LICENSE.TXT index 9ba1971ac0b..63eff5c638a 100644 --- a/LICENSE.TXT +++ b/LICENSE.TXT @@ -27,8 +27,8 @@ Sweden - WWW: http://key-project.org - e-mail: key@ira.uka.de + WWW: https://www.key-project.org/ + e-mail: support@key-project.org The KeY system is protected by the GNU General Public License. From 2754ecca9e96e28f2e1f0048e23d8ea6d38abec5 Mon Sep 17 00:00:00 2001 From: Richard Bubel Date: Wed, 26 Jul 2023 20:47:18 +0200 Subject: [PATCH 52/95] Generate configuration file 'proof-settings.prop' if none exists --- .../uka/ilkd/key/settings/ProofSettings.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/settings/ProofSettings.java b/key.core/src/main/java/de/uka/ilkd/key/settings/ProofSettings.java index 66d3a29c790..e81dd3b0aab 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/settings/ProofSettings.java +++ b/key.core/src/main/java/de/uka/ilkd/key/settings/ProofSettings.java @@ -175,14 +175,19 @@ public void loadSettingsFromStream(Reader in) { * Loads the the former settings from configuration file. */ public void loadSettings() { - try (FileReader in = new FileReader(PROVER_CONFIG_FILE, StandardCharsets.UTF_8)) { - if (Boolean.getBoolean(PathConfig.DISREGARD_SETTINGS_PROPERTY)) { - LOGGER.warn("The settings in {} are *not* read.", PROVER_CONFIG_FILE); - } else { - loadSettingsFromStream(in); + if (!PROVER_CONFIG_FILE.exists()) { + saveSettings(); + LOGGER.info("No proof-settings exists. Generating default settings."); + } else { + try (FileReader in = new FileReader(PROVER_CONFIG_FILE, StandardCharsets.UTF_8)) { + if (Boolean.getBoolean(PathConfig.DISREGARD_SETTINGS_PROPERTY)) { + LOGGER.warn("The settings in {} are *not* read.", PROVER_CONFIG_FILE); + } else { + loadSettingsFromStream(in); + } + } catch (IOException e) { + LOGGER.warn("No proof-settings could be loaded, using defaults", e); } - } catch (IOException e) { - LOGGER.warn("No proof-settings could be loaded, using defaults", e); } } From bcd7472a9a46de9445e6ce9b2813789f58119979 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Thu, 27 Jul 2023 09:10:05 +0200 Subject: [PATCH 53/95] Fix JML warning in example --- key.ui/examples/firstTouch/08-Java5/src/For.java | 1 + 1 file changed, 1 insertion(+) diff --git a/key.ui/examples/firstTouch/08-Java5/src/For.java b/key.ui/examples/firstTouch/08-Java5/src/For.java index f7ed037c0bb..af67d3be381 100644 --- a/key.ui/examples/firstTouch/08-Java5/src/For.java +++ b/key.ui/examples/firstTouch/08-Java5/src/For.java @@ -25,6 +25,7 @@ int sum () { void infiniteLoop() { //@ maintaining \invariant_for(f); //@ assignable \strictly_nothing; + //@ diverges true; for (Object o: f); } From 614852f78a514dac4ccc34151a0293442271564e Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Thu, 27 Jul 2023 09:16:54 +0200 Subject: [PATCH 54/95] Fix default LaF Follow-up to #3226 --- .../main/java/de/uka/ilkd/key/settings/ViewSettings.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/settings/ViewSettings.java b/key.core/src/main/java/de/uka/ilkd/key/settings/ViewSettings.java index 091c2e56f9e..c1e7bae7889 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/settings/ViewSettings.java +++ b/key.core/src/main/java/de/uka/ilkd/key/settings/ViewSettings.java @@ -2,6 +2,7 @@ import java.util.List; import java.util.Set; +import javax.swing.*; /** * This class encapsulates information about: 1) relative font size in the prover view 2) the @@ -141,6 +142,9 @@ public class ViewSettings extends AbstractPropertiesSettings { */ private static final String USER_FOLDER_BOOKMARKS = "[View]folderBookmarks"; + private static final String LOOK_AND_FEEL_DEFAULT = + UIManager.getCrossPlatformLookAndFeelClassName(); + /** * Show Taclet uninstantiated in tooltip -- for learning */ @@ -182,7 +186,8 @@ public class ViewSettings extends AbstractPropertiesSettings { private final PropertyEntry showWholeTaclet = createBooleanProperty(SHOW_WHOLE_TACLET, false); private final PropertyEntry sizeIndex = createIntegerProperty(FONT_INDEX, 2); - private final PropertyEntry lookAndFeel = createStringProperty(LOOK_AND_FEEL, null); + private final PropertyEntry lookAndFeel = + createStringProperty(LOOK_AND_FEEL, LOOK_AND_FEEL_DEFAULT); private final PropertyEntry showSequentViewTooltips = createBooleanProperty(SEQUENT_VIEW_TOOLTIP, true); private final PropertyEntry showSourceViewTooltips = From 6e6898d06b659f81354a1bec3a3bbc1406caa928 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Thu, 27 Jul 2023 09:21:48 +0200 Subject: [PATCH 55/95] Re-enable test for release branch --- .github/workflows/code_quality.yml | 2 +- .github/workflows/codeql.yml | 5 +++-- .github/workflows/javadoc.yml | 1 - .github/workflows/tests.yml | 4 +++- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/code_quality.yml b/.github/workflows/code_quality.yml index 5a8489b6123..00bd2641767 100644 --- a/.github/workflows/code_quality.yml +++ b/.github/workflows/code_quality.yml @@ -6,7 +6,7 @@ on: push: branches: - main - - 'releases/*' + - 'KeY-*' jobs: qodana: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 1fb4812f631..ae93906d0fc 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -4,8 +4,9 @@ on: push: branches: [ "main" ] pull_request: - # The branches below must be a subset of the branches above - branches: [ "main" ] + branches: + - "main" + - "KeY-*" schedule: - cron: '21 21 * * 4' merge_group: diff --git a/.github/workflows/javadoc.yml b/.github/workflows/javadoc.yml index 3aea47e894d..756133f4889 100644 --- a/.github/workflows/javadoc.yml +++ b/.github/workflows/javadoc.yml @@ -6,7 +6,6 @@ on: jobs: doc: - # later limit to master only! runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ef657be2e08..da6bf45f06b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -5,7 +5,9 @@ on: push: branches: [ "main" ] pull_request: - branches: [ "main" ] + branches: + - "main" + - "KeY-*" merge_group: permissions: From 7fe3ebccc5d6169a5389aee114f6577d871e6bab Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Thu, 27 Jul 2023 11:06:54 +0200 Subject: [PATCH 56/95] UI test: mark manual test as disabled --- key.ui/src/test/java/de/uka/ilkd/key/gui/ChaosMonkey.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/key.ui/src/test/java/de/uka/ilkd/key/gui/ChaosMonkey.java b/key.ui/src/test/java/de/uka/ilkd/key/gui/ChaosMonkey.java index a5035d43d12..67b9dea1057 100644 --- a/key.ui/src/test/java/de/uka/ilkd/key/gui/ChaosMonkey.java +++ b/key.ui/src/test/java/de/uka/ilkd/key/gui/ChaosMonkey.java @@ -21,7 +21,7 @@ import org.key_project.util.java.SwingUtil; import bibliothek.gui.dock.dockable.AbstractDockable; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,6 +51,7 @@ final class ChaosMonkey { private static boolean detectedError = false; @Test + @Disabled void clickAllTheButtons() { new Thread(ChaosMonkey::click, "ChaosMonkey").start(); From 29603afa7d4036b3f373c2ff36ab3474674ad063 Mon Sep 17 00:00:00 2001 From: Mattias Ulbrich Date: Thu, 27 Jul 2023 23:29:50 +0200 Subject: [PATCH 57/95] adding ctrl-+ and ctrl-- for font size changes --- .../de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeSettings.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeSettings.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeSettings.java index 28cae1990bd..deec24b7da5 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeSettings.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeSettings.java @@ -103,6 +103,10 @@ public class KeyStrokeSettings extends AbstractPropertiesSettings { } // default mappings + defineDefault(IncreaseFontSizeAction.class, + KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, KeyStrokeManager.SHORTCUT_KEY_MASK)); + defineDefault(DecreaseFontSizeAction.class, + KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, KeyStrokeManager.SHORTCUT_KEY_MASK)); defineDefault(HelpFacade.ACTION_OPEN_HELP.getClass(), KeyStroke.getKeyStroke("F1")); defineDefault(OpenExampleAction.class, KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyStrokeManager.MULTI_KEY_MASK)); From 40d836c896f32b83cec6cd9eaa89312b781dc175 Mon Sep 17 00:00:00 2001 From: Alexander Weigl Date: Fri, 28 Jul 2023 01:39:32 +0200 Subject: [PATCH 58/95] Publishing to Maven Central configured (nearly) --- build.gradle | 80 ++++++++++++++++++++++++++++--------------- key.core/build.gradle | 5 +-- key.ui/build.gradle | 3 ++ 3 files changed, 57 insertions(+), 31 deletions(-) diff --git a/build.gradle b/build.gradle index f12d32e1f52..b7641cfb306 100644 --- a/build.gradle +++ b/build.gradle @@ -49,13 +49,14 @@ static def getDate() { // The $BUILD_NUMBER is an environment variable set by Jenkins. def build = System.env.BUILD_NUMBER == null ? "" : "-${System.env.BUILD_NUMBER}" -group = "org.key_project" -version = "2.11.0$build" +group = "org.key-project" +version = "2.12.0$build" subprojects { apply plugin: "java" apply plugin: "java-library" apply plugin: "maven-publish" + apply plugin: "signing" // GPG signing of artifacts, required by maven central apply plugin: "idea" apply plugin: "eclipse" @@ -107,7 +108,7 @@ subprojects { //options.verbose() options.encoding = 'UTF-8' if (JavaVersion.current().isJava9Compatible()) { - //options.addBooleanOption('html5', true) + options.addBooleanOption('html5', true) } } @@ -133,7 +134,6 @@ subprojects { } - test { // Before we switched to JUnit 5, we used JUnit 4 with a customized discovery of test class. // This discovery called AutoSuite and searched in the compiled classes. AutoSuite was @@ -180,14 +180,14 @@ subprojects { // The following two tasks can be used to execute main methods from the project // The main class is set via "gradle -DmainClass=... execute --args ..." // see https://stackoverflow.com/questions/21358466/gradle-to-execute-java-class-without-modifying-build-gradle - task execute(type:JavaExec) { + task execute(type: JavaExec) { description 'Execute main method from the project. Set main class via "gradle -DmainClass=... execute --args ..."' group "application" mainClass.set(System.getProperty('mainClass')) classpath = sourceSets.main.runtimeClasspath } - task executeInTests(type:JavaExec) { + task executeInTests(type: JavaExec) { description 'Execute main method from the project (tests loaded). Set main class via "gradle -DmainClass=... execute --args ..."' group "application" mainClass.set(System.getProperty('mainClass')) @@ -195,13 +195,13 @@ subprojects { } // findbugs { findbugsTest.enabled = false; ignoreFailures = true } - pmd { + pmd { pmdTest.enabled = false - ignoreFailures = true + ignoreFailures = true toolVersion = "6.53.0" consoleOutput = false rulesMinimumPriority = 5 - ruleSets = ["category/java/errorprone.xml", "category/java/bestpractices.xml"] + ruleSets = ["category/java/errorprone.xml", "category/java/bestpractices.xml"] } task pmdMainChanged(type: Pmd) { @@ -225,7 +225,7 @@ subprojects { checkstyle { toolVersion = "10.6.0" ignoreFailures = true - configFile file("$rootDir/gradle/key_checks.xml") + configFile file("$rootDir/gradle/key_checks.xml") showViolations = false // disable console output } @@ -249,9 +249,7 @@ subprojects { outputLocation = file("build/reports/checkstyle/main_diff.xml") } } - } - - + } // tasks.withType(FindBugs) { @@ -260,13 +258,13 @@ subprojects { // html.enabled = true // } // } - tasks.withType(Pmd) { - reports { - xml.getRequired().set(true) - html.getRequired().set(true) - } - } - + tasks.withType(Pmd) { + reports { + xml.getRequired().set(true) + html.getRequired().set(true) + } + } + task sourcesJar(type: Jar) { description = 'Create a jar file with the sources from this project' from sourceSets.main.allJava @@ -281,7 +279,7 @@ subprojects { publishing { publications { - gpr(MavenPublication) { + mavenJava(MavenPublication) { from components.java artifact sourcesJar artifact javadocJar @@ -296,6 +294,7 @@ subprojects { url = "http://www.gnu.org/licenses/old-licenses/gpl-2.0.html" } } + developers { developer { id = 'key' @@ -313,10 +312,31 @@ subprojects { } repositories { maven { + if (project.version.endsWith("-SNAPSHOT")) { + name = "mavenSnapshot" + url = "https://s01.oss.sonatype.org/content/repositories/snapshots/" + credentials(PasswordCredentials) { + println("username: ", ossrhUsername) + username = ossrhUsername + password = ossrhPassword + } + } else { + name = "mavenStaging" + url = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/" + credentials(PasswordCredentials) { + println("username: " + ossrhPassword) + username = ossrhUsername + password = ossrhPassword + } + } + } + + /* + maven { // deployment to git.key-project.org name = "GitlabPackages" url "https://git.key-project.org/api/v4/projects/35/packages/maven" credentials(HttpHeaderCredentials) { - if(System.getenv("TOKEN") != null) { + if (System.getenv("TOKEN") != null) { name = 'Private-Token' value = System.getenv("TOKEN") } else { @@ -328,17 +348,23 @@ subprojects { header(HttpHeaderAuthentication) } } + */ } } + signing { + useGpgCmd() // works better than the Java implementation, which requires PGP keyrings. + sign publishing.publications.mavenJava + } + license {//configures the license file header header = file("$rootDir/gradle/header") mapping { //find styles here: // http://code.mycila.com/license-maven-plugin/#supported-comment-types - java="SLASHSTAR_STYLE" // DOUBLESLASH_STYLE - javascript="SLASHSTAR_STYLE" + java = "SLASHSTAR_STYLE" // DOUBLESLASH_STYLE + javascript = "SLASHSTAR_STYLE" } mapping("key", "SLASHSTAR_STYLE") } @@ -475,10 +501,10 @@ def getChangedFiles() { // Remove the status prefix def files = new TreeSet() for (file in allFiles) { - if(file.length() > 1) { + if (file.length() > 1) { def a = file.substring(1).trim() - if(! a.isBlank() ) { - files.add(("$rootDir/"+a).toString()) + if (!a.isBlank()) { + files.add(("$rootDir/" + a).toString()) } } } diff --git a/key.core/build.gradle b/key.core/build.gradle index 52050ae6914..f35050c9894 100644 --- a/key.core/build.gradle +++ b/key.core/build.gradle @@ -246,7 +246,4 @@ task generateRAPUnitTests(type: JavaExec) { } sourceSets.test.java.srcDirs("$buildDir/generated-src/rap/") - -// @AW: Delete? weigl: depends: If want that gradle check validates everything then not. -// check.dependsOn << testProofRules << testRunAllProofs - +sourcesJar.dependsOn(runAntlr4Jml, runAntlr4Key, compileJavacc, generateGrammarSource) diff --git a/key.ui/build.gradle b/key.ui/build.gradle index 753293fd012..648b09d9b87 100644 --- a/key.ui/build.gradle +++ b/key.ui/build.gradle @@ -25,6 +25,9 @@ dependencies { api 'org.dockingframes:docking-frames-common:1.1.3p1' api 'org.dockingframes:docking-frames-core:1.1.3p1' + // change to if published on maven central + // api 'org.key-project:docking-frames-common:1.1.3p1' + // api 'org.key-project:docking-frames-core:1.1.3p1' runtimeOnly project(":keyext.ui.testgen") runtimeOnly project(":keyext.exploration") From b1d0baa185db63784e63f27bdaa263a3f4a0f53d Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Fri, 28 Jul 2023 09:05:02 +0200 Subject: [PATCH 59/95] Fix issue dialog not showing file content --- key.ui/src/main/java/de/uka/ilkd/key/gui/IssueDialog.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/IssueDialog.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/IssueDialog.java index 94a2898b027..73af077df3c 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/IssueDialog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/IssueDialog.java @@ -649,14 +649,18 @@ private void updatePreview(PositionedIssueString issue) { txtSource.setText("[SOURCE COULD NOT BE LOADED]"); } else { URI uri = location.getFileURI().get(); + if (uri.getScheme() == null) { + uri = URI.create("file:" + uri.getPath()); + } fTextField.setText("URL: " + uri); fTextField.setVisible(true); try { + URI finalUri = uri; String source = StringUtil.replaceNewlines( fileContentsCache.computeIfAbsent(uri, fn -> { try { - return IOUtil.readFrom(uri).orElseThrow(); + return IOUtil.readFrom(finalUri).orElseThrow(); } catch (IOException e) { LOGGER.debug("Unknown IOException!", e); return "[SOURCE COULD NOT BE LOADED]\n" + e.getMessage(); From feda206ad9dc7022149ca27c5b08910f35ea59f3 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Fri, 28 Jul 2023 09:05:19 +0200 Subject: [PATCH 60/95] Fix watchdog false positive It seems the event thread sometimes enters a timed sleep when there is no event to process. --- key.ui/src/main/java/de/uka/ilkd/key/core/Watchdog.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/core/Watchdog.java b/key.ui/src/main/java/de/uka/ilkd/key/core/Watchdog.java index b64ad30f68b..369a74acc52 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/core/Watchdog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/core/Watchdog.java @@ -83,15 +83,14 @@ private static void run() { anyProgress = true; break; case WAITING: + case BLOCKED: + case TIMED_WAITING: + case TERMINATED: if (thread.getName().equals("AWT-EventQueue-0") && EventQueue.getCurrentEvent() == null) { anyProgress = true; // nothing to do } break; - case BLOCKED: - case TIMED_WAITING: - case TERMINATED: - break; } } From b668547e1890794059c90a736252eab95a4d77b9 Mon Sep 17 00:00:00 2001 From: Alexander Weigl Date: Sun, 30 Jul 2023 20:50:47 +0200 Subject: [PATCH 61/95] update broad release tests --- .github/workflows/tests_winmac.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests_winmac.yml b/.github/workflows/tests_winmac.yml index ad2a88b4f30..705cc1ddd38 100644 --- a/.github/workflows/tests_winmac.yml +++ b/.github/workflows/tests_winmac.yml @@ -36,7 +36,7 @@ jobs: uses: actions/upload-artifact@v3.1.1 if: success() || failure() with: - name: test-results + name: test-results-${{ matrix.os }} path: | **/build/test-results/*/*.xml **/build/reports/ From 6adce6a32f67dd47edfa2e7596f954fe263fe32e Mon Sep 17 00:00:00 2001 From: Alexander Weigl Date: Sun, 30 Jul 2023 21:01:00 +0200 Subject: [PATCH 62/95] fix missing property exception added documentation for publishing on maven central --- build.gradle | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index b7641cfb306..da1d3121f7d 100644 --- a/build.gradle +++ b/build.gradle @@ -312,21 +312,36 @@ subprojects { } repositories { maven { + /** + * To be able to publish things on Maven Central, you need two things: + * + * (1) a JIRA account with permission on group-id `org.key-project` + * (2) a keyserver-published GPG (w/o sub-keys) + * + * Your `$HOME/.gradle/gradle.properties` should like this: + * ``` + * signing.keyId=YourKeyId + * signing.password=YourPublicKeyPassword + * ossrhUsername=your-jira-id + * ossrhPassword=your-jira-password + * ``` + * + * You can test signing with `gradle sign`, and publish with `gradle publish`. + * https://central.sonatype.org/publish/publish-guide/ + */ if (project.version.endsWith("-SNAPSHOT")) { name = "mavenSnapshot" url = "https://s01.oss.sonatype.org/content/repositories/snapshots/" credentials(PasswordCredentials) { - println("username: ", ossrhUsername) - username = ossrhUsername - password = ossrhPassword + username = project.properties.getOrDefault("ossrhUsername","") + password = project.properties.getOrDefault("ossrhPassword","") } } else { name = "mavenStaging" url = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/" credentials(PasswordCredentials) { - println("username: " + ossrhPassword) - username = ossrhUsername - password = ossrhPassword + username = project.properties.getOrDefault("ossrhUsername","") + password = project.properties.getOrDefault("ossrhPassword","") } } } From 33899ed4c23720b6d2515a3f9c95a591df229c26 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Mon, 31 Jul 2023 08:29:40 +0200 Subject: [PATCH 63/95] Proof caching: useful error message --- .../key/gui/actions/ShowProofStatistics.java | 4 +++- .../gui/keyshortcuts/KeyStrokeSettings.java | 4 ++-- .../gui/plugins/caching/CachingException.java | 21 +++++++++++++++++++ .../DefaultReferenceSearchDialogListener.java | 2 +- 4 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingException.java diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ShowProofStatistics.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ShowProofStatistics.java index cf80eb78c43..021d976b867 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ShowProofStatistics.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ShowProofStatistics.java @@ -318,7 +318,9 @@ private void init(MainWindow mainWindow, String stats) { if (proof.closedGoals().stream() .anyMatch(g -> g.node().lookup(ClosedBy.class) != null)) { - JButton copyReferences = new JButton("Copy referenced proof"); + JButton copyReferences = new JButton("Realize cached branches"); + copyReferences.setToolTipText("For each goal closed using the proof cache, copy " + + "the referenced proof steps into this proof."); copyReferences.addActionListener(e -> { dispose(); ReferenceSearchDialog dialog = diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeSettings.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeSettings.java index deec24b7da5..42c4366b639 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeSettings.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeSettings.java @@ -104,9 +104,9 @@ public class KeyStrokeSettings extends AbstractPropertiesSettings { // default mappings defineDefault(IncreaseFontSizeAction.class, - KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, KeyStrokeManager.SHORTCUT_KEY_MASK)); + KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, KeyStrokeManager.SHORTCUT_KEY_MASK)); defineDefault(DecreaseFontSizeAction.class, - KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, KeyStrokeManager.SHORTCUT_KEY_MASK)); + KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, KeyStrokeManager.SHORTCUT_KEY_MASK)); defineDefault(HelpFacade.ACTION_OPEN_HELP.getClass(), KeyStroke.getKeyStroke("F1")); defineDefault(OpenExampleAction.class, KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyStrokeManager.MULTI_KEY_MASK)); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingException.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingException.java new file mode 100644 index 00000000000..d39a3de8f78 --- /dev/null +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingException.java @@ -0,0 +1,21 @@ +package de.uka.ilkd.key.gui.plugins.caching; + +/** + * Helpful error message used when the proof cache cannot + * be applied successfully. + * + * @author Arne Keller + */ +public class CachingException extends Exception { + private static final String EXPLANATION_TEXT = + "Proof caching error: failed to realize cached branch\n\n" + + "The replay system failed to reconstruct the referenced proof. Possible reasons:\n" + + "1) the referenced proof has different \\include directives than the new proof\n" + + "2) the referenced proof uses a different (bootstrap) classpath\n" + + "3) an unknown error occurred\n\n" + + "Try saving and reloading all currently opened proofs. Please also report this bug to the KeY team."; + + public CachingException(Exception e) { + super(EXPLANATION_TEXT, e); + } +} diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/DefaultReferenceSearchDialogListener.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/DefaultReferenceSearchDialogListener.java index bf7cfc681a2..87d6167bae4 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/DefaultReferenceSearchDialogListener.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/DefaultReferenceSearchDialogListener.java @@ -52,7 +52,7 @@ public void copyButtonClicked(ReferenceSearchDialog dialog) { } catch (Exception e) { mediator.startInterface(true); LOGGER.error("failed to copy cache ", e); - IssueDialog.showExceptionDialog(dialog, e); + IssueDialog.showExceptionDialog(dialog, new CachingException(e)); } }).start(); } From 98f852f6a7e9fba15d5e8b704cd79b20f3752104 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Mon, 31 Jul 2023 08:34:12 +0200 Subject: [PATCH 64/95] Fix sizing of statistics dialog --- .../ilkd/key/gui/actions/ShowProofStatistics.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ShowProofStatistics.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ShowProofStatistics.java index 021d976b867..1b8e5f9815e 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ShowProofStatistics.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ShowProofStatistics.java @@ -271,9 +271,6 @@ private void init(MainWindow mainWindow, String stats) { statisticsPane.setBorder(BorderFactory.createEmptyBorder()); statisticsPane.setCaretPosition(0); statisticsPane.setBackground(MainWindow.getInstance().getBackground()); - statisticsPane.setSize(new Dimension(10, 420)); - statisticsPane.setPreferredSize( - new Dimension(statisticsPane.getPreferredSize().width + 15, 420)); JScrollPane scrollPane = new JScrollPane(statisticsPane); scrollPane.setBorder(BorderFactory.createEmptyBorder()); @@ -355,10 +352,12 @@ public void keyTyped(KeyEvent e) { buttonsPane.add(buttonPane2); add(buttonsPane, BorderLayout.PAGE_END); - int w = 50 + Math.max(scrollPane.getPreferredSize().width, - buttonsPane.getPreferredSize().width); - int h = - scrollPane.getPreferredSize().height + buttonsPane.getPreferredSize().height + 100; + pack(); + int w = Math.min(600, 50 + Math.max(scrollPane.getPreferredSize().width, + buttonsPane.getPreferredSize().width)); + int h = Math.min(850, + 50 + scrollPane.getPreferredSize().height + buttonsPane.getPreferredSize().height); + setSize(w, h); setLocationRelativeTo(mainWindow); } From 7c16913f1694f2da9bf18d00ea1966ce5b7e1d48 Mon Sep 17 00:00:00 2001 From: Wolfram Pfeifer Date: Mon, 31 Jul 2023 17:01:17 +0200 Subject: [PATCH 65/95] ensure that after SMT application the next goal is selected correctly --- .../main/java/de/uka/ilkd/key/gui/smt/SolverListener.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java index 867b8d46863..9e5904ffa43 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java @@ -203,11 +203,12 @@ public void launcherStopped(SolverLauncher launcher, Collection probl private void applyResults() { KeYMediator mediator = MainWindow.getInstance().getMediator(); - mediator.stopInterface(true); + // To ensure that the next goal is selected correctly, do not fully stop the interface here! + mediator.stopInterface(false); try { new ProofSMTApplyUserAction(mediator, smtProof, problems).actionPerformed(null); } finally { - mediator.startInterface(true); + mediator.startInterface(false); } } From 3802936580c2ee0bf1a18eeab89f7bad3194c974 Mon Sep 17 00:00:00 2001 From: Wolfram Pfeifer Date: Mon, 31 Jul 2023 17:07:19 +0200 Subject: [PATCH 66/95] renamed RuleAppSMT to SMTRuleApp again (after merge) --- .../ilkd/key/macros/scripts/SMTCommand.java | 2 +- .../main/java/de/uka/ilkd/key/proof/Goal.java | 4 +-- .../de/uka/ilkd/key/proof/Statistics.java | 4 +-- .../proof/io/IntermediateProofReplayer.java | 13 +++---- .../key/proof/io/OutputStreamProofSaver.java | 10 +++--- .../proof/replay/AbstractProofReplayer.java | 6 ++-- .../de/uka/ilkd/key/rule/RuleAppUtil.java | 4 +-- .../smt/{RuleAppSMT.java => SMTRuleApp.java} | 36 +++++++++---------- .../de/uka/ilkd/key/smt/TestUnsatCore.java | 4 +-- .../useractions/ProofSMTApplyUserAction.java | 12 +++---- .../slicing/analysis/DependencyAnalyzer.java | 4 +-- .../key_project/slicing/EndToEndTests.java | 4 +-- 12 files changed, 48 insertions(+), 55 deletions(-) rename key.core/src/main/java/de/uka/ilkd/key/smt/{RuleAppSMT.java => SMTRuleApp.java} (81%) diff --git a/key.core/src/main/java/de/uka/ilkd/key/macros/scripts/SMTCommand.java b/key.core/src/main/java/de/uka/ilkd/key/macros/scripts/SMTCommand.java index c6b158eda70..1ffa9273dc7 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/macros/scripts/SMTCommand.java +++ b/key.core/src/main/java/de/uka/ilkd/key/macros/scripts/SMTCommand.java @@ -85,7 +85,7 @@ private void runSMT(SMTCommandArguments args, SolverTypeCollection su, Goal goal for (SMTProblem problem : probList) { SMTSolverResult finalResult = problem.getFinalResult(); if (finalResult.isValid() == ThreeValuedTruth.VALID) { - IBuiltInRuleApp app = RuleAppSMT.RULE.createApp(args.solver); + IBuiltInRuleApp app = SMTRuleApp.RULE.createApp(args.solver); app = app.tryToInstantiate(problem.getGoal()); problem.getGoal().apply(app); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java b/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java index d14b82478d3..c5bdcdfda1d 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/Goal.java @@ -20,7 +20,7 @@ import de.uka.ilkd.key.rule.*; import de.uka.ilkd.key.rule.inst.SVInstantiations; import de.uka.ilkd.key.rule.merge.MergeRule; -import de.uka.ilkd.key.smt.RuleAppSMT; +import de.uka.ilkd.key.smt.SMTRuleApp; import de.uka.ilkd.key.strategy.AutomatedRuleApplicationManager; import de.uka.ilkd.key.strategy.QueueRuleApplicationManager; import de.uka.ilkd.key.strategy.Strategy; @@ -642,7 +642,7 @@ public ImmutableList apply(final RuleApp ruleApp) { // the first new goal is the one to be closed proof.closeGoal(goalList.head()); } - if (ruleApp instanceof RuleAppSMT) { + if (ruleApp instanceof SMTRuleApp) { // the first new goal is the one to be closed proof.closeGoal(goalList.head()); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/Statistics.java b/key.core/src/main/java/de/uka/ilkd/key/proof/Statistics.java index ae47436b2d1..af25c441f8e 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/Statistics.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/Statistics.java @@ -11,7 +11,7 @@ import de.uka.ilkd.key.rule.*; import de.uka.ilkd.key.rule.OneStepSimplifier.Protocol; import de.uka.ilkd.key.rule.merge.MergeRuleBuiltInRuleApp; -import de.uka.ilkd.key.smt.RuleAppSMT; +import de.uka.ilkd.key.smt.SMTRuleApp; import de.uka.ilkd.key.util.EnhancedStringBuffer; import de.uka.ilkd.key.util.Pair; @@ -245,7 +245,7 @@ private void changeOnNode(final Node node, if (ruleApp instanceof de.uka.ilkd.key.rule.OneStepSimplifierRuleApp) { oss++; ossCaptured += tmpOssCaptured(ruleApp); - } else if (ruleApp instanceof RuleAppSMT) { + } else if (ruleApp instanceof SMTRuleApp) { smt++; } else if (ruleApp instanceof UseDependencyContractApp) { dep++; diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/io/IntermediateProofReplayer.java b/key.core/src/main/java/de/uka/ilkd/key/proof/io/IntermediateProofReplayer.java index 61b07b4e326..7a18c765819 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/io/IntermediateProofReplayer.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/io/IntermediateProofReplayer.java @@ -41,12 +41,9 @@ import de.uka.ilkd.key.settings.DefaultSMTSettings; import de.uka.ilkd.key.settings.ProofIndependentSMTSettings; import de.uka.ilkd.key.settings.ProofIndependentSettings; -import de.uka.ilkd.key.smt.RuleAppSMT; -import de.uka.ilkd.key.smt.SMTFocusResults; -import de.uka.ilkd.key.smt.SMTProblem; +import de.uka.ilkd.key.smt.*; +import de.uka.ilkd.key.smt.SMTRuleApp; import de.uka.ilkd.key.smt.SMTSolverResult.ThreeValuedTruth; -import de.uka.ilkd.key.smt.SolverLauncher; -import de.uka.ilkd.key.smt.SolverTypeCollection; import de.uka.ilkd.key.speclang.Contract; import de.uka.ilkd.key.speclang.OperationContract; import de.uka.ilkd.key.util.Pair; @@ -581,7 +578,7 @@ private IBuiltInRuleApp constructBuiltinApp(BuiltInAppIntermediate currInterm, G } } - if (RuleAppSMT.RULE.name().toString().equals(ruleName)) { + if (SMTRuleApp.RULE.name().toString().equals(ruleName)) { if (!ProofIndependentSettings.DEFAULT_INSTANCE.getSMTSettings().isEnableOnLoad()) { status = SMT_NOT_RUN; throw new SkipSMTRuleException(); @@ -628,9 +625,9 @@ private IBuiltInRuleApp constructBuiltinApp(BuiltInAppIntermediate currInterm, G Optional> unsatCore = SMTFocusResults.getUnsatCore(smtProblem); if (unsatCore.isPresent()) { - return RuleAppSMT.RULE.createApp(name, unsatCore.get()); + return SMTRuleApp.RULE.createApp(name, unsatCore.get()); } else { - return RuleAppSMT.RULE.createApp(name); + return SMTRuleApp.RULE.createApp(name); } } } diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/io/OutputStreamProofSaver.java b/key.core/src/main/java/de/uka/ilkd/key/proof/io/OutputStreamProofSaver.java index 1d4a9a96404..169fdc0a38d 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/io/OutputStreamProofSaver.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/io/OutputStreamProofSaver.java @@ -39,7 +39,7 @@ import de.uka.ilkd.key.rule.merge.procedures.MergeWithPredicateAbstraction; import de.uka.ilkd.key.settings.ProofSettings; import de.uka.ilkd.key.settings.StrategySettings; -import de.uka.ilkd.key.smt.RuleAppSMT; +import de.uka.ilkd.key.smt.SMTRuleApp; import de.uka.ilkd.key.strategy.StrategyProperties; import de.uka.ilkd.key.util.KeYConstants; import de.uka.ilkd.key.util.MiscTools; @@ -490,8 +490,8 @@ private void printSingleCloseAfterMergeRuleApp(CloseAfterMergeRuleBuiltInRuleApp output.append("\")"); } - private void printSingleSMTRuleApp(RuleAppSMT smtApp, Node node, String prefix, - Appendable output) throws IOException { + private void printSingleSMTRuleApp(SMTRuleApp smtApp, Node node, String prefix, + Appendable output) throws IOException { output.append(" (").append(ProofElementID.SOLVERTYPE.getRawName()) .append(" \"").append(smtApp.getSuccessfulSolverName()).append("\")"); } @@ -559,8 +559,8 @@ private void printSingleBuiltInRuleApp(IBuiltInRuleApp appliedRuleApp, Node node if (appliedRuleApp instanceof CloseAfterMergeRuleBuiltInRuleApp) { printSingleCloseAfterMergeRuleApp((CloseAfterMergeRuleBuiltInRuleApp) appliedRuleApp, node, prefix, output); - } else if (appliedRuleApp instanceof RuleAppSMT) { - printSingleSMTRuleApp((RuleAppSMT) appliedRuleApp, node, prefix, output); + } else if (appliedRuleApp instanceof SMTRuleApp) { + printSingleSMTRuleApp((SMTRuleApp) appliedRuleApp, node, prefix, output); } output.append(""); diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/replay/AbstractProofReplayer.java b/key.core/src/main/java/de/uka/ilkd/key/proof/replay/AbstractProofReplayer.java index 62392de1c85..1a61611e322 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/replay/AbstractProofReplayer.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/replay/AbstractProofReplayer.java @@ -39,7 +39,7 @@ import de.uka.ilkd.key.rule.UseOperationContractRule; import de.uka.ilkd.key.rule.inst.InstantiationEntry; import de.uka.ilkd.key.rule.inst.SVInstantiations; -import de.uka.ilkd.key.smt.RuleAppSMT; +import de.uka.ilkd.key.smt.SMTRuleApp; import de.uka.ilkd.key.speclang.Contract; import de.uka.ilkd.key.speclang.OperationContract; import de.uka.ilkd.key.util.Pair; @@ -144,8 +144,8 @@ private IBuiltInRuleApp constructBuiltinApp(Node originalStep, Goal currGoal) builtinIfInsts = builtinIfInsts.append(newFormula); } - if (RuleAppSMT.RULE.displayName().equals(ruleName)) { - return RuleAppSMT.RULE.createApp(null, proof.getServices()); + if (SMTRuleApp.RULE.displayName().equals(ruleName)) { + return SMTRuleApp.RULE.createApp(null, proof.getServices()); } IBuiltInRuleApp ourApp = null; diff --git a/key.core/src/main/java/de/uka/ilkd/key/rule/RuleAppUtil.java b/key.core/src/main/java/de/uka/ilkd/key/rule/RuleAppUtil.java index 27d7b3bb53e..603b51cfbea 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/rule/RuleAppUtil.java +++ b/key.core/src/main/java/de/uka/ilkd/key/rule/RuleAppUtil.java @@ -8,7 +8,7 @@ import de.uka.ilkd.key.proof.Node; import de.uka.ilkd.key.rule.merge.CloseAfterMergeRuleBuiltInRuleApp; import de.uka.ilkd.key.rule.merge.MergeRuleBuiltInRuleApp; -import de.uka.ilkd.key.smt.RuleAppSMT; +import de.uka.ilkd.key.smt.SMTRuleApp; /** * Utilities for working with rule applications. @@ -59,7 +59,7 @@ public static Set ifInstsOfRuleApp(RuleApp ruleApp, Node node) // SMT application: add all formulas as inputs if (ruleApp instanceof MergeRuleBuiltInRuleApp || ruleApp instanceof CloseAfterMergeRuleBuiltInRuleApp - || ruleApp instanceof RuleAppSMT) { + || ruleApp instanceof SMTRuleApp) { node.sequent().antecedent().iterator().forEachRemaining( it -> inputs.add(new PosInOccurrence(it, PosInTerm.getTopLevel(), true))); node.sequent().succedent().iterator().forEachRemaining( diff --git a/key.core/src/main/java/de/uka/ilkd/key/smt/RuleAppSMT.java b/key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java similarity index 81% rename from key.core/src/main/java/de/uka/ilkd/key/smt/RuleAppSMT.java rename to key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java index 22b29782003..5d3bc688041 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/smt/RuleAppSMT.java +++ b/key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java @@ -16,7 +16,7 @@ * The rule application that is used when a goal is closed by means of an external solver. So far it * stores the rule that that has been used and a title containing some information for the user. */ -public class RuleAppSMT extends AbstractBuiltInRuleApp { +public class SMTRuleApp extends AbstractBuiltInRuleApp { public static final SMTRule RULE = new SMTRule(); private final String title; @@ -28,11 +28,11 @@ public class RuleAppSMT extends AbstractBuiltInRuleApp { * @param pio the pos in term to apply the rule on * @param successfulSolverName the name of the solver that was able to close find the proof */ - RuleAppSMT(SMTRule rule, PosInOccurrence pio, String successfulSolverName) { + SMTRuleApp(SMTRule rule, PosInOccurrence pio, String successfulSolverName) { this(rule, pio, null, successfulSolverName); } - RuleAppSMT(SMTRule rule, PosInOccurrence pio, ImmutableList unsatCore, + SMTRuleApp(SMTRule rule, PosInOccurrence pio, ImmutableList unsatCore, String successfulSolverName) { super(rule, pio, unsatCore); this.title = "SMT: " + successfulSolverName; @@ -40,8 +40,8 @@ public class RuleAppSMT extends AbstractBuiltInRuleApp { } @Override - public RuleAppSMT replacePos(PosInOccurrence newPos) { - return new RuleAppSMT(RULE, newPos, ifInsts, successfulSolverName); + public SMTRuleApp replacePos(PosInOccurrence newPos) { + return new SMTRuleApp(RULE, newPos, ifInsts, successfulSolverName); } @Override @@ -75,8 +75,8 @@ public String displayName() { public static class SMTRule implements BuiltInRule { public static final Name name = new Name("SMTRule"); - public RuleAppSMT createApp(String successfulSolverName) { - return new RuleAppSMT(this, null, successfulSolverName); + public SMTRuleApp createApp(String successfulSolverName) { + return new SMTRuleApp(this, null, successfulSolverName); } /** @@ -86,14 +86,14 @@ public RuleAppSMT createApp(String successfulSolverName) { * @param unsatCore formulas required to prove the result * @return rule application instance */ - public RuleAppSMT createApp(String successfulSolverName, - ImmutableList unsatCore) { - return new RuleAppSMT(this, null, unsatCore, successfulSolverName); + public SMTRuleApp createApp(String successfulSolverName, + ImmutableList unsatCore) { + return new SMTRuleApp(this, null, unsatCore, successfulSolverName); } @Override - public RuleAppSMT createApp(PosInOccurrence pos, TermServices services) { - return new RuleAppSMT(this, null, ""); + public SMTRuleApp createApp(PosInOccurrence pos, TermServices services) { + return new SMTRuleApp(this, null, ""); } @@ -117,7 +117,7 @@ public ImmutableList apply(Goal goal, Services services, RuleApp ruleApp) goal.proof().getInitConfig().registerRule(RULE, () -> false); } - // RuleAppSMT app = (RuleAppSMT) ruleApp; + // SMTRuleApp app = (SMTRuleApp) ruleApp; // goal.node().getNodeInfo().setBranchLabel(app.getTitle()); ImmutableList newGoals = goal.split(1); @@ -148,12 +148,12 @@ public Name name() { } - public RuleAppSMT setTitle(String title) { - return new RuleAppSMT(RULE, pio, ifInsts, title); + public SMTRuleApp setTitle(String title) { + return new SMTRuleApp(RULE, pio, ifInsts, title); } @Override - public RuleAppSMT setIfInsts(ImmutableList ifInsts) { + public SMTRuleApp setIfInsts(ImmutableList ifInsts) { setMutable(ifInsts); return this; } @@ -167,8 +167,8 @@ public RuleAppSMT setIfInsts(ImmutableList ifInsts) { * @return a new RuleApp with the same pio and all top level formulas of the goal as ifInsts */ @Override - public RuleAppSMT tryToInstantiate(Goal goal) { - RuleAppSMT app = RULE.createApp(pio, goal.proof().getServices()); + public SMTRuleApp tryToInstantiate(Goal goal) { + SMTRuleApp app = RULE.createApp(pio, goal.proof().getServices()); Sequent seq = goal.sequent(); List ifInsts = new ArrayList<>(); for (SequentFormula ante : seq.antecedent()) { diff --git a/key.core/src/test/java/de/uka/ilkd/key/smt/TestUnsatCore.java b/key.core/src/test/java/de/uka/ilkd/key/smt/TestUnsatCore.java index 63b7b7f6f5a..5d03cedd42d 100644 --- a/key.core/src/test/java/de/uka/ilkd/key/smt/TestUnsatCore.java +++ b/key.core/src/test/java/de/uka/ilkd/key/smt/TestUnsatCore.java @@ -36,8 +36,8 @@ void testUnsatCore() throws ProblemLoaderException { Assertions.assertTrue(env.getLoadedProof().closed()); // find the SMT rule app Proof p = env.getLoadedProof(); - Node n = p.findAny(node -> node.getAppliedRuleApp() instanceof RuleAppSMT); - RuleAppSMT app = ((RuleAppSMT) n.getAppliedRuleApp()); + Node n = p.findAny(node -> node.getAppliedRuleApp() instanceof SMTRuleApp); + SMTRuleApp app = ((SMTRuleApp) n.getAppliedRuleApp()); Assertions.assertEquals("Z3", app.getSuccessfulSolverName()); ImmutableList ifs = app.ifInsts(); Assertions.assertTrue( diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/useractions/ProofSMTApplyUserAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/useractions/ProofSMTApplyUserAction.java index 6fb0e42961e..989c47d2a86 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/useractions/ProofSMTApplyUserAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/useractions/ProofSMTApplyUserAction.java @@ -12,12 +12,8 @@ import de.uka.ilkd.key.proof.Node; import de.uka.ilkd.key.proof.Proof; import de.uka.ilkd.key.rule.IBuiltInRuleApp; -import de.uka.ilkd.key.smt.RuleAppSMT; -import de.uka.ilkd.key.smt.SMTFocusResults; -import de.uka.ilkd.key.smt.SMTProblem; -import de.uka.ilkd.key.smt.RuleAppSMT; -import de.uka.ilkd.key.smt.SMTSolver; -import de.uka.ilkd.key.smt.SMTSolverResult; +import de.uka.ilkd.key.smt.*; +import de.uka.ilkd.key.smt.SMTRuleApp; import org.key_project.util.collection.ImmutableList; @@ -72,9 +68,9 @@ protected void apply() { SMTFocusResults.getUnsatCore(problem.getProblem()); IBuiltInRuleApp app; if (unsatCore.isPresent()) { - app = RuleAppSMT.RULE.createApp(problem.getSolver().name(), unsatCore.get()); + app = SMTRuleApp.RULE.createApp(problem.getSolver().name(), unsatCore.get()); } else { - app = RuleAppSMT.RULE.createApp(problem.getSolver().name()); + app = SMTRuleApp.RULE.createApp(problem.getSolver().name()); } app.tryToInstantiate(goal); goal.apply(app); diff --git a/keyext.slicing/src/main/java/org/key_project/slicing/analysis/DependencyAnalyzer.java b/keyext.slicing/src/main/java/org/key_project/slicing/analysis/DependencyAnalyzer.java index 53ec24a6f4e..8e700f7e08e 100644 --- a/keyext.slicing/src/main/java/org/key_project/slicing/analysis/DependencyAnalyzer.java +++ b/keyext.slicing/src/main/java/org/key_project/slicing/analysis/DependencyAnalyzer.java @@ -32,7 +32,7 @@ import de.uka.ilkd.key.rule.merge.CloseAfterMergeRuleBuiltInRuleApp; import de.uka.ilkd.key.rule.merge.MergeRuleBuiltInRuleApp; import de.uka.ilkd.key.settings.GeneralSettings; -import de.uka.ilkd.key.smt.RuleAppSMT; +import de.uka.ilkd.key.smt.SMTRuleApp; import de.uka.ilkd.key.util.Pair; import org.key_project.slicing.DependencyNodeData; @@ -228,7 +228,7 @@ public AnalysisResults analyze() { executionTime.start(STATISTICS); int steps = proof.countNodes() - proof.closedGoals().size() + (int) proof.closedGoals() - .stream().filter(it -> it.node().getAppliedRuleApp() instanceof RuleAppSMT) + .stream().filter(it -> it.node().getAppliedRuleApp() instanceof SMTRuleApp) .count(); // gather statistics on useful/useless rules RuleStatistics rules = getRuleStatistics(); diff --git a/keyext.slicing/src/test/java/org/key_project/slicing/EndToEndTests.java b/keyext.slicing/src/test/java/org/key_project/slicing/EndToEndTests.java index f901c3ad85b..8c7fcd38d9b 100644 --- a/keyext.slicing/src/test/java/org/key_project/slicing/EndToEndTests.java +++ b/keyext.slicing/src/test/java/org/key_project/slicing/EndToEndTests.java @@ -14,7 +14,7 @@ import de.uka.ilkd.key.proof.init.JavaProfile; import de.uka.ilkd.key.settings.GeneralSettings; import de.uka.ilkd.key.settings.ProofIndependentSettings; -import de.uka.ilkd.key.smt.RuleAppSMT; +import de.uka.ilkd.key.smt.SMTRuleApp; import de.uka.ilkd.key.util.Pair; import org.key_project.slicing.analysis.AnalysisResults; @@ -281,7 +281,7 @@ private Pair sliceProofFullFilename(File proofFile, int expectedTot assertEquals(expectedInSlice + slicedProof.closedGoals().size() - slicedProof.closedGoals().stream() - .filter(x -> x.node().getAppliedRuleApp() instanceof RuleAppSMT) + .filter(x -> x.node().getAppliedRuleApp() instanceof SMTRuleApp) .count(), slicedProof.countNodes()); From adf472e4f361bbdb4078024061e12461878b3fab Mon Sep 17 00:00:00 2001 From: Wolfram Pfeifer Date: Mon, 31 Jul 2023 19:43:23 +0200 Subject: [PATCH 67/95] highlight all formulas for SMT nodes w/o unsat core, removed Optional cleanup --- .../key/proof/io/IntermediateProofReplayer.java | 7 +++---- .../de/uka/ilkd/key/smt/SMTFocusResults.java | 15 +++++++-------- .../java/de/uka/ilkd/key/smt/SMTRuleApp.java | 10 +--------- .../useractions/ProofSMTApplyUserAction.java | 6 +++--- .../ilkd/key/gui/nodeviews/InnerNodeView.java | 17 +++++++++++++++-- 5 files changed, 29 insertions(+), 26 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/io/IntermediateProofReplayer.java b/key.core/src/main/java/de/uka/ilkd/key/proof/io/IntermediateProofReplayer.java index 7a18c765819..f20f88b5f94 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/io/IntermediateProofReplayer.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/io/IntermediateProofReplayer.java @@ -622,10 +622,9 @@ private IBuiltInRuleApp constructBuiltinApp(BuiltInAppIntermediate currInterm, G throw new SkipSMTRuleException(); } else { String name = smtProblem.getSuccessfulSolver().name(); - Optional> unsatCore = - SMTFocusResults.getUnsatCore(smtProblem); - if (unsatCore.isPresent()) { - return SMTRuleApp.RULE.createApp(name, unsatCore.get()); + ImmutableList unsatCore = SMTFocusResults.getUnsatCore(smtProblem); + if (unsatCore != null) { + return SMTRuleApp.RULE.createApp(name, unsatCore); } else { return SMTRuleApp.RULE.createApp(name); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/smt/SMTFocusResults.java b/key.core/src/main/java/de/uka/ilkd/key/smt/SMTFocusResults.java index e39571328a8..37f674c3258 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/smt/SMTFocusResults.java +++ b/key.core/src/main/java/de/uka/ilkd/key/smt/SMTFocusResults.java @@ -48,11 +48,10 @@ private SMTFocusResults() { */ public static boolean focus(SMTProblem smtProblem, Services services) { - Optional> unsatCoreFormulas = getUnsatCore(smtProblem); - if (unsatCoreFormulas.isEmpty()) { + ImmutableList unsatCore = getUnsatCore(smtProblem); + if (unsatCore == null) { return false; } - ImmutableList unsatCore = unsatCoreFormulas.get(); Goal goal = smtProblem.getGoal(); // cache the goal node, because we will apply rules on the goal @@ -110,14 +109,14 @@ public static boolean focus(SMTProblem smtProblem, Services services) { * solver. * * @param problem SMT solver results - * @return formula collection + * @return formula collection or null if the solver did not produce an unsat core */ - public static Optional> getUnsatCore(SMTProblem problem) { + public static ImmutableList getUnsatCore(SMTProblem problem) { SMTSolver solver = problem.getSuccessfulSolver(); if (solver.getFinalResult().isValid() != ThreeValuedTruth.VALID) { - return Optional.empty(); + return null; } String[] lines = solver.getRawSolverOutput().split("\n"); @@ -134,7 +133,7 @@ public static Optional> getUnsatCore(SMTProblem p numbers = parseCVC5Format(lines); } else { // unknown format / no unsat core produced - return Optional.empty(); + return null; } Node goalNode = problem.getNode(); @@ -161,7 +160,7 @@ public static Optional> getUnsatCore(SMTProblem p i++; } - return Optional.of(unsatCoreFormulas); + return unsatCoreFormulas; } /** diff --git a/key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java b/key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java index 5d3bc688041..f2328afd87b 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java @@ -116,17 +116,9 @@ public ImmutableList apply(Goal goal, Services services, RuleApp ruleApp) if (goal.proof().getInitConfig().getJustifInfo().getJustification(RULE) == null) { goal.proof().getInitConfig().registerRule(RULE, () -> false); } - - // SMTRuleApp app = (SMTRuleApp) ruleApp; - // goal.node().getNodeInfo().setBranchLabel(app.getTitle()); - ImmutableList newGoals = goal.split(1); - - return newGoals; + return goal.split(1); } - /** - * {@inheritDoc} - */ @Override public boolean isApplicableOnSubTerms() { return false; diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/useractions/ProofSMTApplyUserAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/useractions/ProofSMTApplyUserAction.java index 989c47d2a86..8d7a727545f 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/useractions/ProofSMTApplyUserAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/useractions/ProofSMTApplyUserAction.java @@ -64,11 +64,11 @@ protected void apply() { continue; } goalsClosed.add(goal); - Optional> unsatCore = + ImmutableList unsatCore = SMTFocusResults.getUnsatCore(problem.getProblem()); IBuiltInRuleApp app; - if (unsatCore.isPresent()) { - app = SMTRuleApp.RULE.createApp(problem.getSolver().name(), unsatCore.get()); + if (unsatCore != null) { + app = SMTRuleApp.RULE.createApp(problem.getSolver().name(), unsatCore); } else { app = SMTRuleApp.RULE.createApp(problem.getSolver().name()); } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/nodeviews/InnerNodeView.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/nodeviews/InnerNodeView.java index 7c26c6ce403..b7e7991164d 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/nodeviews/InnerNodeView.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/nodeviews/InnerNodeView.java @@ -15,6 +15,7 @@ import de.uka.ilkd.key.logic.PosInOccurrence; import de.uka.ilkd.key.logic.PosInTerm; import de.uka.ilkd.key.logic.Sequent; +import de.uka.ilkd.key.logic.SequentFormula; import de.uka.ilkd.key.pp.*; import de.uka.ilkd.key.proof.Node; import de.uka.ilkd.key.proof.Proof; @@ -22,6 +23,7 @@ import de.uka.ilkd.key.proof.event.ProofDisposedListener; import de.uka.ilkd.key.rule.*; +import de.uka.ilkd.key.smt.SMTRuleApp; import org.key_project.util.collection.ImmutableList; import org.slf4j.Logger; @@ -133,8 +135,19 @@ private void highlightIfFormulas(TacletApp tapp) throws BadLocationException { private void highlightIfInsts(IBuiltInRuleApp bapp) throws BadLocationException { final ImmutableList ifs = bapp.ifInsts(); - for (PosInOccurrence pio : ifs) { - highlightPos(pio, IF_FORMULA_HIGHLIGHTER); + if (bapp instanceof SMTRuleApp && ifs.isEmpty()) { + /* Special case for SMTRuleApp: If no unsat core is used, we highlight all formulas. + * For the moment, we do not store all formulas as ifInstantiations, since that would + * clutter saved proofs very much. */ + for (int i = 0; i < node.sequent().size(); i++) { + PosInOccurrence pio = PosInOccurrence.findInSequent(node.sequent(), i + 1, + PosInTerm.getTopLevel()); + highlightPos(pio, IF_FORMULA_HIGHLIGHTER); + } + } else { + for (PosInOccurrence pio : ifs) { + highlightPos(pio, IF_FORMULA_HIGHLIGHTER); + } } } From 3045ae1099f45101b1cae72e22143688783caf43 Mon Sep 17 00:00:00 2001 From: Wolfram Pfeifer Date: Mon, 31 Jul 2023 19:44:29 +0200 Subject: [PATCH 68/95] formatting --- .../ilkd/key/proof/io/OutputStreamProofSaver.java | 2 +- .../java/de/uka/ilkd/key/smt/SMTFocusResults.java | 1 - .../main/java/de/uka/ilkd/key/smt/SMTRuleApp.java | 13 ++++++++----- .../useractions/ProofSMTApplyUserAction.java | 1 - .../uka/ilkd/key/gui/nodeviews/InnerNodeView.java | 9 +++++---- .../de/uka/ilkd/key/gui/smt/SolverListener.java | 10 ++++++---- 6 files changed, 20 insertions(+), 16 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/io/OutputStreamProofSaver.java b/key.core/src/main/java/de/uka/ilkd/key/proof/io/OutputStreamProofSaver.java index 169fdc0a38d..111dbc29381 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/io/OutputStreamProofSaver.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/io/OutputStreamProofSaver.java @@ -491,7 +491,7 @@ private void printSingleCloseAfterMergeRuleApp(CloseAfterMergeRuleBuiltInRuleApp } private void printSingleSMTRuleApp(SMTRuleApp smtApp, Node node, String prefix, - Appendable output) throws IOException { + Appendable output) throws IOException { output.append(" (").append(ProofElementID.SOLVERTYPE.getRawName()) .append(" \"").append(smtApp.getSuccessfulSolverName()).append("\")"); } diff --git a/key.core/src/main/java/de/uka/ilkd/key/smt/SMTFocusResults.java b/key.core/src/main/java/de/uka/ilkd/key/smt/SMTFocusResults.java index 37f674c3258..1f58143dfe5 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/smt/SMTFocusResults.java +++ b/key.core/src/main/java/de/uka/ilkd/key/smt/SMTFocusResults.java @@ -2,7 +2,6 @@ import java.util.Arrays; import java.util.HashSet; -import java.util.Optional; import de.uka.ilkd.key.java.Services; import de.uka.ilkd.key.logic.*; diff --git a/key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java b/key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java index f2328afd87b..8a79bce8ce6 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java +++ b/key.core/src/main/java/de/uka/ilkd/key/smt/SMTRuleApp.java @@ -1,5 +1,8 @@ package de.uka.ilkd.key.smt; +import java.util.ArrayList; +import java.util.List; + import de.uka.ilkd.key.java.Services; import de.uka.ilkd.key.logic.*; import de.uka.ilkd.key.proof.Goal; @@ -9,9 +12,6 @@ import org.key_project.util.collection.ImmutableList; -import java.util.ArrayList; -import java.util.List; - /** * The rule application that is used when a goal is closed by means of an external solver. So far it * stores the rule that that has been used and a title containing some information for the user. @@ -24,6 +24,7 @@ public class SMTRuleApp extends AbstractBuiltInRuleApp { /** * Create a new rule app without ifInsts (will be null). + * * @param rule the SMTRule to apply * @param pio the pos in term to apply the rule on * @param successfulSolverName the name of the solver that was able to close find the proof @@ -33,7 +34,7 @@ public class SMTRuleApp extends AbstractBuiltInRuleApp { } SMTRuleApp(SMTRule rule, PosInOccurrence pio, ImmutableList unsatCore, - String successfulSolverName) { + String successfulSolverName) { super(rule, pio, unsatCore); this.title = "SMT: " + successfulSolverName; this.successfulSolverName = successfulSolverName; @@ -87,7 +88,7 @@ public SMTRuleApp createApp(String successfulSolverName) { * @return rule application instance */ public SMTRuleApp createApp(String successfulSolverName, - ImmutableList unsatCore) { + ImmutableList unsatCore) { return new SMTRuleApp(this, null, unsatCore, successfulSolverName); } @@ -106,6 +107,7 @@ public boolean isApplicable(Goal goal, PosInOccurrence pio) { /** * Create a new goal (to be closed in {@link Goal#apply(RuleApp)} directly afterwards) * with the same sequent as the given one. + * * @param goal the Goal on which to apply ruleApp * @param services the Services with the necessary information about the java programs * @param ruleApp the rule application to be executed @@ -155,6 +157,7 @@ public SMTRuleApp setIfInsts(ImmutableList ifInsts) { * SMT rule is applied to the complete sequent) as this one. * Add all top level formulas of the goal * to the RuleApp's ifInsts. + * * @param goal the goal to instantiate the current RuleApp on * @return a new RuleApp with the same pio and all top level formulas of the goal as ifInsts */ diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/useractions/ProofSMTApplyUserAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/useractions/ProofSMTApplyUserAction.java index 8d7a727545f..b76d77b1a9d 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/useractions/ProofSMTApplyUserAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/useractions/ProofSMTApplyUserAction.java @@ -3,7 +3,6 @@ import java.util.Collection; import java.util.HashSet; import java.util.Iterator; -import java.util.Optional; import de.uka.ilkd.key.core.KeYMediator; import de.uka.ilkd.key.gui.smt.SolverListener; diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/nodeviews/InnerNodeView.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/nodeviews/InnerNodeView.java index b7e7991164d..5d872b57104 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/nodeviews/InnerNodeView.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/nodeviews/InnerNodeView.java @@ -15,15 +15,14 @@ import de.uka.ilkd.key.logic.PosInOccurrence; import de.uka.ilkd.key.logic.PosInTerm; import de.uka.ilkd.key.logic.Sequent; -import de.uka.ilkd.key.logic.SequentFormula; import de.uka.ilkd.key.pp.*; import de.uka.ilkd.key.proof.Node; import de.uka.ilkd.key.proof.Proof; import de.uka.ilkd.key.proof.event.ProofDisposedEvent; import de.uka.ilkd.key.proof.event.ProofDisposedListener; import de.uka.ilkd.key.rule.*; - import de.uka.ilkd.key.smt.SMTRuleApp; + import org.key_project.util.collection.ImmutableList; import org.slf4j.Logger; @@ -136,9 +135,11 @@ private void highlightIfFormulas(TacletApp tapp) throws BadLocationException { private void highlightIfInsts(IBuiltInRuleApp bapp) throws BadLocationException { final ImmutableList ifs = bapp.ifInsts(); if (bapp instanceof SMTRuleApp && ifs.isEmpty()) { - /* Special case for SMTRuleApp: If no unsat core is used, we highlight all formulas. + /* + * Special case for SMTRuleApp: If no unsat core is used, we highlight all formulas. * For the moment, we do not store all formulas as ifInstantiations, since that would - * clutter saved proofs very much. */ + * clutter saved proofs very much. + */ for (int i = 0; i < node.sequent().size(); i++) { PosInOccurrence pio = PosInOccurrence.findInSequent(node.sequent(), i + 1, PosInTerm.getTopLevel()); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java index 9e5904ffa43..9b29bc7a7a4 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/SolverListener.java @@ -327,10 +327,12 @@ private void discardEvent(final SolverLauncher launcher) { private void applyEvent(final SolverLauncher launcher) { launcher.stop(); applyResults(); - /* Previously, the progressDialog was only made invisible which enabled users to - click the apply button more than once, each time creating a new SMT goal. - Disposing of the dialog is fine as it is created anew each time a SolverLauncher - is started anyway (see #launcherStarted(), #prepareDialog()). */ + /* + * Previously, the progressDialog was only made invisible which enabled users to + * click the apply button more than once, each time creating a new SMT goal. + * Disposing of the dialog is fine as it is created anew each time a SolverLauncher + * is started anyway (see #launcherStarted(), #prepareDialog()). + */ progressDialog.dispose(); } From a767ed19565e54295a4e5eab879f5af8370082b7 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Tue, 1 Aug 2023 18:07:54 +0200 Subject: [PATCH 69/95] Fix infinite loop in MainWindow construction --- .../src/main/java/de/uka/ilkd/key/gui/MainWindow.java | 11 ++++++++++- .../de/uka/ilkd/key/gui/settings/FontSizeFacade.java | 10 ++++++---- .../uka/ilkd/key/gui/settings/StandardUISettings.java | 2 +- .../java/org/key_project/util/java/SwingUtil.java | 3 +++ 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/MainWindow.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/MainWindow.java index 019181df058..164dfc59d17 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/MainWindow.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/MainWindow.java @@ -290,7 +290,7 @@ private MainWindow() { KeYGuiExtensionFacade.getStartupExtensions().forEach(it -> it.preInit(this, mediator)); ViewSettings vs = ProofIndependentSettings.DEFAULT_INSTANCE.getViewSettings(); - FontSizeFacade.resizeFonts(vs.getUIFontSizeFactor()); + FontSizeFacade.resizeFonts(this, vs.getUIFontSizeFactor()); termLabelMenu = new TermLabelMenu(this); currentGoalView = new CurrentGoalView(this); @@ -378,6 +378,15 @@ public static MainWindow getInstance(boolean ensureIsVisible) { LOGGER.error("Use the --help option for more command line options."); System.exit(-1); } + // always construct MainWindow on event dispatch thread + if (!EventQueue.isDispatchThread()) { + try { + SwingUtilities.invokeAndWait(MainWindow::getInstance); + } catch (InterruptedException | InvocationTargetException e) { + throw new RuntimeException(e); + } + return instance; + } if (instance == null) { instance = new MainWindow(); if (ensureIsVisible) { diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/FontSizeFacade.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/FontSizeFacade.java index a7536df4add..cd0d0b19f93 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/FontSizeFacade.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/FontSizeFacade.java @@ -39,10 +39,13 @@ public static void saveCurrentFontSizes() { } /** - * @param factor + * Scale all managed fonts by the provided factor. Then attempts to redraw all components. + * + * @param window the main window + * @param factor the factor * @see SwingUtilities#updateComponentTreeUI(Component) */ - public static void resizeFonts(double factor) { + public static void resizeFonts(MainWindow window, double factor) { if (Math.abs(currentFactor - factor) <= 0.1) { return; } @@ -61,8 +64,7 @@ public static void resizeFonts(double factor) { }); // for some reason, the menu bar does not update its font on its own - SwingUtil.setFont(MainWindow.getInstance().getJMenuBar(), - UIManager.getDefaults().getFont("Menu.font")); + SwingUtil.setFont(window.getJMenuBar(), UIManager.getDefaults().getFont("Menu.font")); // redraw all frames and dialogs for (Window w : Window.getWindows()) { diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/StandardUISettings.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/StandardUISettings.java index d61434ab0cd..e15bbb1aece 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/StandardUISettings.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/StandardUISettings.java @@ -189,7 +189,7 @@ public void applySettings(MainWindow window) throws InvalidSettingsInputExceptio gs.setAutoSave((Integer) spAutoSaveProof.getValue()); gs.setTacletFilter(chkMinimizeInteraction.isSelected()); vs.setFontIndex(spFontSizeTreeSequent.getSelectedIndex()); - FontSizeFacade.resizeFonts(vs.getUIFontSizeFactor()); + FontSizeFacade.resizeFonts(MainWindow.getInstance(), vs.getUIFontSizeFactor()); Config.DEFAULT.setDefaultFonts(); Config.DEFAULT.fireConfigChange(); } diff --git a/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java b/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java index c6c51f86734..d46bd8f12e4 100644 --- a/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java +++ b/key.ui/src/main/java/org/key_project/util/java/SwingUtil.java @@ -157,6 +157,9 @@ public static JScrollPane createScrollPane(JTable table) { * @param font the font */ public static void setFont(JComponent component, Font font) { + if (component == null) { + return; + } component.setFont(font); for (int i = 0; i < component.getComponentCount(); i++) { Component c = component.getComponent(i); From 2c62182732252fb952b26ff0d6b8ff1f9a66094b Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Wed, 2 Aug 2023 08:41:29 +0200 Subject: [PATCH 70/95] Fix most remaining font scaling issues --- .../java/de/uka/ilkd/key/gui/MainWindow.java | 5 +-- .../ilkd/key/gui/configuration/Config.java | 11 +++-- .../ilkd/key/gui/settings/FontSizeFacade.java | 45 +++++++++++-------- .../uka/ilkd/key/gui/settings/SettingsUi.java | 5 ++- .../key/gui/settings/StandardUISettings.java | 8 ++-- 5 files changed, 43 insertions(+), 31 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/MainWindow.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/MainWindow.java index 164dfc59d17..ce0b7eeb515 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/MainWindow.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/MainWindow.java @@ -289,8 +289,9 @@ private MainWindow() { mediator = getMainWindowMediator(userInterface); KeYGuiExtensionFacade.getStartupExtensions().forEach(it -> it.preInit(this, mediator)); + Config.DEFAULT.setDefaultFonts(); ViewSettings vs = ProofIndependentSettings.DEFAULT_INSTANCE.getViewSettings(); - FontSizeFacade.resizeFonts(this, vs.getUIFontSizeFactor()); + FontSizeFacade.resizeFonts(vs.getUIFontSizeFactor()); termLabelMenu = new TermLabelMenu(this); currentGoalView = new CurrentGoalView(this); @@ -539,8 +540,6 @@ private void layoutMain() { selectionBackAction.update(); selectionForwardAction.update(); - Config.DEFAULT.setDefaultFonts(); - // create menubar JMenuBar bar = createMenuBar(); setJMenuBar(bar); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/configuration/Config.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/configuration/Config.java index b5371d4896a..c372ff41150 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/configuration/Config.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/configuration/Config.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.List; import javax.swing.UIManager; +import javax.swing.plaf.FontUIResource; import de.uka.ilkd.key.settings.ProofIndependentSettings; @@ -72,10 +73,12 @@ private int readSizeIndex() { public void setDefaultFonts() { int idx = readSizeIndex(); - UIManager.put(KEY_FONT_PROOF_TREE, new Font("Default", Font.PLAIN, SIZES[idx])); - UIManager.put(KEY_FONT_SEQUENT_VIEW, new Font("Monospaced", Font.PLAIN, SIZES[idx])); - UIManager.put(KEY_FONT_GOAL_LIST_VIEW, new Font("Default", Font.PLAIN, SIZES[2])); - UIManager.put(KEY_FONT_PROOF_LIST_VIEW, new Font("Default", Font.PLAIN, SIZES[2])); + UIManager.put(KEY_FONT_PROOF_TREE, new FontUIResource("Default", Font.PLAIN, SIZES[idx])); + UIManager.put(KEY_FONT_SEQUENT_VIEW, + new FontUIResource("Monospaced", Font.PLAIN, SIZES[idx])); + UIManager.put(KEY_FONT_GOAL_LIST_VIEW, new FontUIResource("Default", Font.PLAIN, SIZES[2])); + UIManager.put(KEY_FONT_PROOF_LIST_VIEW, + new FontUIResource("Default", Font.PLAIN, SIZES[2])); } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/FontSizeFacade.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/FontSizeFacade.java index cd0d0b19f93..fcd7e142c94 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/FontSizeFacade.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/FontSizeFacade.java @@ -4,16 +4,18 @@ import java.util.HashMap; import java.util.Map; import javax.swing.*; +import javax.swing.plaf.FontUIResource; -import de.uka.ilkd.key.gui.MainWindow; - -import org.key_project.util.java.SwingUtil; +import static de.uka.ilkd.key.gui.configuration.Config.KEY_FONT_GOAL_LIST_VIEW; +import static de.uka.ilkd.key.gui.configuration.Config.KEY_FONT_PROOF_LIST_VIEW; +import static de.uka.ilkd.key.gui.configuration.Config.KEY_FONT_PROOF_TREE; +import static de.uka.ilkd.key.gui.configuration.Config.KEY_FONT_SEQUENT_VIEW; /** * @author Alexander Weigl * @version 1 (10.05.19) */ -public class FontSizeFacade { +public final class FontSizeFacade { private static final String[] KEYS = new String[] { "Button.font", "CheckBox.font", "CheckBoxMenuItem.acceleratorFont", "CheckBoxMenuItem.font", "ColorChooser.font", "ComboBox.font", "EditorPane.font", "FormattedTextField.font", "IconButton.font", @@ -25,15 +27,20 @@ public class FontSizeFacade { "RadioButtonMenuItem.acceleratorFont", "RadioButtonMenuItem.font", "ScrollPane.font", "Slider.font", "Spinner.font", "TabbedPane.font", "TabbedPane.smallFont", "Table.font", "TableHeader.font", "TextArea.font", "TextField.font", "TextPane.font", "TitledBorder.font", - "ToggleButton.font", "ToolBar.font", "ToolTip.font", "Tree.font", "Viewport.font" }; - private static final Map originalFontSize = new HashMap<>(); + "ToggleButton.font", "ToolBar.font", "ToolTip.font", "Tree.font", "Viewport.font", + KEY_FONT_PROOF_TREE, KEY_FONT_PROOF_LIST_VIEW, KEY_FONT_SEQUENT_VIEW, + KEY_FONT_GOAL_LIST_VIEW }; + private static final Map ORIGINAL_FONT_SIZES = new HashMap<>(); private static double currentFactor = 1; - public static void saveCurrentFontSizes() { + private FontSizeFacade() { + } + + private static void saveCurrentFontSizes() { for (String k : KEYS) { - Font f = UIManager.getDefaults().getFont(k); + Font f = UIManager.getFont(k); if (f != null) { - originalFontSize.put(k, (float) f.getSize()); + ORIGINAL_FONT_SIZES.put(k, (float) f.getSize()); } } } @@ -41,31 +48,31 @@ public static void saveCurrentFontSizes() { /** * Scale all managed fonts by the provided factor. Then attempts to redraw all components. * - * @param window the main window * @param factor the factor * @see SwingUtilities#updateComponentTreeUI(Component) */ - public static void resizeFonts(MainWindow window, double factor) { + public static void resizeFonts(double factor) { if (Math.abs(currentFactor - factor) <= 0.1) { return; } currentFactor = factor; - if (originalFontSize.isEmpty()) { + if (ORIGINAL_FONT_SIZES.isEmpty()) { saveCurrentFontSizes(); } - originalFontSize.forEach((key, value) -> { - Font f = UIManager.getDefaults().getFont(key); - if (f != null) { - UIManager.getDefaults().put(key, f.deriveFont((float) (value * factor))); + ORIGINAL_FONT_SIZES.forEach((key, value) -> { + Font f = UIManager.getFont(key); + // https://stackoverflow.com/a/6930659/5837178 + if (f instanceof FontUIResource) { + UIManager.put(key, + new FontUIResource(f.getName(), f.getStyle(), (int) (value * factor))); + } else if (f != null) { + UIManager.put(key, f.deriveFont((float) (value * factor))); } }); - // for some reason, the menu bar does not update its font on its own - SwingUtil.setFont(window.getJMenuBar(), UIManager.getDefaults().getFont("Menu.font")); - // redraw all frames and dialogs for (Window w : Window.getWindows()) { SwingUtilities.updateComponentTreeUI(w); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/SettingsUi.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/SettingsUi.java index 6d1532e8be9..5f548319bea 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/SettingsUi.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/SettingsUi.java @@ -37,6 +37,8 @@ public SettingsUi(MainWindow mainWindow, JDialog frame) { this.frame = frame; this.mainWindow = mainWindow; treeSettingsPanels.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + // TODO: scale this with the global font factor too + treeSettingsPanels.setFont(treeSettingsPanels.getFont().deriveFont(16.0f)); treeSettingsPanels.setCellRenderer(new DefaultTreeCellRenderer() { private static final long serialVersionUID = 1770380144400699946L; @@ -50,11 +52,9 @@ public Component getTreeCellRendererComponent(JTree tree, Object value, boolean // root entry lbl = (JLabel) super.getTreeCellRendererComponent(tree, "KeY Settings", sel, expanded, leaf, row, hasFocus); - lbl.setFont(lbl.getFont().deriveFont(16f)); } else { lbl = (JLabel) super.getTreeCellRendererComponent(tree, panel.getDescription(), sel, expanded, leaf, row, hasFocus); - lbl.setFont(lbl.getFont().deriveFont(16f)); if (node.isLeaf()) { lbl.setIcon(panel.getIcon()); @@ -104,6 +104,7 @@ public void keyReleased(KeyEvent e) { } private void setSettingsPanel(JComponent comp) { + SwingUtilities.updateComponentTreeUI(comp); root.setRightComponent(comp); // set divider location slightly more to the right to avoid horizontal scroll bar diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/StandardUISettings.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/StandardUISettings.java index e15bbb1aece..fa5efd67127 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/StandardUISettings.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/StandardUISettings.java @@ -188,9 +188,11 @@ public void applySettings(MainWindow window) throws InvalidSettingsInputExceptio vs.setConfirmExit(chkConfirmExit.isSelected()); gs.setAutoSave((Integer) spAutoSaveProof.getValue()); gs.setTacletFilter(chkMinimizeInteraction.isSelected()); - vs.setFontIndex(spFontSizeTreeSequent.getSelectedIndex()); - FontSizeFacade.resizeFonts(MainWindow.getInstance(), vs.getUIFontSizeFactor()); - Config.DEFAULT.setDefaultFonts(); + if (vs.sizeIndex() != spFontSizeTreeSequent.getSelectedIndex()) { + vs.setFontIndex(spFontSizeTreeSequent.getSelectedIndex()); + Config.DEFAULT.setDefaultFonts(); + } + FontSizeFacade.resizeFonts(vs.getUIFontSizeFactor()); Config.DEFAULT.fireConfigChange(); } From f0cfb3cdca97bbdeadd5f2dcd7e4793f10b266bf Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Wed, 2 Aug 2023 09:08:30 +0200 Subject: [PATCH 71/95] Fix yet another edge case in font resizing --- .../uka/ilkd/key/gui/configuration/Config.java | 16 ++++++++++++---- .../gui/nodeviews/SequentViewChangeListener.java | 1 - .../ilkd/key/gui/prooftree/ProofTreeView.java | 5 +++-- .../ilkd/key/gui/settings/FontSizeFacade.java | 8 +------- .../key/gui/settings/StandardUISettings.java | 6 ++---- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/configuration/Config.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/configuration/Config.java index c372ff41150..38a5d824d9b 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/configuration/Config.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/configuration/Config.java @@ -24,6 +24,7 @@ public class Config { /** The index of the current size */ private int sizeIndex = readSizeIndex(); + private double sizeFactor = readSizeFactor(); /** cached ConfigChange event */ private final ConfigChangeEvent configChangeEvent = new ConfigChangeEvent(this); @@ -71,14 +72,21 @@ private int readSizeIndex() { return s; } + private double readSizeFactor() { + return ProofIndependentSettings.DEFAULT_INSTANCE.getViewSettings().getUIFontSizeFactor(); + } + public void setDefaultFonts() { + sizeFactor = readSizeFactor(); int idx = readSizeIndex(); - UIManager.put(KEY_FONT_PROOF_TREE, new FontUIResource("Default", Font.PLAIN, SIZES[idx])); + UIManager.put(KEY_FONT_PROOF_TREE, + new FontUIResource("Default", Font.PLAIN, (int) (sizeFactor * SIZES[idx]))); UIManager.put(KEY_FONT_SEQUENT_VIEW, - new FontUIResource("Monospaced", Font.PLAIN, SIZES[idx])); - UIManager.put(KEY_FONT_GOAL_LIST_VIEW, new FontUIResource("Default", Font.PLAIN, SIZES[2])); + new FontUIResource("Monospaced", Font.PLAIN, (int) (sizeFactor * SIZES[idx]))); + UIManager.put(KEY_FONT_GOAL_LIST_VIEW, + new FontUIResource("Default", Font.PLAIN, (int) (sizeFactor * SIZES[2]))); UIManager.put(KEY_FONT_PROOF_LIST_VIEW, - new FontUIResource("Default", Font.PLAIN, SIZES[2])); + new FontUIResource("Default", Font.PLAIN, (int) (sizeFactor * SIZES[2]))); } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/nodeviews/SequentViewChangeListener.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/nodeviews/SequentViewChangeListener.java index bfb907a49fd..705db05f6e1 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/nodeviews/SequentViewChangeListener.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/nodeviews/SequentViewChangeListener.java @@ -60,7 +60,6 @@ public void componentShown(ComponentEvent e) { @Override public void propertyChange(PropertyChangeEvent evt) { - reprint(); } @Override diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java index f2157f220bc..84494f7db8b 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java @@ -325,8 +325,9 @@ private void setProofTreeFont() { // set row height before changing the font (since the latter repaints the component) delegateView.setRowHeight(rowHeight); - renderer.setFont(myFont); - delegateView.setFont(myFont); + // convert any FontUIResource to Font, so the font is actually updated + renderer.setFont(myFont.deriveFont((float) myFont.getSize())); + delegateView.setFont(myFont.deriveFont((float) myFont.getSize())); } else { LOGGER.debug("KEY-PROOF_TREE_FONT not available, use standard font."); delegateView.setRowHeight(rowHeight); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/FontSizeFacade.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/FontSizeFacade.java index fcd7e142c94..67f2e834baa 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/FontSizeFacade.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/FontSizeFacade.java @@ -6,10 +6,6 @@ import javax.swing.*; import javax.swing.plaf.FontUIResource; -import static de.uka.ilkd.key.gui.configuration.Config.KEY_FONT_GOAL_LIST_VIEW; -import static de.uka.ilkd.key.gui.configuration.Config.KEY_FONT_PROOF_LIST_VIEW; -import static de.uka.ilkd.key.gui.configuration.Config.KEY_FONT_PROOF_TREE; -import static de.uka.ilkd.key.gui.configuration.Config.KEY_FONT_SEQUENT_VIEW; /** * @author Alexander Weigl @@ -27,9 +23,7 @@ public final class FontSizeFacade { "RadioButtonMenuItem.acceleratorFont", "RadioButtonMenuItem.font", "ScrollPane.font", "Slider.font", "Spinner.font", "TabbedPane.font", "TabbedPane.smallFont", "Table.font", "TableHeader.font", "TextArea.font", "TextField.font", "TextPane.font", "TitledBorder.font", - "ToggleButton.font", "ToolBar.font", "ToolTip.font", "Tree.font", "Viewport.font", - KEY_FONT_PROOF_TREE, KEY_FONT_PROOF_LIST_VIEW, KEY_FONT_SEQUENT_VIEW, - KEY_FONT_GOAL_LIST_VIEW }; + "ToggleButton.font", "ToolBar.font", "ToolTip.font", "Tree.font", "Viewport.font" }; private static final Map ORIGINAL_FONT_SIZES = new HashMap<>(); private static double currentFactor = 1; diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/StandardUISettings.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/StandardUISettings.java index fa5efd67127..b69c7cbdd1b 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/StandardUISettings.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/StandardUISettings.java @@ -188,10 +188,8 @@ public void applySettings(MainWindow window) throws InvalidSettingsInputExceptio vs.setConfirmExit(chkConfirmExit.isSelected()); gs.setAutoSave((Integer) spAutoSaveProof.getValue()); gs.setTacletFilter(chkMinimizeInteraction.isSelected()); - if (vs.sizeIndex() != spFontSizeTreeSequent.getSelectedIndex()) { - vs.setFontIndex(spFontSizeTreeSequent.getSelectedIndex()); - Config.DEFAULT.setDefaultFonts(); - } + vs.setFontIndex(spFontSizeTreeSequent.getSelectedIndex()); + Config.DEFAULT.setDefaultFonts(); FontSizeFacade.resizeFonts(vs.getUIFontSizeFactor()); Config.DEFAULT.fireConfigChange(); } From 205f53ee45542ef48e0237a0971379b5987cc4dc Mon Sep 17 00:00:00 2001 From: Wolfram Date: Wed, 2 Aug 2023 14:41:50 +0200 Subject: [PATCH 72/95] fixed small bug where proof slicing failed due to an invalid path name (happened for taclet proofs) --- .../main/java/org/key_project/slicing/SlicingProofReplayer.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/keyext.slicing/src/main/java/org/key_project/slicing/SlicingProofReplayer.java b/keyext.slicing/src/main/java/org/key_project/slicing/SlicingProofReplayer.java index defc4a32a8d..c18da0766ca 100644 --- a/keyext.slicing/src/main/java/org/key_project/slicing/SlicingProofReplayer.java +++ b/keyext.slicing/src/main/java/org/key_project/slicing/SlicingProofReplayer.java @@ -228,6 +228,8 @@ private File saveProof(Proof currentProof, Proof proof) throws IOException { filename = MiscTools.removeFileExtension(currentProof.getProofFile().getName()); } else { filename = MiscTools.removeFileExtension(currentProof.name().toString()); + // make sure that no special chars are in name (e.g., "Taclet: seqPerm ..." for taclet proofs) + filename = MiscTools.toValidFileName(filename); } int prevSlice = filename.indexOf("_slice"); if (prevSlice != -1) { From 7fe36fbfec2f53a5be38aa1d3f08cc21f1b7728b Mon Sep 17 00:00:00 2001 From: Wolfram Date: Wed, 2 Aug 2023 14:54:14 +0200 Subject: [PATCH 73/95] removed SMT calls from taclet proofs --- .../seqPerm/Taclet_seqPermExists.proof | 136 ++++++++++---- .../seqPerm/Taclet_seqPermForall.proof | 170 ++++++++++++++---- 2 files changed, 244 insertions(+), 62 deletions(-) diff --git a/key.core/tacletProofs/seqPerm/Taclet_seqPermExists.proof b/key.core/tacletProofs/seqPerm/Taclet_seqPermExists.proof index 725b1cf6d19..ab2668330b5 100644 --- a/key.core/tacletProofs/seqPerm/Taclet_seqPermExists.proof +++ b/key.core/tacletProofs/seqPerm/Taclet_seqPermExists.proof @@ -2,54 +2,54 @@ \settings { "#Proof-Settings-Config-File -#Wed Apr 12 13:29:52 CEST 2023 -[Labels]UseOriginLabels=true -[StrategyProperty]QUERYAXIOM_OPTIONS_KEY=QUERYAXIOM_OFF -[SMTSettings]invariantForall=false -[Strategy]ActiveStrategy=JavaCardDLStrategy -[StrategyProperty]USER_TACLETS_OPTIONS_KEY1=USER_TACLETS_OFF -[StrategyProperty]QUANTIFIERS_OPTIONS_KEY=QUANTIFIERS_NON_SPLITTING_WITH_PROGS -[StrategyProperty]USER_TACLETS_OPTIONS_KEY2=USER_TACLETS_OFF +#Wed Aug 02 14:52:57 CEST 2023 [Choice]DefaultChoices=JavaCard-JavaCard\\:on, Strings-Strings\\:on, assertions-assertions\\:on, bigint-bigint\\:on, floatRules-floatRules\\:strictfpOnly, initialisation-initialisation\\:disableStaticInitialisation, intRules-intRules\\:arithmeticSemanticsIgnoringOF, integerSimplificationRules-integerSimplificationRules\\:full, javaLoopTreatment-javaLoopTreatment\\:efficient, mergeGenerateIsWeakeningGoal-mergeGenerateIsWeakeningGoal\\:off, methodExpansion-methodExpansion\\:modularOnly, modelFields-modelFields\\:showSatisfiability, moreSeqRules-moreSeqRules\\:on, permissions-permissions\\:off, programRules-programRules\\:Java, reach-reach\\:on, runtimeExceptions-runtimeExceptions\\:ban, sequences-sequences\\:on, wdChecks-wdChecks\\:off, wdOperator-wdOperator\\:L -[StrategyProperty]LOOP_OPTIONS_KEY=LOOP_INVARIANT -[StrategyProperty]INF_FLOW_CHECK_PROPERTY=INF_FLOW_CHECK_FALSE +[Labels]UseOriginLabels=true +[SMTSettings]SelectedTaclets= [SMTSettings]UseBuiltUniqueness=false [SMTSettings]explicitTypeHierarchy=false [SMTSettings]instantiateHierarchyAssumptions=true -[StrategyProperty]NON_LIN_ARITH_OPTIONS_KEY=NON_LIN_ARITH_NONE -[SMTSettings]SelectedTaclets= -[StrategyProperty]DEP_OPTIONS_KEY=DEP_ON -[StrategyProperty]AUTO_INDUCTION_OPTIONS_KEY=AUTO_INDUCTION_OFF -[Strategy]MaximumNumberOfAutomaticApplications=10000 -[StrategyProperty]STOPMODE_OPTIONS_KEY=STOPMODE_DEFAULT -[StrategyProperty]CLASS_AXIOM_OPTIONS_KEY=CLASS_AXIOM_FREE +[SMTSettings]integersMaximum=2147483645 +[SMTSettings]integersMinimum=-2147483645 +[SMTSettings]invariantForall=false +[SMTSettings]maxGenericSorts=2 [SMTSettings]useConstantsForBigOrSmallIntegers=true -[StrategyProperty]MPS_OPTIONS_KEY=MPS_MERGE -[StrategyProperty]SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OPTIONS_KEY=SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OFF -[Strategy]Timeout=-1 -[StrategyProperty]SYMBOLIC_EXECUTION_ALIAS_CHECK_OPTIONS_KEY=SYMBOLIC_EXECUTION_ALIAS_CHECK_NEVER -[StrategyProperty]QUERY_NEW_OPTIONS_KEY=QUERY_RESTRICTED [SMTSettings]useUninterpretedMultiplication=true +[StrategyProperty]AUTO_INDUCTION_OPTIONS_KEY=AUTO_INDUCTION_OFF [StrategyProperty]BLOCK_OPTIONS_KEY=BLOCK_CONTRACT_INTERNAL +[StrategyProperty]CLASS_AXIOM_OPTIONS_KEY=CLASS_AXIOM_FREE +[StrategyProperty]DEP_OPTIONS_KEY=DEP_ON +[StrategyProperty]INF_FLOW_CHECK_PROPERTY=INF_FLOW_CHECK_FALSE +[StrategyProperty]LOOP_OPTIONS_KEY=LOOP_INVARIANT [StrategyProperty]METHOD_OPTIONS_KEY=METHOD_CONTRACT -[StrategyProperty]USER_TACLETS_OPTIONS_KEY3=USER_TACLETS_OFF -[SMTSettings]maxGenericSorts=2 +[StrategyProperty]MPS_OPTIONS_KEY=MPS_MERGE +[StrategyProperty]NON_LIN_ARITH_OPTIONS_KEY=NON_LIN_ARITH_NONE [StrategyProperty]OSS_OPTIONS_KEY=OSS_ON +[StrategyProperty]QUANTIFIERS_OPTIONS_KEY=QUANTIFIERS_NON_SPLITTING_WITH_PROGS +[StrategyProperty]QUERYAXIOM_OPTIONS_KEY=QUERYAXIOM_OFF +[StrategyProperty]QUERY_NEW_OPTIONS_KEY=QUERY_RESTRICTED [StrategyProperty]SPLITTING_OPTIONS_KEY=SPLITTING_DELAYED -[SMTSettings]integersMinimum=-2147483645 +[StrategyProperty]STOPMODE_OPTIONS_KEY=STOPMODE_DEFAULT +[StrategyProperty]SYMBOLIC_EXECUTION_ALIAS_CHECK_OPTIONS_KEY=SYMBOLIC_EXECUTION_ALIAS_CHECK_NEVER +[StrategyProperty]SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OPTIONS_KEY=SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OFF +[StrategyProperty]USER_TACLETS_OPTIONS_KEY1=USER_TACLETS_OFF +[StrategyProperty]USER_TACLETS_OPTIONS_KEY2=USER_TACLETS_OFF +[StrategyProperty]USER_TACLETS_OPTIONS_KEY3=USER_TACLETS_OFF [StrategyProperty]VBT_PHASE=VBT_SYM_EX -[SMTSettings]integersMaximum=2147483645 +[Strategy]ActiveStrategy=JavaCardDLStrategy +[Strategy]MaximumNumberOfAutomaticApplications=10000 +[Strategy]Timeout=-1 " } \proofObligation "#Proof Obligation Settings -#Wed Apr 12 13:29:52 CEST 2023 -name=seqPermExists +#Wed Aug 02 14:52:57 CEST 2023 class=de.uka.ilkd.key.taclettranslation.lemma.TacletProofObligationInput +name=seqPermExists "; \proof { -(keyLog "0" (keyUser "Julian" ) (keyVersion "80a871ca3bac8bb405ecc216fcb6fa9ef6f8a395")) +(keyLog "0" (keyUser "Wolfram" ) (keyVersion "802791f53995f75600352ac8d6929fd89f529c86")) (autoModeTime "0") @@ -57,13 +57,13 @@ class=de.uka.ilkd.key.taclettranslation.lemma.TacletProofObligationInput (rule "impRight" (formula "1") (newnames "v_iv,f_s1,v_x,f_phi,f_s2")) (rule "notRight" (formula "2")) (rule "notLeft" (formula "2")) -(rule "seqPermDef" (formula "1") (inst "s=s") (inst "iv=iv") (userinteraction)) +(rule "seqPermDef" (formula "1") (inst "iv=iv") (inst "s=s") (userinteraction)) (rule "andLeft" (formula "1")) (rule "exLeft" (formula "2") (inst "sk=s_0") (userinteraction)) (rule "andLeft" (formula "2")) (rule "andLeft" (formula "2")) (rule "seqNPermRange" (formula "3") (inst "iv=iv") (userinteraction)) -(rule "seqNPermDefReplace" (formula "4") (inst "iv=iv") (inst "jv=jv") (userinteraction)) +(rule "seqNPermDefReplace" (formula "4") (inst "jv=jv") (inst "iv=iv") (userinteraction)) (rule "apply_subst_for" (formula "6") (term "1,0,0") (userinteraction)) (rule "apply_subst_for" (formula "6") (term "1,0,1") (userinteraction)) (rule "equiv_right" (formula "6") (userinteraction)) @@ -241,7 +241,79 @@ class=de.uka.ilkd.key.taclettranslation.lemma.TacletProofObligationInput (rule "closeFalse" (formula "1")) ) (branch "Case '<-'" - (builtin "SMTRule") + (rule "exLeft" (formula "1") (inst "sk=v_iv_0") (userinteraction)) + (rule "andLeft" (formula "1") (userinteraction)) + (rule "andLeft" (formula "1") (userinteraction)) + (rule "instAll" (formula "2") (term "0") (ifseqformula "7") (userinteraction)) + (rule "replace_known_left" (formula "2") (term "0,0") (ifseqformula "1") (userinteraction)) + (rule "applyEqRigid" (formula "2") (term "1,1,0") (ifseqformula "6") (userinteraction)) + (rule "replace_known_left" (formula "2") (term "1,0") (ifseqformula "3") (userinteraction)) + (builtin "One Step Simplification" (formula "2")) + (rule "exLeft" (formula "2") (inst "sk=jv_0") (userinteraction)) + (rule "andLeft" (formula "2") (userinteraction)) + (rule "andLeft" (formula "2") (userinteraction)) + (rule "instAll" (formula "4") (term "1,0") (ifseqformula "11") (userinteraction)) + (rule "replace_known_left" (formula "4") (term "1,0") (ifseqformula "3") (userinteraction)) + (rule "replace_known_left" (formula "4") (term "0,0") (ifseqformula "2") (userinteraction)) + (builtin "One Step Simplification" (formula "4")) + (rule "seqGetAlphaCast" (formula "4") (term "1,1") (userinteraction)) + (rule "applyEqReverse" (formula "5") (term "1,1") (ifseqformula "4") (userinteraction)) + (rule "applyEq" (formula "5") (term "0,1,1") (ifseqformula "6") (userinteraction)) + (rule "castDel" (formula "5") (term "1,1") (userinteraction)) + (rule "eqSymm" (formula "5")) + (rule "inEqSimp_ltToLeq" (formula "3")) + (rule "polySimp_mulComm0" (formula "3") (term "1,0,0")) + (rule "polySimp_addComm1" (formula "3") (term "0")) + (rule "inEqSimp_ltToLeq" (formula "14") (term "1,0,0")) + (rule "polySimp_mulComm0" (formula "14") (term "1,0,0,1,0,0")) + (rule "inEqSimp_commuteLeq" (formula "2")) + (rule "inEqSimp_commuteLeq" (formula "14") (term "0,0,0")) + (rule "applyEq" (formula "3") (term "0,1,0") (ifseqformula "10")) + (rule "applyEq" (formula "8") (term "0") (ifseqformula "5")) + (rule "inEqSimp_sepPosMonomial0" (formula "14") (term "1,0,0")) + (rule "polySimp_mulComm0" (formula "14") (term "1,1,0,0")) + (rule "polySimp_rightDist" (formula "14") (term "1,1,0,0")) + (rule "mul_literals" (formula "14") (term "0,1,1,0,0")) + (rule "polySimp_mulLiterals" (formula "14") (term "1,1,1,0,0")) + (rule "polySimp_elimOne" (formula "14") (term "1,1,1,0,0")) + (rule "inEqSimp_sepNegMonomial0" (formula "3")) + (rule "polySimp_mulLiterals" (formula "3") (term "0")) + (rule "polySimp_elimOne" (formula "3") (term "0")) + (rule "nnf_ex2all" (formula "14")) + (rule "nnf_notAnd" (formula "1") (term "0")) + (rule "nnf_notAnd" (formula "1") (term "0,0")) + (rule "inEqSimp_notLeq" (formula "1") (term "1,0,0")) + (rule "polySimp_rightDist" (formula "1") (term "1,0,0,1,0,0")) + (rule "mul_literals" (formula "1") (term "0,1,0,0,1,0,0")) + (rule "polySimp_addAssoc" (formula "1") (term "0,0,1,0,0")) + (rule "add_literals" (formula "1") (term "0,0,0,1,0,0")) + (rule "add_zero_left" (formula "1") (term "0,0,1,0,0")) + (rule "inEqSimp_sepPosMonomial1" (formula "1") (term "1,0,0")) + (rule "polySimp_mulLiterals" (formula "1") (term "1,1,0,0")) + (rule "polySimp_elimOne" (formula "1") (term "1,1,0,0")) + (rule "inEqSimp_notGeq" (formula "1") (term "0,0,0")) + (rule "times_zero_1" (formula "1") (term "1,0,0,0,0,0")) + (rule "add_literals" (formula "1") (term "0,0,0,0,0")) + (rule "inEqSimp_sepPosMonomial0" (formula "1") (term "0,0,0")) + (rule "mul_literals" (formula "1") (term "1,0,0,0")) + (rule "commute_or_2" (formula "1") (term "0")) + (rule "commute_or" (formula "1") (term "0,0")) + (rule "allLeft" (formula "1") (inst "t=jv_0")) + (rule "replace_known_left" (formula "1") (term "0,0,0") (ifseqformula "10")) + (builtin "One Step Simplification" (formula "1")) + (rule "inEqSimp_commuteGeq" (formula "1") (term "1")) + (rule "inEqSimp_contradInEq1" (formula "1") (term "1") (ifseqformula "5")) + (rule "inEqSimp_homoInEq1" (formula "1") (term "0,1")) + (rule "polySimp_pullOutFactor1b" (formula "1") (term "0,0,1")) + (rule "add_literals" (formula "1") (term "1,1,0,0,1")) + (rule "times_zero_1" (formula "1") (term "1,0,0,1")) + (rule "add_zero_right" (formula "1") (term "0,0,1")) + (rule "leq_literals" (formula "1") (term "0,1")) + (builtin "One Step Simplification" (formula "1")) + (rule "inEqSimp_contradInEq0" (formula "4") (ifseqformula "1")) + (rule "qeq_literals" (formula "4") (term "0")) + (builtin "One Step Simplification" (formula "4")) + (rule "closeFalse" (formula "4")) ) ) } diff --git a/key.core/tacletProofs/seqPerm/Taclet_seqPermForall.proof b/key.core/tacletProofs/seqPerm/Taclet_seqPermForall.proof index 152f8f0a07f..0e35eda800d 100644 --- a/key.core/tacletProofs/seqPerm/Taclet_seqPermForall.proof +++ b/key.core/tacletProofs/seqPerm/Taclet_seqPermForall.proof @@ -2,54 +2,57 @@ \settings { "#Proof-Settings-Config-File -#Wed Apr 12 13:30:00 CEST 2023 -[Labels]UseOriginLabels=true -[StrategyProperty]QUERYAXIOM_OPTIONS_KEY=QUERYAXIOM_OFF -[SMTSettings]invariantForall=false -[Strategy]ActiveStrategy=JavaCardDLStrategy -[StrategyProperty]USER_TACLETS_OPTIONS_KEY1=USER_TACLETS_OFF -[StrategyProperty]QUANTIFIERS_OPTIONS_KEY=QUANTIFIERS_NON_SPLITTING_WITH_PROGS -[StrategyProperty]USER_TACLETS_OPTIONS_KEY2=USER_TACLETS_OFF +#Wed Aug 02 14:34:25 CEST 2023 [Choice]DefaultChoices=JavaCard-JavaCard\\:off, Strings-Strings\\:on, assertions-assertions\\:safe, bigint-bigint\\:on, floatRules-floatRules\\:strictfpOnly, initialisation-initialisation\\:disableStaticInitialisation, intRules-intRules\\:arithmeticSemanticsIgnoringOF, integerSimplificationRules-integerSimplificationRules\\:full, javaLoopTreatment-javaLoopTreatment\\:efficient, mergeGenerateIsWeakeningGoal-mergeGenerateIsWeakeningGoal\\:off, methodExpansion-methodExpansion\\:modularOnly, modelFields-modelFields\\:treatAsAxiom, moreSeqRules-moreSeqRules\\:on, permissions-permissions\\:off, programRules-programRules\\:Java, reach-reach\\:on, runtimeExceptions-runtimeExceptions\\:ban, sequences-sequences\\:on, wdChecks-wdChecks\\:off, wdOperator-wdOperator\\:L -[StrategyProperty]LOOP_OPTIONS_KEY=LOOP_INVARIANT -[StrategyProperty]INF_FLOW_CHECK_PROPERTY=INF_FLOW_CHECK_FALSE +[Labels]UseOriginLabels=true +[NewSMT]Axiomatisations=false +[NewSMT]Presburger=false +[NewSMT]sqrtSMTTranslation=SMT +[SMTSettings]SelectedTaclets= [SMTSettings]UseBuiltUniqueness=false [SMTSettings]explicitTypeHierarchy=false [SMTSettings]instantiateHierarchyAssumptions=true -[StrategyProperty]NON_LIN_ARITH_OPTIONS_KEY=NON_LIN_ARITH_NONE -[SMTSettings]SelectedTaclets= -[StrategyProperty]DEP_OPTIONS_KEY=DEP_ON -[StrategyProperty]AUTO_INDUCTION_OPTIONS_KEY=AUTO_INDUCTION_OFF -[Strategy]MaximumNumberOfAutomaticApplications=10000 -[StrategyProperty]STOPMODE_OPTIONS_KEY=STOPMODE_DEFAULT -[StrategyProperty]CLASS_AXIOM_OPTIONS_KEY=CLASS_AXIOM_FREE +[SMTSettings]integersMaximum=2147483645 +[SMTSettings]integersMinimum=-2147483645 +[SMTSettings]invariantForall=false +[SMTSettings]maxGenericSorts=2 [SMTSettings]useConstantsForBigOrSmallIntegers=true -[StrategyProperty]MPS_OPTIONS_KEY=MPS_MERGE -[StrategyProperty]SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OPTIONS_KEY=SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OFF -[Strategy]Timeout=-1 -[StrategyProperty]SYMBOLIC_EXECUTION_ALIAS_CHECK_OPTIONS_KEY=SYMBOLIC_EXECUTION_ALIAS_CHECK_NEVER -[StrategyProperty]QUERY_NEW_OPTIONS_KEY=QUERY_RESTRICTED [SMTSettings]useUninterpretedMultiplication=true +[StrategyProperty]AUTO_INDUCTION_OPTIONS_KEY=AUTO_INDUCTION_OFF [StrategyProperty]BLOCK_OPTIONS_KEY=BLOCK_CONTRACT_INTERNAL +[StrategyProperty]CLASS_AXIOM_OPTIONS_KEY=CLASS_AXIOM_FREE +[StrategyProperty]DEP_OPTIONS_KEY=DEP_ON +[StrategyProperty]INF_FLOW_CHECK_PROPERTY=INF_FLOW_CHECK_FALSE +[StrategyProperty]LOOP_OPTIONS_KEY=LOOP_INVARIANT [StrategyProperty]METHOD_OPTIONS_KEY=METHOD_CONTRACT -[StrategyProperty]USER_TACLETS_OPTIONS_KEY3=USER_TACLETS_OFF -[SMTSettings]maxGenericSorts=2 +[StrategyProperty]MPS_OPTIONS_KEY=MPS_MERGE +[StrategyProperty]NON_LIN_ARITH_OPTIONS_KEY=NON_LIN_ARITH_DEF_OPS [StrategyProperty]OSS_OPTIONS_KEY=OSS_ON +[StrategyProperty]QUANTIFIERS_OPTIONS_KEY=QUANTIFIERS_NON_SPLITTING_WITH_PROGS +[StrategyProperty]QUERYAXIOM_OPTIONS_KEY=QUERYAXIOM_OFF +[StrategyProperty]QUERY_NEW_OPTIONS_KEY=QUERY_RESTRICTED [StrategyProperty]SPLITTING_OPTIONS_KEY=SPLITTING_DELAYED -[SMTSettings]integersMinimum=-2147483645 +[StrategyProperty]STOPMODE_OPTIONS_KEY=STOPMODE_DEFAULT +[StrategyProperty]SYMBOLIC_EXECUTION_ALIAS_CHECK_OPTIONS_KEY=SYMBOLIC_EXECUTION_ALIAS_CHECK_NEVER +[StrategyProperty]SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OPTIONS_KEY=SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OFF +[StrategyProperty]USER_TACLETS_OPTIONS_KEY1=USER_TACLETS_OFF +[StrategyProperty]USER_TACLETS_OPTIONS_KEY2=USER_TACLETS_OFF +[StrategyProperty]USER_TACLETS_OPTIONS_KEY3=USER_TACLETS_OFF [StrategyProperty]VBT_PHASE=VBT_SYM_EX -[SMTSettings]integersMaximum=2147483645 +[Strategy]ActiveStrategy=JavaCardDLStrategy +[Strategy]MaximumNumberOfAutomaticApplications=10000 +[Strategy]Timeout=-1 " } \proofObligation "#Proof Obligation Settings -#Wed Apr 12 13:30:00 CEST 2023 -name=seqPermForall +#Wed Aug 02 14:34:25 CEST 2023 class=de.uka.ilkd.key.taclettranslation.lemma.TacletProofObligationInput +name=seqPermForall "; \proof { -(keyLog "0" (keyUser "Julian" ) (keyVersion "80a871ca3bac8bb405ecc216fcb6fa9ef6f8a395")) +(keyLog "0" (keyUser "Wolfram" ) (keyVersion "802791f53995f75600352ac8d6929fd89f529c86")) (autoModeTime "0") @@ -65,7 +68,114 @@ class=de.uka.ilkd.key.taclettranslation.lemma.TacletProofObligationInput (branch "Case '->'" (rule "exLeft" (formula "3") (inst "sk=s_0") (userinteraction)) (rule "seqNPermDefReplace" (formula "3") (term "1,0") (inst "jv=jv") (inst "iv=iv") (userinteraction)) - (builtin "SMTRule") + (rule "andLeft" (formula "3") (userinteraction)) + (rule "andLeft" (formula "3") (userinteraction)) + (rule "allRight" (formula "6") (inst "sk=v_iv_0") (userinteraction)) + (rule "impRight" (formula "6") (userinteraction)) + (rule "andLeft" (formula "1") (userinteraction)) + (rule "instAll" (formula "2") (term "0") (ifseqformula "6") (userinteraction)) + (rule "impLeft" (formula "2") (userinteraction)) + (branch "Case 1" + (rule "replace_known_left" (formula "8") (term "0") (ifseqformula "1")) + (builtin "One Step Simplification" (formula "8")) + (rule "inEqSimp_ltRight" (formula "8")) + (rule "polySimp_mulComm0" (formula "1") (term "0,0")) + (rule "polySimp_addComm0" (formula "1") (term "0")) + (rule "inEqSimp_ltToLeq" (formula "3")) + (rule "polySimp_mulComm0" (formula "3") (term "1,0,0")) + (rule "polySimp_addComm1" (formula "3") (term "0")) + (rule "applyEqRigid" (formula "1") (term "0,1,0") (ifseqformula "6")) + (rule "inEqSimp_sepNegMonomial0" (formula "3")) + (rule "polySimp_mulLiterals" (formula "3") (term "0")) + (rule "polySimp_elimOne" (formula "3") (term "0")) + (rule "inEqSimp_sepNegMonomial1" (formula "1")) + (rule "polySimp_mulLiterals" (formula "1") (term "0")) + (rule "polySimp_elimOne" (formula "1") (term "0")) + (rule "inEqSimp_contradInEq0" (formula "3") (ifseqformula "1")) + (rule "andLeft" (formula "3")) + (rule "inEqSimp_homoInEq1" (formula "3")) + (rule "polySimp_pullOutFactor1b" (formula "3") (term "0")) + (rule "add_literals" (formula "3") (term "1,1,0")) + (rule "times_zero_1" (formula "3") (term "1,0")) + (rule "add_zero_right" (formula "3") (term "0")) + (rule "leq_literals" (formula "3")) + (rule "closeFalse" (formula "3")) + ) + (branch "Case 2" + (rule "exLeft" (formula "2") (inst "sk=jv_0") (userinteraction)) + (rule "andLeft" (formula "2") (userinteraction)) + (rule "andLeft" (formula "2") (userinteraction)) + (rule "instAll" (formula "4") (term "1,0") (ifseqformula "10") (userinteraction)) + (rule "replace_known_left" (formula "4") (term "0,0") (ifseqformula "2") (userinteraction)) + (rule "replace_known_left" (formula "4") (term "1,0") (ifseqformula "3") (userinteraction)) + (builtin "One Step Simplification" (formula "4")) + (rule "eqTermCut" (formula "4") (term "1,1") (inst "s=v_iv_0") (userinteraction)) + (branch "Assume (int)s_0[jv_0] = v_iv_0" + (rule "eqSymm" (formula "5")) + (rule "inEqSimp_ltToLeq" (formula "8") (term "1,0,0")) + (rule "polySimp_mulComm0" (formula "8") (term "1,0,0,1,0,0")) + (rule "inEqSimp_ltToLeq" (formula "3")) + (rule "polySimp_mulComm0" (formula "3") (term "1,0,0")) + (rule "polySimp_addComm1" (formula "3") (term "0")) + (rule "inEqSimp_commuteLeq" (formula "8") (term "0,0,0")) + (rule "inEqSimp_commuteLeq" (formula "2")) + (rule "applyEqRigid" (formula "5") (term "1,0") (ifseqformula "4")) + (rule "applyEq" (formula "3") (term "0,1,0") (ifseqformula "10")) + (rule "applyEq" (formula "13") (term "0") (ifseqformula "5")) + (rule "inEqSimp_sepPosMonomial0" (formula "8") (term "1,0,0")) + (rule "polySimp_mulComm0" (formula "8") (term "1,1,0,0")) + (rule "polySimp_rightDist" (formula "8") (term "1,1,0,0")) + (rule "polySimp_mulLiterals" (formula "8") (term "1,1,1,0,0")) + (rule "mul_literals" (formula "8") (term "0,1,1,0,0")) + (rule "polySimp_elimOne" (formula "8") (term "1,1,1,0,0")) + (rule "inEqSimp_sepNegMonomial0" (formula "3")) + (rule "polySimp_mulLiterals" (formula "3") (term "0")) + (rule "polySimp_elimOne" (formula "3") (term "0")) + (rule "nnf_imp2or" (formula "8") (term "0")) + (rule "nnf_notAnd" (formula "8") (term "0,0")) + (rule "inEqSimp_notLeq" (formula "8") (term "1,0,0")) + (rule "polySimp_rightDist" (formula "8") (term "1,0,0,1,0,0")) + (rule "mul_literals" (formula "8") (term "0,1,0,0,1,0,0")) + (rule "polySimp_addAssoc" (formula "8") (term "0,0,1,0,0")) + (rule "add_literals" (formula "8") (term "0,0,0,1,0,0")) + (rule "add_zero_left" (formula "8") (term "0,0,1,0,0")) + (rule "inEqSimp_sepPosMonomial1" (formula "8") (term "1,0,0")) + (rule "polySimp_mulLiterals" (formula "8") (term "1,1,0,0")) + (rule "polySimp_elimOne" (formula "8") (term "1,1,0,0")) + (rule "inEqSimp_notGeq" (formula "8") (term "0,0,0")) + (rule "mul_literals" (formula "8") (term "1,0,0,0,0,0")) + (rule "add_zero_right" (formula "8") (term "0,0,0,0,0")) + (rule "inEqSimp_sepPosMonomial0" (formula "8") (term "0,0,0")) + (rule "mul_literals" (formula "8") (term "1,0,0,0")) + (rule "commute_or_2" (formula "8") (term "0")) + (rule "commute_or" (formula "8") (term "0,0")) + (rule "allLeft" (formula "8") (inst "t=jv_0")) + (rule "replace_known_right" (formula "8") (term "0,0") (ifseqformula "14")) + (builtin "One Step Simplification" (formula "8")) + (rule "inEqSimp_commuteGeq" (formula "8") (term "1")) + (rule "inEqSimp_contradInEq1" (formula "8") (term "0") (ifseqformula "2")) + (rule "qeq_literals" (formula "8") (term "0,0")) + (builtin "One Step Simplification" (formula "8")) + (rule "inEqSimp_contradInEq0" (formula "3") (ifseqformula "8")) + (rule "andLeft" (formula "3")) + (rule "inEqSimp_homoInEq1" (formula "3")) + (rule "polySimp_pullOutFactor1b" (formula "3") (term "0")) + (rule "add_literals" (formula "3") (term "1,1,0")) + (rule "times_zero_1" (formula "3") (term "1,0")) + (rule "add_zero_right" (formula "3") (term "0")) + (rule "leq_literals" (formula "3")) + (rule "closeFalse" (formula "3")) + ) + (branch "Assume (int)s_0[jv_0] != v_iv_0" + (rule "notLeft" (formula "4") (userinteraction)) + (rule "seqGetAlphaCast" (formula "12") (term "0") (userinteraction)) + (rule "applyEqReverse" (formula "13") (term "0") (ifseqformula "1") (userinteraction)) + (rule "applyEq" (formula "13") (term "0,0") (ifseqformula "6") (userinteraction)) + (rule "castDel" (formula "13") (term "0") (userinteraction)) + (builtin "One Step Simplification" (formula "13")) + (rule "closeTrue" (formula "13") (userinteraction)) + ) + ) ) (branch "Case '<-'" (rule "exLeft" (formula "3") (inst "sk=s_0") (userinteraction)) From ce9953f7190168f609c1f4b9db1979915bc6a0dd Mon Sep 17 00:00:00 2001 From: Wolfram Date: Wed, 2 Aug 2023 15:03:42 +0200 Subject: [PATCH 74/95] fix for small UI bug where checkbox was disabled instead of deselected --- .../de/uka/ilkd/key/gui/smt/settings/SMTSettingsProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/settings/SMTSettingsProvider.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/settings/SMTSettingsProvider.java index 4a81638267b..f33e31d840e 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/settings/SMTSettingsProvider.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/smt/settings/SMTSettingsProvider.java @@ -206,6 +206,6 @@ public void setSmtSettings(ProofIndependentSMTSettings settings) { // Timeout can have up to 3 decimal places in seconds to still be an integer in ms. timeoutField.setValue(((double) this.settings.getTimeout()) / 1000); maxProcesses.setValue(this.settings.getMaxConcurrentProcesses()); - enableOnLoad.setEnabled(this.settings.isEnableOnLoad()); + enableOnLoad.setSelected(this.settings.isEnableOnLoad()); } } From 14b9d811a6970b83af9e764827fa7579f33002a7 Mon Sep 17 00:00:00 2001 From: Wolfram Date: Wed, 2 Aug 2023 17:24:42 +0200 Subject: [PATCH 75/95] fix for #3209: More robust saving of proof management report via GUI dialog --- .../de/uka/ilkd/key/gui/KeYFileChooser.java | 5 ++ .../proofmanagement/CheckConfigDialog.java | 57 +++++++++++++++---- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/KeYFileChooser.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/KeYFileChooser.java index db963aaff85..f072da01c4a 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/KeYFileChooser.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/KeYFileChooser.java @@ -49,6 +49,10 @@ public String getDescription() { public static final FileFilter STATISTICS_FILTER = new FileNameExtensionFilter("proof statistics files (.csv, .html)", "csv", "html"); + /** file filter for proof management reports (*.html) */ + public static final FileFilter PROOF_MANAGEMENT_REPORT_FILTER = + new FileNameExtensionFilter("proof management reports (.html)", "html"); + /** The Constant for the filter for dot files. */ public static final FileFilter DOT_FILTER = new FileNameExtensionFilter( "dot graphviz files (.dot)", "dot"); @@ -102,6 +106,7 @@ private KeYFileChooser(File initDir) { // for simplicity, we always show all filters addChoosableFileFilter(DEFAULT_FILTER); addChoosableFileFilter(STATISTICS_FILTER); + addChoosableFileFilter(PROOF_MANAGEMENT_REPORT_FILTER); addChoosableFileFilter(JAVA_FILTER); addChoosableFileFilter(COMPRESSED_FILTER); addChoosableFileFilter(INTERACTION_LOG_FILTER); diff --git a/keyext.proofmanagement/src/main/java/org/key_project/proofmanagement/CheckConfigDialog.java b/keyext.proofmanagement/src/main/java/org/key_project/proofmanagement/CheckConfigDialog.java index 1a078b2a1a9..ff8f7e077c6 100644 --- a/keyext.proofmanagement/src/main/java/org/key_project/proofmanagement/CheckConfigDialog.java +++ b/keyext.proofmanagement/src/main/java/org/key_project/proofmanagement/CheckConfigDialog.java @@ -2,6 +2,7 @@ import java.awt.*; import java.awt.event.*; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import javax.swing.*; @@ -29,6 +30,7 @@ class CheckConfigDialog extends JDialog { private final JButton cancelButton = new JButton("Cancel"); private final JTextField bundleFileField = new JTextField(); + private final JCheckBox reportCheck = new JCheckBox("Generate Report"); private final JTextField reportFileField = new JTextField(); private final Component glassPane = new BlockingGlassPane(); @@ -38,8 +40,15 @@ class CheckConfigDialog extends JDialog { private class ProofManagementCheckWorker extends SwingWorker { @Override protected Void doInBackground() throws Exception { - Path reportPath = reportFileField.getText().isEmpty() ? null - : Paths.get(reportFileField.getText(), "report.html"); + Path reportPath = null; + if (reportCheck.isSelected()) { + reportPath = Paths.get(reportFileField.getText()); + if (Files.isDirectory(reportPath)) { + // add default name + reportPath = reportPath.resolve("report.html"); + } + } + Main.check(missingProofsCheck.isSelected(), settingsCheck.isSelected(), replayCheck.isSelected(), @@ -47,6 +56,7 @@ protected Void doInBackground() throws Exception { Paths.get(bundleFileField.getText()), reportPath); if (reportPath != null) { + // automatically open the report in browser Desktop.getDesktop().open(reportPath.toFile()); } return null; @@ -165,11 +175,12 @@ public CheckConfigDialog(Frame parent, String title, boolean modal) { Box checkersBox = Box.createHorizontalBox(); checkersBox.setBorder(BorderFactory.createTitledBorder("Available Checkers")); - // default: run all checks + // default: run all checks and generate html report missingProofsCheck.setSelected(true); settingsCheck.setSelected(true); replayCheck.setSelected(true); dependencyCheck.setSelected(true); + reportCheck.setSelected(true); checkersBoxInner.add(missingProofsCheck); checkersBoxInner.add(settingsCheck); @@ -205,27 +216,51 @@ public CheckConfigDialog(Frame parent, String title, boolean modal) { bundleBox.add(chooseBundleButton); centerBox.add(bundleBox); - Box reportBox = Box.createHorizontalBox(); - reportBox.setBorder(BorderFactory.createTitledBorder("Report location")); + Box reportBox = Box.createVerticalBox(); + reportBox.setBorder(BorderFactory.createTitledBorder("HTML report")); + + Box innerReportBox = Box.createHorizontalBox(); reportFileField.setMaximumSize(new Dimension(Integer.MAX_VALUE, buttonDim.height)); reportFileField.setEditable(false); - reportBox.add(reportFileField); - reportBox.add(Box.createHorizontalStrut(5)); + innerReportBox.add(reportFileField); + innerReportBox.add(Box.createHorizontalStrut(5)); JButton chooseReportLocationButton = new JButton("Choose report location..."); + chooseReportLocationButton.setToolTipText("Choose the location or file for the HTML report. " + + "By default, the filename will be \"report.html\"."); + reportCheck.addItemListener(e -> { + if (e.getStateChange() == ItemEvent.SELECTED) { + chooseReportLocationButton.setEnabled(true); + reportFileField.setEnabled(true); + } else if (e.getStateChange() == ItemEvent.DESELECTED) { + chooseReportLocationButton.setEnabled(false); + reportFileField.setEnabled(false); + } + }); chooseReportLocationButton.addActionListener(e -> { - KeYFileChooser fc = KeYFileChooser.getFileChooser("Choose file"); - fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + KeYFileChooser fc = KeYFileChooser.getFileChooser("Choose file or directory"); + fc.setFileFilter(KeYFileChooser.PROOF_MANAGEMENT_REPORT_FILTER); + fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); if (fc.showOpenDialog(CheckConfigDialog.this) == JFileChooser.APPROVE_OPTION) { reportFileField.setText(fc.getSelectedFile().toString()); } }); chooseReportLocationButton.setPreferredSize(buttonDim); chooseReportLocationButton.setMinimumSize(buttonDim); - reportBox.add(chooseReportLocationButton); + innerReportBox.add(chooseReportLocationButton); + Box reportCheckBoxAlignmentBox = Box.createHorizontalBox(); + reportCheckBoxAlignmentBox.add(reportCheck); + reportCheckBoxAlignmentBox.add(Box.createHorizontalGlue()); + reportBox.add(reportCheckBoxAlignmentBox); + reportBox.add(innerReportBox); centerBox.add(reportBox); runButton.addActionListener(e -> { + if (bundleFileField.getText().isEmpty()) { + JOptionPane.showMessageDialog(this, "Please choose a proof bundle to check!", + "Error", JOptionPane.ERROR_MESSAGE); + return; + } setGlassPane(glassPane); glassPane.setVisible(true); runButton.setText("Stop"); @@ -245,7 +280,7 @@ public CheckConfigDialog(Frame parent, String title, boolean modal) { add(buttonsBox, BorderLayout.SOUTH); buttonsBox.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); - setMinimumSize(new Dimension(400, 200)); + setMinimumSize(new Dimension(400, 320)); setPreferredSize(new Dimension(600, 400)); runButton.setEnabled(true); From 0013f6905bec83ee9a3aead24cce9231d4a22148 Mon Sep 17 00:00:00 2001 From: Wolfram Date: Wed, 2 Aug 2023 17:26:31 +0200 Subject: [PATCH 76/95] formatting --- .../src/main/java/de/uka/ilkd/key/gui/KeYFileChooser.java | 2 +- .../org/key_project/proofmanagement/CheckConfigDialog.java | 7 ++++--- .../java/org/key_project/slicing/SlicingProofReplayer.java | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/KeYFileChooser.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/KeYFileChooser.java index f072da01c4a..043bb8af714 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/KeYFileChooser.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/KeYFileChooser.java @@ -51,7 +51,7 @@ public String getDescription() { /** file filter for proof management reports (*.html) */ public static final FileFilter PROOF_MANAGEMENT_REPORT_FILTER = - new FileNameExtensionFilter("proof management reports (.html)", "html"); + new FileNameExtensionFilter("proof management reports (.html)", "html"); /** The Constant for the filter for dot files. */ public static final FileFilter DOT_FILTER = new FileNameExtensionFilter( diff --git a/keyext.proofmanagement/src/main/java/org/key_project/proofmanagement/CheckConfigDialog.java b/keyext.proofmanagement/src/main/java/org/key_project/proofmanagement/CheckConfigDialog.java index ff8f7e077c6..ddb5d526caf 100644 --- a/keyext.proofmanagement/src/main/java/org/key_project/proofmanagement/CheckConfigDialog.java +++ b/keyext.proofmanagement/src/main/java/org/key_project/proofmanagement/CheckConfigDialog.java @@ -225,8 +225,9 @@ public CheckConfigDialog(Frame parent, String title, boolean modal) { innerReportBox.add(reportFileField); innerReportBox.add(Box.createHorizontalStrut(5)); JButton chooseReportLocationButton = new JButton("Choose report location..."); - chooseReportLocationButton.setToolTipText("Choose the location or file for the HTML report. " + - "By default, the filename will be \"report.html\"."); + chooseReportLocationButton + .setToolTipText("Choose the location or file for the HTML report. " + + "By default, the filename will be \"report.html\"."); reportCheck.addItemListener(e -> { if (e.getStateChange() == ItemEvent.SELECTED) { chooseReportLocationButton.setEnabled(true); @@ -258,7 +259,7 @@ public CheckConfigDialog(Frame parent, String title, boolean modal) { runButton.addActionListener(e -> { if (bundleFileField.getText().isEmpty()) { JOptionPane.showMessageDialog(this, "Please choose a proof bundle to check!", - "Error", JOptionPane.ERROR_MESSAGE); + "Error", JOptionPane.ERROR_MESSAGE); return; } setGlassPane(glassPane); diff --git a/keyext.slicing/src/main/java/org/key_project/slicing/SlicingProofReplayer.java b/keyext.slicing/src/main/java/org/key_project/slicing/SlicingProofReplayer.java index c18da0766ca..6109d4e37c7 100644 --- a/keyext.slicing/src/main/java/org/key_project/slicing/SlicingProofReplayer.java +++ b/keyext.slicing/src/main/java/org/key_project/slicing/SlicingProofReplayer.java @@ -228,7 +228,8 @@ private File saveProof(Proof currentProof, Proof proof) throws IOException { filename = MiscTools.removeFileExtension(currentProof.getProofFile().getName()); } else { filename = MiscTools.removeFileExtension(currentProof.name().toString()); - // make sure that no special chars are in name (e.g., "Taclet: seqPerm ..." for taclet proofs) + // make sure that no special chars are in name (e.g., "Taclet: seqPerm ..." for taclet + // proofs) filename = MiscTools.toValidFileName(filename); } int prevSlice = filename.indexOf("_slice"); From e1e578a06c75ea59a7833cf93dbb1aae2a3837d7 Mon Sep 17 00:00:00 2001 From: Wolfram Date: Wed, 2 Aug 2023 22:38:21 +0200 Subject: [PATCH 77/95] hide 'pressed' in keyboard settings for better readability --- .../main/java/de/uka/ilkd/key/gui/actions/KeyAction.java | 8 ++------ .../de/uka/ilkd/key/gui/actions/MainWindowAction.java | 2 ++ .../uka/ilkd/key/gui/keyshortcuts/ShortcutSettings.java | 5 +++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/KeyAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/KeyAction.java index 9f38214082f..44212747b8f 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/KeyAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/KeyAction.java @@ -10,6 +10,8 @@ import de.uka.ilkd.key.gui.extension.impl.KeYGuiExtensionFacade; import de.uka.ilkd.key.gui.keyshortcuts.KeyStrokeManager; +import static de.uka.ilkd.key.gui.keyshortcuts.KeyStrokeManager.SHORTCUT_KEY_MASK; + /** * Common class for all "actions" (menu entries / toolbar buttons) the user can trigger. * If you want the keyboard shortcuts ({@link #setAcceleratorKey(KeyStroke)} to work, the action @@ -57,12 +59,6 @@ public abstract class KeyAction extends AbstractAction { */ public static final String LOCAL_ACCELERATOR = "LOCAL_ACCELERATOR"; - - /** - * @see KeyStrokeManager#SHORTCUT_KEY_MASK - */ - protected static final int SHORTCUT_KEY_MASK = KeyStrokeManager.SHORTCUT_KEY_MASK; - public String getName() { return (String) getValue(NAME); } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/MainWindowAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/MainWindowAction.java index 40206950333..009bc1f8c79 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/MainWindowAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/MainWindowAction.java @@ -10,6 +10,8 @@ import de.uka.ilkd.key.gui.MainWindow; import de.uka.ilkd.key.gui.keyshortcuts.KeyStrokeManager; +import static de.uka.ilkd.key.gui.keyshortcuts.KeyStrokeManager.SHORTCUT_KEY_MASK; + /** * {@link KeyAction} extended to automatically override the accelerator key after the default is * set using {@link #setAcceleratorKey(KeyStroke)} / {@link #setAcceleratorLetter(int)} using the diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/ShortcutSettings.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/ShortcutSettings.java index 3aa1ceca0f2..89e7194dd33 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/ShortcutSettings.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/ShortcutSettings.java @@ -48,7 +48,7 @@ public JComponent getPanel(MainWindow window) { p.keySet().stream().sorted().map(Object::toString).collect(Collectors.toList()); List shortcuts = - actionNames.stream().map(p::getProperty).collect(Collectors.toList()); + actionNames.stream().map(p::getProperty).map(s -> s.replace("pressed ", "")).collect(Collectors.toList()); List actions = actionNames.stream().map(KeyStrokeManager::findAction).collect(Collectors.toList()); @@ -81,7 +81,8 @@ public void keyPressed(KeyEvent e) { } KeyStroke ks = KeyStroke.getKeyStrokeForEvent(e); - txtCaptureShortcut.setText(ks.toString()); + String shortened = ks.toString().replace("pressed ", ""); + txtCaptureShortcut.setText(shortened); boolean shortcutComplete = ks.getModifiers() > 0 && ks.getKeyCode() != KeyEvent.VK_UNDEFINED From 806f819e2b02748da335cf9b3538988467ebe521 Mon Sep 17 00:00:00 2001 From: Wolfram Pfeifer Date: Fri, 4 Aug 2023 11:24:21 +0200 Subject: [PATCH 78/95] fixed positioning of some dialogs --- .../main/java/de/uka/ilkd/key/gui/InvariantConfigurator.java | 4 ++-- key.ui/src/main/java/de/uka/ilkd/key/gui/LogView.java | 1 + .../de/uka/ilkd/key/gui/actions/ShowActiveSettingsAction.java | 2 +- .../ilkd/key/gui/lemmatagenerator/LemmaSelectionDialog.java | 4 +--- .../de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java | 4 +++- .../main/java/de/uka/ilkd/key/gui/utilities/StdDialog.java | 2 +- .../java/org/key_project/slicing/ui/RuleStatisticsDialog.java | 2 +- 7 files changed, 10 insertions(+), 9 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/InvariantConfigurator.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/InvariantConfigurator.java index 13d567fae75..acfc70eb1dc 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/InvariantConfigurator.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/InvariantConfigurator.java @@ -190,9 +190,9 @@ public InvariantDialog() throws RuleAbortException { parser.setAbbrevMap(getAbbrevMap()); parse(); - this.pack(); + pack(); setLocationRelativeTo(getOwner()); - this.setVisible(true); + setVisible(true); } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/LogView.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/LogView.java index e71764adce1..45a33aca8fd 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/LogView.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/LogView.java @@ -116,6 +116,7 @@ public void windowDeiconified(WindowEvent e) { }); dialog.setContentPane(ui); dialog.setSize(800, 600); + dialog.setLocationRelativeTo(MainWindow.getInstance()); dialog.setVisible(true); } } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ShowActiveSettingsAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ShowActiveSettingsAction.java index 550867295e6..261b75943ce 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ShowActiveSettingsAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ShowActiveSettingsAction.java @@ -72,10 +72,10 @@ public ViewSettingsDialog(TreeModel model, JComponent startComponent) { this.getOptionTree().getParent().setMinimumSize(getOptionTree().getPreferredSize()); this.getContentPane().setPreferredSize(computePreferredSize(model)); - this.setLocationRelativeTo(MainWindow.getInstance()); this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); setIconImage(IconFactory.keyLogo()); this.pack(); + this.setLocationRelativeTo(MainWindow.getInstance()); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/lemmatagenerator/LemmaSelectionDialog.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/lemmatagenerator/LemmaSelectionDialog.java index e1a26c6bf8c..57fc568692d 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/lemmatagenerator/LemmaSelectionDialog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/lemmatagenerator/LemmaSelectionDialog.java @@ -48,10 +48,8 @@ public LemmaSelectionDialog() { this.getContentPane().add(getContentPanel()); this.getContentPane().add(Box.createHorizontalStrut(10)); this.setMinimumSize(new Dimension(300, 300)); - this.setLocationRelativeTo(MainWindow.getInstance()); - this.pack(); - + this.setLocationRelativeTo(MainWindow.getInstance()); } public ImmutableSet showModal(List taclets) { diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java index 3077e23a9c8..90217f12b04 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java @@ -317,7 +317,9 @@ public void actionPerformed(ActionEvent e) { referenceSearchButton.updateState(nodes.get(0).proof()); } if (!mismatches.isEmpty()) { - JOptionPane.showMessageDialog((JComponent) e.getSource(), + // since e.getSource() is the popup menu, it is better to use the MainWindow + // instance here as a parent + JOptionPane.showMessageDialog(MainWindow.getInstance(), "No matching branch found for node(s) " + Arrays.toString(mismatches.toArray()), "Proof Caching error", JOptionPane.WARNING_MESSAGE); } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/utilities/StdDialog.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/utilities/StdDialog.java index 4f5d0a309a9..90d8782af1e 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/utilities/StdDialog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/utilities/StdDialog.java @@ -34,7 +34,6 @@ public StdDialog(String title, int strut, boolean helpButton) { } public StdDialog(String title, JComponent content, int strut, boolean helpButton) { - this.setLocationRelativeTo(MainWindow.getInstance()); this.setTitle(title); this.setModal(true); // content.setMaximumSize(new Dimension(Integer.MAX_VALUE,Integer.MAX_VALUE)); @@ -76,6 +75,7 @@ public void windowClosing(WindowEvent e) { } else { this.pack(); } + this.setLocationRelativeTo(MainWindow.getInstance()); } public void setContent(JComponent content) { diff --git a/keyext.slicing/src/main/java/org/key_project/slicing/ui/RuleStatisticsDialog.java b/keyext.slicing/src/main/java/org/key_project/slicing/ui/RuleStatisticsDialog.java index b1b7172a21e..f13c39ec760 100644 --- a/keyext.slicing/src/main/java/org/key_project/slicing/ui/RuleStatisticsDialog.java +++ b/keyext.slicing/src/main/java/org/key_project/slicing/ui/RuleStatisticsDialog.java @@ -85,13 +85,13 @@ private void createUI(Window window) { + buttonPane.getPreferredSize().height + 100; setSize(w, h); - setLocationRelativeTo(window); statisticsPane.setText(genTable( statistics.sortBy( Comparator.comparing((Quadruple it) -> it.second) .reversed()))); statisticsPane.setCaretPosition(0); + setLocationRelativeTo(window); } /** From 2a6f62a0f3c06d6125b2a73014d701af2384f503 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Fri, 4 Aug 2023 12:20:13 +0200 Subject: [PATCH 79/95] Fix NPE if there is no most recent file Fixes #3238 --- .../de/uka/ilkd/key/gui/RecentFileMenu.java | 5 ++++- .../gui/actions/EditMostRecentFileAction.java | 17 +++++++++++++---- .../gui/actions/OpenMostRecentFileAction.java | 18 ++++++++++++------ 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/RecentFileMenu.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/RecentFileMenu.java index 05eeef2941f..e05b8f8dc14 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/RecentFileMenu.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/RecentFileMenu.java @@ -232,8 +232,11 @@ public final void loadFrom(String filename) { } } + /** + * @return the absolute path to the most recently opened file (maybe null) + */ public String getMostRecent() { - return mostRecentFile.getAbsolutePath(); + return mostRecentFile != null ? mostRecentFile.getAbsolutePath() : null; } /** diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/EditMostRecentFileAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/EditMostRecentFileAction.java index 5e1c4d90649..ac8b4e66454 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/EditMostRecentFileAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/EditMostRecentFileAction.java @@ -5,6 +5,8 @@ import java.io.File; import java.io.IOException; +import de.uka.ilkd.key.core.KeYSelectionEvent; +import de.uka.ilkd.key.core.KeYSelectionListener; import de.uka.ilkd.key.gui.MainWindow; import de.uka.ilkd.key.gui.fonticons.IconFactory; @@ -15,13 +17,11 @@ /** * Opens the last opened file in an editor (well, it tries) */ -public final class EditMostRecentFileAction extends MainWindowAction { +public final class EditMostRecentFileAction extends MainWindowAction + implements KeYSelectionListener { private static final Logger LOGGER = LoggerFactory.getLogger(EditMostRecentFileAction.class); - /** - * - */ private static final long serialVersionUID = -6214327707255790570L; public EditMostRecentFileAction(MainWindow mainWindow) { @@ -31,10 +31,14 @@ public EditMostRecentFileAction(MainWindow mainWindow) { setIcon(IconFactory.editFile(MainWindow.TOOLBAR_ICON_SIZE)); setTooltip("Open the last opened file with the default external editor"); + setEnabled(mainWindow.getRecentFiles() != null + && mainWindow.getRecentFiles().getMostRecent() != null); Desktop desktop = Desktop.getDesktop(); if (!desktop.isSupported(Desktop.Action.EDIT) && !desktop.isSupported(Desktop.Action.OPEN)) { setEnabled(false); + } else { + mainWindow.getMediator().addKeYSelectionListener(this); } lookupAcceleratorKey(); } @@ -55,6 +59,11 @@ public void actionPerformed(ActionEvent e) { } } + @Override + public void selectedProofChanged(KeYSelectionEvent e) { + setEnabled(true); + } + /** *

* The method {@link #workWithFile(File)} of the default instance {@link #getInstance()} is used diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/OpenMostRecentFileAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/OpenMostRecentFileAction.java index 58f400518f7..df5c7aae226 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/OpenMostRecentFileAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/OpenMostRecentFileAction.java @@ -5,6 +5,8 @@ import java.io.File; import java.nio.file.Path; +import de.uka.ilkd.key.core.KeYSelectionEvent; +import de.uka.ilkd.key.core.KeYSelectionListener; import de.uka.ilkd.key.gui.KeYFileChooser; import de.uka.ilkd.key.gui.MainWindow; import de.uka.ilkd.key.gui.ProofSelectionDialog; @@ -13,12 +15,8 @@ /** * Loads the last opened file */ - -public final class OpenMostRecentFileAction extends MainWindowAction { - - /** - * - */ +public final class OpenMostRecentFileAction extends MainWindowAction + implements KeYSelectionListener { private static final long serialVersionUID = 4855372503837208313L; public OpenMostRecentFileAction(MainWindow mainWindow) { @@ -27,6 +25,9 @@ public OpenMostRecentFileAction(MainWindow mainWindow) { setIcon(IconFactory.openMostRecent(MainWindow.TOOLBAR_ICON_SIZE)); setTooltip("Reload last opened file."); setAcceleratorLetter(KeyEvent.VK_R); + setEnabled(mainWindow.getRecentFiles() != null + && mainWindow.getRecentFiles().getMostRecent() != null); + mainWindow.getMediator().addKeYSelectionListener(this); } public void actionPerformed(ActionEvent e) { @@ -50,4 +51,9 @@ public void actionPerformed(ActionEvent e) { } } } + + @Override + public void selectedProofChanged(KeYSelectionEvent e) { + setEnabled(true); + } } From a11b09953734d82cc14a3d4f9493ee3c0b517718 Mon Sep 17 00:00:00 2001 From: Mattias Ulbrich Date: Fri, 4 Aug 2023 12:23:08 +0200 Subject: [PATCH 80/95] cleaning up the example code of SITA --- key.ui/examples/firstTouch/10-SITA/SITA3.java | 53 ++++++++++--------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/key.ui/examples/firstTouch/10-SITA/SITA3.java b/key.ui/examples/firstTouch/10-SITA/SITA3.java index 8892cae9434..a53d1dc11ef 100644 --- a/key.ui/examples/firstTouch/10-SITA/SITA3.java +++ b/key.ui/examples/firstTouch/10-SITA/SITA3.java @@ -7,34 +7,37 @@ class SITA3{ @ requires 0 <= l && l < r && @ r <= a1.length && r <= a2.length; @ assignable \nothing; - @ ensures ( l <= \result && \result < r && - @ a1[\result] == a2[\result]) - @ | \result == r ; + @ ensures (l <= \result && \result < r && + @ a1[\result] == a2[\result]) + @ || \result == r; @ ensures (\forall int j; l <= j && j < \result; - @ a1[j] != a2[j] ); + @ a1[j] != a2[j]); @*/ public int commonEntry(int l, int r) { int k = l; - /*@ loop_invariant - @ l <= k && k <= r - @ && (\forall int i; l <= i && i < k; a1[i] != a2[i] ); - @ - @ assignable \nothing; - @ decreases a1.length - k; - @*/ + /*@ loop_invariant + @ l <= k && k <= r + @ && (\forall int i; l <= i && i < k; a1[i] != a2[i]); + @ + @ assignable \nothing; + @ decreases a1.length - k; + @*/ while(k < r) { - if(a1[k] == a2[k]){break;} - k++; } + if(a1[k] == a2[k]) { + break; + } + k++; + } return k; } /*@ public normal_behaviour - @ requires 0<= pos1 && 0<= pos2 && - @ pos1 < a.length && pos2 < a.length ; + @ requires 0<= pos1 && 0<= pos2 && + @ pos1 < a.length && pos2 < a.length; @ ensures - @ a[pos1] == \old(a[pos2]) && - @ a[pos2] == \old(a[pos1]); + @ a[pos1] == \old(a[pos2]) && + @ a[pos2] == \old(a[pos1]); @ assignable a[pos1], a[pos2]; @*/ public void swap(int[] a,int pos1, int pos2) { @@ -44,13 +47,13 @@ public void swap(int[] a,int pos1, int pos2) { a[pos2] = temp; } - /*@ public normal_behaviour - @ requires a1.length == a2.length; - @ ensures (\forall int i;0<= i && i < a1.length; - @ a1[i] == a2[i] ==> - @ (\forall int j;0<= j && j < i; a1[j] == a2[j])); - @ assignable a1[*],a2[*]; - @*/ + /*@ public normal_behaviour + @ requires a1.length == a2.length; + @ ensures (\forall int i; 0 <= i && i < a1.length; + @ a1[i] == a2[i] ==> + @ (\forall int j;0 <= j && j < i; a1[j] == a2[j])); + @ assignable a1[*],a2[*]; + @*/ public void rearrange(){ int m = 0 ; int k = 0; @@ -60,7 +63,7 @@ public void rearrange(){ @ (\forall int i;0<= i && i < k; @ a1[i] == a2[i]) && @ (\forall int j; k <= j && j < m; - @ a1[j] != a2[j]) ; + @ a1[j] != a2[j]); @ @ assignable a1[*],a2[*]; @ decreases a1.length - m; From 217de0c7032e496d79ce5eb5f5c8bfc1e38ef4eb Mon Sep 17 00:00:00 2001 From: Wolfram Pfeifer Date: Fri, 4 Aug 2023 12:39:15 +0200 Subject: [PATCH 81/95] updated logo and license date --- build.gradle | 2 +- .../java/de/uka/ilkd/key/util/KeYConstants.java | 2 +- .../uka/ilkd/key/gui/fonticons/IconFactory.java | 3 +-- .../resources/de/uka/ilkd/key/gui/LICENSE.TXT | 2 +- .../uka/ilkd/key/gui/images/key-shadow-2.12.png | Bin 0 -> 88787 bytes 5 files changed, 4 insertions(+), 5 deletions(-) create mode 100644 key.ui/src/main/resources/de/uka/ilkd/key/gui/images/key-shadow-2.12.png diff --git a/build.gradle b/build.gradle index da1d3121f7d..e24b9a97d92 100644 --- a/build.gradle +++ b/build.gradle @@ -478,7 +478,7 @@ task alldoc(type: Javadoc) { //stylesheetFile = new File( projectDir, 'src/javadoc/stylesheet.css' ) windowTitle = 'KeY API Documentation' docTitle = "KeY JavaDoc ($project.version) -- ${getDate()}" - bottom = "Copyright © 2003-2022 The KeY-Project." + bottom = "Copyright © 2003-2023 The KeY-Project." use = true links += "https://docs.oracle.com/en/java/javase/11/docs/api/" links += "http://www.antlr2.org/javadoc/" diff --git a/key.core/src/main/java/de/uka/ilkd/key/util/KeYConstants.java b/key.core/src/main/java/de/uka/ilkd/key/util/KeYConstants.java index a0927e748ee..4c8a789d4dc 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/util/KeYConstants.java +++ b/key.core/src/main/java/de/uka/ilkd/key/util/KeYConstants.java @@ -7,6 +7,6 @@ public interface KeYConstants { KeYResourceManager.getManager().getVersion() + " (internal: " + INTERNAL_VERSION + ")"; String COPYRIGHT = UnicodeHelper.COPYRIGHT + " Copyright 2001" - + UnicodeHelper.ENDASH + "2021 " + "Karlsruhe Institute of Technology, " + + UnicodeHelper.ENDASH + "2023 " + "Karlsruhe Institute of Technology, " + "Chalmers University of Technology, and Technische Universit\u00e4t Darmstadt"; } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/fonticons/IconFactory.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/fonticons/IconFactory.java index 6431aebd932..5a480091305 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/fonticons/IconFactory.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/fonticons/IconFactory.java @@ -163,8 +163,7 @@ public final class IconFactory { private static final Image keyLogo = getImage("images/key-color.png"); private static final Image keyLogoShadow = getImage("images/key-shadow.png"); // The following should be updated with every major version step. - // private static final Image keyVersionLogo = getImage("images/key-shadow-2.8.png"); - private static final Image keyVersionLogo = getImage("images/key-shadow-2.10.png"); + private static final Image keyVersionLogo = getImage("images/key-shadow-2.12.png"); private static final Image keyLogoSmall = getImage("images/key-color-icon-square.gif"); private static final Image oneStepSimplifier = getImage("images/toolbar/oneStepSimplifier.png"); diff --git a/key.ui/src/main/resources/de/uka/ilkd/key/gui/LICENSE.TXT b/key.ui/src/main/resources/de/uka/ilkd/key/gui/LICENSE.TXT index 265275b2020..59aea0c0cba 100644 --- a/key.ui/src/main/resources/de/uka/ilkd/key/gui/LICENSE.TXT +++ b/key.ui/src/main/resources/de/uka/ilkd/key/gui/LICENSE.TXT @@ -3,7 +3,7 @@ Copyright (C) 2001-2011 Universitaet Karlsruhe (TH), Germany Universitaet Koblenz-Landau, Germany Chalmers University of Technology, Sweden - Copyright (C) 2011-2021 Karlsruhe Institute of Technology, Germany + Copyright (C) 2011-2023 Karlsruhe Institute of Technology, Germany Technical University Darmstadt, Germany Chalmers University of Technology, Sweden diff --git a/key.ui/src/main/resources/de/uka/ilkd/key/gui/images/key-shadow-2.12.png b/key.ui/src/main/resources/de/uka/ilkd/key/gui/images/key-shadow-2.12.png new file mode 100644 index 0000000000000000000000000000000000000000..7b122b5fd98ee38a97a14d4f04ffe667384a8edd GIT binary patch literal 88787 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

BRlwwNejsSrg&3aMINK&b`3f5PF63X!r3c2Hk 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%0A_q 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 JPDHLkV1l-Iy#@dP literal 0 HcmV?d00001 From e7d7e5253f601496ee38d342283c12067db6d4fd Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Fri, 4 Aug 2023 12:40:42 +0200 Subject: [PATCH 82/95] Only enable CE and test gen if Z3_CE is there Fixes #771 --- .../key/gui/testgen/CounterExampleAction.java | 35 +++++++++++++++++-- .../key/gui/testgen/TestGenerationAction.java | 34 ++++++++++++++++-- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/CounterExampleAction.java b/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/CounterExampleAction.java index c2417b013e5..9fe2d0f8494 100644 --- a/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/CounterExampleAction.java +++ b/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/CounterExampleAction.java @@ -1,6 +1,8 @@ package de.uka.ilkd.key.gui.testgen; import java.awt.event.ActionEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import javax.swing.*; import de.uka.ilkd.key.control.AutoModeListener; @@ -20,19 +22,23 @@ import de.uka.ilkd.key.proof.init.InitConfig; import de.uka.ilkd.key.proof.mgt.SpecificationRepository; import de.uka.ilkd.key.settings.DefaultSMTSettings; +import de.uka.ilkd.key.settings.ProofIndependentSettings; import de.uka.ilkd.key.smt.SolverLauncherListener; import de.uka.ilkd.key.smt.counterexample.AbstractCounterExampleGenerator; import de.uka.ilkd.key.smt.counterexample.AbstractSideProofCounterExampleGenerator; +import de.uka.ilkd.key.smt.solvertypes.SolverTypes; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class CounterExampleAction extends MainWindowAction { +public class CounterExampleAction extends MainWindowAction implements PropertyChangeListener { private static final long serialVersionUID = -1931682474791981751L; private static final Logger LOGGER = LoggerFactory.getLogger(CounterExampleAction.class); private static final String NAME = "Search for Counterexample"; private static final String TOOLTIP = "Search for a counterexample for the selected goal"; + private static final String TOOLTIP_EXTRA = ". Install Z3 to enable this functionality!"; + private boolean haveZ3CE = false; public CounterExampleAction(MainWindow mainWindow) { super(mainWindow); @@ -53,6 +59,10 @@ public CounterExampleAction(MainWindow mainWindow) { * is implemented by the {@link AbstractCounterExampleGenerator}. */ public void init() { + ProofIndependentSettings.DEFAULT_INSTANCE.getSMTSettings() + .addPropertyChangeListener(this); + checkZ3CE(); + final KeYSelectionListener selListener = new KeYSelectionListener() { @Override public void selectedNodeChanged(KeYSelectionEvent e) { @@ -66,7 +76,7 @@ public void selectedNodeChanged(KeYSelectionEvent e) { // Can be applied only to root nodes - setEnabled(selNode.childrenCount() == 0 && !selNode.isClosed()); + setEnabled(haveZ3CE && selNode.childrenCount() == 0 && !selNode.isClosed()); } } @@ -115,6 +125,27 @@ public void actionPerformed(ActionEvent e) { } } + @Override + public void propertyChange(PropertyChangeEvent evt) { + checkZ3CE(); + } + + /** + * @return whether Z3 is installed + */ + private boolean checkZ3CE() { + haveZ3CE = SolverTypes.Z3_CE_SOLVER.isInstalled(false); + if (!haveZ3CE) { + setEnabled(false); + setTooltip(TOOLTIP + TOOLTIP_EXTRA); + } else if (!isEnabled()) { + Node selNode = getMediator().getSelectedNode(); + setEnabled(selNode != null && selNode.childrenCount() == 0 && !selNode.isClosed()); + setTooltip(TOOLTIP); + } + return haveZ3CE; + } + /** * Performs the {@link SemanticsBlastingMacro} in a side proof hidden to the user and shows the * result with help of the {@link SolverListener}. diff --git a/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/TestGenerationAction.java b/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/TestGenerationAction.java index 24d2d3bef44..1ddce7c040d 100644 --- a/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/TestGenerationAction.java +++ b/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/TestGenerationAction.java @@ -1,6 +1,8 @@ package de.uka.ilkd.key.gui.testgen; import java.awt.event.ActionEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import javax.swing.*; import de.uka.ilkd.key.control.AutoModeListener; @@ -11,6 +13,8 @@ import de.uka.ilkd.key.gui.fonticons.IconFactory; import de.uka.ilkd.key.proof.Proof; import de.uka.ilkd.key.proof.ProofEvent; +import de.uka.ilkd.key.settings.ProofIndependentSettings; +import de.uka.ilkd.key.smt.solvertypes.SolverTypes; /** @@ -19,11 +23,13 @@ * * @author mihai */ -public class TestGenerationAction extends MainWindowAction { +public class TestGenerationAction extends MainWindowAction implements PropertyChangeListener { private static final long serialVersionUID = -4911859008849602897L; private static final String NAME = "Generate Testcases..."; private static final String TOOLTIP = "Generate test cases for open goals"; + private static final String TOOLTIP_EXTRA = ". Install Z3 to enable this functionality!"; + private boolean haveZ3CE = false; public TestGenerationAction(MainWindow mainWindow) { super(mainWindow); @@ -48,11 +54,15 @@ public void actionPerformed(ActionEvent e) { * has to be invoked after the Main class has been initialised with the KeYMediator. */ public void init() { + ProofIndependentSettings.DEFAULT_INSTANCE.getSMTSettings() + .addPropertyChangeListener(this); + checkZ3CE(); + final KeYSelectionListener selListener = new KeYSelectionListener() { @Override public void selectedNodeChanged(KeYSelectionEvent e) { final Proof proof = getMediator().getSelectedProof(); - setEnabled(proof != null); + setEnabled(haveZ3CE && proof != null); } @Override @@ -78,4 +88,24 @@ public void autoModeStopped(ProofEvent e) { }); selListener.selectedNodeChanged(new KeYSelectionEvent(getMediator().getSelectionModel())); } + + /** + * @return whether Z3 is installed + */ + private boolean checkZ3CE() { + haveZ3CE = SolverTypes.Z3_CE_SOLVER.isInstalled(false); + if (!haveZ3CE) { + setEnabled(false); + setTooltip(TOOLTIP + TOOLTIP_EXTRA); + } else if (!isEnabled()) { + setEnabled(getMediator().getSelectedProof() != null); + setTooltip(TOOLTIP); + } + return haveZ3CE; + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + checkZ3CE(); + } } From a8973aab01d61c63c12af07963b0960487f9c972 Mon Sep 17 00:00:00 2001 From: Wolfram Pfeifer Date: Fri, 4 Aug 2023 11:24:21 +0200 Subject: [PATCH 83/95] fixed positioning of some dialogs --- .../main/java/de/uka/ilkd/key/gui/InvariantConfigurator.java | 4 ++-- key.ui/src/main/java/de/uka/ilkd/key/gui/LogView.java | 1 + .../de/uka/ilkd/key/gui/actions/ShowActiveSettingsAction.java | 2 +- .../ilkd/key/gui/lemmatagenerator/LemmaSelectionDialog.java | 4 +--- .../de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java | 4 +++- .../main/java/de/uka/ilkd/key/gui/utilities/StdDialog.java | 2 +- .../java/org/key_project/slicing/ui/RuleStatisticsDialog.java | 2 +- 7 files changed, 10 insertions(+), 9 deletions(-) diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/InvariantConfigurator.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/InvariantConfigurator.java index 13d567fae75..acfc70eb1dc 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/InvariantConfigurator.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/InvariantConfigurator.java @@ -190,9 +190,9 @@ public InvariantDialog() throws RuleAbortException { parser.setAbbrevMap(getAbbrevMap()); parse(); - this.pack(); + pack(); setLocationRelativeTo(getOwner()); - this.setVisible(true); + setVisible(true); } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/LogView.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/LogView.java index e71764adce1..45a33aca8fd 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/LogView.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/LogView.java @@ -116,6 +116,7 @@ public void windowDeiconified(WindowEvent e) { }); dialog.setContentPane(ui); dialog.setSize(800, 600); + dialog.setLocationRelativeTo(MainWindow.getInstance()); dialog.setVisible(true); } } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ShowActiveSettingsAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ShowActiveSettingsAction.java index 550867295e6..261b75943ce 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ShowActiveSettingsAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ShowActiveSettingsAction.java @@ -72,10 +72,10 @@ public ViewSettingsDialog(TreeModel model, JComponent startComponent) { this.getOptionTree().getParent().setMinimumSize(getOptionTree().getPreferredSize()); this.getContentPane().setPreferredSize(computePreferredSize(model)); - this.setLocationRelativeTo(MainWindow.getInstance()); this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); setIconImage(IconFactory.keyLogo()); this.pack(); + this.setLocationRelativeTo(MainWindow.getInstance()); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/lemmatagenerator/LemmaSelectionDialog.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/lemmatagenerator/LemmaSelectionDialog.java index e1a26c6bf8c..57fc568692d 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/lemmatagenerator/LemmaSelectionDialog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/lemmatagenerator/LemmaSelectionDialog.java @@ -48,10 +48,8 @@ public LemmaSelectionDialog() { this.getContentPane().add(getContentPanel()); this.getContentPane().add(Box.createHorizontalStrut(10)); this.setMinimumSize(new Dimension(300, 300)); - this.setLocationRelativeTo(MainWindow.getInstance()); - this.pack(); - + this.setLocationRelativeTo(MainWindow.getInstance()); } public ImmutableSet showModal(List taclets) { diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java index 3077e23a9c8..90217f12b04 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java @@ -317,7 +317,9 @@ public void actionPerformed(ActionEvent e) { referenceSearchButton.updateState(nodes.get(0).proof()); } if (!mismatches.isEmpty()) { - JOptionPane.showMessageDialog((JComponent) e.getSource(), + // since e.getSource() is the popup menu, it is better to use the MainWindow + // instance here as a parent + JOptionPane.showMessageDialog(MainWindow.getInstance(), "No matching branch found for node(s) " + Arrays.toString(mismatches.toArray()), "Proof Caching error", JOptionPane.WARNING_MESSAGE); } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/utilities/StdDialog.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/utilities/StdDialog.java index 4f5d0a309a9..90d8782af1e 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/utilities/StdDialog.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/utilities/StdDialog.java @@ -34,7 +34,6 @@ public StdDialog(String title, int strut, boolean helpButton) { } public StdDialog(String title, JComponent content, int strut, boolean helpButton) { - this.setLocationRelativeTo(MainWindow.getInstance()); this.setTitle(title); this.setModal(true); // content.setMaximumSize(new Dimension(Integer.MAX_VALUE,Integer.MAX_VALUE)); @@ -76,6 +75,7 @@ public void windowClosing(WindowEvent e) { } else { this.pack(); } + this.setLocationRelativeTo(MainWindow.getInstance()); } public void setContent(JComponent content) { diff --git a/keyext.slicing/src/main/java/org/key_project/slicing/ui/RuleStatisticsDialog.java b/keyext.slicing/src/main/java/org/key_project/slicing/ui/RuleStatisticsDialog.java index b1b7172a21e..f13c39ec760 100644 --- a/keyext.slicing/src/main/java/org/key_project/slicing/ui/RuleStatisticsDialog.java +++ b/keyext.slicing/src/main/java/org/key_project/slicing/ui/RuleStatisticsDialog.java @@ -85,13 +85,13 @@ private void createUI(Window window) { + buttonPane.getPreferredSize().height + 100; setSize(w, h); - setLocationRelativeTo(window); statisticsPane.setText(genTable( statistics.sortBy( Comparator.comparing((Quadruple it) -> it.second) .reversed()))); statisticsPane.setCaretPosition(0); + setLocationRelativeTo(window); } /** From 8b7663beb8d18e131882c652e1a6c883c30f31aa Mon Sep 17 00:00:00 2001 From: Mattias Ulbrich Date: Fri, 4 Aug 2023 12:23:08 +0200 Subject: [PATCH 84/95] cleaning up the example code of SITA --- key.ui/examples/firstTouch/10-SITA/SITA3.java | 53 ++++++++++--------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/key.ui/examples/firstTouch/10-SITA/SITA3.java b/key.ui/examples/firstTouch/10-SITA/SITA3.java index 8892cae9434..a53d1dc11ef 100644 --- a/key.ui/examples/firstTouch/10-SITA/SITA3.java +++ b/key.ui/examples/firstTouch/10-SITA/SITA3.java @@ -7,34 +7,37 @@ class SITA3{ @ requires 0 <= l && l < r && @ r <= a1.length && r <= a2.length; @ assignable \nothing; - @ ensures ( l <= \result && \result < r && - @ a1[\result] == a2[\result]) - @ | \result == r ; + @ ensures (l <= \result && \result < r && + @ a1[\result] == a2[\result]) + @ || \result == r; @ ensures (\forall int j; l <= j && j < \result; - @ a1[j] != a2[j] ); + @ a1[j] != a2[j]); @*/ public int commonEntry(int l, int r) { int k = l; - /*@ loop_invariant - @ l <= k && k <= r - @ && (\forall int i; l <= i && i < k; a1[i] != a2[i] ); - @ - @ assignable \nothing; - @ decreases a1.length - k; - @*/ + /*@ loop_invariant + @ l <= k && k <= r + @ && (\forall int i; l <= i && i < k; a1[i] != a2[i]); + @ + @ assignable \nothing; + @ decreases a1.length - k; + @*/ while(k < r) { - if(a1[k] == a2[k]){break;} - k++; } + if(a1[k] == a2[k]) { + break; + } + k++; + } return k; } /*@ public normal_behaviour - @ requires 0<= pos1 && 0<= pos2 && - @ pos1 < a.length && pos2 < a.length ; + @ requires 0<= pos1 && 0<= pos2 && + @ pos1 < a.length && pos2 < a.length; @ ensures - @ a[pos1] == \old(a[pos2]) && - @ a[pos2] == \old(a[pos1]); + @ a[pos1] == \old(a[pos2]) && + @ a[pos2] == \old(a[pos1]); @ assignable a[pos1], a[pos2]; @*/ public void swap(int[] a,int pos1, int pos2) { @@ -44,13 +47,13 @@ public void swap(int[] a,int pos1, int pos2) { a[pos2] = temp; } - /*@ public normal_behaviour - @ requires a1.length == a2.length; - @ ensures (\forall int i;0<= i && i < a1.length; - @ a1[i] == a2[i] ==> - @ (\forall int j;0<= j && j < i; a1[j] == a2[j])); - @ assignable a1[*],a2[*]; - @*/ + /*@ public normal_behaviour + @ requires a1.length == a2.length; + @ ensures (\forall int i; 0 <= i && i < a1.length; + @ a1[i] == a2[i] ==> + @ (\forall int j;0 <= j && j < i; a1[j] == a2[j])); + @ assignable a1[*],a2[*]; + @*/ public void rearrange(){ int m = 0 ; int k = 0; @@ -60,7 +63,7 @@ public void rearrange(){ @ (\forall int i;0<= i && i < k; @ a1[i] == a2[i]) && @ (\forall int j; k <= j && j < m; - @ a1[j] != a2[j]) ; + @ a1[j] != a2[j]); @ @ assignable a1[*],a2[*]; @ decreases a1.length - m; From d62dd44db7c2966cd1c9e998c3f005df04ed8e4d Mon Sep 17 00:00:00 2001 From: Wolfram Pfeifer Date: Fri, 4 Aug 2023 12:39:15 +0200 Subject: [PATCH 85/95] updated logo and license date --- build.gradle | 2 +- .../java/de/uka/ilkd/key/util/KeYConstants.java | 2 +- .../uka/ilkd/key/gui/fonticons/IconFactory.java | 3 +-- .../resources/de/uka/ilkd/key/gui/LICENSE.TXT | 2 +- .../uka/ilkd/key/gui/images/key-shadow-2.12.png | Bin 0 -> 88787 bytes 5 files changed, 4 insertions(+), 5 deletions(-) create mode 100644 key.ui/src/main/resources/de/uka/ilkd/key/gui/images/key-shadow-2.12.png diff --git a/build.gradle b/build.gradle index da1d3121f7d..e24b9a97d92 100644 --- a/build.gradle +++ b/build.gradle @@ -478,7 +478,7 @@ task alldoc(type: Javadoc) { //stylesheetFile = new File( projectDir, 'src/javadoc/stylesheet.css' ) windowTitle = 'KeY API Documentation' docTitle = "KeY JavaDoc ($project.version) -- ${getDate()}" - bottom = "Copyright © 2003-2022 The KeY-Project." + bottom = "Copyright © 2003-2023 The KeY-Project." use = true links += "https://docs.oracle.com/en/java/javase/11/docs/api/" links += "http://www.antlr2.org/javadoc/" diff --git a/key.core/src/main/java/de/uka/ilkd/key/util/KeYConstants.java b/key.core/src/main/java/de/uka/ilkd/key/util/KeYConstants.java index a0927e748ee..4c8a789d4dc 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/util/KeYConstants.java +++ b/key.core/src/main/java/de/uka/ilkd/key/util/KeYConstants.java @@ -7,6 +7,6 @@ public interface KeYConstants { KeYResourceManager.getManager().getVersion() + " (internal: " + INTERNAL_VERSION + ")"; String COPYRIGHT = UnicodeHelper.COPYRIGHT + " Copyright 2001" - + UnicodeHelper.ENDASH + "2021 " + "Karlsruhe Institute of Technology, " + + UnicodeHelper.ENDASH + "2023 " + "Karlsruhe Institute of Technology, " + "Chalmers University of Technology, and Technische Universit\u00e4t Darmstadt"; } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/fonticons/IconFactory.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/fonticons/IconFactory.java index 6431aebd932..5a480091305 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/fonticons/IconFactory.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/fonticons/IconFactory.java @@ -163,8 +163,7 @@ public final class IconFactory { private static final Image keyLogo = getImage("images/key-color.png"); private static final Image keyLogoShadow = getImage("images/key-shadow.png"); // The following should be updated with every major version step. - // private static final Image keyVersionLogo = getImage("images/key-shadow-2.8.png"); - private static final Image keyVersionLogo = getImage("images/key-shadow-2.10.png"); + private static final Image keyVersionLogo = getImage("images/key-shadow-2.12.png"); private static final Image keyLogoSmall = getImage("images/key-color-icon-square.gif"); private static final Image oneStepSimplifier = getImage("images/toolbar/oneStepSimplifier.png"); diff --git a/key.ui/src/main/resources/de/uka/ilkd/key/gui/LICENSE.TXT b/key.ui/src/main/resources/de/uka/ilkd/key/gui/LICENSE.TXT index 265275b2020..59aea0c0cba 100644 --- a/key.ui/src/main/resources/de/uka/ilkd/key/gui/LICENSE.TXT +++ b/key.ui/src/main/resources/de/uka/ilkd/key/gui/LICENSE.TXT @@ -3,7 +3,7 @@ Copyright (C) 2001-2011 Universitaet Karlsruhe (TH), Germany Universitaet Koblenz-Landau, Germany Chalmers University of Technology, Sweden - Copyright (C) 2011-2021 Karlsruhe Institute of Technology, Germany + Copyright (C) 2011-2023 Karlsruhe Institute of Technology, Germany Technical University Darmstadt, Germany Chalmers University of Technology, Sweden diff --git a/key.ui/src/main/resources/de/uka/ilkd/key/gui/images/key-shadow-2.12.png b/key.ui/src/main/resources/de/uka/ilkd/key/gui/images/key-shadow-2.12.png new file mode 100644 index 0000000000000000000000000000000000000000..7b122b5fd98ee38a97a14d4f04ffe667384a8edd GIT binary patch literal 88787 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

BRlwwNejsSrg&3aMINK&b`3f5PF63X!r3c2Hk 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%0A_q zp9D!ZYN^Ea+>fPt|h&@bwFRId;U)d#%H9Q zYC~P=Og)F$lhaOS+;q1Z;;|FrK;1MyT{r$?V~ApAB$|_$GdZDIHMNhvI=4x|?7+3; zdg34ItOo{JLnahz-c*X4*(uZeKOqI$!~u(NE`=J~@ZSXm@&i*8^hqZ&g~PyUcdL+a zI>9OwzZCC%drx4m>pe|RsKT9ZQ&C+kT4!QxEUi^+L()+=%)?a4X(nqt@c9)Lgpdqx z+4^=RAe<`f)}6i~x*?4v7;ImVh4!85q&VOzo2O`fAFi-w7G2`j?Qo_(UH>DAxJzKk ztT6|G@-C2Y(&SjaS8nBaWmbLds=D1R3ts@*Mvx~=7d_KMFeDh671~8gAN)?G9bXH7 zN?`;P8;C^5I4nE}(agHHzd`7_h<$BQ8~1F=1BWwzBWW>-Kb&A$k%;_?^SS!_7rmsk)b0eo?p>M} z3+=)TGWWc;_R`rFDXagL>Ho9mpK*SN-SIr^3E=#@UkWfDb^W z4wc*m;`HSHe)7uxDH#*h!sORgb7UTIrZ4G8->TF|Hea+lPgAADZq>FO{me_+#91GE z-Q@tkg+emWUfrQ=vVPV*OgfJ+c|D`3NRF8|U52-tl)Yz9$E&n^?mndjgS3HR=53Zr zOe}q7vIwM&%i-@pp9Rm?gC%Up^xnDk9%>HAey{`l4v;s_Z?e+YcVY`QTJ)koaRI#J zQyEF{D@dyTm^)6pl_D422~-LL6-D_eGC~7FTgpKd7O_FWy&k0^0_YHTDo+O{pBH}= zjpAHn>@IT(80bj7)@c<~0pDP&$dqne;a(k32U5hO8V)WmE^aT1&E~>_ndvy_#IBA+ zTSK1>{~0Skcp&5uaVEqu8Lm_5Y{(>KU2(Q4jw!Hkw?7@(UGrC=!#R>t`1{au}JDKo;-*86&d1{{MciS1PqL{XTi+ZY89BVcGaf@lL%Ju4r9IO$Tn<}xW*^nm zFm~Nv<|(aBZ&|z>?_3|0ll;y5%K~>IsKb!^$Gf)=x7=*O6~+M86+wu-Ty!0ST#5sG zq6m#YxQ*=j%{mJVBYVG-{VcO@EDgkIhqwdU+d7AcV;DjX9EHpTUL=7V0NM~91+dxa z3|0kWg0ZI6hu8E9KeaYfb-Y9+pwz z$pGm*=jZ47!#tz5JkulAUKN<)q_{~}OR0)M{T0^TI4n^mV3J77$v57_gy^JgS*C5} zn{BywBC?eUINr;2zM5g?nw2PRD|uTxx6nBb>Pc?m9VifwuJ62;$c?R|8Dx3U+<~Z~ z5%@|`J+Y>iXD>tl%Cski6gVd5yaF;cLY237iP!(Y|)eQqAg|QkuxCA;JGDmv<}20a58teMVvpq;43B^8((Z^+*>A6bdT=h3lX>;^ws@FP zO&j~x%?ug@XfN2F?J+Rl5mFex({o#U+~K!@a$B?`)1qF8_g*ceR#&zoV7IKcdSHyJ zq1N@^7AXe8pMNa-XG$)ZN=A$ozg#t4AOo=RC1e1Mvqiqw`fj-&g= z2()Ir4243U5Xlu)hg9aDQ}dbM&^e z9AWu^3R0Jl&#&eOMu8_pZ@)wv-R>q0I;-(!==tbP57WK#CBu|z$n3uqxRuK#u#!t- zTI?wUjjZN8t@GJcih6X^Ga)e6t30(X-k8}M0w_YlrWoC5h{~$(pED)uTY4R8FH5Xa zpBox^Qx_$EYl(;ptwv@TL>H9v7|3}k#$7A`1{r|G}3X$zbC_-dp>qbafnc10l zR`wo|+m7rVUn4?R_MX`#x4rkgZ8D#;-}8I^Ouc$}UFUV3=W!m#=kxwBV-=!VKfeqg z-T7SBT`Bm8aiXBA4g>lmz#?D{=x(ZYx?(2RS@z9kYeF`uFRy3y`Ii$d4};(e7kq`| z8jWWp!=!2-8VI}cCA(gJ%o}(-MHh04zgSe{=;?XSoWP4m6GR(u6=YhZ$iqS391B{v zHF#XGP};*@`${}g;42u%xZ`;7u6Mu{$S692W|^KCHw?+nk8wWDXnX#ji7{2k!~Wk1 z7Ms9&_gXC`4bwc*i4{8n*^M$yo(xA?d`cNu6@HtPmx)nU0eh|}+O%H5gL(rCOK|xgjUOK$w*V0#NpY@2#Jy9@jlkAg z{?&f)XZN7Zh<=3Nv?wbXE9O%{BABpSJdz72BNmv(#-d<;5mqxcUCR}@k}?H6{U2Kl z-@NJkWeo=!JiSD!>F;#e#YM^_R^M_zh`8*K_-F7pkhJYkLPRWL&qX&q&*$;Fnp%tx zCrJtuem-CVc^T&Tf`ZWZYVFxsS|~YJQCzUNoJ{96M|sN|2k%pH+7|-@UtW?Ha6RbmeoE@it8&N9P;%_10TH2iu zQ5PjQCPF4?o|84hf$v^V7D^F`I+bLs*)*ThVTXISWExx9t6! zWbWNe3#;`Gu7m~mqq?mw>XwFq>+2z-peG{@g&jxZ`|VvYK;2Kx(|K)CRP>l|3tD)r zxATZ|{<>7&z29G;_8bfUv<{k(Z>0)MB%h5)*Sm;a4H3DT_olg7l76w%`~e<+&s+oc zJ5n-2Q5mkceW@wvMPXCxMWHnH=2|G$=+au}4*4%V1f}mDyHdQybI=_`ZZw{eZjm%= zo++9~mK629=e2(_=S}3=a%zD`$gXc6!yuk$5%$YSyN5I;@ReSo$3kmhon>ra^|txo z6sPY^hV!>Gkjs_BC9}z;dPo0^j+FH|zU+RdAY!kX(+{sS{#U=;p<&#FZ+rXk!c@Ud zil0_L4?7f*KnqVcoUF!e3}1$r1Pu z2z7Tco~D+7ZZJD+;3(ZC{rlM*OOC4PeCEs3!+Du(dN;?u_`=KXyyMdjo~|Uq+YL17 zb?%wwjxipDQq5D~87HI&5&ik1g%7ygTgXE)Y_XBn?&*tTfYC`q?L34dM<}^+uP3|h%t$-%$q6Oxoz$g zctj?PsG7j#6##yLH`1tVymT+na^phRKR?Zsg5oly%>O5P{zOjfJ7P~MiiLI};hN)U zL{oYHeUJRD6< zk@{1A{26nLp}7XQoFiU9w9MJL+C2<|`roRl8WWyMmOv&bG|Ne z%d)LnnwFwvqy4wkLpPhf%(sQ>mDjaS#J}oZ^;f$_83jMXAN=nL+V>ef_XO4-2nI8W zyq7CCRVLGxfgGXDz4tx!_a~$-Txj53E^N*dO=*C}%|K3gh*Ffp-{M$}7~?|t*1+1! z9k^C~S6)^r4r*N!emVG{h59w~>f}kecCO2(XzlZO(u28YSJT47U&3%8nZpC`o9y$& z@fIqcK^+5Zi1zKQ-)3j|uK$tkm1jg<{L-&1~Zy#}Y%+r2ZX! z?x9H%>mks(_YP;m^5-oBUM$S?;UGSt58`xU1KW2ViNOZRnSZ^zuy(qc8$ZJ5?Z8UM z!?()|r^Nf^{pzz6k>q8)J7(&-;oRizlcAkDXPt|S`H9MX$=gef!y>dueobhKAcazj z7+X#}QUg9<#w|s{`d0mQ){nk3{W*u5SNN>vYiq?!7rJnbYeVxFa&SFB`+|K%vcu!O z(4TutI1jvmWCm8@bSIZBd!^!*7Gj}Q4nJZ;B83dxhn{5h08)V}WR%EZ|uPSN`3DocwO%JWeZiP;d4$X=XyJDnA-cCB^ za{@JyO(a0`NWNdf*PvRziSZU=iVJOl$Yk4l?~qR8g&{LmY=5)zkf5(B+i0@2H%;1@Jf?4PVa>d5OCErmz(_rbs zdmhk9ECXTVmfah`x-J@TI!mu~_nUFvn<@Ibx0$jTgr9S!UtLsRU%x%48H3)r_Pv}| z8lbvwDJPPU3!DW!I)l3tW&HU#T9kqIihl<1lZ8YSM$>XE2fhY-sXDFnQqYoyj&OCD z^K|sca@nM6s8bcqN{w*5yN$~5cKZ`NnfBbuK|cV?Kf?9zx1_~!-mJ^tg;#5u9X;=!6F}v8Kf}b{nWX|KcR|BLhFdT@GVmT6bwJC=1qA*8f?ovoo zWG0mz&q3t7qo7$mn;(9V6eo;ubmfsJGqpU1Znc#um6=hkBL?6z41|PaJfwM5r6?>C zEC58wrb2YGJEyS`(J_>3YS3pnZ6v85x^Z*&W~6;q+@;YVJq&rX)_;rrs`(fu1TQVG zC$}6PPwX0{TDEVzSS||4ND0g*5P^sFomW(i6iIx?fm&y;FSf_#P>j?OA+YwKhaGrt z{oR?l^c%aKCxqad(@nR7(z!RgNjCzX-=yCjM3mkszk|yuQGr6WT9j~@6JPR2h!2I# zt$a072Ow2n7|h@wV^jr0{1bxc4b>tJ-@(s$MTd)f@OQ_#ejL-YkH#xHqJDY|MCv7u zJ#%?nyIY1~f{;@D7|!36!rwGGGRJJUEfU?hGVH-5y=Z!J(4OTrQ;F&eoU>QY+dT|2>vfHO1?Dokoy2SNO#l>;9x^YsSytX{>Xr zvb;NB(J3m7rtxGscTuT@Uq4_t)w(JyC z1w8c~-if=6q0&{8N9eaBA&cm|EWbkx`|}q<>!LzkZ7BWZC)qZ0J+<^lQN_a(Y@aBV zE0Z#s@NmY`KwIqD>5nw=MQ>H%IHM`%A;i z)IqgBZyOO%Iur#mtu%4M*$LQabDOOBzhv9j^p{hOGbEEQ0~O5)SFc_%wm9~=syE7G z-lfH3RP=t82El*n=*}ZH6G9ph`J}fTHmM+!;*-TaVH||PTXflkrFH!vZ;&$fnULx> zpEV>Cgc3InTP_NkBAixCuw}-Xz_W9GSb6Y}c-3a@D!um{OzN#vJPtsJ31La_34&N{ zklOlveXK&!9lv0f^k=YkIPZ?8%Ys*~S17@hA~Nn7mzVSxy-#9pKmYXHf25-tNjrO4rdt~FA?I7nLRabyi;QT zX}V{ir{!=sh0pfMZy}3PeXWob&U&98){3)HI!-%0*)YNYla+}tqk)TQWIoaq|3O?x z7!N~pJUrWxuY={5Xw#y{?N~HFh|Hy>*khRYRX&;DQ6LMQMif~V;cD;3M|lfC4mUwd zdZWv^2nm}?;?~9TZ1f*?)+C$ys2;?|_yDBK*&Kn|i#YgDmNZ$yE9KRF)TRqi7>Aub z$@nhOkw-@G9O`nEL;JtI7D7>O9~hyE7vD80%_2zRa5Xk zQ!`9HN$JrkomuIMVwEuLohg2ndg39k`dqujlI7#CDOD1G~C{my~-^|~#$2D1`* z1TT}=dpMA6J%bXI8^!*-HPQoJncpjyIfmPvpI`i~>Djl|aeI4qKmHEy&Vk=*`?tth z?^m(Kz~jyWBgeL-ya>(^jo5ZUI6$k9!2aZ*^o0eJ4yq0)ybD38-|$SYv)7n? z`f<$4DW==oyOklCz6t>AeeK+KP_3z~BxvA2>^;W@9Q)#4&j*=PCokGQ;0X*Ld11Tm z^!x0!zkGsO-_rKUk?h4kl-Cu65MkH5|K%S*#wTFX!ElRA*kIO-#ZX zpR%B6FiZosgiFYz$?S*NNGa}IW*XcYO$sv-e|VJ7XUd|GQ7yjCMVqYFJ7puv5a&!9 zk<*$idG$K_>AP?$3@B)GNd8v>8a)A#VO`p*DVu)B;z*&wH+-Cda4L^`^&-tAUE1GI zTcj7UohPnlV@Apm#0BJo(O@GvsSEh_!B8VX6P?DST4p&e(@W!HeBB+@QD?A?@pMM~-+t7&b%sKaW zxaG>=qJLPjFDg)IF}3MTDo8v8Lv>J$^uSn%`hfXwucBMv)oTWw!LO>w0{q-%6`V&( z6$@u>{?H%!W*YM1cZ{;w!Li8LPdLF{5qU|9Sqia#qeX?PfYb+-6(Md5jkMXR^pJ7F zY+pxt7xx(cOP;bnoa@Puz<4vWXpB4Kj$M`MfAg0>r^ZIj;i+*KvDA9y@NTCw7DPMY zY_91vyMGCi;xQo6b*`63h;R~-dnA9u?Sd`C%2Kz-d2j@ynZ5I(x1ZeAXs@FoFK3Et zA8@_(^C5YfF%*o&-WnagzBN&V&8&FwQk*K$;;R|IpxFBTW^uW(R|jS&XLS80`X}i< zxE*zErvH}{G}CR<{cOQXGAV*NeS?_vsB9)Y1IgQ~BYqW85f$tP`m#)xc!VQ)T0$3F zxI-}-GglSc1*q`MDDL8#u$bZ7zX;F*t{232;hUXCBB>cflj~LUv_C`9k4&JJvy)k7RCw0#g|AO#AP^hba9uxr_t;CwcfT6d+9%G?05@}nc8 zG*v5TE9x~lciBpv2$7vvP4J7RX1KioSKoG&*$#CKeKwn7^oz)k>3K49KdlMBrEWjr zrOoNPtChN7RBt66xX)|Xd$dJt`f#lFtpc2sMaw|4hxG-RN1Y(5>g&D2`)mb%53N^|-Vz!+1c zatN+K<|rw2M^>Jto#n28b7(5fG9x!H+kYZzs}l-eqKcXw)2G%Y!3$r`z|0qG)e?EW zNv$VdQcWHkY|2EP92!MIaWK)cFQM``&y%?y!7EXFL}i(v`TZA(oi78bIWtw5mY4$>G>|_Y;7*m5Gv(D_%KOblR z{_@GA@zoD`&wA9F0Z8=gg<)W4we&L zlvUK`pWd}>POjEuGkE8?<$AYH4@KIJ?8R)wY_+w!vT(64Wh2Fr{aZ7C?)=_*QRcWe zTCc(R<+J?(1vq1mC!M(#&rh<@XViZIv}cp>{InRebS-kj!?=-AB~kZpgfl}fT^U8J z-b_fb=bQ>D(+Ni5{lGCPNST{3bNSZ_PRc!yk~3Jz_vq2fTK6v15y`U|L3frcrZo(; zzYtg6TTup3eMm?KX>zYB-jw@evV8Dlo=0#ehsM+uWexu9s#}dlPS7sHYJ1|GRz8?V zSk+9IgcOa_RVx4UGNp30g+?{nCN5wVz6uZz#%}X=m}xM&eJNGDem(9JkVHiF>s7`j z&DK|+X2v(X;cy4QNLI#k zHykgrjMmm4M(Y`04NgwQT19@Y53-WQ_CPnS&orN#wek62yIGU|wMX*Jh}>dB3>2Oa z@JcC~MtkzyGe9hxFn|VjsOVE_2>9}q_8QR54>2XD9;FZL zV@qpNnBqdhH>OWBL5zC69~#5|cz;-K^|Qcu_ECp_f%J7}0b8~RAH@vFaQ>%QT;-Vb zDi~d~v)pbtco3Q4izO`YGOBk;H6G1sj@J%tt>Cl~;j?uFXe(xgh@lxcRO}s@eWvF> zeqa9hfd0vlm|dj6keDi58BwxiJ#5n~`To6lZ;gZ3(7}h=A3wC6yAM>pbA?+H_?gwm zpB0PW$L${obnnv6OfFG$Bnx^*Xvt<>lDC0HE+RYl{_6hLd2yKP_&2>>0EChg{ln7} zYO9!0hbWotK93zH3)ht9YjrMRX}a6qzps*)E=>Yyb6Y$Uo?Hn5#AfEoeu-f{#31zg zp45-_w$m2M(iEMT03#}S$%5vTyk}SoAzY09w{|To;g(+Wdv6yeq&{E$8o$ZY=##6? zB!#xVNor;Kte_%t0Gr{;<;UEni-(B8?P(+e_cZLi50b7IBY@t{-W4^+)j>NPM(dTHesGlFMj!vBd~$wPuk1vvYvE!St@#h*}9Q9HRY->9=L2>6O` zYoId2Wv8b5&pI=vxunnhp@1>{q;eOAaj_BR8T1)qu;b$5X_Y>2mc>0REsJyD7&Pwp zJ}>e(sr?dTXQvdmao>=J67$U5;Zpol3Vqq)`45^*yfw|3TS75z%Y=n$l$62@*FAGl zRZT!|ld{})GORJBttL7yYp*pkX?Z8+7miSr!>CWL9{1g4iBx{AcfrBoX~yzamr2z=$L!n|2@ii+RU9Z-9BNZ2s_*obm>|Nx?>RhW_Mb0o%H8sf^gD7!JCDjd?`xRfCn`-l z&Bi=@>g{ldR&ACHy5wmFGyn0I`eq|;E1%zpLgyu!m(}!38OO{swEk-?yt92`aGtP2 z>mcuHn>!%!1I%96({+@8dPuAZsWxdS10gq-*42e@)_DcTIsVpYqt`^h1M?S#A7dIX z;%{<_LJj{<3(##{^3eVowK_g+aC*bZa^!H;O@rDi;LEz8d-Fz`em-lI!(%iiigSc7JNU>S+N7K9R8V9rP3hMdh)ui^r!wR7`Zo&=R z4{gC7j|exAMHuA2vV&44`?iwGd}E9Fi`;cwCJ4u?^u(HZRG#qWq$N~4+|jwV@C4Dy zs`1NddcYALh6w|4EcE8JT!f@BHgx(?bLtO`51;;JGxzN~i&e$=*j9TiFca@Q^Pm1X z#fj~f4?DCayL(o#JSII&>%T}N9NuysrO{1~)a7?JjpS}T%PaY9LiT2ZGD#8@eV*^4^Wlzwr(=LvL(3lZ1+ z&b-_c@u4MOmojDy?P8nE$~d=P8I$kSLm195+%t!@>{akMrzI>DT%z17PaKBT`lSy` z-PztGgdfF`sXIPw-^U6NVq(L5j;%Wz3X2TJhDFkrcHGJU7F}=&>S**Lut&N>@$~e+ z&qKqnm>`y4q389I0rMW4p}Bba*@=%o zRq%WP>@3ht_iF+6btPwCaN{?c=$?8 z=!)41MArk5P_ZW}0128%wcI7u#1ag5Z$irMUJdlz`y)uF8I^t4IE?SoA;Dy!xp!eP z_HxakB&Oy3_TNA9qAiPf9*E3C#_J=tn`#E$(3$g4B*2!)f92cIP0vZdyez?oQ#WR- zR5t$k10Gr5Gcrl+f|nVoxLM~%`5lH}0zGLhl=?l=(8wqsh_9x1HB$47xCkvG)s?vo zsY0}sK>>_lEvXh}&A~2;^2daf4wgZHOI4h~T1^EjkMVQq(-Ggd76Stuz$;Ou%ne+V z`Uvn!@u(zOq#Vt8BX|K}c=;e1?*j&iK?5wE&s@pdCtkmy6TRVju+J~m+L~lR2jq8J z8=8&t*PJ6DOw`%yQLFFuE%o%vg-YZYJhQDn2Y=S7A~qb-egDk5%^I+%_v?69Oo!W_ z-e^3Q!?7+0yHVV>|gB1MwaHn~ufr0Ho~l^f6r&f6(Rqg(sRaZh-M4 z;dRUf3@>jjxxz8eb|xu9i?TJs)19e$ zi*w%SkVQv)r)#L_Y!951KvMOtT0ePR3>=u`6xKoDU}qwyY{am=oWvbu4g5@#m}Ja# zUWeDS_cbQ4kdvHJMvDkvs9-<5UA==AaVd;6@LjHo4*mM0Yj&1&@tmEFmh6uhuR zq%KQN2qBVi{f$kelTB)(GB-%gP>MTWblgaH_7kE5kWp|Hy&Tn=+WkRmZenUGi+r9x zM?X4w!QlkHjF|yEDUcNpa8p96uQS&l3_FuRePULaW%kLFEI9{roL^M#v*rY+d|vW( z`1^^+-QO`(NMGfkT@P3I2AdR;^=1B z9D!6%OpOvw!P|U6-#@^8XC&&nMb*u%175&f?cxw{aD^e;-*U^rVX)u& zpR2V)w5v8EUVW8vN#^$+eaZ7#u4&%swx77;WI~^&;#9v;B%|5@0Zd;?aqPcmt~yUP zU7n_u47#;l$MvXM?NZD%oz=Rdjes`^;6qr3ou9{HcWe_P@tveR{u7H7XdjS)yM`(z zlhY1oe4#VzeQ6|RzWTR?p~1l~=lFUUR_Kh+jw}id`1yqA+E@vHpEg@`)nm7szAmEwng2k9hjEN^NJ0iGztT^7 zo8g>OjcbYf50niXdDbwS2pmTG4?*Pt_IOsMJEoS%)djntOSsq#P~N$UO?t=7+S62{ zgcwK#3V+2S3%Lm8;Ng=`AufoeNTLKU>}joLscxa;@b3w!qa=vD@|12Q!#S4CVx0jv zuEjV9`xFu_Dw><4r+I!FQ`f$-+I1rN%pMC476M1U@SLF;tZR*=)spJp9?baI7qW0$ zHL~?RjDVEMXOL&$;>Qn3&9Rr7S@#lN`4J~G-)~RC;8)bbhDtKNJa>E0iB;>I*~8gn ze0!YS@^|{f(!-Y5ea>W5dtGHoe&#rk*{NW+`C550hwB@v{zY6TEazlS z96xV`pJ}q>+qZL`{>Ex;@JZ_^w}A{!0B=+-9t)BfE~o@H%a0lM7IMyjB?&e_@Im)g zya@4gwTo1jSGP8QK{cq5p^6C+!0scH_uo7C|COw{fst3QS6>MH>D$-5_-uTc!4mf{ zK?CJ&jH@G-#vXPwCr;r6iZR$B9DuEtK?aQ|!+UV!18$Ay#ba^zIL-~#ZiS=3EvNX= zPlvXe(XD-f>$-xMA8+OL5spKw6s#GB#v!ZG%OR&3I^F}*gt>_`Co0~XE1P9Pl`d%C zyyG&N7qEGz$7iBCbX6!d5TkUoYm#zho5lqrYsKC`bU*Cxx z)lWj|%JFB*cE+XfYTJ4gRR2KI21+F^)Xk%vi^mS>>FMvN>;oQElz<~x+DUeU7M?;Z z2yP@P%7kjHN2UH2dJR5gP?^KEj<%G!0Vo9?A6(&s3597qpokN?{Z(@fV_)09GWtwj z=l$sVy6h@EC}Nw|(-lzy0zg67UgMcxst#Xx5I_@wfbC%wmZe}SXIgj zV(*#5;WP)me)%7Jml;CzGKv7tWv zflqwyJR)w`$46J{!a-s0z~A7!;FkZaK+0nEFQ2a8CcQRl2v%WXi3dG0!Xq8Wl%Z;y zZ2emg%~?P$5lALEZKl`gfp=hYFVXG?>0@9@FrmKV;Gdh5iFL%_NJ>N}giR6Q2IspT%g)?Xsv5XMbEc z1_ibpMq;=e9z-sC_pV&g$8LV20OHEftlP>8<3usBjC^jOv*@O!qQHcR%_+-I6l1O~ zHhP+u$63@v*W7l3HtfarH66WHZH`v@UvcNzhDf|wnY%|J_Rj^Wg?xS}5jqk>)MP{k zjK{#pM6M7BA_@quryard$j}Tz)Pw9A~2lp1|rrilEEJ2rHng0_H|Zb!3nEhFgP1B8MI#mm=mr8|5J}Tu2UH zfx0lsQ_&qL zh$suKPhRL5wBj)M%0%;oJOB#roV(mQgWa+3Q9_WQf7`@3o9?Q3R1FpFXfWF85AD{ul&&}x40s+msU%=C~0Q$$lDdtb{p_RU_$ zfic%x;5{g*z5|Lz*R+RPyrmzJ52CNV?Jt>HX8yL-i4+q#9&V)g6Y|-mQ^I=&T)pXG z-Oa9eP&EM%E(1N2G*gV&kN2hDzBzsi;NjyFY<*PNl4z#**e!s!;&jqSyqh@|pZtMX zqo32stIfrAW8rR@f!|^H?2))6x0M$`l>@(-vp&(E`SNM`O!#1`A8nsDVYPVf)mF^O zLM{Qy+{_7p;Q{J$5W@{>h`5*s`)cpIi>XJu-Zwgv=Jy{AL@LECIEwzq(+`ewGt1xl z<9m*#m>|pK<;Fz~OX{}UyFlyVs5<{O49kzYlTcw5!5EvPrBXAf)K{j<%E)Uq6A{#d~OCT4k9j({kd zG{Oa{T*HuLjM!3FrH4-BVJ%1G`CmNIlCTTM7ENU__%U*W{1=AI)okZ{*Sgb?XCbj` zIzp$iKM<1VRgEplJ z|H8|H>xz+T1Zou;f8-7w!66j8ff({KIA7B4i{DRfN7P#l;0X_d{W4(rQl7-&U z)?yq>4n-`SJAoy~N%3x}yZh|1sZ46a2F36<-#-%jQPLkGc|3>c()o*0(TAo$#fCoq2etkHRLwuS|TwU$LUPuv_i_<-2^fTH+Fqz6GE)*oIc z_`?niw@T`{`6llRPj?}zAB)|-B3qPJQZ#ku5VW2S3bY|H{M8AM2K&$mAMcgV1zj#l zi_?gG+oFb=2R(w$98sJwb7Fl2TPvj?CB&5@BvN(OBwj6n^diWs);OHBdM2#nPDW1A zleu3j^-o~q>@cRppUcyd(l(qQD(u_C7s=jMf(+=oO#<(9asN^w};-0HhjqJK{ zU^bo^EpZLp@5O=?KgBR@z}jt6yMKGH%pmy57PuGP8K%}7k>^kqMX(QqMXH+qRD3lw?rU|X!k za2)c4A1lRqAb5K;oVZ%R30)+1lKfgh4X^e;Y-ZzO6&dS90@cqtHK;pKA&7aU-dE<% zJCYE2O&KN(qP$7Wi}d;Nlzu<*TZz7=p zB*&z8q3|DwIsI2HkIMesIK&5YGP~RJVve?B&O3Ut5$PDmPK>dEC5v9>z?6c{7i^42 zAFyiLTV6`-;igKzx-BKRId~f1Z;oQ_DHImLretv_sYY%Xju~&pYdqqrY!c|EGyirr zM-lsK^bfuHgxGpmFF3%$dTXZb07dZg0A7!cAr0AY}w(VU2DUvLtF+=z%H7 z>xk6~o>2?E)R6)y*2JSZ&aRl2Yi1eFCSUQM_o|Cm{hQ1ZR}ot0Dle@0kBgsm1b2(A zXE--=C-zrFf(}oEP0K}T!wiDcjbQ?#^u>!%ql@#Cqb#m0zhCN(7)Nt#ujkgSOXMlq z9Hp&G1ZYG5m_0p-8jU%hCTlX^YuGZ{RxR9A@^RYr!R8If5G<=>ur@4ZaENUCWv!Jq zhQz;To|FADWKey>eSTT!WN)snOE%YOJ}OV*%!KEsH@c0MEq1(XM2~+~iToiw6krf| zDf~6U&f-K}O@w4`bn?*1m_w5Do_ot&MebQ%tTB z;=AhTAH3OMvIpLLud^P9YGq-akF$^@{haCeQ*ZgC)oILM+9@m{2)JU3EdTR{AAiZ~ z3sntM8U2%Iv(>(Hyiqm`Ux^X`Y3)86X>Oncgf(*1-Tl!6?FoV=z^xQq+#0K@*k4Is zSAnveNG*orTqVFJkzmlJ#cMRUn^w?N4ul)h4p>*Al)#^F@EmRe7~Y&OFdzaKcRKU4 zq)%ctx~fM-JA!dB3rNTA_v;}h#Y9GfEt7QSNdm+$ypjE5I)M5Z3{2 zkbfr2S7n_8 z3M;kilU~Zlz9xS=#^QTWj*prO17UIAZ*qaDNktzgZQCWqtu4h;dQcSfCE;1#S_2}L zXTTXru#ZQ|@TtuNqL`T86{eBL7!pgt^@KpG0QMI_8F(<5l9C*&Rrh%!N~}xjew_`M zM>4lPbusgROw5V#N)5APPkQFNP~x!gyvyF*%jE0Os1GZiMw(d2-XSp^K*%33Xg_|E z#U5s5$y~5#_wL=Fp2YmG;3MHwYB&890c!uIGgnKdsVNU9r`T$gBPe?O7DH&>y1G)E z)t%p5qC)|b%bxy^h~O8S!>wPz`8+ClTJj~7vG;Rq*iwV(?+fj1oH#7yhTf=Td;Xx; zwvr!yb3T3%G3bL-ZI|<3a6lS=V_dCUdgTkm7~!aaT%O_y~Lm0-MGh> zz7s9}EuBMvhypP5ijWEBO2@p@z)Ia=e_8)&tT8a?yxcOkjLvy>I#*e(o$gFI2hCk_ zq0*p}{WFHl{+^yt)xbjAtt4GUlk-c=&|zh6Qs+jo=&~pi<_aftx;Zf;3-Fq`H4G|$ zwdT>hwU=NLguPF+0N;`5urnDnvwZ@FWn!QZ5EN9DiGf@|O9$&kkm}Ks2A;wmn{d#? zXO!?DXDgc{?+3l)zN49BWpeX$X9aEx_NppVp)Zr8`roBJrlqm->eHHr-5>nfIv1Q| zmcE$Qnru(}bt|cKr~lvbI3)-SNBSZ_!R&*+Ci9o_bArKuVensz+rEYf1cR;o3sa$z z4;;Luk(D~!MdEvS?Ml39iFb4#N>5f-+3TI-czUp;bCC1=MY{9Rgz!l?}Lo=-( z;eEQ(1{f&=74PKW1@Ut5|8#?5mbDTz3gcl9*RzI>xBc-=@p!!`Ugw-PRdX4iSFQgJ zX}-l@p^TTWB|+)q_Yf{0h(5R~pS6DmRtv;NmFKc-+?7R;fEJg>+Q2;t(CeE6IZCvh z+Le6=ssSzUPNj$z(pZ==np3)HQFRdzn zd;82<20d*BX_f|4!t{GV$oq#|`rD#9l3|uY<0q|B*ZI)0f7@3 z0zi_7X|G&{Oc$ojZJ6RU3c(FMxn*}@H*Vv@(NhqKwecc#+ylK1V3TF@KRUkG>bxI*t`1Pp+)YTobzn<-7yrIM1V!x;tiGOpj>%>@8 z99H3@`t=3TmVU`y5J~_AEFaJU#1v`hv%;s%4+z;x_4E=q(myop)e}WCNj@dnSIwT+ z{VjclMdHjIN11u>B(%=r4Gh1Wgx~HeFzl5ub1xn!MkNol9+w_S9D&2=b-#q|% zXEWfrops4FKb;Ib%;X;PXk+J-a2DpOhwnkF2yk*ixUTrm>MHjo5t>=VbhO z;VSdZ5ITKNW_mLja*vJc@;?^5-7JevwOHlS4QF{m7X@L~_Pm>=rEKXGsCqvZ?V|o9 z28kRt^yqC_T=141938$FoAlHnWO1X|)}m2rkkj1JkSN7#uqMgEGc383n`%1PAGkJ8NNH#v4XCXPM=j%nzf+ zL}e-@g@a#hMxe|54wDhxKMQmAHLPk+1S`(~L)+EW^=|9TFiyX65`(L;$O-^)`aa1w%Xn}uGxheWq_G0vPfcmJJl)t}bIa2Y=azhE#ZxvK!x zpmGHA_lOC!$U?fX(2^c#^8~1Uo1Ug-4!bi8Xc5&e@Sp&meo-)6=iJb4zB znoSS9v+05!7YNGnmKk`Zc^zIkxy-$GH*E4$1tQer#|{CPaDuY#>SOr+nkZIJs?@MWPX<}OAZkg^l^pc z|Fi&3y2P14{FJwcq?tx1Z%=Y>?W;>H4t|O!zo%@Gn+$E6M5)0BLNR8$n4oD-Tds0>?lSzTgPe6q!cE>fkmcQ@ zBB3)^LqrX{FzutWEfE-Y21#Q%v$hgh>`IQ{1js>U&)P4aj2n}IixEZu(1N$_<74uyt9NeG#I6AJk)T{Ue-`uR)-!JGT5aIfoC z+<$j3yQKc*Y#abso{0ogKUkbj+wOAnp7Z=P`?&e5!TI=qXl7x^cl2aFnn2aLRz>Iw z*o@h7e(8^Q7_t;Du;Q=L3OtndSm%??A${lMBYsDeiy3i!({bxf)i2MYqpU}IU+C8g zXX*$9fy-74BW0?gk*^43^fPkyQZOcC{!A%ZgHNQb>1WMlcjG(j{oQU_{_cS4yO{H& zu?{V7bq6%9vSJO$7-9z)Qr5pJ6_JSyBINjv-V7qZRu?`b1|?@yhyMBx%u#<#+wp`4 zv7cjzt`}n9!{Ki&cHib3oqhOzRN4NkFho48BH?$2uj$>E((3%e&-gWADZo>uew74v zC^C2O?#JhI!zE=CEo#A-ht<2d|6D~yrM9Xn*fX=A+7dlDZ+Hh|;Q&x{9Jl^(*KU_K z0OcHa^AAT5n6&_4JU_)kA!-`tYg#iD53Kh4cgU%u-eFz}xf^D>M2q7n2dUYlK7iDA z-NZ3#%q$;(9qurKChq|UO!jq&20VCzc9s6IYwr=mlE9MuJO)!t&qDeKo_^4R+;wZX zi}6vTiPrqTS$jn+DsTqIwV9|9ElK_T`AS*0pg*whn;1k{Zb+F56nmiJdzCgq9(y`R zU#LIzNZ?Dk^yz8VXUR#Q0(ng6snMwaaj&A*-bdQ*S+iVY$_`++`*u)$Z= zd+tf-80#}4G|LvTviq8rE}oXMe6e0`kZGY=KbxFag%_|@E$Vs5ezo%I=0A2NIZ*s@jlFO` zp6mJ1K{o+7K4f4u;qWT3o;Im>C~PQzqQPZI{uaZc=x_v|Y8n4E#MP!-rEdq!`lzhX>GKc9TcI?%Fl*pix>#a9d&0w;tPpy!`POvD19! zh3zD%s!3BUZ)?Ak)I1NygX$c2k-ds)4yhyHqWr%b-VvS~g=|Qc z=t1S}j?eO3*m}exlceS8Tu)WKMAwwl_Z?;UExfCwxM?po2h3^vL=}R!7@d z%D7NLhJ36hKQ*em{)!>7?R{aPNES$OU(=;eWC}8==bAJU^BRwTtALV@@Y)YF1p|TFphWm(5>~QZ!h+Sm z9*<;DJzq6ujSg4(V*|i)xg;eg94oQ;=W0q zR`*1yQT?V+H@p)~1C!${Hh#6P8HWeSL^aji_wxMJw^@dBA{_p_`c_jp#JLbdT6B#Y zEh)DCeau#!M-NZ>$|D*?$(B4dHa0GMy^PWa*hetNyF>AYt#){271Xl|0%_O~a#;>c zjrLcQjPvR3YccvO*eTRyNAfCo*etbypuBPqG%9!fmwTt5Vv$@=U{g_0vaJ)rhS6s z=<2G4k}>Cl79JUl750AU7wCn7Ek9O#9Lfgt0XS9Q8_L*NTkYB(C^`s4){(1+`n|(} z6yPqs`>Ith<>B)1#ovAPYd>@5MWFPUfT4lxcuY9ezszWEQ$cVs)=hWT zpuz!p!QA1PAanAquP$uID{EM>U}1n?T9=QV6{SBmyHqp77SrP8C>8@NOmq z1v`!0Vd1{$|Elw|*`qm(UfgcP`itG9xwkM){iJtaVHY7V+PnI6**u-e-;?D5L7ief z0++JzkNaPUe0QsB&aH(s+8PzWJdok33)1|@9X8TFq!ZYI`+;cy3lz7Y?v)r;NAQ9= z?q5K!a-zk%NLl7|LnQu@1OVon69cA(*(vVpuoQ*UUwDy|M|bn?`Z*dQ;D74OUma!| z&v7x`yym1Cl7CsJJjEzb2@=jgQxm9&5W7{VKJQ^!?j4ua%iWa87zMU0c7l86fCLso zMDys63;ZZAOa#C#Wm!iT@7){z(dBYB<2*c2aRtgPM^OfivhfaJYWW|Uz5*!fFYJ10 zkd|(w1OXB076lO$k?s}{mhPonT0y!&KoOSi?oNrNQ*!BUzWaaQ_nUEcc7_>N?%vv+HQI$ICt$-VS|C$Fd?+X6$Ezb?iyqdEysrY}@lxFr{xi_yt>#T!7 zh$5jL>3FujEgDT1Ok1fa&#yBq?3p7jEs6|pI_vKS9ta^hXhv|{vZ>c8`R#+GSc~BD z2~Smn_-!fDx0ydRB`={zxPWx6C|+Q`_?takD=(D(5Xd-*c|`{;p>Smds)MGo1F>tN zT*Rz0=eqV2gYFGJrMvLR0bZtA_5?HtC(|&cX&LqP>R)~rW36u^<%8dPOo3wC8XgaF z*}(eZeY!${>>lqll(`JDnogeDy)TVt};%0Ji{*(Z{%Fd@S*8?cI@UjFdz0QL_ zJ&z9e{;R`juE7L)OOV#&FPA_4hoa8?x3K46IUYD6of{T(k~B%<&B2&VOcM$5sYjEx z+0~FFVIuZc&aYQ3OL7puFHoHXR-oUD-xL9IdJxKL30GGpt#3H7sX)O|~ zS)By<>ysQnKrmu&){4xprwcVrF1ap@pbjH~Fd?1dM}O_MN}3MYZB1S?Gkuhq=OO{8 zpi@JmhRrFpJB81k1;#j`#UN0#Vb z+O~=iL=+4{_tlirrJ`LuHv~YHo(5A~rhXFO`ES;=0T8k*On-vEmfhKSz*AUZz;`_? z#;t1q_DwZPJeSfrT1jSy39H0iMGa-cxzhG5_MZy(u#op6Wr0&i562 zcLAt&j|Lk*@b>O}XJ!pnnYu&&-*Wrnu|$m*I_dCOO!*^G#6#}=I7wzJ6&pWf`7eLf z;!P4f6E_!8RO)8*)_>|`C}l!bG*^K!kE|pTXBVREw&aZ zS&K}NyZN12oh@N+#uS~HeSPZJoaalm7nt71gNA?22B856aoe88{Jt{T<~x8gOgq1x zvxcWRQFeNKfn#9Pqm;?bi(pl~)DMq+mHEQUWsf@!+rezsIuY*y zp(fA5QNMO%n{42GA`Ev^l*ym8N?ukfj^b74sj6ZNs0~d@YI{TZlv>6yhEs6Sb6lWi zX;N|Vn8Ee0&_kv2P4tr_WQoCPsC+=g(i&`?@V!uP)zoAC?N!gm5aC6{o@<-PQ*eTp zbCH07d9)dm)5C-d8^L+jl+k}MP$}#dD1HG>I75X{eSEhkIi2c!2q;o9}VQS_7|!E7o#%v1umFmPev_y|>p!xDd1 z)1)>(`9?4C45;2g3Z)5$0+=dh?xqC!)#5tKt`>ezzU8F9T46GwHe~x zfJK8p4WJc*mu`&@_cutF@R0?*Lcm*uLCLsYg9NlikIC1tmgI(<76@O>5?{i3@I@m+-0N54hrXE>L=oT(>dt5q%h8}u8_wRdwO#> zA(DvdXTHIrsEP&w$?no1#K9XdIpE-e9RR%OF$6fj{6;Y+DfZsT{%ClwF{^GERkq*sMDVe3Z$ChWNwI-4*`Bxt5Wz@dI{oEo2AqF^_}8=Kf8(nF{S(YM{9K&8$&9-H%uX zLs*yKhXA_=U38$Qb^?iC{3Z-vt2^nsW4);cVl*!0{twZ5ow(s`a(~$V^;XQzod!Y) zuL@(GoHmUJE#oRY7Dseb#&6a=3l9KhT#wS2WV>84Hi5S#OTY~%I#i`JNfCh3msOs4 zEt(hi1#SkU&k1JW>qK+g>;?l=D397J!>Xun&S$ZBlTcNyo?tehlgjH9k<16RQIMe`&eK8WvWGj1-#^TFo(R_!@93S*d1hvZ z*q&u2e5M*mSVvhynVZIW)7wRL80^PqU{Q;{sugm0+ zOo%l68J>lDFI{UiFa;gvupjef%%!HK#eo*ipvfQ+@aRB4_jBw!c=JI?X&@{Nrw)oJ zR#z{s?TV7spHBdk3;hIVe7KT~Bt!}umHyRZ1rAObQZS*Q1Ld5WeIXzFXA?$-qmA21 z#Zy!;U?@d@JKE44sCjFa_3@6C;|~uyrs~Ipoa+w%w6qu9>^w9lsg_hSO$J|i*)(s_ zS`)Z+>!*yUwlo92>IPVp=}j#roa{Kz4zP!-ol_Z~wQTw%K>lU&LYjT9W_a?VewOGV zXSuwMKTj-pN@WoUT71o|-QK8xfR+y`m6Bxs3IJe~x(-q3Ce2_M@p-yBH zw=hCZRDEvObo_@w=8GK2qmG}YcaK%n&y9No;p}!|rs2r@q)_JcLJn@o z(*;GtbFdXSVpVcf3Pz`=DZxe@5Kts-Mh$*>+u0e^FNmX{!10q^MJ88#Zu=w{WLE#+xlq&X--FQCL4|1)m7YUs5Fuye88B zL{lu9jVf09y1D6#!H<~%)Q=3F%8VggMmSG$g&Rjn*Uq%Xv>%!cM)aw3@rJfZC_EZ6 zo=rAlzCwr}gJ7A*xZCaq4Rdpg)`GGdN=xIOEv1+N!J#rNDh(IKuOtreI53e-2d`gg zi1T{*bj^9x#Y)G{299Jg|4}X4+H^7>&|_LHFt^vO5Fc4P&esBS5xaKp6v8wLSp{uo z)ky!I;qBN`Nrp4U4236>kdQD%n`*-~7G9Pm9s^QFRx>&P*Jzn-~RGx<}Sv z8J=dd@bVD15OZ!7Vc?ZMC2H4Y{PDZU>v;dGb4KjXKsq{Ur5+s_*~_$K;1yk1(p-iACR z=wf^#d#zR;>-tK@KT+|RDW~0WpPOTDtt5@q`3MWf` zQH9$G)5E+DU#DzxKZ}VW?qiZk)J&vHl#I_Wpg{NkRb`HxZZwpr-^nrjWprpF60?Q2 za(3Z^O)!MTc;+po7%Rh>_kmP4Map7IC!Hk>KcE$$%yZU)P9!NFO^cHy`$dy4{0Pge z(?b25o|3Q4X)|`C6zagKmoDH{8cwbKA3ov{TauS9fBCKy@KB2^8JkkVyB6K;j?tXu z9Bx9@&V*0RUWk`OILZCW>w6z7!z!Qimw!n2SCZXQBg|>IrXnl4A|vN}^!sD4lTQlD zc`9Y{v6LHg74$kovq6m5(KC2vft;~dms1xsZlDRT+O*P)e%0dqIMKRzg5O};L$F#zCtP2+_mpVOnjf!2kHb*Sn?%_v zQl3?rcJZ{eAvn9+sN_TF>8_$3zlEK!D)tITo)_FD@q2W|0B~v8g!Nx|gD;sYd^?9d z*0y>(bURwP@2hdI^dh~a*EDzpbPLqDO5&?DC=mU7&t7S)_Xc`;ATwz^|AqJ$Pv(60 z=Xq-IQoCu@`{(_-6i*&rZk#l2kAGb3!2DH67=k}Fu6q_QxvJmT*7l=d>X6>Lfgiii z(ii^D-CZub;(rqpq~(wN@H#%dRsJ`LbYaa?6W5P2GzGaRI+uaIY>Yiv%^wQ=vwqDu zwVfFl$<@F7#MS2X$qnX0K9Fbm%zH^QW3!CGE76D`7{46Wb}}rW`*i8Wq47jO@7&$s z!{;6KM;V>nRI%lSmWPtgEZv4&>@&i&6G2`4w_`TH+qmr| ziLb;}Q|!JdlNNli;f~@p8P8W_3TMKhRcCEzlhDn4zLWFLa02N<5|V9p9S|tSxgN;) zZakXD;!o9ZU;{5(vQqQCP(k_)|5%0Fk0;pceFdC79Sm2@98go0elYWBs6geOv8fAH zPpI?krlbc6*^_^OlA^4PmsmDN&s<(x&--k0+2~(&zpOF~yoyOtl?vTIcQ{m|AZ}G! z5ca90m!eUv&wg2Qy)bwxY7XTeL6`%rTT^qRzlOp(4N{h%hNVQ3kFVpvxXyB%%{Y>H zcer90eS;>#5NYpFSqCO8SEJ;%CW@tDl!!pjJe9HeioJyX?`H{) z(D3VxpG$52%m~8UcGN14=AE3SS3R$Oa{k7WUUmrCbPSg!dbe-KKt&bf#r!X0mua&Z zBs>&vI$xce_2U8O=>|SPuJoc_YnyjKh9+Qf|!r`BCTY4NZU|R+D*zboeq1 z*_gQh=}-A{DC%-`K> z{ibb%JDAAecZS=7U!v(5)18(tysdq@@1P=5T$2TGQB4rtjy9#r{>2%1)A`i}R(+5GiBL(si>P zkiQxmEL?ccw)j5qvhhbgDUs~7a>&6tmsKVmKYOHQZ7{CHxB<)fIL^4H$@(7qeQ+-DS8O&N43RCHo+TevvJVIe6RC>_W9))Ee^V|1Xw zz(8ugRv9=a_d_e^_E^#CaqqoN@swgn;uT~+(_n7H3?w^Qu~E$;k3?zks~i|{KcVsq z+*7^!Q^l4SH>snW7ZJNJQ`7nH^{fMJIQ&UqB@0DWpl>B@hc#4Vrw;XoDeH|ovdhCI^xNW3^~t)FJbv-0zPt^xWH!MLx%>%GNhAM|4r(Zaes7 zL`v!*gKSNE>UsMMQf(s&2io^g_{(l~hynX>BX*#5p&lCcHd@7AiT6CEXl ztV*oPGoH4aW~GcxVx-U`t#b4hT9Op&S0ANFsK3En?sE7HJ}YUvO)?^|An0wEZi>E; zn+<|;oG4us+LTc|2d3rE*t@NdE?u*jiJT^vn&ziM-{C$vUJ#&drhE15Tje+RC7)yO zc7p284@A$rS1enM1)~(7tUZd5PG_)8`D4v*NwGxVQl&DKVBP0|l5vNv8w$@&*FRzzwKTzhJ$Y*_sOmSe3`hr#LVkbM zD*oRpc%ZxQ@w7kL@m_IKapJ2F(DcN0T)3Ucx81$joA2(cqYw0#atZ}5+utM~+~i}S zl@1e+`A8ns>HXx)r(s~A;L0D@iFkom&|Bk#xuZhSI=1WsX8H@`z>e_vVDE_!?&I*~*C^Q3#nUB8wl4|M+OEZsjBtVPYqUb-7Oe5YAaF zykT*Bku3f3zBfbFeB+IRpNGsTn?x!-(mCz6JvdmX1{Y-{>1ya(8% z6gW~cGTxTOrG+(z>p37uUX~PBk#i+D*|-NXey7@ttEsN@-m#~<4Z{AxAaUR(A2ue< z6DR(7LHla8*jH6y-I-MLR?lN(eX@dzyn4ZQuC7jGr>l^n)3F00*_q<-62sL9e?vf) zV1|x7(E8U9lW3ydg`L;3hXc#?c`Hv5wRMD{)6sc+5+c`f76FcxjXD31zG6}gC8`e0 z&XQOQkZI=IvSP4(gfv5R0rb^Q(%*Kwg_lZh>q*&;`c|HU27Ok`uYRiBcN7^1O({_zRpY z4gYzxt$X0Vr#vveXFYAWj8#~ZoBP+0m-W#HG}f=zU>Vg@7 zYM_Rq(^+I`U(&8*dD!fV5!)KBG2TsS1D~9<5}4GX5%y27NZ?mosCxfyP*Q-w_v%8` zbL%>CRoM2sff*{qVvq^Ue*)G9#$_Loa@x%d@X*{ z23V~ee!MqB(5aCi^WH*2-Y;p9{@#;dk2E)ZeezzD(CQxLV{EnC0P_KH2&TRc`E^kg zC@MeN=tumw7(8+xuxM%K^@p3LAN4>(ir`<#P6q2dGZGIO@gVYicf(Qws|UNK6SI8F zX9Lofv5%D{=R>g2>hjzvYzO8Pj3S9u6sQ>(Mr6%el}#zK){IB=#EEgrj}|Az5zn%@ zX9=HrEIm!>(_9ipG;b?K%UpP&5inT81t2OMdFz?-9DM?6eSh>}A}|jRYTN3?FZ?nN z9laUX11ppIB-F0EKUAK%y@@Cqm&RU6t`M{p*tD)E2qb5E#B|lm$3R9%=Z=?d>)*`A zuTA04+r4Gbcs&|q9=e9Xv3Fd=tn?zz+@K>_eyld6#c^iHb9cG2#dCuhoqFr5;ydlJ z65)%Q0*wMw;*%5~FVC??HoP~EUCysILmJYS_g%>+tOQg`5LH!zc57u*JHpWd#M>|M zPO2F+Kgr3I@v=<{S6c~L-w@EU)*9p{T*x7)ZWcepJ(=Vf`=)=HYCi}a-G+_~L7&C%Ui+R9KnC?Y!FIA)f{ArL5(xgkN+Fp|H_QqJ#VgO} zL_3T4Mlmk7J>USwtACg*_COB* ze34ZW*xh~rZ8^TpG(Vv>jnpiM4e_FxQb&bsQOv{MOjrx{+0YHzTIo+lGh#nZta0gj ztD=zpse+fmcP*2q&*lK(dXMs{PI@@&&YcZX0ReXI8JqqK6T-i1bl}A;x*M-ZAg#T< z?4UeDlCt0xZex;{H1!uMvUluwwCpr@Qt25&b$1%`d8{7EhNSVpB|nE7LerOi8HE z{SSoZ&Azpbf2qo1bW?mKA#LvWyvzYFQI-xy}9&q?|i8yUzWc}P#``FUB>?fP;g zWnj3LG8(2h_S=+oL%?e~9`gcd^t6jz!2{Q!x{{xtKffY+6*|u%e+<+YQ_@8CpM)Tl zaepaIBdbraHrGlXOquKMe#+!)PnBDWB{pC_dh!m6Z;FTVDwajR1xa0e+7>IMEoh74 z#~vQ4sDF7COhgWGuXqwv+WlO-{+JVq|0LiUWHITO8p>g|s2UY*#3Mf*_r4d$B4git z3LlJ;n;0xC{Bx+@$8?dT5c>TsI{L3khrSjU!mbuqsbk=4gPzCi)p=!KCMR^^y7;M4 zfake4kzUl|hG)aM9n!5cT8M)i$~<>k#*$+F9iigiXavB>=NPJ8M;yV%%Uruec4% zI1=Zvd%)@V-hj&wNjHlU7ex@oDDLtpnNG$ZnUY66KDl%Y>vi1LRj{m_VhLi*i&Gr0 zEd0E`8Y4%)?L8rR=q;7$(`|Tl!_}%gcNAYWrNhKz3TKV#a7%P*^NTgLFb@!74tg=; zLJRN|@?CY1A9iw;q2M-lDfVU-x4^i@-Tz-Q#En+|C4U z9O3Ipn!mz!WIXz)9?;T#2}vE7=355l7#c`0M2i6@E1Tg#Iq{VpVp!4&tC@E{hT~K-J2ar4J(6jq)2$%!cZ&NrAEp9Ny*7& z6%`fLV_&AtD=gQ9s~u={M^3mB*F`>+{uR|#{eeNRn6AA9Py+}h)63?h6w<@D{aQSn ze*?=hG6w<*%INxDa^&G9u2d{%V7a)e;&y!R?(VjZ!QwUnsU7^hywacu;OXJaV-IH< z7$1#O0e*QE;V5Q;a7+j=bbLoYi!ogr3Dw9c@1u;RI?Iw6;hV`VyOkJB`6?W(IF->G z@(d;~f{n`e@@0-T*9^~Z3PE4JfCCS^Bh1(?$EJ{mQmtXS{eWGGsCN6r%SnnRy2a(5 z`TpR`=0n_u`>x60&lN27Z>dVUgF-S*h3CyerPt~nPgBUY81sVNK>oE0U3%2aVC}|d zxFF9m#R>SL@ZYW$rmw8teaH%cpmk$!J_$P~Y5S(NLMq!{D) zgsuf|su&p_l_qU(Tb@#rucaVllyfU+Ocyr^HUmqFTQ)~ztjsZe9BAG?6#B^eo}{qI zYkW57=;2QI=WqKJ@Dol|%-E;^Faw-i)t>9zTjkGSW68%(do%%pFcqiF8lWHAAsJYL z&NBJ{L=dQk7r7|xws{s+y~Q?89ycG;OAy#x+#E6|k&8Y}P#~3CBzFM1S)SVjI`qX4=r>K>z~#gh{nPt&+F< zag2eMR%th7h3$eU3A(>!&0HMDvo#pK`ZF?5V205z*ytVTQSw-P^him|y7oP(Y(^r! zTN@J_|Av`GOH%&Zd#EsP zO*};fd0=29e#~FN0lw+ouzYa5zzTD>QIf5hUq?ReAN#fIve~ZOxuS4nVSR4>&4~Dpgu~Xs6HGe; z)B6FD7S#k8{^-i8+b7DmISgLU}xDlLqt!hGa~%ywAMM zYaFt5iRY>cHH8*^1CyefCI7dGgg(E-7X~+cAYMT0xQ-_$ZwZPhm8bLz*AMnfAnJA5 zWv<#L70ilXO@G`-1Oqf?$@P7gHicFBjM%-DZ_e4-2iQ0cg$%T&W+~^~UvNr8^WrwR z)Ul-7SK#vLK}l@=rPQ*_Q@TjeS(V1kCHL-Seu zZDX8DN@!%9iY`sONd+fFnQ)|@1qvTPq@1BA*EIBPxpf5efZQx3qNFD3ZD7h!J{=Vm zuh)mgRuui$B3V6~g%lejDSNe8G*Z!ddzt^^)6wSB9NI&)rk za(hq*>{O)BI5U&i}9Hm4hmR~&!Vq7$${4Y*U5O??O_XlL1Bg?-}b2xUV$P=;dW?6Hp(2<5lnbBh-^LYX8Y_Fen7(Lcbr&BL5s>_6_s1 ziO5YqZgK9|EMZ*L^E<{O8w^A5ONjyA?Cs5N&B|%I|9ie@rxVp<4+OZn1xi*3D-Ld~ zfBpejm>sqXQuwkT?I1YY-!psMa!qr*%R(>o=Z1hmc5WTh3ALM#XGyFVW*NYhn-l&N z%fF}XL5CFKA#~nA({<}y=a=82a@?va=)`E`GRzI33T*s{S4pY6|G@e&V{-<~5r7dn zaMtUEW7Vq-zF%~glat$y7Tbr6Zd+`oiq$|IH-<+>HWSQtQ$n3NVW+xgA_uUXa&BG2 zzdG+t@u*CDFTB6NPw+KkS?WA|9UWgTCGkql19f(1r;O&t_M>MvVe1~rV81-;coCPe z$pMCh1m?TQ0%kYuM8yDQo`@+vi@~UM;D6`KkttkR0&1iG@Z&Jh<{4pOigR_Z&(8>| ze;nCAp`U#~Fg}}PJEMHJ!kUx{a0q+CPxq> z(_`%_88GuGEUB^97l$5bhyWDKC`dQ|AhhJ=WSA1N0;W5mW8gj~UXN!b{qW^9R4AqK z^V}SxtX8)b7p6T+8%u|6i4RtO)`meWikp*~?4f zSmf`8bQlDXxRckQfx$JUzNm|a76py;AHkMf*=T=SRaw1kn1Al#8A2Ae1z733n~P1p z{yJJPFg}Fpq1#lZAQbZ_MCt7=;XN%dd{hO{x9(6=U)_+F!6dK?j9R&Typ1 zPEk5>s*v4qi4C~(>3uGZXX~7P(R9LI8X*|7SM4ck44V-46sD1mUmNVdVu557m+d(s zcU3dEtW;?5<^AEc=e=0}p~*7fEj0kQN52wB#LA1^cCx%_!~?Azc%a zZX-RioG_zNgtYp@?!PLEhnFXN5U-_+ldR$@jYt-GwOAJKE7uwpDZqKU?#;5g?oOkS zqNdQ?{`&O`@SuS}vGPGtu}sH63o1()!pNkYl*Ve!^mDRgg!^!55&-cya~-Y& zzEP2*G2*wlKV-h1n~^q5TYPc+=XBkog_ghqr{}O^eeUM0#)7ILa!m`|5$~3_LJ_+m z86{+52$Xb7bI1!ZG2H5+s;Ni)8|hfmkdYH~V7)HGra>ZI>L3v$q}_c+vi$}QlH%)P zL594t!n)bzpozd{Q^$)+(1Cp6r@ksBAFkIJ&4_!TcPdm-NJ&i{2oyWHnm6b^g+y#m zzxuV{acLV6)vtxi(LUZ$O74-7IFhy*+jwx(ej;uOC!5j%q}|V-Kf$l!2VV@>eP~;a z&A0USB?x_*UtRDL5YS@KBs?G7d=MEiRDkr!i9{NblFzoR9Z9Kw)pgR!!%?IRas6+{ zghe03w-OXNYJC`M456E9e=*_3y!AAn1S_>-XZYzNkLUwEC3;ZlX2!9(_f*KZC*IiB z>fD;}d94h!Yz#FO6|oK!{9kmdt@{G`mTK*quQoCch=(Tx?H2LwZ{Gg=FXs}JAP~Pe z6%+`uLl(u9j=W4xadnf-=?YZy(fcvx`HErkKQk9oC*nWyIUGDSiO^lacl|{$bugGh z_ea8Aqph9P8xC1;yPofX#2f|C#~1~%~gu^>0vI?>se7yUy4!e5-3JL{YONqsqjk>W1d9iM{|4syj zo3kz9P6m^d%#pk~I`DAdM8m$rk_F_Hune&Kq3}V}C^f6f%JRZ$r=@k`yg{>*3vijD z3XYsOCJKNTQ|b*wqISp#m`IGiwbROMBaK!GUlpzf1#eoFlbuw=&3t)dSG%_vTrO+M zFe7ZEHh?K!B{nz`h|kca8AX0tw9!0x)Aj^#Qrcdna|$;p90HchG;;Z|_(h?`$Iv=L zal04sDw6V#{%U4C%zbjKEP@_j@iKTXG&ms6Kw)QVX{uxM-~MqzS%Ug|D|7WUnwJ^# z4%Rem2q+X(9(UbHu~I8rid#v2T26o5a(%mG)Vx5scGbKjz!mcTxH!{mVU zD6t}$?}mxBH6E}qf>%{egk#4hiLah|CaNe%wXJ%$LvHH_uK4fFJhG@xb&?`e9@fR;#ynJ3l ze|MSJ@_I6hpCPdM-QfMs=E3zq*M~1T?EPeipeO&I3N87tiE=tZ$PN;biU5pfhd{}; z5LfqwH$XTwGsTwPJGPkuiF) z2pu3($>V)n`W?7#k3l~TnkDLEF0;1~&~mSte{=+bs?eg_=gGR8A9xj2lk*EsCpeZg zr>dwM4k1dBrnuS!Y2B0^dZ0=9chhVmnA*9gFdx`Bnob2pjdwLyH|`Vgc5g%w$t58={pQG2zOgw26*x`OW<{w5k~aUj)_)R7{Zo0kL^!3{0-xNb^qlY zd1zT_!&;^?bu9i7>^xZIBtJ#Tyegakq^m6Q_5J0L7ZMWOLbmf;3G+a{0ElU9+w8wO z1B}=*MCdU4O_fq0oKwd^zjX}p#15Yu>$m_mz!e3KyDt-!c-Q=STF0`6%|Q5sVK(Fs z6m9w5hBAa-LSkrX^KRFArGL-15eMAgKMu%a<(jnD~w%TT{^YpYbEj`@@KP0+u3SJekB-d#C?-6m!=5cXk;d2-#hJn0b z``r_r?fvEJh6lrulgGlD@`BmM9ZZ7ReS(`;_KDztA%~UVfui;)dWe5hUA*6cE)+?~$LhT!lO}qch zuog_!7rGcq71~@n$#32MmQWPJQ>ovVB8rsNE*wuWwz*AWOSeF#5p(86PR-_9rd$*| z!Q$hMR{}r&e=PvA_=|1TZ9T3}CWOu>J(Kxn5mVX-;3ZU>c2T?ud>4@xHJDM%MBB|( z8Sk;mB_F53iU(Wgf!&@JoQxQUTom;cZO>mDPc(?nQ0kC*qMbCU?BBhhWorpV)vlTP zI2GQWOf#gxO+UpgOH^>)*o!;H%5+@Y+5`ReaPi*_garF{?q_))zW8NV%o9Bo1Pel# z@UlcX*qE0qUw5jMGDrCGFWSN55bD5Y0zQG`l=Fe=yDZMnjuqzydY+`RDo}1f3dPEK`ag`P$6rzJcXlIQdDv_Qeo#@%CKa8`$_@7gT*lO!^4D$p!lE-T~01kk#O zfKYTOqZSpRGnO0N1 zmfOb`C0grYCZwj^x3=fv^La7=qs(Gh4QhK)%FvZ^c}_+cF(W1Qb04$!+RTNhmHCzKiSHjU4oXb5uJzanWT5QRf>3wASA%pH&o^aMX zrdS2FVNT>Mlh_@cOLg;{w=nKy#wL|5x9M1#Zb)WEMhIt6f2oR3(^H|59=rfhw~>Zq zum6>Dx)cAUZ?UGvr|%c9GCMu&Wif>NL%M%fw#cUUH_?>XzjWLw9c8!%h9*=mgHHIm z-fp43>b>U5IUGxxu}-BUooGrY8Am`O<Lno6EIZ|E=c2if_%e|N7#S)gKj z*Ld|E`bAY9K-lYN{E1=pUjTZTG~qk(41j5ci}ge0Y;Jf3IkYRjw;gu)NSc?h>YzKWSNx)VjQQx(xP z+nDP+T}#%AL8}|n`7z8^=RhS{;W|`tY67dm3ykp*7qep%t{t#mrAhn;dn=|%m*ehc zd0vj%ww*ztQEnxF??Guwda`?)Qf7|2)tH~$;vWk7grOn2pM{hR3|P2qBEKzMtNv1s zSH-+DbQwEnBgvb_;_+xYf!k@eT(%g)nso9jgDhOvtrO_io>=f?R%kRf2*YGWC(-Wfu6buQ)3w5K zxU!b^VDaC7JNVzf+;`*rggeTleJt`pG!sBRXFpI@O!cU61^9NUBA;_0Rq%#<5!}X5 zco>Fd8u3$kles{L*z<>x6n^ zPJ~%&xRg?aLFm>_;!4tZ?-ej1@LLdXmZ-Nz$`<2Nooqo`^Cp4D6G9iGN81zIvRML9 z#U3!FP&?UYE?7=0PU}S7Jci5BPd%eZ!E$ak=4%<2)5(vr zULx5(lNc8mA0LNB&_MtK{ga*PiOffeTDYB;M1ju^O`&$Y0g)QapEJvepRk>hx#Ptk z%++TBEcXc_`CA8#XqM_9o=0r@Z(&;# z*V0$sw}8hX@0OpT>dme&eFOnbEvU@Z6mZU3PdiQ<$664&2s?(~42gb96gG?5nWCp2 z53ig;0-vAk+IAE8{qiPW`Ztp$1LY2VM{OEJ1gvH9h}tEh<5UzND%elnRKX(rs5#dj zV{dE=ONjRbr;atul~l{&ONUG>Ti11%nS3JwuC39e0kB9( zHVzKgyDSu=SuJt(_oceGXwi7r^aR%SvunzmNYsZhBIdy28G_M2G_lv>luL1Se|SQ0bZ1mQxVrR@<^OeMS)nB zIEaV|8x{0QhvG`0DyX63$YWWkMdF@Yv^=1S8Nm7&M>6Bma=F)j&E3fnC=31)Q&fFn z_^1^^M<9Xs2G_ZqAJXeFAI$rfJEsY>Uu&&ylxWv@|pw>?gGqr%@Rz*D3B{o^ysHE@4RjX6Gv=4^k7rH<4_6;IaN0f|KF%qc0E6dYE`wog2la> zuZhJ)mh*%Qq&1mC5i9XT?gpD!?$5*nQae9ZX0EFuBZ3XPBXZkE{0>!6pJN!Ol?$QC zsrncmddhq*$Vo)q+nXj_Zh+XT2aRAc^emWVWMVxwDUBX_DsXMKcQr!m9|hRY7QGf9 z34v5av6n9cK&hKhmkeG(+Qa-~@}4qKVtiH|kumS$n6NmwGrHM)zVO=rqET8ut~80z zcFD5^qt&VYs;%XR!!8(V0GDMu2xUEq^mcYu`w#BQi~BukwftdeT?geKsst3S@;ja_ zOJOK`4i*}&(*Ic5pdZ*b*2JtkHqLEm6sVPU3)VDGmziSCj{#0y6%09j;V(M4QQ?pU z&w!rKFM>VA1ofk2zVvt%YMYIHm2!>n3KP01IYi9}SANfd-4Yoc z9d4~5=GW->AKb{r#bqzsF&*j{=+&E z&)X#8OG7ZV8PfU`#jEmKS-g76iOzBNz3EJc34oXf=*ZE&+R4RMHtEuP)Raz8Pm@(e z|2d4H6&vL!JibWFLs@WYK%QOmZm=X{E0JBfKN@mGQAw!j_Z@o(rS8z&?h+Ra zlMYWc<2$RCvkaK9YlF}w)s9L_T(~8t-T4F)?r5KqY$+b2<4??B*ei%c%4YZtYRcN~(R#}ZA&(moT4+aUZn(X51R9M=2JB9`U^ znFi7TNn}iv%NTuuL1W%sn3ph`;_i*NRjctu0(ki(5mu$muK-C*|CS6HaQs7=o z7_E@i|3 z2?=@5{e51)e*kt}*Eyej$5G$`FobXNYM%0x2@+m8lR_l zIUyywxY8O^0r-U5%OH2+SOemnbGAqWKIdp(ME4n7w3-j`rYV6vPOY4tMR#6MTG&b(~<9e2Q7 zl<&Fu*4)UY%)Xs@QQ;|BRaQ?SRhQh3$QEMt)O$rqkwA~+u(hSZ#Z|NRJaOqTwX!*u zfnB(0$B|iCLs^no3BXViH)aK^|E-;zzxrET`xgnz!Bkm?dwGbyt7OjlkUR5 z-bPwY1y%x4s@P1Yhra7BNY{h6Gydy}3)C%$+jQQy`FGUap5cf3w-=pEx?~+(ek1=O zU;`IA{JU5%0O!igX?|U~GxojFy(#0T+vj<4&#|SwAIMa%zo&K1wpUhcXLSX&=k?hl z@4Z}2b{<@$XSY@-g3OZdj5?nAY8>Y(OalWLf)zepiY)`iW!odXJI+D3@Cnm#;ZC~6 z>u=eD3X1~c9@o=nu!CdOiPoK|`rZAfL}AZS{tOX#Sd32QZ!CQqCv1@K5YHT42c=fm zg0ZfZe?Mh{W(8}#{)N3V=zv8$CHIj6YB5tZfS-LSB0;=guDFs={jI4!$EBp#I)yMI zL4Yt+_uI@5whdHvYp=O!CS*r1#_k`>tUee}Ec2Yo;!F(I+(KTDeuAQXtD< z7IL`qF8wn{$03JGZNYEpT;BVDym+DSX5xDhLiFNGF?FctL1q8>iM{5(lWOqyeD7TUhR}>RT`EBb^Lf4>blzhGjIU8&1N=n@>S65$uH+w zf=_yv;jyFLv*Xe>^fkY<5YCx;e);)ke{)cES98gJ_p==w#N?LM?B*dGPI$1&&Di$P zBA&Ht$eQz~PukBHPqT~+3OGXsV4sm$s!4ReY0j`;i?RbK09o77Mq-AkpPNdko(6j9 zsIRi7L6T-jkG0wHTuQ~shGL-RYxfeod=9_pO)J2qE_)1+hw$FfD2LH=Oz~K8m>FK?%R%epEA(+WA42Vp{Nqi8*i=m2humV^A_BJX&VzZzx(VX)RbWRc2}%s z3YPxOevzQ_^nx+Mkoi*`Mfu_0Kf`UN`Ah?MLMZ@Y?B-m=k(H28=RF)YDIBw}Hg(V{ zM;f{t8Xryg=Ncmgo{JIezY&k;Npb}KVd6>V3iIyNlV2$=kM_XW4}e}*A~CR;aC@d( zr&kh%q}Wg^x9Ekl(t;VD5FW0~y9kcsce1jwMXrA?u$aooLz4uTofR_lXar`=p!3qT z>z-_&@+$kMCF}JILgzm`H09|6ma-*)n)B4$_Yi?&71EL5C3OH5=cDO8lwK&Sh5ge0 zglyU|O%Ty&u zb#pT!p`YEC6Sxw)DQaa@E|7gRFUrockLU9rl2_R06)iRO@2~DBW9=5z=XBFUTjxbK zaNSnlN}^G={>kkr&?+j1D4#R=>$zt@y2b+i0;w zszv@X9z5=aBjWyV0TAqA!)koUcF2twD|!G8=JVET4Xr0&={+u8yVB;35>drKw2xYUrA zPI0ookfApZM`Y-+UpXxa2BJ(09rpiQ+2?0l0kn>8L+ZV7hzpv6o__LiR7J*X83nO_+ z4$`3?c#^I=a`N-Z6`->~+4*2-qWPc-pVaZRZ_micBk6tSB7N}L!BZNWwD-@(ALM;) z^M^%8ziGXm|D1gD1v1WU(+-hV=)z~l_&Z`0$!5v$bA<8oOZxBNw$XK=aWTP=a~`jn z2k+A6vWxiN%~+XV!LL6+FMJ>l{~Zm=hU(r2xjR>R3SD%#|12P`?5q9!;zIZNb05Eg zl1*^LXG7P@m@#i49nonO@3G_|hrgy*Wa$>*_mik8d*#pqgyT9-pO$Oqi|UG+Yf!xD zf2fYl$reMvLi=FzO18vtxV=aJ@1MdD%G<^Bx9Y`B1*_`+a3%s{V;0}JBnYrSw_SLs zZmgyXq@}`{LKk-X9y{KDS5S$leBcnM!O1C^^1yHVP_=lL<;7+U`H0*;afn-j)F_YPy*tPG=ZKKyOgsJ3 zd0GI7P`oZdLWNk$dWg!pos3s}dvT9AI5^ZfRZdP$tZi-kyq9I;q8^B&By#iQS34Duz{I zx*=gk;X0VSX4AZUbHs1M$aD#ofdfsRl-3CXZu5RAnOj&N6=Rf3Dg2tGF9K>B{_O2c z>5Qn7(5=22gd?OUgn*T;e>tEgF9RGcrqe{aEQ6&IX^YmSG;3k=+jf-+*@z#3tHz_M z)^iMveoS0TX0HM8mOy84!PQK%MDURWAYR@l{8N|hCB}nOpPiX+xjR4Neb3e1_v}@q ztC5?J(D{ELNf58=UE*x&&PIDJ<87&(T_cT`|MeY~x1gl2x=sQZbe=gxa2Rm|0y%HR zXa@;GNXZWl4X(J%M)SvK%q>-*yYLe z2}l0pk?0HULVN+NP6Nl)p7}w{(|Fv|qE8`oS6>)=8I7Y(Ac0o*cCa8dkz!OKqQrY! zR@#99d=8Q>5gYhKyD3YXn>KIGuUZ|zsOHiBH}62H0BGXclnJx7K)Xeb4Aus^zQU`(FuG zdG|NghX-eZ>nlU(np7$I?pSH>$Ax1&5i;4x_kQN~G)ZY05WK z?e@XB3fu~-w(_>pJ)t?8N~K-QuR#CYYK%F$7Z4mQyQ4?Vore(3S48kcFhM&GiEOkO zpv?{FA%2RU6}_KnPilkz$lmwhqMp3uK1L5pXOGn5#4n6cev1BZR%ff3o5j9*ip&OK zRsjkYUYjUY%F&iNNgpkYNVADlynLpfYX7^|q86<9${?YCfv52#*R*v^ypd`b?FYZK zjkSU*hu;Q>iUYV)kCMlydN(zRRyKwMWuaoD*b6eo7u1zyUglZN! zlNP4=KH!IW=4>PqTyR1(^%R4?*O66!0dF$fOV*l0Ys=fHf#+>`HyeUmPm%g+drJoeJ8y&C0XfKDAfFD zVrYj%vHy>DIo5n?CNBoo1eWopNn61Vh)TCgb%|&CZO++XPJt(ylE^q&7({SNGYMz| zGq9;(aI#M2irg$cS0C+6tN>LD_{!J5F!QrImY}wRdNPYg6CHsqXLVgaW&koY?LNI^ z2L8p952;OU?rsy<;6i36%XrGeTAOy}K5qY5_4K(`?=Tq?^v*VIN?O5j*aa)YxmR$Y z8&23d|2VagtW*5bC&y%K<-EU-gWrKIm=po)*20!EUgxZ&!*-AqXH;tCx@x8dU~*ZpZ`Q?p^x?~`Fes}K;f}(7jU$fG}xsZU;=-n?M46T zG`pob*K5zNUL%1xT)r*@s}n!;!#`lqS(ukM%%z=+Hf5NNf^ted)~iTf3M8XXT?xFN znGR39XixZXc)0i&aI>ngJHXp1p`aIc3+;Q{?-Y*dR#>c|o~yley!YlJtZv*+gh^2X zPn`q%<#hPbLQnGfA+04>pDI5e?mypqZ+`hF6XRUHsIl%S?0-FGKWXo|&>G%4c{h9I zPdL*zKehQ4ab*&^3!ZnT--`40`MO)wJ)Z5@*q1zCa6*2auemrJ92nr2lmvTN7meO! zj0@vy_KxAZkTs#Wyu0 zp5_ErtT&tPwb^4D$L2UzU`{R|Dw^eRa4_Hs#^xD%eKxUvU8E89E&^0Rb29iW#u74D zauILNp0aLCfpTf3T$jQN*+6a6KsyDlmx0EQwca<*fN*yk5^%_1H)rq`Ke)5~+;8d4 zmoFuHnu>~bSYZ$IvyUQVFv6MhT6JQ(L-xE0dp{=+?jGX8A^b3#;lFU^1XXt7y3t5}*XGUDtg z1%cpjNOHIpCsqH^h*?g2YExEaSXId$qDo*BNZK`B?kYMcCNEC59A-q+;{fU!9jIC$ z*{nsG7E7RjxPZUnmVw+(5Dbc`rDx!sJY#bXi=OqN$|fDM_diyE*6778>^A~kC&`he z{>4JtpC98=PJC0)Y zGU_~#3~af#O!@PJ0aYOKwnO2_Wd3x=*R3fwL={c+o6d-rH&8O>{oX8$NFgY$EGdHk6RVISk z=TS-X47%kpu21o|j>Bvhzb3=|{>+@jzk(3?{E1I1S0g?^bavoJVU&eeJC)aNY2G6v zHm~eZnrPDO+^43k7a04llhtxHmj0VftG=(J zW&hfY-9ku8Y6ReZ#XYx)x3{;yIbT5b{+{ggS2is>;YWo1I=`ZXynp%0|5sZ1A|4&C z!e=r=x~C{O8ROp`)BTmJ#^h(#xA{mzRozWnIUo^08G5g`MoTtLPm!}9Xok}g?h|tu z_RXX}WVT6w$VV}a!KqE$dq>ch>%#saY;mHM<9ZI;Uv#92n89l*Uf9oah7*0Btc|HQ z+Tj-yGxApRJg&2XeVq>g0>8%vIW41c)fw&7&eW(SF~rZPnH2`^K)OiR&f(vd4U}?% ze@z3Z_n#e9A-#3W9yINm6r$5||REGejhsdmC)sq7_A^<3S{y01@EGO3i+ch0i zgo?uMKz}C|WJJ_5$mwqk9o!U-7>g45rT{f|D3KD|^;c;S*1p5P*cZVBkW3}W1HU4S zbTTksRn{LsX=Y1D@m1{5T94OplplHFyn8j7xAQme!XFuY1JpDLdfm8=PM4Uj6L~lJ zg@p90iF;Efg-d`O^g2-J&2Mz);r2HzsBdkq#kuLTygWwPKoU!x@Z{q#QR8=#*Hnrj ztGqNzhZ-n&svWgYt9gEDwx0N7bZH>npa4(`Et|Ab-30|&r3hGD7aj(EJNfltH+T7c z9PiL;2NQdsoPnmujGqYZoIt@B4$qyTxMpl#t7#mz{{DF@x9{KXb#5Ka9U`JGs35^K zw20i0Xk3PuZx{Wj=XK<}S_*l^9iNabQBw;OjktCp^ujFdd!E{ORxgtGUF2dYWZSY& z7I=Fev`PG4_hh=Jg}f2-9hvO&^`y_kTL@z>NS88u*q4n`W94iWo1G%_POC=`f!GT- zHtqtc2S^j^7EkJc{&7;+&W6~4py=+{*|AX1n~q}xW?YhEIu$)~V2pxxN+I%+xF6mH znpGPYmlKV*z+3*OB)`*2a(k}}|Br&n@4t~^%+URxNNTjO5ZdH=`eW^GT z2#Qj$Zq&@;U4nXG`{mr0D>*I}qO#n@&-B}A)=qs`+pD8_4-$pMoH)E{x(;j~D~v z4>@A9f4ZIgqcI6&k&a4EzFyjgNQd`ppXpgo1&1*xW3TQQCa){?`Gyj#jCVEh^E0hl z@#{o6Uk~m-uHDDK>z?a#fGJ1Oel|x9y`O$ zd(7r8*wo3A-pAlaU;!Bt3piY{b?FIG8_~32*RJh)-O{UcKqeG_?470k7$E!;TmiYbS#Laq z;-$`g$8D2ru6vTV*%B1J5Q92*tF|8j3QG$tSuX?Hi|+M)-}Z9>*n6ER_Ba-D5Fbq` zRP1_m=>{9WaeMP>1K9L;F$e*YjKykAr z^6gLm1Qp8PZTM;)*Tv?R^K5f8GV`^zwP}eh zy5WFFFGljJIDJ8U>+ij~>CjH=d*xGTZ(_eF>9wNWy3}Z(N79>8{bU!-Pl*mA6g&7c zo7Jya==qswM(}eoYr^bbn&P-+d2mMJwb2VdB_KH>R1 zCZeLHMH{)~lJC-lSajFZ=FhO)BQ|* zh1Snx;^f=V$k)*eAa-1*S%}I*`Kj#z-++tt{`kFd$8xmrgy*D7lXlv}ElKC51yI~| z7s-Vbaj>%|T$z^(oFby8upkKmKE9hyYk011T?$f`tToNAk7l4(%Qg#}_aWofa{oC* zb8}bJt_HMQI5Hc!Mx_=0KJ^EGDokc#13<)DYid@f_Fv_dZe9h?@%OWRcdP{Q3QOLx zk}6hzlVaG65(!mQ-aW`Bd-*}Rgg#K|?<8tFmkW4`Y_mTmtEeiXfprQtd989~woCY# z7@cL=QB&=Fbv>@TlWWP&R}R$DC|3N@l?6L~Ex|v9OM1w4$*%3uKyt0hr0l?JhHi-T zYXC7ZUrd#W9;3Bt@naeVL`OIB&hi=!)(ca@A~zBmYev>rPYwXatI?@lD!kKet%oLU zdQ{2)N$RUX<9aqGU8=$a8ZH7;ED8jT|zk1DyRqofTu@|sZGaW^^vf_%xBi4T}gAm zN~hvATYX$?WPZ5t@U&LZpNxaE@7LcC&k13}1@xn+^vyEPOxb~JEmN?;>o}RC@HMWw; zIdef1N0JQ??P^qjc9|Tyj6I+}!F@-34nfR(2D5e9D)#iR@$Y%kF2!#SYAEFzCv9SV zo(^_&UohQB2197Gm!0n*P-;qhS8uq|0^CU;&1Bs;v>IhD1ggFd)=h;5K)3~Kh+nTI zKiSHq)1R4etekVIr-^)&<@O;mRo-pf55}Smv$|^W+jd7(+HLEll*Wi;k6BhAUsb9= zajOoffwPC#{23co#Ypr@@>uZLVIXkAJW?W&Q3iEa`op#NMeW=HKwXuR8P6wa0FHY% zzYF|GNLrD97Cn2jwv#>r0_469>ZQo5+Iurs#;KB!j{-@dM{S_fe2td5D2H=Qz1T~k z?;at>oO}C<3vG~;KLy?AZS&(6s&iU0=^6>gYE|afy%0CxzOu2{;%RJV_HmFg1h`M~ z3a)aF2(FnOb{xhFYY+9$5pg9Y2-s<%(w|qu_PLsIE3ZQKGf)L39jOU>!1CU^b$`>? zxpm3Ac4=%8bJenz-FXC*RVPMA^_Pz9=JI#^6g7ranuLvp#YUO9>(-ZSm?JBnTNuWU zk5nK-jIT@e!CMd>oo7YxsOajG1(Z#ay3^I8@)$y{-GlqNEW$p2<_z9PSdNg${DFq9 z<>54TJP8{yKR5_j=qa{Q-3_Fx?AudwpohpO+_o7>ZrwX0$-{_##U?Sk^EOsz{r4{U zz1n2_Dz$^I0bG*Mi2{lGt^OJvp+bg$Jpo?9l@Z%dAUqsPlSFjCn<69$@AA4NQzV$F zL$(nr`?zkHiQT~|nCJNCAw+FbiF6mNn-*-6o+zXZPK;^_do*U;)v^($xwH&MW0CyC zJfwu#e9uy|c?{0X{?d}p8JzT$`6yYSGTVz&vVnraT~d~pl>kzv1?n~6bK?yCvzh)> z5VGjK;EX`cdm}G>dd+{h2*(%VUHApUETdWG zVi=NkNiwbTG4MQ4Dtr2tcVz{A8u?to(`y)xc+7n)*ue`VbM!yc9@yGOK^3ho`BN8b zKlRYmbmZ**-6<%iM%&t&?@{M}`-Yu8we6HU!P_$?piVabX>Y8M12TS6klT{+0~yuF zd!mtib1mInt!{Caf0%TdUeZ=kzlcPooscL z_euFJo7H)~n&`_W6zm_#%n++18taKqeeJ)P0uA@of{grxG*k$SBL*gKNe{fj3+|OhFYatO#@V zHqYKN$6;Lx0SNp1dv>!T(itvBR^q;?({sD+Z{No*njBK)RBNO^ z(_EuBa`834`YM3-olINou=5xKWP&O5>9;7wqTtKlf)wlQyTMdG3eSaO!%#F;R-;a5 zv%ROoBaOW2*&+kqzO+@C(iZBJWn_DKYNtgureVop59EEvdT|O1rik45kkH-L`C;;vgzi86Fo=NNG_7$EDJRMRXR&nK|TUIWIB@>{_X!0`b^dLr7k`=a#k`M z%JZV)iaK?nFK(r5H*lP@s_aB1?ETipU!+vKvktVdQNv%5yd@L{@k?7a`h3a59 z&SACn+T;B*=H>!a*qp$-atSEvd~*5eSJbNY(nGLr+(~TU+xu~o%k?a{MkS;xXIfRa zZ+vDY)GE5U-mF?Qi}gG=mztu)&Sou~uV$;I`DCoF;!E40iuGDal@D@wgu&l{%}<9| z=~547WBUW5Mo}3s1XFU%i`$JdOnbOV1|#yh()s3Fh7Pp+As5{njj>8-w2BCA64kc6 z&+be4m=J>nIZqUylInSWu?v3kkmrnOWBc#1@$oD#OxJgfiMoV1L9yLa|MyESQt{?@ znE^8dGdwg%mI{iPPwg8z%IISEqxx|&uXCM@QfTQKKk*!#$l=HRzxzMIFiZnk|3&IQ z2YP(SeC4aZiQE`f#-P{FvE_UY=pLMOFD@29LP3SQ>)lGBLV6DmXZN*a*RwY(>X$um zB75(ZFp+^8z2WV%JFHaKV3H2`=pIU<%5jwXb$j|n8#IKzQzMd*&ON8zDmo;fL`=9Zn7*gq zCybeS+fT;|rijo+!H4U#uv0n?(|7zb9>(G_6|ku)E7nj!Khw|b7tED~2n2*=>8; zx^5${OLvMYjnQ@?q3>PVr})(-^(hK}Rh(QjBMr>t8H@#eR;j<~ulrynz?pxtMl_)W z%J4ScOnrfc`6EkQ^`|I$wpvL4j*ug4Z)nkLbjb~pSf9|MR$Bk zO3Gn>I}TRRHWGw)nKN+!%yH`c{P!&Uir(^xc>@7#n3q-i;y;{pb@TrLLaMsq*I!_v7 zej6fY>{3a2uz>#w1%ZXxjI`d#C>7DrPeI)YWQ?7?y7B;w^+dX907lU_sKE)UNI*QM zC&nw-X^DCNZMtbjq}@DhgqIKgE>2jRG`bkLQCA=ZCp=?|`zwy6jUf6Z9g9I?2d*@m zPXoJ+nmUUq{Y>r_v{k(BY(f8;aY9DwX@G7X^6C*ET3SKH{@U2wcsh0ywmh0JM-wgi zcI)DZX26l(-dHBwNN7zsRJT1pk6P}@ErV$s2Z)A+-TgB}*ezO5Q1?w60D)JzSlnp8 zl{Z!muY2sd^6|FhcJKF*@}YXF482GelM!_krL1rF=wo6fdwUloyav?+Q_|q1jb>(3 zXJKb&H`W+(rxSuK`feoJXg@k=#fNaRy?+E?2bdsB3cKi^nbb5kwou#>@74@GhW!1{N?~XOF%}(IsW^E zebrwCWw|OQIp>I0gt$cEfUPKEdXqx8+dM;kXmV|+59CE z*qcCNq$i@{eW?2Qlz(KXYN!vKb(U@x)5OqYer+F`A)f}%nH&tjVijMNrDSJT8jesX zyDr_aHn3;}6HnbU!|cF4Voux81=V@?sI`|DG9!VfLg_a*pf{#9ui1HxX`cN2psa7d zKxKhtmr(1JgEy`sDz46XPYCGK4WF0+-FYO65+WpI)b9w5Rwx2kBmPuuvc z58glXO)uJs1*IHYWQy`fh_CXd+40@}{-;M@we}Z#H5e}6?&g$z9B)U#heq#)UJ)Dg z%|`9`mAnayQEpmz0M-ydiP)p$O;@+)Ajxv1t3x~q7DkmJ0rL-o8|?hYL+!ug)w?5$z27C9lx@rB0c$Z`FD_?JjnnSO@Dv51PgabvhU26#y{2F% znW2%9Rf4-y$Uy*=ijl~Sn=00`s6k~c%*PB3#J z*?G{B>VmtG5^aWEh%~%dM@eD%DbbTR6j*B2MNPrWKW5;mgvTPYN;1B~l{C~xxk1hv zeFes}aKyT}_wg6R)b9%93~pGnme0h=GyR9n+h=-PN-o?f9 zJta`cO7~2Ii~KrIe^pM^>BJUv@tl{!CP7z`V4s2@3QD8063RUinUMyjh@8YqqZ1R^ z)*?~Uy!@|}h|D6~0p7BCi6)SuOPiJCi7$$#ElKACW#TQ~239apxa|W*Y|Iy$=n+^> z>~a*?!n!H#&ESi^nxu)g`u&e*xEx$5GR03ClT@m7X)*c~i$~^O+QS~VoSY>dhLS?9 zl%>R>fh$y_+$9;~o-g`J#_bP^kSMlVsWe8PWQmcf?D#2p z6uUSJ)_uMi0Jg#;u(Mxy@^A!yJr`OJa@?aQjDnXVMXQWjp*>EO<&wLf$gY~x1Cg@k z8tPREl^5m&D!C>K$B!pG!b$qXU&)%1*T@yaU)q- zNN2B^HkQNH9`0|*SrSLY z%UP0P1&b3;DtXR|%OqKt)cTSFz>C*GTtX|#(f<0AEHiZC?i<@3f`?fG-)G$d=7It==t4E#B7$E&Ca5&%m4v`w!Qy2dbjz3{>S+MOzHsj z_lYqFsV0a#89zA>Tl~E|I+aqpeg%^l=tF(shzS!6MA{jD<(ajItu;p|%i*{y<7WIy z4eGx6&A>}y@=M#)Z;zs&dAVTXQ}!ap)TQN4yT#LriVD~Z?ebN`y3e{v%qDdkRpiW+ z@a8Q;VNZle;`9rx6uNFx*u{*K!4+n?f8gkOgx1jN_>|Pb`E^aU z@>G?`&txm@SB?o4Gmg6Q;}OA)V;m5rOtMTMi1odLHn)2z0heBFIFTV{lWw=nlChRm zjum(|;nOx3gQLC<+Py)dqnHoEL_w!b7WCjty{d5UEOXr5lm&LbYge)lvVhd?N2ubX zl21%`9V>a#w-W@4?n)t3?m#L^CuCV8G3F>SAx(S3JGtl{MKN#KD=|d^qAoaMZ4r~S zC{}|SEE0drWN$H9sZFp(&_QwFF7_C{t--0OH^_!I$4aRMEwoyD*KrM<^FspCC4<*L zpR2r-2kIFo(mv>(h6U$lB4tD+7`%eCMmp%8J4;|DMfm!N^qNH|_)AhP?82=f{1%y1 zOOrs7#(E)Z--a&|LxFXXcZPvWw%pV;j)8U`YjAXw*leAS{}l^M8yV>Kg9p^gQrog^t1 z9)s;SNF;Q1syfXt({ats9GUQ5&DNy!V+N4z1nU#cTx%QRC9fItU#I>hcb7h$%sGQn zm|P3_s}rY-gEfM&WRhPbapnbajX%Xoch?)p6ls<;e#GHnQJ<$sg28*{Gc<(P{oriD zwG4EV*i7#qDFO;_#$)xB^C*FV)YuAPh^_|bR(Y!h;g_vliup4t$c3^ke?yPfsgeR`r-emRa!12-17-=u!R0**h0ieBc&Xjt1sTMp4l$9N;WQUvu?(x zXeT_zc2#?Y`<;_JTC|x`p^m%_W4aV&p=(;5)AG8Xs><&tT&gxtkKnW9&rvNI8U`%r-XbYU8XT!P0K{infPr**UNVdXC14nF1UA$U$$c3K(1XIew0U6}ALI)+Q6IZMGwV>O!AJg3z9GkK_B!Ul@G zrZM3VoQ!n%idfpt#!Ej7=gUI~CVq|Z+Fsj61V-LBvAPm=l(N*?2Ak>OOl7iCbH2k~CZhp%;y}g5jk6$Tm1eONz^1Z1Kx8q%m zQ4_BETlZ5%8L12M=^Y%z5cT&-tNXGT+dy2^bDzemO zKo1}2k}^lGcE6Y%QPeQ$K>dDwHunB$(ke$6vcG#maP7^2xj~Wx^LqWo3wHre5s`L6 zs7?h#x7&Fg%3L&l2W(_hjSz|EyrGPAa|-l!)FCNo?Zeu8~ie z09WA8nyl=r5)5E{LocEk3`^ z6RVvhyYRf(>XVoJ3^fI^Sn^c#7YPCb?CL#*I)env8YAs9Xa$WS4bJhC5mt$S)CY3n z;YP(BsJ#2P324oZ*2mH$G0AIIn&R`pVzN!s8$WqFXnVykbudcTl(>J;YCgW#A`u{n z6Vfo=SxcgMbK|lt(~Rk5V~)9a)Pc3?@FD#|<{Z8eC)WjLeo^Q!dKFTfP`xq0hmM7mLdU9$*7R$8p-*&7R{a*Y*k}8$^xRZ7+U=a+?W1~JKDxCF z1okyvWKp-Oyg0#^ye5cmNFedy)&?dNoN*%QznkfMY1w9blO_imoPc{#3)IjvQuS!; zQ6^c`GJk&Ta1B`oEn;>p57Fwvvqr`iLB0lZ{|JN-l}K;gLtZ>>AUio*S?N>|#Me#J zNw~`7Me-*WQ$Cd6xXsc8i=DL^eK}}Jr1miQewWYQxwO-rjj+B|X8@hSXZUX^Xp_I> zGUHz~2prP6BUigmV8KUoZy5)O^m|Ts#7Z z#+7qtxS1;vxELXO8iB3Jy#EpDRr54|AddBpl+Rz@lx@9OTz-}?5w z`c7MZW4sgzk0w;!qqqhns-mh24tRxWksIRRdbOq`kHl0z9N+))U?MW4CV%5l=ssZ( z6CeDHqVIwkf^YCv33Bn{zj3iIKpg@-78ooG>;e7U-D_VD0+3>%CO|>oW10Z9cfL5V z2Gy3K|21*jZG9H|R-p0LE_5uo$T(sNr*~j}{B}s=*zz`WZEGjyQ9a5YW`VJTcsNvY zl@JRdR?Yz;$WUVl45Rke(E(DfZGn7pt`iETZj7c6S%U|Ri4GI);#t(Lc+P6`V+yqm zuf4(-Tv`*UsHprL9SMQ2=#C!{q5TQ~azGKKZUCm#yY5w-@$=EV2aS!{jM%2%eFRSc z!(7Rq^v=7!mEM@1!xZViie$^U0uQnJUSJ!v`j9$LJ^I+ayq1La1cL!q8Dw zsZHg{9l|zkc>`#3S$g)U`Ggof`|+4ZHun2|MfUdegSA*Mj-?%J61c)P0OQJSNVCCV zhj6hm`)w0Rv(t4x;nRfUw~1lZiEbAUtUQUm%>uuj+U^pqHrCF_F<>eC>VgwUm7swb z6>=EohiK{O%B^G}hWxB?lM%O*s`0(3zk1oovGjE5o?@1rqIk^8}_1}frJ()RZD5Xw;Z zb7k8E0XRW1*5*KtnFdJp9tdalNVP-(YEnDDqMeSz9p#Kc_gC}#jqIR?6pfFM2Mnya z;7(UCPz4~?h2O7zU0nX7AD#rAFYQ?Gwf@eM1KNw`Fdy!&uIUpqSaR}D3bB);i}B>Fr-h*RyHh0qOQ67P6I?4zk5ycog!1R2dK&qqpR@FwIPLCt)uS}*vmhCdp8a0Z zestMN^_&F)RV2oDt+9Kxr5F=qb|2Rip`biEnzZPA)MRC^sT>_+_WmPpg}Y6{kXh0l zp&dm6)!keui;X=!t^y!Ng0)5|XF!pIk)dJp z_a!3fLgM4L?!Q_gYd>($M89*ILF!Gkd$@8@N>P<00=JteXmqZK5CU=#&V&DK+w7v_ zEzY<2^G#qG+5G|>OR(3Vk1qZJ2VOb6^{A(BW!pJSKZ{&EeTXrn8%27_W?y`pUY?ST z@;uTlz{5Okydg~RIk2@}xFqPQp7iGXe*x47EBL+`@1O@q%pE9@YJ5DDxQLyL_>40& zGv3n>`*niCY6pr9F9-ssIA{C)KB6cx0HBm|mNb0dr##QOkeBs*-?w?5+cZtB@B6Zd z#Y-Ym)>>(;l|l$%t(8PXQc78nc-iOOTI>3GUk0u9c9S^|@OAgjp_F1{%DhHL>=uOu zFN81^qPIkp7w^+jN~5*buB0u?GNY8rec#tYh|F4RFm%_OUax1OC^Cb=z_i7560`ac*rNh9)7v5&!2h_OYt%MG#I~wgLeV=w$>?px*_(13%9XWUGn(A2R>jw z{_&6F?AfydfX(xqf*`Pi!GNr_F>BiKy4MStU@qQUHgYLQ zUt4Rf*4juZby171gCNk%tfiFNT5E(5&SE!F6q$vE1rvs$SzKI%bHT5-);F2wt`UED z2Yxa+3jp|W91N|Fgn)k@p2EksdO+tvd?S4W{+1nD_*a)qCH%M4!{3i)_okFJ_3)M; z!!&>&xZ)cbe_<6~Pp4691x|DVzndIEhY4>7(5Z9meFB4UDqP0@0W_QEK}TsVI~1{Y zvADQM{eGX8mX^d|Fc4{)iagIn6h+eaeQAuLZnvwFBvIXNSEOmGvMf`1o~tknWs)Q^ z2m)!0kwtu+gb=bIaK+5zZb1-`wN_jqKHRLs(XlB}7L8b3j)c`(yMF2{rF5=%YppdE zNnx#&GS*sCsLk0{tCbmJOqOLf2!fK-i@3UWF8Jx`X*)GF#g9Gq7;oT)-;;WF02sUx zuM~v0gYZA1o_3sj3qlOWr-<>B;VFD|Cqpc~8B;-qp9OFP*ihW&41jlrci=&qg&t+P zJHhHP`~w=c)V&9nF2WeV<6!(!cnZHqySP>cM{t`U{0e{{!L>>7nt(^Z`1$Y@KIWcm zHq?WUP09W2*|Q>!V@lJM27`ex#!wu`GKwPEZnr5(5;-w3A+^?mh!g;2j1gLEskN4^ zR!hWjETxpfS}R;ky|}pqy369})>;7!-TqBh{O-UJI8ZHh8%E;!Y60 ziR`t}9L)ertsc(M>C1HonoafK<1%8Oot?#*GiNp>_cTpKmSysmTW%3al1OVUO-)US zEX$;nQVJoYF-AC&_dJh^$C8=J^E@~Uy?RqhmGfu_eRtu=Tx-qM=bY6pgm5JfCAll5 zTq&c?^PC-_SFQBto_mgiATVJVn&stXZnauwi=+igw4tn8d7i2V2{vjp4SI9EibzgxdT9&rb25isss-J zK@bSv_l32VwALaB0@7Lw-}ea^X1FsmIl|wg^K5VhtS9z7&sj=o3vG8Rgy6-+MRvq4 zrQ|B1`@V0NmzOyR0vm>*1%R7xzS#gkL+TA0j1QU(_xizxRyzRPfB*gB{`>F8nKNfZ zzu%`gjtSVD;M?ss<#{e#c6$^>E~8#ltaP&0QWQm~K6Zca`q?&s5Q5j=yT9W&h7f|2 zBq{r+d!A>D*LW}(l+O(Y11p4BL+HNm^W@~D?Q}Z4E>RA+oWL7mZ_r>5(QL5S7d9pL znVA{7@4owJz4Z>PC3vkh<#{f&)?#8}0@hk;x7%clDT&({Ls1lM_&HUAZ?HRX* zT(5N3jjh+~p(t-G_1+g37qJ0UyIE)ZgkGjG-0l-=5D=RB& ztotgN0~-^%v(kZv)EhJyCo~)G^@%HzJ8(I{S6%b~;Iim}wSqHR>kUO{cAzTPpaxvc zdY4kNQmX77;CWv8T9wR!9TEEazZ*1Yum@;}{rbjL$<`6PbI}8rlRPjadiS>@{08HP zDsflg8UqDEz)lXf)9Ek(OifKOFzhvO6+#CZQg6^;-_a0z17HgT?_%)o@p__n&#x!^ z^{8F|G}s?ht?()wkpn|Af9$cx7yzoWunnO%XfXb0HrWPMY}wMDnVBH~SWour-?tI@ zH`rZN33@X)E8Jlt5_h;tXSRmW8#EX*G@EUMjj&@^x+DAs*Cw{uUUjo_wgwFvi~*WW zxWQJ?#LTZ>Y{m87ph1H%LPP8gc8Z4VuWjsvm>V*0(BK-t{|`Jjq4wCaET8}Y002ov JPDHLkV1l-Iy#@dP literal 0 HcmV?d00001 From df5a080fa303f57254964e8217bc11470e101580 Mon Sep 17 00:00:00 2001 From: Wolfram Pfeifer Date: Fri, 4 Aug 2023 13:09:02 +0200 Subject: [PATCH 86/95] avoid empty message for reloading status --- .../de/uka/ilkd/key/proof/io/AbstractProblemLoader.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/io/AbstractProblemLoader.java b/key.core/src/main/java/de/uka/ilkd/key/proof/io/AbstractProblemLoader.java index d0a5bc786db..bc8238110f4 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/io/AbstractProblemLoader.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/io/AbstractProblemLoader.java @@ -760,9 +760,9 @@ private ReplayResult replayProof(Proof proof) { status = parserResult.getStatus(); errors.addAll(parserResult.getErrors()); } - status += - (status.isEmpty() ? "" : "\n\n") + (replayResult != null ? replayResult.getStatus() - : "Error while loading proof."); + status += (status.isEmpty() ? "Proof replayed successfully." : "\n\n") + + (replayResult != null ? replayResult.getStatus() + : "Error while loading proof."); if (replayResult != null) { errors.addAll(replayResult.getErrors()); } From e53ca79993dcde747e28088df8077ebe4dd802c7 Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Fri, 4 Aug 2023 14:19:37 +0200 Subject: [PATCH 87/95] Fix UI glitch with proof caching --- .../de/uka/ilkd/key/proof/mgt/ProofCorrectnessMgt.java | 4 ++-- .../ilkd/key/gui/plugins/caching/CachingExtension.java | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/mgt/ProofCorrectnessMgt.java b/key.core/src/main/java/de/uka/ilkd/key/proof/mgt/ProofCorrectnessMgt.java index ef1055d9586..ee6e35779a1 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/mgt/ProofCorrectnessMgt.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/mgt/ProofCorrectnessMgt.java @@ -179,8 +179,8 @@ public void updateProofStatus() { ImmutableSet presumablyClosed = DefaultImmutableSet.nil(); for (Proof p : all) { if (!p.isDisposed()) { - if (p.closedGoals().size() > 0 && p.closedGoals().stream() - .anyMatch(goal -> goal.node().lookup(ClosedBy.class) != null)) { + if (p.openGoals().size() > 0 && p.openGoals().stream() + .allMatch(goal -> goal.node().lookup(ClosedBy.class) != null)) { p.mgt().proofStatus = ProofStatus.CLOSED_BY_CACHE; } else if (p.openGoals().size() > 0) { p.mgt().proofStatus = ProofStatus.OPEN; diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java index 90217f12b04..6904548574c 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/caching/CachingExtension.java @@ -176,10 +176,8 @@ public void taskProgress(int position) { @Override public void taskFinished(TaskFinishedInfo info) { - if (info.getSource() instanceof TryCloseMacro) { - tryToClose = true; - } - if (!tryToClose) { + tryToClose = info.getSource() instanceof TryCloseMacro; + if (tryToClose) { return; // try close macro was running, no need to do anything here } Proof p = info.getProof(); @@ -187,9 +185,9 @@ public void taskFinished(TaskFinishedInfo info) { || info.getSource() instanceof ProofMacro)) { return; } - // show statistics if closed by reference + // unmark interactive goals if (p.countNodes() > 1 && p.openGoals().stream() - .allMatch(goal -> goal.node().lookup(ClosedBy.class) != null)) { + .anyMatch(goal -> goal.node().lookup(ClosedBy.class) != null)) { // mark goals as automatic again p.openGoals().stream().filter(goal -> goal.node().lookup(ClosedBy.class) != null) .forEach(g -> { From c1086c84eefa8ec58066195c74b0f15436a28260 Mon Sep 17 00:00:00 2001 From: Mattias Ulbrich Date: Fri, 4 Aug 2023 14:45:40 +0200 Subject: [PATCH 88/95] deactivating "diverges true" from loop specification --- key.ui/examples/firstTouch/08-Java5/src/For.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/key.ui/examples/firstTouch/08-Java5/src/For.java b/key.ui/examples/firstTouch/08-Java5/src/For.java index af67d3be381..da56d87303a 100644 --- a/key.ui/examples/firstTouch/08-Java5/src/For.java +++ b/key.ui/examples/firstTouch/08-Java5/src/For.java @@ -1,4 +1,4 @@ -class For implements Iterable { +final class For implements Iterable { int[] a; Trivial it; @@ -25,13 +25,15 @@ int sum () { void infiniteLoop() { //@ maintaining \invariant_for(f); //@ assignable \strictly_nothing; - //@ diverges true; + //disabled //@ diverges true; + // this would remove the syntax warning, but triggers other strange + // behaviour cases (and is not traditional Java) for (Object o: f); } - public java.util.Iterator iterator () { return it; } + public Trivial iterator () { return it; } - class Trivial implements java.util.Iterator { + final class Trivial implements java.util.Iterator { public boolean hasNext() { return true; } public Object next() { return null; } public void remove() { } From 677985f1ded0831f43806dbfe596a7405ec6e28d Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Fri, 4 Aug 2023 15:05:52 +0200 Subject: [PATCH 89/95] Fix paycard example --- .../examples/firstTouch/09-Quicktour/paycard/LogFile.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/key.ui/examples/firstTouch/09-Quicktour/paycard/LogFile.java b/key.ui/examples/firstTouch/09-Quicktour/paycard/LogFile.java index 7f7684aa2c8..320045ab388 100644 --- a/key.ui/examples/firstTouch/09-Quicktour/paycard/LogFile.java +++ b/key.ui/examples/firstTouch/09-Quicktour/paycard/LogFile.java @@ -66,9 +66,11 @@ public void addRecord(int balance) throws CardException { int i=1; /*@ loop_invariant @ 0<=i && i <= logArray.length - @ && max!=null && - @ (\forall int j; 0 <= j && j= logArray[j].balance); + @ && max!=null + @ && (\forall int j; 0 <= j && j= logArray[j].balance) + @ && (\exists int j; 0 <= j && j Date: Fri, 4 Aug 2023 15:11:13 +0200 Subject: [PATCH 90/95] change docking frames dependencies to maven central versions --- key.ui/build.gradle | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/key.ui/build.gradle b/key.ui/build.gradle index 648b09d9b87..40097c9a568 100644 --- a/key.ui/build.gradle +++ b/key.ui/build.gradle @@ -23,11 +23,8 @@ dependencies { //logging implementation used by the slf4j implementation 'ch.qos.logback:logback-classic:1.4.8' - api 'org.dockingframes:docking-frames-common:1.1.3p1' - api 'org.dockingframes:docking-frames-core:1.1.3p1' - // change to if published on maven central - // api 'org.key-project:docking-frames-common:1.1.3p1' - // api 'org.key-project:docking-frames-core:1.1.3p1' + api 'org.key-project:docking-frames-common:1.1.3p1' + api 'org.key-project:docking-frames-core:1.1.3p1' runtimeOnly project(":keyext.ui.testgen") runtimeOnly project(":keyext.exploration") From b5877de8f29ec0a48d3a72aa981ab1e51bfa807e Mon Sep 17 00:00:00 2001 From: Mattias Ulbrich Date: Fri, 4 Aug 2023 15:13:49 +0200 Subject: [PATCH 91/95] removing the SmansEtAl example from first touch since it was inconsistent, doubled entry --- .../firstTouch/07-Cell/CellClient_mWD.key | 43 ------------------- .../firstTouch/07-Cell/Cell_CellWD.key | 43 ------------------- .../firstTouch/07-Cell/Cell_getXWD.key | 43 ------------------- .../firstTouch/07-Cell/Cell_setXWD.key | 43 ------------------- key.ui/examples/firstTouch/07-Cell/README.txt | 8 ---- .../examples/firstTouch/07-Cell/project.key | 37 ---------------- .../examples/firstTouch/07-Cell/src/Cell.java | 36 ---------------- .../firstTouch/07-Cell/src/CellClient.java | 13 ------ key.ui/examples/heap/SmansEtAl/README.txt | 2 +- 9 files changed, 1 insertion(+), 267 deletions(-) delete mode 100644 key.ui/examples/firstTouch/07-Cell/CellClient_mWD.key delete mode 100644 key.ui/examples/firstTouch/07-Cell/Cell_CellWD.key delete mode 100644 key.ui/examples/firstTouch/07-Cell/Cell_getXWD.key delete mode 100644 key.ui/examples/firstTouch/07-Cell/Cell_setXWD.key delete mode 100644 key.ui/examples/firstTouch/07-Cell/README.txt delete mode 100644 key.ui/examples/firstTouch/07-Cell/project.key delete mode 100644 key.ui/examples/firstTouch/07-Cell/src/Cell.java delete mode 100644 key.ui/examples/firstTouch/07-Cell/src/CellClient.java diff --git a/key.ui/examples/firstTouch/07-Cell/CellClient_mWD.key b/key.ui/examples/firstTouch/07-Cell/CellClient_mWD.key deleted file mode 100644 index f44e650317d..00000000000 --- a/key.ui/examples/firstTouch/07-Cell/CellClient_mWD.key +++ /dev/null @@ -1,43 +0,0 @@ -\settings { -" -[StrategyProperty]QUERYAXIOM_OPTIONS_KEY=QUERYAXIOM_ON -[SMTSettings]invariantForall=false -[Strategy]ActiveStrategy=JavaCardDLStrategy -[StrategyProperty]USER_TACLETS_OPTIONS_KEY1=USER_TACLETS_OFF -[StrategyProperty]QUANTIFIERS_OPTIONS_KEY=QUANTIFIERS_NON_SPLITTING_WITH_PROGS -[StrategyProperty]USER_TACLETS_OPTIONS_KEY2=USER_TACLETS_OFF -[Choice]DefaultChoices=assertions-assertions\\:on , initialisation-initialisation\\:disableStaticInitialisation , intRules-intRules\\:arithmeticSemanticsIgnoringOF , programRules-programRules\\:Java , runtimeExceptions-runtimeExceptions\\:allow , JavaCard-JavaCard\\:off , Strings-Strings\\:on , modelFields-modelFields\\:treatAsAxiom , bigint-bigint\\:on , sequences-sequences\\:on , moreSeqRules-moreSeqRules\\:off , reach-reach\\:on , integerSimplificationRules-integerSimplificationRules\\:full , permissions-permissions\\:off , wdOperator-wdOperator\\:L , wdChecks-wdChecks\\:on , mergeGenerateIsWeakeningGoal-mergeGenerateIsWeakeningGoal\\:off -[StrategyProperty]LOOP_OPTIONS_KEY=LOOP_SCOPE_INV_TACLET -[StrategyProperty]INF_FLOW_CHECK_PROPERTY=INF_FLOW_CHECK_FALSE -[SMTSettings]UseBuiltUniqueness=false -[SMTSettings]explicitTypeHierarchy=false -[SMTSettings]instantiateHierarchyAssumptions=true -[StrategyProperty]NON_LIN_ARITH_OPTIONS_KEY=NON_LIN_ARITH_NONE -[SMTSettings]SelectedTaclets= -[StrategyProperty]DEP_OPTIONS_KEY=DEP_ON -[StrategyProperty]AUTO_INDUCTION_OPTIONS_KEY=AUTO_INDUCTION_OFF -[Strategy]MaximumNumberOfAutomaticApplications=10000 -[StrategyProperty]STOPMODE_OPTIONS_KEY=STOPMODE_DEFAULT -[StrategyProperty]CLASS_AXIOM_OPTIONS_KEY=CLASS_AXIOM_FREE -[SMTSettings]useConstantsForBigOrSmallIntegers=true -[StrategyProperty]MPS_OPTIONS_KEY=MPS_MERGE -[StrategyProperty]SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OPTIONS_KEY=SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OFF -[Strategy]Timeout=-1 -[StrategyProperty]SYMBOLIC_EXECUTION_ALIAS_CHECK_OPTIONS_KEY=SYMBOLIC_EXECUTION_ALIAS_CHECK_NEVER -[StrategyProperty]QUERY_NEW_OPTIONS_KEY=QUERY_OFF -[SMTSettings]useUninterpretedMultiplication=true -[StrategyProperty]BLOCK_OPTIONS_KEY=BLOCK_CONTRACT_INTERNAL -[StrategyProperty]METHOD_OPTIONS_KEY=METHOD_CONTRACT -[StrategyProperty]USER_TACLETS_OPTIONS_KEY3=USER_TACLETS_OFF -[SMTSettings]maxGenericSorts=2 -[StrategyProperty]OSS_OPTIONS_KEY=OSS_ON -[StrategyProperty]SPLITTING_OPTIONS_KEY=SPLITTING_DELAYED -[SMTSettings]integersMinimum=-2147483645 -[StrategyProperty]VBT_PHASE=VBT_SYM_EX -[SMTSettings]integersMaximum=2147483645 -" -} - -\javaSource "src"; - -\chooseContract "CellClient[CellClient::m()].JML normal_behavior operation contract WD.0"; diff --git a/key.ui/examples/firstTouch/07-Cell/Cell_CellWD.key b/key.ui/examples/firstTouch/07-Cell/Cell_CellWD.key deleted file mode 100644 index 1852c63a829..00000000000 --- a/key.ui/examples/firstTouch/07-Cell/Cell_CellWD.key +++ /dev/null @@ -1,43 +0,0 @@ -\settings { -" -[StrategyProperty]QUERYAXIOM_OPTIONS_KEY=QUERYAXIOM_ON -[SMTSettings]invariantForall=false -[Strategy]ActiveStrategy=JavaCardDLStrategy -[StrategyProperty]USER_TACLETS_OPTIONS_KEY1=USER_TACLETS_OFF -[StrategyProperty]QUANTIFIERS_OPTIONS_KEY=QUANTIFIERS_NON_SPLITTING_WITH_PROGS -[StrategyProperty]USER_TACLETS_OPTIONS_KEY2=USER_TACLETS_OFF -[Choice]DefaultChoices=assertions-assertions\\:on , initialisation-initialisation\\:disableStaticInitialisation , intRules-intRules\\:arithmeticSemanticsIgnoringOF , programRules-programRules\\:Java , runtimeExceptions-runtimeExceptions\\:allow , JavaCard-JavaCard\\:off , Strings-Strings\\:on , modelFields-modelFields\\:treatAsAxiom , bigint-bigint\\:on , sequences-sequences\\:on , moreSeqRules-moreSeqRules\\:off , reach-reach\\:on , integerSimplificationRules-integerSimplificationRules\\:full , permissions-permissions\\:off , wdOperator-wdOperator\\:L , wdChecks-wdChecks\\:on , mergeGenerateIsWeakeningGoal-mergeGenerateIsWeakeningGoal\\:off -[StrategyProperty]LOOP_OPTIONS_KEY=LOOP_SCOPE_INV_TACLET -[StrategyProperty]INF_FLOW_CHECK_PROPERTY=INF_FLOW_CHECK_FALSE -[SMTSettings]UseBuiltUniqueness=false -[SMTSettings]explicitTypeHierarchy=false -[SMTSettings]instantiateHierarchyAssumptions=true -[StrategyProperty]NON_LIN_ARITH_OPTIONS_KEY=NON_LIN_ARITH_NONE -[SMTSettings]SelectedTaclets= -[StrategyProperty]DEP_OPTIONS_KEY=DEP_ON -[StrategyProperty]AUTO_INDUCTION_OPTIONS_KEY=AUTO_INDUCTION_OFF -[Strategy]MaximumNumberOfAutomaticApplications=10000 -[StrategyProperty]STOPMODE_OPTIONS_KEY=STOPMODE_DEFAULT -[StrategyProperty]CLASS_AXIOM_OPTIONS_KEY=CLASS_AXIOM_FREE -[SMTSettings]useConstantsForBigOrSmallIntegers=true -[StrategyProperty]MPS_OPTIONS_KEY=MPS_MERGE -[StrategyProperty]SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OPTIONS_KEY=SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OFF -[Strategy]Timeout=-1 -[StrategyProperty]SYMBOLIC_EXECUTION_ALIAS_CHECK_OPTIONS_KEY=SYMBOLIC_EXECUTION_ALIAS_CHECK_NEVER -[StrategyProperty]QUERY_NEW_OPTIONS_KEY=QUERY_OFF -[SMTSettings]useUninterpretedMultiplication=true -[StrategyProperty]BLOCK_OPTIONS_KEY=BLOCK_CONTRACT_INTERNAL -[StrategyProperty]METHOD_OPTIONS_KEY=METHOD_CONTRACT -[StrategyProperty]USER_TACLETS_OPTIONS_KEY3=USER_TACLETS_OFF -[SMTSettings]maxGenericSorts=2 -[StrategyProperty]OSS_OPTIONS_KEY=OSS_ON -[StrategyProperty]SPLITTING_OPTIONS_KEY=SPLITTING_DELAYED -[SMTSettings]integersMinimum=-2147483645 -[StrategyProperty]VBT_PHASE=VBT_SYM_EX -[SMTSettings]integersMaximum=2147483645 -" -} - -\javaSource "src"; - -\chooseContract "Cell[Cell::Cell()].JML normal_behavior operation contract WD.0"; diff --git a/key.ui/examples/firstTouch/07-Cell/Cell_getXWD.key b/key.ui/examples/firstTouch/07-Cell/Cell_getXWD.key deleted file mode 100644 index 61ff50edb73..00000000000 --- a/key.ui/examples/firstTouch/07-Cell/Cell_getXWD.key +++ /dev/null @@ -1,43 +0,0 @@ -\settings { -" -[StrategyProperty]QUERYAXIOM_OPTIONS_KEY=QUERYAXIOM_ON -[SMTSettings]invariantForall=false -[Strategy]ActiveStrategy=JavaCardDLStrategy -[StrategyProperty]USER_TACLETS_OPTIONS_KEY1=USER_TACLETS_OFF -[StrategyProperty]QUANTIFIERS_OPTIONS_KEY=QUANTIFIERS_NON_SPLITTING_WITH_PROGS -[StrategyProperty]USER_TACLETS_OPTIONS_KEY2=USER_TACLETS_OFF -[Choice]DefaultChoices=assertions-assertions\\:on , initialisation-initialisation\\:disableStaticInitialisation , intRules-intRules\\:arithmeticSemanticsIgnoringOF , programRules-programRules\\:Java , runtimeExceptions-runtimeExceptions\\:allow , JavaCard-JavaCard\\:off , Strings-Strings\\:on , modelFields-modelFields\\:treatAsAxiom , bigint-bigint\\:on , sequences-sequences\\:on , moreSeqRules-moreSeqRules\\:off , reach-reach\\:on , integerSimplificationRules-integerSimplificationRules\\:full , permissions-permissions\\:off , wdOperator-wdOperator\\:L , wdChecks-wdChecks\\:on , mergeGenerateIsWeakeningGoal-mergeGenerateIsWeakeningGoal\\:off -[StrategyProperty]LOOP_OPTIONS_KEY=LOOP_SCOPE_INV_TACLET -[StrategyProperty]INF_FLOW_CHECK_PROPERTY=INF_FLOW_CHECK_FALSE -[SMTSettings]UseBuiltUniqueness=false -[SMTSettings]explicitTypeHierarchy=false -[SMTSettings]instantiateHierarchyAssumptions=true -[StrategyProperty]NON_LIN_ARITH_OPTIONS_KEY=NON_LIN_ARITH_NONE -[SMTSettings]SelectedTaclets= -[StrategyProperty]DEP_OPTIONS_KEY=DEP_ON -[StrategyProperty]AUTO_INDUCTION_OPTIONS_KEY=AUTO_INDUCTION_OFF -[Strategy]MaximumNumberOfAutomaticApplications=10000 -[StrategyProperty]STOPMODE_OPTIONS_KEY=STOPMODE_DEFAULT -[StrategyProperty]CLASS_AXIOM_OPTIONS_KEY=CLASS_AXIOM_FREE -[SMTSettings]useConstantsForBigOrSmallIntegers=true -[StrategyProperty]MPS_OPTIONS_KEY=MPS_MERGE -[StrategyProperty]SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OPTIONS_KEY=SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OFF -[Strategy]Timeout=-1 -[StrategyProperty]SYMBOLIC_EXECUTION_ALIAS_CHECK_OPTIONS_KEY=SYMBOLIC_EXECUTION_ALIAS_CHECK_NEVER -[StrategyProperty]QUERY_NEW_OPTIONS_KEY=QUERY_OFF -[SMTSettings]useUninterpretedMultiplication=true -[StrategyProperty]BLOCK_OPTIONS_KEY=BLOCK_CONTRACT_INTERNAL -[StrategyProperty]METHOD_OPTIONS_KEY=METHOD_CONTRACT -[StrategyProperty]USER_TACLETS_OPTIONS_KEY3=USER_TACLETS_OFF -[SMTSettings]maxGenericSorts=2 -[StrategyProperty]OSS_OPTIONS_KEY=OSS_ON -[StrategyProperty]SPLITTING_OPTIONS_KEY=SPLITTING_DELAYED -[SMTSettings]integersMinimum=-2147483645 -[StrategyProperty]VBT_PHASE=VBT_SYM_EX -[SMTSettings]integersMaximum=2147483645 -" -} - -\javaSource "src"; - -\chooseContract "Cell[Cell::getX()].JML normal_behavior operation contract WD.0"; diff --git a/key.ui/examples/firstTouch/07-Cell/Cell_setXWD.key b/key.ui/examples/firstTouch/07-Cell/Cell_setXWD.key deleted file mode 100644 index 3af1164e6e6..00000000000 --- a/key.ui/examples/firstTouch/07-Cell/Cell_setXWD.key +++ /dev/null @@ -1,43 +0,0 @@ -\settings { -" -[StrategyProperty]QUERYAXIOM_OPTIONS_KEY=QUERYAXIOM_ON -[SMTSettings]invariantForall=false -[Strategy]ActiveStrategy=JavaCardDLStrategy -[StrategyProperty]USER_TACLETS_OPTIONS_KEY1=USER_TACLETS_OFF -[StrategyProperty]QUANTIFIERS_OPTIONS_KEY=QUANTIFIERS_NON_SPLITTING_WITH_PROGS -[StrategyProperty]USER_TACLETS_OPTIONS_KEY2=USER_TACLETS_OFF -[Choice]DefaultChoices=assertions-assertions\\:on , initialisation-initialisation\\:disableStaticInitialisation , intRules-intRules\\:arithmeticSemanticsIgnoringOF , programRules-programRules\\:Java , runtimeExceptions-runtimeExceptions\\:allow , JavaCard-JavaCard\\:off , Strings-Strings\\:on , modelFields-modelFields\\:treatAsAxiom , bigint-bigint\\:on , sequences-sequences\\:on , moreSeqRules-moreSeqRules\\:off , reach-reach\\:on , integerSimplificationRules-integerSimplificationRules\\:full , permissions-permissions\\:off , wdOperator-wdOperator\\:L , wdChecks-wdChecks\\:on , mergeGenerateIsWeakeningGoal-mergeGenerateIsWeakeningGoal\\:off -[StrategyProperty]LOOP_OPTIONS_KEY=LOOP_SCOPE_INV_TACLET -[StrategyProperty]INF_FLOW_CHECK_PROPERTY=INF_FLOW_CHECK_FALSE -[SMTSettings]UseBuiltUniqueness=false -[SMTSettings]explicitTypeHierarchy=false -[SMTSettings]instantiateHierarchyAssumptions=true -[StrategyProperty]NON_LIN_ARITH_OPTIONS_KEY=NON_LIN_ARITH_NONE -[SMTSettings]SelectedTaclets= -[StrategyProperty]DEP_OPTIONS_KEY=DEP_ON -[StrategyProperty]AUTO_INDUCTION_OPTIONS_KEY=AUTO_INDUCTION_OFF -[Strategy]MaximumNumberOfAutomaticApplications=10000 -[StrategyProperty]STOPMODE_OPTIONS_KEY=STOPMODE_DEFAULT -[StrategyProperty]CLASS_AXIOM_OPTIONS_KEY=CLASS_AXIOM_FREE -[SMTSettings]useConstantsForBigOrSmallIntegers=true -[StrategyProperty]MPS_OPTIONS_KEY=MPS_MERGE -[StrategyProperty]SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OPTIONS_KEY=SYMBOLIC_EXECUTION_NON_EXECUTION_BRANCH_HIDING_OFF -[Strategy]Timeout=-1 -[StrategyProperty]SYMBOLIC_EXECUTION_ALIAS_CHECK_OPTIONS_KEY=SYMBOLIC_EXECUTION_ALIAS_CHECK_NEVER -[StrategyProperty]QUERY_NEW_OPTIONS_KEY=QUERY_OFF -[SMTSettings]useUninterpretedMultiplication=true -[StrategyProperty]BLOCK_OPTIONS_KEY=BLOCK_CONTRACT_INTERNAL -[StrategyProperty]METHOD_OPTIONS_KEY=METHOD_CONTRACT -[StrategyProperty]USER_TACLETS_OPTIONS_KEY3=USER_TACLETS_OFF -[SMTSettings]maxGenericSorts=2 -[StrategyProperty]OSS_OPTIONS_KEY=OSS_ON -[StrategyProperty]SPLITTING_OPTIONS_KEY=SPLITTING_DELAYED -[SMTSettings]integersMinimum=-2147483645 -[StrategyProperty]VBT_PHASE=VBT_SYM_EX -[SMTSettings]integersMaximum=2147483645 -" -} - -\javaSource "src"; - -\chooseContract "Cell[Cell::setX(int)].JML normal_behavior operation contract WD.0"; diff --git a/key.ui/examples/firstTouch/07-Cell/README.txt b/key.ui/examples/firstTouch/07-Cell/README.txt deleted file mode 100644 index d8364c1880e..00000000000 --- a/key.ui/examples/firstTouch/07-Cell/README.txt +++ /dev/null @@ -1,8 +0,0 @@ -example.name = Cell -example.path = Dynamic Frames -example.additionalFile.2 = src/CellClient.java -example.additionalFile.1 = src/Cell.java - -The examples from the paper "An Automatic Verifier for Java-like Programs Based on Dynamic Frames" by Jan Smans, Bart Jacobs, Frank Piessens and Wolfram Schulte. - -All proof obligations are verifiable without user interaction. diff --git a/key.ui/examples/firstTouch/07-Cell/project.key b/key.ui/examples/firstTouch/07-Cell/project.key deleted file mode 100644 index 10dfac0e2cb..00000000000 --- a/key.ui/examples/firstTouch/07-Cell/project.key +++ /dev/null @@ -1,37 +0,0 @@ -\settings { -"#Proof-Settings-Config-File -#Fri Sep 11 22:56:40 CEST 2009 -[View]FontIndex=2 -[General]UseOCL=false -[StrategyProperty]METHOD_OPTIONS_KEY=METHOD_CONTRACT -[StrategyProperty]USER_TACLETS_OPTIONS_KEY3=USER_TACLETS_OFF -[StrategyProperty]LOOP_OPTIONS_KEY=LOOP_SCOPE_INV_TACLET -[StrategyProperty]USER_TACLETS_OPTIONS_KEY2=USER_TACLETS_OFF -[StrategyProperty]USER_TACLETS_OPTIONS_KEY1=USER_TACLETS_OFF -[StrategyProperty]OSS_OPTIONS_KEY=OSS_ON -[DecisionProcedure]WaitForAllProvers=false -[StrategyProperty]QUANTIFIERS_OPTIONS_KEY=QUANTIFIERS_NON_SPLITTING_WITH_PROGS -[StrategyProperty]NON_LIN_ARITH_OPTIONS_KEY=NON_LIN_ARITH_NONE -[DecisionProcedure]Timeout=600 -[StrategyProperty]DEP_OPTIONS_KEY=DEP_ON -[View]ShowWholeTaclet=false -[View]MaxTooltipLines=40 -[General]DnDDirectionSensitive=true -[General]StupidMode=true -[DecisionProcedure]savefile=false -[Strategy]Timeout=-1 -[Strategy]MaximumNumberOfAutomaticApplications=10000 -[Choice]DefaultChoices=assertions-assertions\:on , programRules-programRules\:Java , intRules-intRules\:arithmeticSemanticsIgnoringOF , initialisation-initialisation\:disableStaticInitialisation , runtimeExceptions-runtimeExceptions\:ban -[StrategyProperty]STOPMODE_OPTIONS_KEY=STOPMODE_DEFAULT -[DecisionProcedure]ActiveRule=Simplify -[General]UseJML=true -[View]HideClosedSubtrees=false -[View]HideIntermediateProofsteps=false -[Strategy]ActiveStrategy=JavaCardDLStrategy -[StrategyProperty]SPLITTING_OPTIONS_KEY=SPLITTING_DELAYED -" -} - -\javaSource "src"; - -\chooseContract diff --git a/key.ui/examples/firstTouch/07-Cell/src/Cell.java b/key.ui/examples/firstTouch/07-Cell/src/Cell.java deleted file mode 100644 index e45b6360de1..00000000000 --- a/key.ui/examples/firstTouch/07-Cell/src/Cell.java +++ /dev/null @@ -1,36 +0,0 @@ -class Cell { - private int x; - - /*@ normal_behavior - @ assignable \nothing; - @ ensures getX() == 0; - @ ensures \fresh(footprint); - @*/ - Cell() { - } - - /*@ normal_behavior - @ assignable \nothing; - @ accessible footprint; - @ ensures \result == getX(); - @*/ - int getX() { - return x; - } - - /*@ normal_behavior - @ assignable footprint; - @ ensures getX() == value; - @ ensures \new_elems_fresh(footprint); - @*/ - void setX(int value) { - x = value; - } - - /*@ model \locset footprint; - @ accessible footprint: footprint; - @ represents footprint = x; - @*/ - - //@ accessible \inv: \nothing; -} diff --git a/key.ui/examples/firstTouch/07-Cell/src/CellClient.java b/key.ui/examples/firstTouch/07-Cell/src/CellClient.java deleted file mode 100644 index 7300bdc8ea8..00000000000 --- a/key.ui/examples/firstTouch/07-Cell/src/CellClient.java +++ /dev/null @@ -1,13 +0,0 @@ -class CellClient { - - //@ ensures \result.getX() == 5; - Cell m() { - Cell c1 = new Cell(); - c1.setX(5); - - Cell c2 = new Cell(); - c2.setX(10); - - return c1; - } -} diff --git a/key.ui/examples/heap/SmansEtAl/README.txt b/key.ui/examples/heap/SmansEtAl/README.txt index 054be2f6e72..8665d908431 100644 --- a/key.ui/examples/heap/SmansEtAl/README.txt +++ b/key.ui/examples/heap/SmansEtAl/README.txt @@ -1,4 +1,4 @@ -example.name = Smans et al. +example.name = Smans et al. / Cell example.path = Dynamic Frames example.additionalFile.1 = src/Cell.java example.additionalFile.2 = src/CellClient.java From eb34e254b3e2d2c774fddde53055e379b999db06 Mon Sep 17 00:00:00 2001 From: Wolfram Pfeifer Date: Sat, 5 Aug 2023 00:08:08 +0200 Subject: [PATCH 92/95] better default keyboard shortcuts, corrected docs URL, cleanup --- .github/ISSUE_TEMPLATE/config.yml | 2 +- .../de/uka/ilkd/key/java/Recoder2KeY.java | 2 +- .../uka/ilkd/key/speclang/njml/JmlChecks.java | 2 +- .../speclang/njml/NJmlTranslatorTests.java | 2 +- key.ui/build.gradle | 2 +- .../firstTouch/09-Quicktour/README.txt | 2 +- .../java/de/uka/ilkd/key/gui/MainWindow.java | 5 +- .../key/gui/actions/AbandonTaskAction.java | 3 - .../ilkd/key/gui/actions/AutoModeAction.java | 1 - .../gui/actions/EditMostRecentFileAction.java | 1 - .../ilkd/key/gui/actions/ExitMainAction.java | 3 - .../ilkd/key/gui/actions/GoalBackAction.java | 4 - .../gui/actions/GoalSelectAboveAction.java | 2 - .../gui/actions/GoalSelectBelowAction.java | 2 - .../gui/actions/IncreaseFontSizeAction.java | 1 - .../gui/actions/KeYProjectHomepageAction.java | 3 +- .../key/gui/actions/MainWindowAction.java | 2 + .../ilkd/key/gui/actions/OpenFileAction.java | 2 - .../gui/actions/OpenMostRecentFileAction.java | 2 - .../gui/actions/OpenSingleJavaFileAction.java | 4 - .../gui/actions/PrettyPrintToggleAction.java | 1 - .../gui/actions/ProofManagementAction.java | 2 - .../key/gui/actions/PruneProofAction.java | 1 - .../ilkd/key/gui/actions/SaveFileAction.java | 4 - .../gui/actions/SearchInProofTreeAction.java | 2 +- .../gui/actions/SearchInSequentAction.java | 6 - .../gui/actions/SearchModeChangeAction.java | 4 +- .../key/gui/actions/SelectionBackAction.java | 3 - .../gui/actions/SelectionForwardAction.java | 4 - .../key/gui/actions/ShowProofStatistics.java | 1 - .../key/gui/actions/TacletOptionsAction.java | 3 - .../key/gui/actions/UnicodeToggleAction.java | 1 - .../ilkd/key/gui/docking/DockingLayout.java | 2 +- .../de/uka/ilkd/key/gui/help/HelpFacade.java | 9 +- .../gui/keyshortcuts/KeyStrokeManager.java | 27 +-- .../gui/keyshortcuts/KeyStrokeSettings.java | 164 ++++++++---------- .../gui/keyshortcuts/ShortcutSettings.java | 6 +- .../uka/ilkd/key/gui/nodeviews/MainFrame.java | 2 +- .../action_history/UndoHistoryButton.java | 3 +- .../ProofTreeSettingsMenuFactory.java | 2 +- .../ilkd/key/gui/prooftree/ProofTreeView.java | 8 +- .../key/gui/settings/SettingsManager.java | 29 ++-- keyext.proofmanagement/README.md | 2 +- .../key_project/slicing/SlicingExtension.java | 2 +- .../slicing/ui/SlicingLeftPanel.java | 2 + .../key/gui/testgen/TestgenExtension.java | 9 +- scripts/proveRules | 2 +- scripts/runAllProofs | 2 +- 48 files changed, 143 insertions(+), 207 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 11e29748829..4c3cbb092e0 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,7 +1,7 @@ blank_issues_enabled: false contact_links: - name: FAQ - url: https://key-project.org/docs/faq + url: https://keyproject.github.io/key-docs/faq about: Documentation - name: KeY Discussions url: https://github.com/keyproject/key/discussions diff --git a/key.core/src/main/java/de/uka/ilkd/key/java/Recoder2KeY.java b/key.core/src/main/java/de/uka/ilkd/key/java/Recoder2KeY.java index 9eba82aa418..9bd63ed42e0 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/java/Recoder2KeY.java +++ b/key.core/src/main/java/de/uka/ilkd/key/java/Recoder2KeY.java @@ -396,7 +396,7 @@ private List recoderCompilationUnitsAsFiles(String if (ex.getCause() instanceof UnresolvedReferenceException) { String extraMsg = "Consider using a classpath in your input file if this is a " + "classtype that cannot be resolved (see " - + "https://key-project.org/docs/user/Classpath for more details)."; + + "https://keyproject.github.io/key-docs/user/Classpath for more details)."; String msg = String.format("%s%n%s", ex.getCause().getMessage(), extraMsg); reportError(msg, ex); } else { diff --git a/key.core/src/main/java/de/uka/ilkd/key/speclang/njml/JmlChecks.java b/key.core/src/main/java/de/uka/ilkd/key/speclang/njml/JmlChecks.java index 96009eed1b9..81e2040ac76 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/speclang/njml/JmlChecks.java +++ b/key.core/src/main/java/de/uka/ilkd/key/speclang/njml/JmlChecks.java @@ -79,7 +79,7 @@ private void checkRequires(List clauses) { if (isRequiresClause(clause) && otherClause) { addWarning(clause, "Diverging Semantics form JML Reference: Requires does not initiate a new contract. " - + "See https://www.key-project.org/docs/user/JMLGrammar/#TODO"); + + "See https://keyproject.github.io/key-docs/user/JMLGrammar/#TODO"); } } } diff --git a/key.core/src/test/java/de/uka/ilkd/key/speclang/njml/NJmlTranslatorTests.java b/key.core/src/test/java/de/uka/ilkd/key/speclang/njml/NJmlTranslatorTests.java index 0e04016166b..788e6182ffb 100644 --- a/key.core/src/test/java/de/uka/ilkd/key/speclang/njml/NJmlTranslatorTests.java +++ b/key.core/src/test/java/de/uka/ilkd/key/speclang/njml/NJmlTranslatorTests.java @@ -86,7 +86,7 @@ public void testWarnRequires() throws URISyntaxException { PositionedString message = warnings.head(); assertEquals( "Diverging Semantics form JML Reference: Requires does not initiate a new contract. " - + "See https://www.key-project.org/docs/user/JMLGrammar/#TODO (Test.java, 5/38)", + + "See https://keyproject.github.io/key-docs/user/JMLGrammar/#TODO (Test.java, 5/38)", message.toString()); } diff --git a/key.ui/build.gradle b/key.ui/build.gradle index 648b09d9b87..6fadede9859 100644 --- a/key.ui/build.gradle +++ b/key.ui/build.gradle @@ -68,7 +68,7 @@ run { // this can be used to solve a problem where the OS hangs during debugging of popup menus // (see https://docs.oracle.com/javase/10/troubleshoot/awt.htm#JSTGD425) - //jvmArgs += "-Dsun.awt.disablegrab=true" + jvmArgs += "-Dsun.awt.disablegrab=true" } task runWithProfiler(type: JavaExec) { diff --git a/key.ui/examples/firstTouch/09-Quicktour/README.txt b/key.ui/examples/firstTouch/09-Quicktour/README.txt index 41d4432a213..939198d717d 100644 --- a/key.ui/examples/firstTouch/09-Quicktour/README.txt +++ b/key.ui/examples/firstTouch/09-Quicktour/README.txt @@ -13,4 +13,4 @@ This is the PayCard example from the KeY-quicktour. The source code for this quicktour, along with a tutorial on how to run it in KeY can be found in the KeY online -documentation at https://www.key-project.org/docs/ +documentation at https://keyproject.github.io/key-docs/ diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/MainWindow.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/MainWindow.java index ce0b7eeb515..d8fae0a8f8f 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/MainWindow.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/MainWindow.java @@ -269,8 +269,9 @@ public final class MainWindow extends JFrame { * This class should only be instantiated once! */ private MainWindow() { - getRootPane().getInputMap().put(HelpFacade.ACTION_OPEN_HELP.getAcceleratorKey(), - HelpFacade.ACTION_OPEN_HELP); + InputMap inputMap = + getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + inputMap.put(HelpFacade.ACTION_OPEN_HELP.getAcceleratorKey(), HelpFacade.ACTION_OPEN_HELP); getRootPane().getActionMap().put(HelpFacade.ACTION_OPEN_HELP, HelpFacade.ACTION_OPEN_HELP); setTitle(KeYResourceManager.getManager().getUserInterfaceTitle()); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/AbandonTaskAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/AbandonTaskAction.java index d2ff95a41b7..5edffe51fa8 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/AbandonTaskAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/AbandonTaskAction.java @@ -1,7 +1,6 @@ package de.uka.ilkd.key.gui.actions; import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; import de.uka.ilkd.key.gui.MainWindow; import de.uka.ilkd.key.gui.fonticons.IconFactory; @@ -20,11 +19,9 @@ public AbandonTaskAction(MainWindow mainWindow, Proof proof) { super(mainWindow); setName("Abandon Proof"); setIcon(IconFactory.abandon(16)); - setAcceleratorLetter(KeyEvent.VK_W); setTooltip("Drop current proof."); getMediator().enableWhenProofLoaded(this); - lookupAcceleratorKey(); this.proof = proof; } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/AutoModeAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/AutoModeAction.java index ad28dc50f41..ba6627a425f 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/AutoModeAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/AutoModeAction.java @@ -69,7 +69,6 @@ public AutoModeAction(MainWindow mainWindow) { setName(getStartCommand()); setTooltip(MainWindow.AUTO_MODE_TEXT); setIcon(startLogo); - setAcceleratorKey(START_KEY); enable(); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/EditMostRecentFileAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/EditMostRecentFileAction.java index 5e1c4d90649..51cf737403f 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/EditMostRecentFileAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/EditMostRecentFileAction.java @@ -36,7 +36,6 @@ public EditMostRecentFileAction(MainWindow mainWindow) { && !desktop.isSupported(Desktop.Action.OPEN)) { setEnabled(false); } - lookupAcceleratorKey(); } public void actionPerformed(ActionEvent e) { diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ExitMainAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ExitMainAction.java index 09a7b2de92b..e35bfa2c02f 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ExitMainAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ExitMainAction.java @@ -1,7 +1,6 @@ package de.uka.ilkd.key.gui.actions; import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowListener; import java.util.EventObject; @@ -34,8 +33,6 @@ public ExitMainAction(MainWindow mainWindow) { setName("Exit"); setIcon(IconFactory.quit(16)); setTooltip("Leave KeY."); - setAcceleratorLetter(KeyEvent.VK_Q); - lookupAcceleratorKey(); } public final WindowListener windowListener = new WindowAdapter() { diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalBackAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalBackAction.java index 6bac9303c3a..2af5ad85f1f 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalBackAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalBackAction.java @@ -1,14 +1,12 @@ package de.uka.ilkd.key.gui.actions; import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; import de.uka.ilkd.key.control.AutoModeListener; import de.uka.ilkd.key.core.KeYSelectionEvent; import de.uka.ilkd.key.core.KeYSelectionListener; import de.uka.ilkd.key.gui.MainWindow; import de.uka.ilkd.key.gui.fonticons.IconFactory; -import de.uka.ilkd.key.gui.keyshortcuts.KeyStrokeManager; import de.uka.ilkd.key.proof.Goal; import de.uka.ilkd.key.proof.Node; import de.uka.ilkd.key.proof.Proof; @@ -54,8 +52,6 @@ public GoalBackAction(MainWindow mainWindow, boolean longName) { putValue(SHORT_DESCRIPTION, "Undo the last rule application."); initListeners(); updateName(); - setAcceleratorLetter(KeyEvent.VK_Z); - KeyStrokeManager.lookupAndOverride(this); } /** diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalSelectAboveAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalSelectAboveAction.java index 2ffe2b3578c..6073ebae640 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalSelectAboveAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalSelectAboveAction.java @@ -1,7 +1,6 @@ package de.uka.ilkd.key.gui.actions; import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; import de.uka.ilkd.key.gui.MainWindow; import de.uka.ilkd.key.gui.fonticons.IconFactory; @@ -20,7 +19,6 @@ public final class GoalSelectAboveAction extends MainWindowAction { */ public GoalSelectAboveAction(MainWindow mainWindow) { super(mainWindow, true); - setAcceleratorLetter(KeyEvent.VK_K); setName("Select Goal Above"); setIcon(IconFactory.selectGoalAbove(MainWindow.TOOLBAR_ICON_SIZE)); setTooltip( diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalSelectBelowAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalSelectBelowAction.java index e655ae4708b..ead7945a6f8 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalSelectBelowAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/GoalSelectBelowAction.java @@ -1,7 +1,6 @@ package de.uka.ilkd.key.gui.actions; import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; import de.uka.ilkd.key.gui.MainWindow; import de.uka.ilkd.key.gui.fonticons.IconFactory; @@ -20,7 +19,6 @@ public final class GoalSelectBelowAction extends MainWindowAction { */ public GoalSelectBelowAction(MainWindow mainWindow) { super(mainWindow, true); - setAcceleratorLetter(KeyEvent.VK_J); setName("Select Goal Below"); setIcon(IconFactory.selectGoalBelow(MainWindow.TOOLBAR_ICON_SIZE)); setTooltip( diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/IncreaseFontSizeAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/IncreaseFontSizeAction.java index 86dbc762262..8541d1998c1 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/IncreaseFontSizeAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/IncreaseFontSizeAction.java @@ -27,7 +27,6 @@ public IncreaseFontSizeAction(MainWindow mainWindow) { setIcon(IconFactory.plus(16)); Config.DEFAULT.addConfigChangeListener(this); - lookupAcceleratorKey(); } @Override diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/KeYProjectHomepageAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/KeYProjectHomepageAction.java index f21daa2814f..293a43b229c 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/KeYProjectHomepageAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/KeYProjectHomepageAction.java @@ -25,10 +25,11 @@ public class KeYProjectHomepageAction extends MainWindowAction { public KeYProjectHomepageAction(MainWindow mainWindow) { super(mainWindow); - setName("Online Help"); + setName("KeY Homepage"); setEnabled(desktopEnabled()); setTooltip("Opens the KeY project homepage in the default browser"); setIcon(IconFactory.help(16)); + lookupAcceleratorKey(); } private static boolean desktopEnabled() { diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/MainWindowAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/MainWindowAction.java index 009bc1f8c79..b6be35890a8 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/MainWindowAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/MainWindowAction.java @@ -40,10 +40,12 @@ protected MainWindowAction(MainWindow mainWindow, boolean onlyActiveWhenProofAva } } + @Override protected void setAcceleratorLetter(int letter) { setAcceleratorKey(KeyStroke.getKeyStroke(letter, SHORTCUT_KEY_MASK)); } + @Override protected void setAcceleratorKey(KeyStroke keyStroke) { boolean trigger = getAcceleratorKey() == null; putValue(ACCELERATOR_KEY, keyStroke); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/OpenFileAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/OpenFileAction.java index c39c2a038eb..f0cadae77ab 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/OpenFileAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/OpenFileAction.java @@ -1,7 +1,6 @@ package de.uka.ilkd.key.gui.actions; import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; import java.io.File; import java.nio.file.Path; import javax.swing.*; @@ -24,7 +23,6 @@ public OpenFileAction(MainWindow mainWindow) { setName("Load..."); setIcon(IconFactory.openKeYFile(MainWindow.TOOLBAR_ICON_SIZE)); setTooltip("Browse and load problem or proof files."); - setAcceleratorLetter(KeyEvent.VK_O); } public void actionPerformed(ActionEvent e) { diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/OpenMostRecentFileAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/OpenMostRecentFileAction.java index 58f400518f7..2204fc516c8 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/OpenMostRecentFileAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/OpenMostRecentFileAction.java @@ -1,7 +1,6 @@ package de.uka.ilkd.key.gui.actions; import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; import java.io.File; import java.nio.file.Path; @@ -26,7 +25,6 @@ public OpenMostRecentFileAction(MainWindow mainWindow) { setName("Reload"); setIcon(IconFactory.openMostRecent(MainWindow.TOOLBAR_ICON_SIZE)); setTooltip("Reload last opened file."); - setAcceleratorLetter(KeyEvent.VK_R); } public void actionPerformed(ActionEvent e) { diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/OpenSingleJavaFileAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/OpenSingleJavaFileAction.java index 907fa570d3e..cc3f22a73aa 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/OpenSingleJavaFileAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/OpenSingleJavaFileAction.java @@ -1,8 +1,6 @@ package de.uka.ilkd.key.gui.actions; import java.awt.event.ActionEvent; -import java.awt.event.InputEvent; -import java.awt.event.KeyEvent; import java.io.File; import java.util.Collections; import javax.swing.*; @@ -25,8 +23,6 @@ public OpenSingleJavaFileAction(MainWindow mainWindow) { setName("Open Single Java File..."); // setIcon(IconFactory.openKeYFile(MainWindow.TOOLBAR_ICON_SIZE)); setTooltip("Browse and load a single Java file without classpath."); - setAcceleratorKey(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_DOWN_MASK)); - lookupAcceleratorKey(); } public void actionPerformed(ActionEvent e) { diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/PrettyPrintToggleAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/PrettyPrintToggleAction.java index 09445f5badb..3e168a69d27 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/PrettyPrintToggleAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/PrettyPrintToggleAction.java @@ -4,7 +4,6 @@ import java.awt.event.ActionEvent; import java.beans.PropertyChangeListener; import java.util.EventObject; -import javax.swing.*; import javax.swing.JCheckBoxMenuItem; import de.uka.ilkd.key.gui.MainWindow; diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ProofManagementAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ProofManagementAction.java index a7d56994fe4..dff27ae688b 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ProofManagementAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ProofManagementAction.java @@ -1,7 +1,6 @@ package de.uka.ilkd.key.gui.actions; import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; import de.uka.ilkd.key.core.KeYSelectionEvent; import de.uka.ilkd.key.core.KeYSelectionListener; @@ -25,7 +24,6 @@ public ProofManagementAction(MainWindow mainWindow) { setName("Proof Management"); setTooltip("Browse contracts and possible proof targets"); setIcon(IconFactory.proofMgt(16)); - setAcceleratorLetter(KeyEvent.VK_M); setEnabled(enabled()); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/PruneProofAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/PruneProofAction.java index e44de9144a3..bc087d58a6f 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/PruneProofAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/PruneProofAction.java @@ -40,7 +40,6 @@ public PruneProofAction(MainWindow mainWindow) { putValue(NAME, "Prune Proof"); putValue(SMALL_ICON, IconFactory.pruneLogo(MainWindow.TOOLBAR_ICON_SIZE)); putValue(SHORT_DESCRIPTION, "Prune the tree below the selected node."); - lookupAcceleratorKey(); } /** diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SaveFileAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SaveFileAction.java index 2fa88800361..c2496df40c7 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SaveFileAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SaveFileAction.java @@ -1,7 +1,6 @@ package de.uka.ilkd.key.gui.actions; import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; import de.uka.ilkd.key.gui.MainWindow; import de.uka.ilkd.key.gui.fonticons.IconFactory; @@ -22,10 +21,7 @@ public SaveFileAction(MainWindow mainWindow) { setName("Save..."); setIcon(IconFactory.saveFile(MainWindow.TOOLBAR_ICON_SIZE)); setTooltip("Save current proof."); - setAcceleratorLetter(KeyEvent.VK_S); - mainWindow.getMediator().enableWhenProofLoaded(this); - lookupAcceleratorKey(); } public void actionPerformed(ActionEvent e) { diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SearchInProofTreeAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SearchInProofTreeAction.java index db859c3f003..1c8a0fdb623 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SearchInProofTreeAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SearchInProofTreeAction.java @@ -19,7 +19,7 @@ public SearchInProofTreeAction(MainWindow mainWindow) { setIcon(IconFactory.search2(16)); setTooltip("Search for rule names or node numbers in the proof tree."); - this.setAcceleratorKey(de.uka.ilkd.key.gui.prooftree.ProofTreeView.searchKeyStroke); + setAcceleratorKey(de.uka.ilkd.key.gui.prooftree.ProofTreeView.SEARCH_KEY_STROKE); getMediator().enableWhenProofLoaded(this); } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SearchInSequentAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SearchInSequentAction.java index 36857fabe3f..2882eba9743 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SearchInSequentAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SearchInSequentAction.java @@ -1,9 +1,6 @@ package de.uka.ilkd.key.gui.actions; -import java.awt.Toolkit; import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; -import javax.swing.KeyStroke; import de.uka.ilkd.key.gui.MainWindow; import de.uka.ilkd.key.gui.fonticons.IconFactory; @@ -25,9 +22,6 @@ public SearchInSequentAction(MainWindow mainWindow, SequentViewSearchBar searchB setName("Search in Sequent View"); setIcon(IconFactory.search(16)); setTooltip("Search for strings in the current sequent."); - // Key combination for this action: STRG+F. - this.setAcceleratorKey(KeyStroke.getKeyStroke(KeyEvent.VK_F, - Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); getMediator().enableWhenProofLoaded(this); } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SearchModeChangeAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SearchModeChangeAction.java index 134b7ab2321..6e6cd6dc470 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SearchModeChangeAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SearchModeChangeAction.java @@ -28,9 +28,9 @@ public SearchModeChangeAction(MainWindow mainWindow, SequentViewSearchBar search if (mode == SequentViewSearchBar.SearchMode.HIGHLIGHT) { setAcceleratorLetter(KeyEvent.VK_H); } else if (mode == SequentViewSearchBar.SearchMode.HIDE) { - setAcceleratorLetter(KeyEvent.VK_ESCAPE); - } else if (mode == SequentViewSearchBar.SearchMode.REGROUP) { setAcceleratorLetter(KeyEvent.VK_I); + } else if (mode == SequentViewSearchBar.SearchMode.REGROUP) { + setAcceleratorLetter(KeyEvent.VK_G); } this.searchBar = searchBar; diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SelectionBackAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SelectionBackAction.java index 84dceedce57..866dc673d3d 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SelectionBackAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SelectionBackAction.java @@ -1,7 +1,6 @@ package de.uka.ilkd.key.gui.actions; import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; import javax.swing.*; import de.uka.ilkd.key.gui.MainWindow; @@ -34,8 +33,6 @@ public SelectionBackAction(MainWindow mainWindow, SelectionHistory history) { setName("Back"); setIcon(IconFactory.PREVIOUS.get(MainWindow.TOOLBAR_ICON_SIZE)); setTooltip("Undo last navigation operation."); - setAcceleratorKey(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, - java.awt.event.InputEvent.CTRL_DOWN_MASK | java.awt.event.InputEvent.ALT_DOWN_MASK)); } /** diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SelectionForwardAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SelectionForwardAction.java index 847ff578e21..5ead166e870 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SelectionForwardAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/SelectionForwardAction.java @@ -1,8 +1,6 @@ package de.uka.ilkd.key.gui.actions; import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; -import javax.swing.*; import de.uka.ilkd.key.gui.MainWindow; import de.uka.ilkd.key.gui.SelectionHistory; @@ -34,8 +32,6 @@ public SelectionForwardAction(MainWindow mainWindow, SelectionHistory history) { setName("Forward"); setIcon(IconFactory.NEXT.get(MainWindow.TOOLBAR_ICON_SIZE)); setTooltip("Redo last undone navigation operation."); - setAcceleratorKey(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, - java.awt.event.InputEvent.CTRL_DOWN_MASK | java.awt.event.InputEvent.ALT_DOWN_MASK)); } /** diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ShowProofStatistics.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ShowProofStatistics.java index 1b8e5f9815e..ce4d8e322b5 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ShowProofStatistics.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/ShowProofStatistics.java @@ -56,7 +56,6 @@ public ShowProofStatistics(MainWindow mainWindow, Proof proof) { setName("Show Proof Statistics"); setIcon(IconFactory.statistics(16)); getMediator().enableWhenProofLoaded(this); - lookupAcceleratorKey(); this.proof = proof; } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/TacletOptionsAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/TacletOptionsAction.java index c7026acad41..86e7e12f849 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/TacletOptionsAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/TacletOptionsAction.java @@ -1,7 +1,6 @@ package de.uka.ilkd.key.gui.actions; import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; import de.uka.ilkd.key.gui.MainWindow; import de.uka.ilkd.key.gui.configuration.ChoiceSelector; @@ -20,10 +19,8 @@ public TacletOptionsAction(MainWindow mainWindow) { super(mainWindow); setName("Show Taclet Options"); setIcon(IconFactory.configure(16)); - setAcceleratorLetter(KeyEvent.VK_T); getMediator().enableWhenProofLoaded(this); - lookupAcceleratorKey(); } @Override diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/UnicodeToggleAction.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/UnicodeToggleAction.java index 205389a2996..0cd28cb39e7 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/UnicodeToggleAction.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/actions/UnicodeToggleAction.java @@ -3,7 +3,6 @@ import java.awt.event.ActionEvent; import java.beans.PropertyChangeListener; import java.util.EventObject; -import javax.swing.*; import javax.swing.JCheckBoxMenuItem; import de.uka.ilkd.key.gui.MainWindow; diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/docking/DockingLayout.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/docking/DockingLayout.java index f89ec376e0d..1c75b570293 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/docking/DockingLayout.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/docking/DockingLayout.java @@ -161,7 +161,7 @@ final class SaveLayoutAction extends MainWindowAction { setMenuPath("View.Layout"); if (key != null) { setAcceleratorKey(KeyStroke.getKeyStroke(key, - InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK)); + KeyStrokeManager.SHORTCUT_KEY_MASK | InputEvent.SHIFT_DOWN_MASK)); } KeyStrokeManager.lookupAndOverride(this, getClass().getName() + "$" + layoutName); } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/help/HelpFacade.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/help/HelpFacade.java index 3721189f7d8..3ac18d958ae 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/help/HelpFacade.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/help/HelpFacade.java @@ -43,7 +43,7 @@ public class HelpFacade { * * @see #KEY_HELP_URL */ - public static String HELP_BASE_URL = "https://key-project.org/docs/"; + public static String HELP_BASE_URL = "https://keyproject.github.io/key-docs/"; static { if (System.getProperty("KEY_HELP_URL") != null) { @@ -138,12 +138,17 @@ public void actionPerformed(ActionEvent e) { return new HelpAction(); } + /* + * TODO: While a good idea in principle, this only works partially at the moment: The source + * component of the ActionEvent is always the root pane, which means that always the main docs + * page is opened. + */ private static class OpenHelpAction extends KeyAction { private static final long serialVersionUID = 85722762932429493L; public OpenHelpAction() { setName("Open help"); - setAcceleratorKey(KeyStroke.getKeyStroke(KeyEvent.VK_F1, KeyEvent.CTRL_DOWN_MASK)); + setAcceleratorKey(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0)); lookupAcceleratorKey(); } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeManager.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeManager.java index 94dc623fcaa..0fc190a3993 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeManager.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeManager.java @@ -1,7 +1,7 @@ package de.uka.ilkd.key.gui.keyshortcuts; import java.awt.*; -import java.awt.event.KeyEvent; +import java.awt.event.InputEvent; import java.lang.ref.WeakReference; import java.util.Collection; import java.util.HashMap; @@ -21,8 +21,7 @@ * includes all combinations using the Windows key), *

  • the * "sacred keybindings" must not be touched, - *
  • the theme for strategy macros should be consistent (currently either F keys or CTRL + SHIFT + - * letter). + *
  • the theme for strategy macros should be consistent (currently CTRL + SHIFT + letter). * * * @author bruns @@ -31,22 +30,15 @@ public final class KeyStrokeManager { /** * This constant holds the typical key to be used for shortcuts (usually - * {@link java.awt.Event#CTRL_MASK}) + * {@link InputEvent#CTRL_DOWN_MASK}) */ public static final int SHORTCUT_KEY_MASK = getShortcutMask(); - - /** - * If true, F keys are used for macros, otherwise CTRL+SHIFT+letter. - */ - public static final boolean FKEY_MACRO_SCHEME = Boolean.getBoolean("key.gui.fkeyscheme"); - /** * This constant holds the typical key combination to be used for auxiliary shortcuts - * ({@link KeyEvent#SHIFT_MASK} plus usually {@link KeyEvent#CTRL_MASK}) + * ({@link InputEvent#SHIFT_DOWN_MASK} plus usually {@link InputEvent#CTRL_DOWN_MASK}) */ - public static final int MULTI_KEY_MASK = SHORTCUT_KEY_MASK | KeyEvent.SHIFT_DOWN_MASK; - + public static final int MULTI_KEY_MASK = SHORTCUT_KEY_MASK | InputEvent.SHIFT_DOWN_MASK; /** * List of actions, that requested a {@link KeyStroke}. @@ -55,6 +47,9 @@ public final class KeyStrokeManager { */ static final Map> actions = new HashMap<>(100); + private KeyStrokeManager() { + } + /** * Get a {@link KeyStroke} for the given key. If no {@link KeyStroke} is defined, * defaultValue is returned. @@ -143,10 +138,6 @@ public static KeyStrokeSettings getSettings() { return KeyStrokeSettings.getInstance(); } - /** - * @param clazz - * @return - */ static Action findAction(String clazz) { return actions.getOrDefault(clazz, new WeakReference<>(null)).get(); } @@ -156,7 +147,7 @@ static Action findAction(String clazz) { */ private static int getShortcutMask() { try { - return Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(); + return Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx(); } catch (HeadlessException e) { return 0; } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeSettings.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeSettings.java index 42c4366b639..faf2ec02574 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeSettings.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/KeyStrokeSettings.java @@ -1,5 +1,6 @@ package de.uka.ilkd.key.gui.keyshortcuts; +import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.io.File; import java.io.FileWriter; @@ -10,7 +11,6 @@ import javax.swing.*; import de.uka.ilkd.key.gui.actions.*; -import de.uka.ilkd.key.gui.help.HelpFacade; import de.uka.ilkd.key.gui.settings.SettingsManager; import de.uka.ilkd.key.macros.*; import de.uka.ilkd.key.settings.AbstractPropertiesSettings; @@ -19,11 +19,19 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static de.uka.ilkd.key.gui.keyshortcuts.KeyStrokeManager.MULTI_KEY_MASK; +import static de.uka.ilkd.key.gui.keyshortcuts.KeyStrokeManager.SHORTCUT_KEY_MASK; + /** - * A settings for storing and retrieving {@link KeyStroke}s. + * Class for storing and retrieving {@link KeyStroke}s. + * + * If possible, define the keyboard shortcuts in the static block here. By that, it is easier to + * detect and prevent possible duplicates. In addition, be careful to avoid combinations that are + * used by the docking framework, such as Ctrl+E or Ctrl+M. * - * @author Alexander Weigl + * @author Alexander Weigl, Wolfram Pfeifer (overhaul, v2) * @version 1 (09.05.19) + * @version 2 (04.08.23) */ public class KeyStrokeSettings extends AbstractPropertiesSettings { /** @@ -44,86 +52,68 @@ public class KeyStrokeSettings extends AbstractPropertiesSettings { */ private static KeyStrokeSettings INSTANCE = null; - /** - * default {@link KeyStroke}s - */ private static final Properties DEFAULT_KEYSTROKES = new Properties(); + // define the default mappings static { - if (KeyStrokeManager.FKEY_MACRO_SCHEME) { - // use F keys for macros, CTRL+SHIFT+letter for other actions - defineDefault(FullAutoPilotProofMacro.class, KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0)); - defineDefault(AutoPilotPrepareProofMacro.class, - KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0)); - defineDefault(PropositionalExpansionMacro.class, - KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0)); - defineDefault(FullPropositionalExpansionMacro.class, - KeyStroke.getKeyStroke(KeyEvent.VK_F4, 0)); - defineDefault(TryCloseMacro.class, KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0)); - defineDefault(FinishSymbolicExecutionMacro.class, - KeyStroke.getKeyStroke(KeyEvent.VK_F6, 0)); - defineDefault(OneStepProofMacro.class, KeyStroke.getKeyStroke(KeyEvent.VK_F7, 0)); - defineDefault(HeapSimplificationMacro.class, KeyStroke.getKeyStroke(KeyEvent.VK_F9, 0)); - defineDefault(UpdateSimplificationMacro.class, - KeyStroke.getKeyStroke(KeyEvent.VK_F10, 0)); - defineDefault(IntegerSimplificationMacro.class, - KeyStroke.getKeyStroke(KeyEvent.VK_F11, 0)); - defineDefault(QuickSaveAction.class, - KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyStrokeManager.MULTI_KEY_MASK)); - defineDefault(QuickLoadAction.class, - KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyStrokeManager.MULTI_KEY_MASK)); - } else { - // use CTRL+SHIFT+letter for macros, F keys for other actions - defineDefault(FullAutoPilotProofMacro.class, - KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyStrokeManager.MULTI_KEY_MASK)); - defineDefault(AutoPilotPrepareProofMacro.class, - KeyStroke.getKeyStroke(KeyEvent.VK_D, KeyStrokeManager.MULTI_KEY_MASK)); - defineDefault(PropositionalExpansionMacro.class, - KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyStrokeManager.MULTI_KEY_MASK)); - defineDefault(FullPropositionalExpansionMacro.class, - KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyStrokeManager.MULTI_KEY_MASK)); - defineDefault(TryCloseMacro.class, - KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyStrokeManager.MULTI_KEY_MASK)); - defineDefault(FinishSymbolicExecutionMacro.class, - KeyStroke.getKeyStroke(KeyEvent.VK_X, KeyStrokeManager.MULTI_KEY_MASK)); - defineDefault(OneStepProofMacro.class, - KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, KeyStrokeManager.MULTI_KEY_MASK)); - defineDefault(HeapSimplificationMacro.class, - KeyStroke.getKeyStroke(KeyEvent.VK_H, KeyStrokeManager.MULTI_KEY_MASK)); - defineDefault(UpdateSimplificationMacro.class, - KeyStroke.getKeyStroke(KeyEvent.VK_L, KeyStrokeManager.MULTI_KEY_MASK)); - defineDefault(IntegerSimplificationMacro.class, - KeyStroke.getKeyStroke(KeyEvent.VK_I, KeyStrokeManager.MULTI_KEY_MASK)); - defineDefault(SMTPreparationMacro.class, - KeyStroke.getKeyStroke(KeyEvent.VK_Y, KeyStrokeManager.MULTI_KEY_MASK)); - defineDefault(KeYProjectHomepageAction.class, - KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0)); - defineDefault(QuickSaveAction.class, KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0)); - defineDefault(QuickLoadAction.class, KeyStroke.getKeyStroke(KeyEvent.VK_F6, 0)); - } - - // default mappings - defineDefault(IncreaseFontSizeAction.class, - KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, KeyStrokeManager.SHORTCUT_KEY_MASK)); - defineDefault(DecreaseFontSizeAction.class, - KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, KeyStrokeManager.SHORTCUT_KEY_MASK)); - defineDefault(HelpFacade.ACTION_OPEN_HELP.getClass(), KeyStroke.getKeyStroke("F1")); - defineDefault(OpenExampleAction.class, - KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyStrokeManager.MULTI_KEY_MASK)); - defineDefault(EditMostRecentFileAction.class, - KeyStroke.getKeyStroke(KeyEvent.VK_E, KeyStrokeManager.MULTI_KEY_MASK)); - defineDefault(PrettyPrintToggleAction.class, - KeyStroke.getKeyStroke(KeyEvent.VK_P, KeyStrokeManager.MULTI_KEY_MASK)); - defineDefault(UnicodeToggleAction.class, - KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyStrokeManager.MULTI_KEY_MASK)); - defineDefault(IncreaseFontSizeAction.class, - KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, KeyStrokeManager.MULTI_KEY_MASK)); - defineDefault(DecreaseFontSizeAction.class, - KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, KeyStrokeManager.MULTI_KEY_MASK)); - - defineDefault(PruneProofAction.class, KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0)); - defineDefault(GoalBackAction.class, - KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyStrokeManager.SHORTCUT_KEY_MASK)); + // use CTRL+SHIFT+letter for macros + defineDefault(FullAutoPilotProofMacro.class, KeyEvent.VK_V, MULTI_KEY_MASK); + defineDefault(AutoPilotPrepareProofMacro.class, KeyEvent.VK_D, MULTI_KEY_MASK); + defineDefault(PropositionalExpansionMacro.class, KeyEvent.VK_A, MULTI_KEY_MASK); + defineDefault(FullPropositionalExpansionMacro.class, KeyEvent.VK_S, MULTI_KEY_MASK); + defineDefault(TryCloseMacro.class, KeyEvent.VK_C, MULTI_KEY_MASK); + defineDefault(FinishSymbolicExecutionMacro.class, KeyEvent.VK_X, MULTI_KEY_MASK); + defineDefault(OneStepProofMacro.class, KeyEvent.VK_SPACE, MULTI_KEY_MASK); + defineDefault(HeapSimplificationMacro.class, KeyEvent.VK_H, MULTI_KEY_MASK); + defineDefault(UpdateSimplificationMacro.class, KeyEvent.VK_L, MULTI_KEY_MASK); + defineDefault(IntegerSimplificationMacro.class, KeyEvent.VK_I, MULTI_KEY_MASK); + defineDefault(SMTPreparationMacro.class, KeyEvent.VK_Y, MULTI_KEY_MASK); + + // other actions with Shift + Ctrl + _ + defineDefault(SearchInProofTreeAction.class, KeyEvent.VK_F, MULTI_KEY_MASK); + defineDefault(PrettyPrintToggleAction.class, KeyEvent.VK_P, MULTI_KEY_MASK); + defineDefault(UnicodeToggleAction.class, KeyEvent.VK_U, MULTI_KEY_MASK); + defineDefault(ProofManagementAction.class, KeyEvent.VK_M, MULTI_KEY_MASK); + + // actions with F keys + defineDefault(QuickSaveAction.class, KeyEvent.VK_F5, 0); + defineDefault(QuickLoadAction.class, KeyEvent.VK_F6, 0); + + // actions with Ctrl + _ + defineDefault(IncreaseFontSizeAction.class, KeyEvent.VK_PLUS, SHORTCUT_KEY_MASK); + defineDefault(DecreaseFontSizeAction.class, KeyEvent.VK_MINUS, SHORTCUT_KEY_MASK); + defineDefault(AbandonTaskAction.class, KeyEvent.VK_W, SHORTCUT_KEY_MASK); + defineDefault(PruneProofAction.class, KeyEvent.VK_DELETE, SHORTCUT_KEY_MASK); + defineDefault(GoalBackAction.class, KeyEvent.VK_Z, SHORTCUT_KEY_MASK); + // does not work at the moment, maybe because the button is not in a menu? + // defineDefault(UndoHistoryButton.UndoAction.class, KeyEvent.VK_U, SHORTCUT_KEY_MASK); + defineDefault(CopyToClipboardAction.class, KeyEvent.VK_C, SHORTCUT_KEY_MASK); + defineDefault(ExitMainAction.class, KeyEvent.VK_Q, SHORTCUT_KEY_MASK); + defineDefault(GoalSelectAboveAction.class, KeyEvent.VK_K, SHORTCUT_KEY_MASK); + defineDefault(GoalSelectBelowAction.class, KeyEvent.VK_J, SHORTCUT_KEY_MASK); + defineDefault(AutoModeAction.class, KeyEvent.VK_SPACE, SHORTCUT_KEY_MASK); + defineDefault(OpenMostRecentFileAction.class, KeyEvent.VK_R, SHORTCUT_KEY_MASK); + defineDefault(SaveBundleAction.class, KeyEvent.VK_B, SHORTCUT_KEY_MASK); + defineDefault(SaveFileAction.class, KeyEvent.VK_S, SHORTCUT_KEY_MASK); + defineDefault(SettingsManager.ShowSettingsAction.class, KeyEvent.VK_N, SHORTCUT_KEY_MASK); + defineDefault(TacletOptionsAction.class, KeyEvent.VK_T, SHORTCUT_KEY_MASK); + defineDefault(OpenFileAction.class, KeyEvent.VK_O, SHORTCUT_KEY_MASK); + defineDefault(SearchInSequentAction.class, KeyEvent.VK_F, SHORTCUT_KEY_MASK); + + // "special" keystrokes + defineDefault(SearchNextAction.class, KeyEvent.VK_F3, 0); + defineDefault(SearchPreviousAction.class, KeyEvent.VK_F3, InputEvent.SHIFT_DOWN_MASK); + defineDefault(SelectionBackAction.class, KeyEvent.VK_LEFT, + SHORTCUT_KEY_MASK | InputEvent.ALT_DOWN_MASK); + defineDefault(SelectionForwardAction.class, KeyEvent.VK_RIGHT, + SHORTCUT_KEY_MASK | InputEvent.ALT_DOWN_MASK); + + /* + * Do not use this! It produces strange behavior, as the constructor there calls + * lookupAcceleratorKey() again, which then accesses the partially initialized + * KeyStrokeSettings. In addition, the rest of the default definitions are not stored then. + */ + // defineDefault(HelpFacade.ACTION_OPEN_HELP.getClass(), KeyEvent.VK_F1, 0); } private KeyStrokeSettings(Properties init) { @@ -137,15 +127,16 @@ private KeyStrokeSettings(Properties init) { Runtime.getRuntime().addShutdownHook(new Thread(this::save)); } - public static void defineDefault(T any, KeyStroke ks) { - defineDefault(any.getClass(), ks); - } - public static void defineDefault(Class clazz, KeyStroke ks) { DEFAULT_KEYSTROKES.setProperty(clazz.getName(), ks.toString()); } - static KeyStrokeSettings loadFromConfig() { + // convenience method to make the definitions above better readable + private static void defineDefault(Class clazz, int keyCode, int modifiers) { + defineDefault(clazz, KeyStroke.getKeyStroke(keyCode, modifiers)); + } + + private static KeyStrokeSettings loadFromConfig() { return new KeyStrokeSettings(SettingsManager.loadProperties(SETTINGS_FILE)); } @@ -156,9 +147,6 @@ public static KeyStrokeSettings getInstance() { return INSTANCE; } - /** - * {@inheritDoc} - */ @Override public void readSettings(Properties props) { properties.putAll(props); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/ShortcutSettings.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/ShortcutSettings.java index 89e7194dd33..883998c15b0 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/ShortcutSettings.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/keyshortcuts/ShortcutSettings.java @@ -47,8 +47,9 @@ public JComponent getPanel(MainWindow window) { List actionNames = p.keySet().stream().sorted().map(Object::toString).collect(Collectors.toList()); - List shortcuts = - actionNames.stream().map(p::getProperty).map(s -> s.replace("pressed ", "")).collect(Collectors.toList()); + // for the view, we hide "pressed" to increase readability + List shortcuts = actionNames.stream().map(p::getProperty) + .map(s -> s.replace("pressed ", "")).collect(Collectors.toList()); List actions = actionNames.stream().map(KeyStrokeManager::findAction).collect(Collectors.toList()); @@ -81,6 +82,7 @@ public void keyPressed(KeyEvent e) { } KeyStroke ks = KeyStroke.getKeyStrokeForEvent(e); + // for the view, we hide "pressed" to increase readability String shortened = ks.toString().replace("pressed ", ""); txtCaptureShortcut.setText(shortened); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/nodeviews/MainFrame.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/nodeviews/MainFrame.java index 11784cea470..d8ab77b0fd4 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/nodeviews/MainFrame.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/nodeviews/MainFrame.java @@ -84,7 +84,7 @@ public void ancestorAdded(AncestorEvent event) {} // FIXME put this somewhere descent getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_C, - Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "copy"); + Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx()), "copy"); getActionMap().put("copy", new CopyToClipboardAction(mainWindow)); setLayout(new BorderLayout()); add(scrollPane); diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/action_history/UndoHistoryButton.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/action_history/UndoHistoryButton.java index 4c1174095da..c99e9e5c661 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/action_history/UndoHistoryButton.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/plugins/action_history/UndoHistoryButton.java @@ -252,7 +252,7 @@ public void refreshState() { /** * The main purpose of this GUI component: the undo button / action. */ - private final class UndoAction extends MainWindowAction { + public final class UndoAction extends MainWindowAction { /** * Calling this function should perform the undo operation. @@ -269,7 +269,6 @@ private final class UndoAction extends MainWindowAction { super(mainWindow); setIcon(actionIcon.get(iconSize)); setTooltip("Undo the last action performed on the proof"); - setAcceleratorLetter(KeyEvent.VK_U); this.callback = callback; } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeSettingsMenuFactory.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeSettingsMenuFactory.java index a04baa361a1..e41c24199e9 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeSettingsMenuFactory.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeSettingsMenuFactory.java @@ -69,7 +69,7 @@ private static CButton createSearch(ProofTreeView view) { CButton button = new CButton(); button.setText("Search"); button.setIcon(IconFactory.search2(ICON_SIZE)); - button.setAccelerator(de.uka.ilkd.key.gui.prooftree.ProofTreeView.searchKeyStroke); + button.setAccelerator(de.uka.ilkd.key.gui.prooftree.ProofTreeView.SEARCH_KEY_STROKE); button.addActionListener(e -> view.showSearchPanel()); return button; } diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java index 84494f7db8b..62edaed0f14 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/prooftree/ProofTreeView.java @@ -27,6 +27,7 @@ import de.uka.ilkd.key.gui.extension.api.TabPanel; import de.uka.ilkd.key.gui.extension.impl.KeYGuiExtensionFacade; import de.uka.ilkd.key.gui.fonticons.IconFactory; +import de.uka.ilkd.key.gui.keyshortcuts.KeyStrokeManager; import de.uka.ilkd.key.java.Services; import de.uka.ilkd.key.logic.PosInOccurrence; import de.uka.ilkd.key.pp.LogicPrinter; @@ -72,9 +73,8 @@ public class ProofTreeView extends JPanel implements TabPanel { /** * KeYStroke for the search panel: STRG+SHIFT+F */ - public static final KeyStroke searchKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_F, - java.awt.event.InputEvent.CTRL_DOWN_MASK | java.awt.event.InputEvent.SHIFT_DOWN_MASK - | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()); + public static final KeyStroke SEARCH_KEY_STROKE = KeyStroke.getKeyStroke(KeyEvent.VK_F, + KeyStrokeManager.MULTI_KEY_MASK); private static final long serialVersionUID = 3732875161168302809L; @@ -287,7 +287,7 @@ public void mouseReleased(MouseEvent e) { final ActionListener keyboardAction = (ActionEvent e) -> showSearchPanel(); - registerKeyboardAction(keyboardAction, searchKeyStroke, + registerKeyboardAction(keyboardAction, SEARCH_KEY_STROKE, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); KeYGuiExtensionFacade.installKeyboardShortcuts(mediator, this, diff --git a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/SettingsManager.java b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/SettingsManager.java index e92c2b21b8d..3d5e3f4e51d 100644 --- a/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/SettingsManager.java +++ b/key.ui/src/main/java/de/uka/ilkd/key/gui/settings/SettingsManager.java @@ -12,7 +12,7 @@ import javax.swing.*; import de.uka.ilkd.key.gui.MainWindow; -import de.uka.ilkd.key.gui.actions.KeyAction; +import de.uka.ilkd.key.gui.actions.MainWindowAction; import de.uka.ilkd.key.gui.colors.ColorSettingsProvider; import de.uka.ilkd.key.gui.extension.ExtensionManager; import de.uka.ilkd.key.gui.extension.impl.KeYGuiExtensionFacade; @@ -150,21 +150,22 @@ public boolean remove(SettingsProvider o) { return settingsProviders.remove(o); } - public Action getActionShowSettings(MainWindow window) { - class ShowSettingsAction extends KeyAction { - private static final long serialVersionUID = 153753479823919818L; + public class ShowSettingsAction extends MainWindowAction { + private static final long serialVersionUID = 153753479823919818L; - public ShowSettingsAction() { - setName("Show Settings"); - setIcon(IconFactory.editFile(16)); - lookupAcceleratorKey(); - } + public ShowSettingsAction(MainWindow mainWindow) { + super(mainWindow); + setName("Show Settings"); + setIcon(IconFactory.editFile(16)); + } - @Override - public void actionPerformed(ActionEvent e) { - showSettingsDialog(window); - } + @Override + public void actionPerformed(ActionEvent e) { + showSettingsDialog(mainWindow); } - return new ShowSettingsAction(); + } + + public Action getActionShowSettings(MainWindow window) { + return new ShowSettingsAction(window); } } diff --git a/keyext.proofmanagement/README.md b/keyext.proofmanagement/README.md index e1c09f90a09..3c85260c377 100644 --- a/keyext.proofmanagement/README.md +++ b/keyext.proofmanagement/README.md @@ -59,7 +59,7 @@ The available options correspond to the features described in the section above. `` is the path of the proof bundle to check and can either denote a directory or a zip file. The directory structure of the bundle has to conform that described in -[classpath documentation](https://key-project.org/docs/user/Classpath/). +[classpath documentation](https://keyproject.github.io/key-docs/user/Classpath/). An example of a (zipped) proof bundle would be: ``` bundle.zproof diff --git a/keyext.slicing/src/main/java/org/key_project/slicing/SlicingExtension.java b/keyext.slicing/src/main/java/org/key_project/slicing/SlicingExtension.java index 0d2807359cd..d5c4d3c55cb 100644 --- a/keyext.slicing/src/main/java/org/key_project/slicing/SlicingExtension.java +++ b/keyext.slicing/src/main/java/org/key_project/slicing/SlicingExtension.java @@ -32,7 +32,7 @@ /** * Proof slicing extension. - * For more details see the user + * For more details see the user * guide. * * @author Arne Keller diff --git a/keyext.slicing/src/main/java/org/key_project/slicing/ui/SlicingLeftPanel.java b/keyext.slicing/src/main/java/org/key_project/slicing/ui/SlicingLeftPanel.java index e788b9b5308..6abce9daa23 100644 --- a/keyext.slicing/src/main/java/org/key_project/slicing/ui/SlicingLeftPanel.java +++ b/keyext.slicing/src/main/java/org/key_project/slicing/ui/SlicingLeftPanel.java @@ -26,6 +26,7 @@ import de.uka.ilkd.key.gui.extension.api.TabPanel; import de.uka.ilkd.key.gui.fonticons.IconFactory; import de.uka.ilkd.key.gui.help.HelpFacade; +import de.uka.ilkd.key.gui.help.HelpInfo; import de.uka.ilkd.key.proof.Proof; import de.uka.ilkd.key.proof.ProofTreeEvent; import de.uka.ilkd.key.proof.ProofTreeListener; @@ -49,6 +50,7 @@ * * @author Arne Keller */ +@HelpInfo(path = "/user/ProofSlicing/") public class SlicingLeftPanel extends JPanel implements TabPanel, KeYSelectionListener, ProofTreeListener { /** diff --git a/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/TestgenExtension.java b/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/TestgenExtension.java index f6ed1a4eb56..ae2b464102c 100644 --- a/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/TestgenExtension.java +++ b/keyext.ui.testgen/src/main/java/de/uka/ilkd/key/gui/testgen/TestgenExtension.java @@ -43,13 +43,8 @@ private void init(MainWindow window) { @Override public void init(MainWindow window, KeYMediator mediator) { init(window); - if (KeyStrokeManager.FKEY_MACRO_SCHEME) { - KeyStrokeSettings.defineDefault(TestGenMacro.class, - KeyStroke.getKeyStroke(KeyEvent.VK_F8, 0)); - } else { - KeyStrokeSettings.defineDefault(TestGenMacro.class, - KeyStroke.getKeyStroke(KeyEvent.VK_T, KeyStrokeManager.MULTI_KEY_MASK)); - } + KeyStrokeSettings.defineDefault(TestGenMacro.class, KeyStroke.getKeyStroke(KeyEvent.VK_T, + KeyStrokeManager.MULTI_KEY_MASK)); } @Override diff --git a/scripts/proveRules b/scripts/proveRules index 56d04722989..419b09c5c2a 100755 --- a/scripts/proveRules +++ b/scripts/proveRules @@ -1,7 +1,7 @@ #!/bin/sh # -# ProveRules documentation can be found at: https://key-project.org/docs/devel/ProveRules/ +# ProveRules documentation can be found at: https://keyproject.github.io/key-docs/devel/ProveRules/ # LIST_TESTS_FLAG=--list-tests diff --git a/scripts/runAllProofs b/scripts/runAllProofs index 77e86aa689e..461d4cf65d5 100755 --- a/scripts/runAllProofs +++ b/scripts/runAllProofs @@ -1,7 +1,7 @@ #!/bin/sh # -# RunAllProofs documentation can be found at: https://key-project.org/docs/devel/Testing/RunAllProves/ +# RunAllProofs documentation can be found at: https://keyproject.github.io/key-docs/Testing/RunAllProves/ # LIST_TESTS_FLAG=--list-tests From d24cfd568e91f486f8ff3cf6b7aa5a459ba5b77f Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Sat, 5 Aug 2023 08:52:26 +0200 Subject: [PATCH 93/95] Repair example index --- key.ui/examples/index/samplesIndex.txt | 1 - .../resources/de/uka/ilkd/key/gui/actions/runallproofsui.txt | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/key.ui/examples/index/samplesIndex.txt b/key.ui/examples/index/samplesIndex.txt index 781b23b8734..c2036e62fe5 100644 --- a/key.ui/examples/index/samplesIndex.txt +++ b/key.ui/examples/index/samplesIndex.txt @@ -48,7 +48,6 @@ heap/permutedSum/README.txt heap/quicksort/README.txt # Dynamic Frames -firstTouch/07-Cell/README.txt ## Block & Loop Contracts heap/block_loop_contracts/Simple/README.txt heap/block_loop_contracts/Divide/README.txt diff --git a/key.ui/src/main/resources/de/uka/ilkd/key/gui/actions/runallproofsui.txt b/key.ui/src/main/resources/de/uka/ilkd/key/gui/actions/runallproofsui.txt index ef828ea2ee4..ea2aafaa44f 100644 --- a/key.ui/src/main/resources/de/uka/ilkd/key/gui/actions/runallproofsui.txt +++ b/key.ui/src/main/resources/de/uka/ilkd/key/gui/actions/runallproofsui.txt @@ -7,6 +7,5 @@ firstTouch/01-Agatha/project.key firstTouch/02-Subset/project.key firstTouch/05-ReverseArray/reverseArray.key firstTouch/06-BinarySearch/project.key -firstTouch/07-Cell/project.key firstTouch/08-Java5/project.key -firstTouch/09-Quicktour/project.key \ No newline at end of file +firstTouch/09-Quicktour/project.key From 980e976e02cc65f8977f2e856784f2036d443c0c Mon Sep 17 00:00:00 2001 From: Alexander Weigl Date: Sun, 13 Aug 2023 10:01:07 +0200 Subject: [PATCH 94/95] update samplesIndex.txt --- key.ui/examples/index/samplesIndex.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/key.ui/examples/index/samplesIndex.txt b/key.ui/examples/index/samplesIndex.txt index 781b23b8734..b6e9fd641ff 100644 --- a/key.ui/examples/index/samplesIndex.txt +++ b/key.ui/examples/index/samplesIndex.txt @@ -47,8 +47,6 @@ heap/saddleback_search/README.txt heap/permutedSum/README.txt heap/quicksort/README.txt -# Dynamic Frames -firstTouch/07-Cell/README.txt ## Block & Loop Contracts heap/block_loop_contracts/Simple/README.txt heap/block_loop_contracts/Divide/README.txt From 655396dcbc9e3884614705b68e2c4c023747cb6a Mon Sep 17 00:00:00 2001 From: Arne Keller Date: Mon, 14 Aug 2023 08:43:26 +0200 Subject: [PATCH 95/95] Fix bug in icon selection --- .../de/uka/ilkd/key/proof/mgt/ProofCorrectnessMgt.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/key.core/src/main/java/de/uka/ilkd/key/proof/mgt/ProofCorrectnessMgt.java b/key.core/src/main/java/de/uka/ilkd/key/proof/mgt/ProofCorrectnessMgt.java index ee6e35779a1..be75f6480df 100644 --- a/key.core/src/main/java/de/uka/ilkd/key/proof/mgt/ProofCorrectnessMgt.java +++ b/key.core/src/main/java/de/uka/ilkd/key/proof/mgt/ProofCorrectnessMgt.java @@ -179,12 +179,15 @@ public void updateProofStatus() { ImmutableSet presumablyClosed = DefaultImmutableSet.nil(); for (Proof p : all) { if (!p.isDisposed()) { - if (p.openGoals().size() > 0 && p.openGoals().stream() - .allMatch(goal -> goal.node().lookup(ClosedBy.class) != null)) { + // some branch is closed via cache: + if (p.openGoals().size() == 0 && p.closedGoals().stream() + .anyMatch(goal -> goal.node().lookup(ClosedBy.class) != null)) { p.mgt().proofStatus = ProofStatus.CLOSED_BY_CACHE; } else if (p.openGoals().size() > 0) { + // some branch is open p.mgt().proofStatus = ProofStatus.OPEN; } else { + // all branches are properly closed p.mgt().proofStatus = ProofStatus.CLOSED; presumablyClosed = presumablyClosed.add(p); }