summaryrefslogtreecommitdiff
path: root/src/JavaGUI2
diff options
context:
space:
mode:
authorhdaniels <unknown>2005-09-10 09:15:54 +0000
committerhdaniels <unknown>2005-09-10 09:15:54 +0000
commitf882f97a22c9ed16c6f1735930698b8fba162351 (patch)
tree801627b8d67b6da30c6529d93d8851ee71478f89 /src/JavaGUI2
parentaa92464b1ce95f405bb1b30b0faa8cbf94fa1ac6 (diff)
Lots of refactorings for gfeditor
Diffstat (limited to 'src/JavaGUI2')
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/AbstractProber.java105
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/AstNodeData.java64
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/ChainCommandTuple.java60
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/ConstraintCallback.java15
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Display.java69
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/DynamicTree2.java113
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/ExportFormatMenu.java67
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GFCommand.java63
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GFEditor2.java2800
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GfAstNode.java79
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GfCapsule.java621
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GfeditResult.java61
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Hmsg.java77
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/HtmlMarkedArea.java63
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/InputCommand.java47
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/LanguageManager.java39
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/LinPosition.java37
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Linearization.java760
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/LinkCommand.java28
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/MarkedArea.java43
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/MarkedAreaHighlightingStatus.java48
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/NewCategoryMenuResult.java57
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Printname.java217
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/PrintnameLoader.java38
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/PrintnameManager.java23
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/ReadDialog.java20
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RealCommand.java138
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RefinedAstNodeData.java25
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RefinementMenu.java518
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RefinementMenuCollector.java51
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RefinementMenuTransformer.java223
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/SelfPropertiesCommand.java175
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/SelfResultProber.java (renamed from src/JavaGUI2/de/uka/ilkd/key/ocl/gf/CompletableProber.java)59
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/StringTuple.java54
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/SubtypingProber.java107
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/TreeAnalyser.java387
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/TreeAnalysisResult.java92
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/TypesLoader.java29
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/UnrefinedAstNodeData.java30
-rw-r--r--src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Utils.java91
40 files changed, 5055 insertions, 2538 deletions
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/AbstractProber.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/AbstractProber.java
index 159fe3067..0439ec6a4 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/AbstractProber.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/AbstractProber.java
@@ -15,8 +15,6 @@
package de.uka.ilkd.key.ocl.gf;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
import java.io.IOException;
import java.util.logging.*;
@@ -27,18 +25,18 @@ import java.util.logging.*;
*
*/
abstract class AbstractProber {
- protected final BufferedReader fromProc;
- protected final BufferedWriter toProc;
+ /**
+ * reference to the editor whose readRefinementMenu method is used
+ */
+ protected final GfCapsule gfCapsule;
protected static Logger logger = Logger.getLogger(AbstractProber.class.getName());
/**
* A constructor which sets some fields
- * @param fromGf the stdout from the GF process
- * @param toGf the stdin from the GF process
+ * @param gfCapsule The encapsulation of GF
*/
- public AbstractProber(BufferedReader fromGf, BufferedWriter toGf) {
- this.fromProc = fromGf;
- this.toProc = toGf;
+ public AbstractProber(GfCapsule gfCapsule) {
+ this.gfCapsule = gfCapsule;
}
/**
@@ -49,9 +47,9 @@ abstract class AbstractProber {
*/
protected String readHmsg(String readresult) {
if (readresult.equals("<hmsg>")) {
- skipChild("<hmsg>");
+ gfCapsule.skipChild("<hmsg>");
try {
- String next = fromProc.readLine();
+ String next = gfCapsule.fromProc.readLine();
if (logger.isLoggable(Level.FINER)) {
logger.finer("2 " + next);
}
@@ -71,22 +69,28 @@ abstract class AbstractProber {
* @param readresult the first line with the opening tag
*/
protected void readLinearizations(String readresult) {
- skipChild("<linearizations>");
+ gfCapsule.skipChild("<linearizations>");
}
- /** Reads the tree child of the XML from beginning to end */
+ /**
+ * Reads the tree child of the XML from beginning to end
+ */
protected void readTree() {
- skipChild("<tree>");
+ gfCapsule.skipChild("<tree>");
}
- /** Reads the message child of the XML from beginning to end */
+ /**
+ * Reads the message child of the XML from beginning to end
+ */
protected void readMessage() {
- skipChild("<message>");
+ gfCapsule.skipChild("<message>");
}
- /** Reads the menu child of the XML from beginning to end */
+ /**
+ * Reads the menu child of the XML from beginning to end
+ */
protected void readMenu() {
- skipChild("<menu>");
+ gfCapsule.skipChild("<menu>");
}
/**
@@ -97,23 +101,24 @@ abstract class AbstractProber {
try {
String next = "";
//read <gfedit>
- String readresult = fromProc.readLine();
+ String readresult = gfCapsule.fromProc.readLine();
if (logger.isLoggable(Level.FINER)) {
logger.finer("1 " + next);
}
//read either <hsmg> or <lineatization>
- readresult = fromProc.readLine();
+ readresult = gfCapsule.fromProc.readLine();
if (logger.isLoggable(Level.FINER)) {
logger.finer("1 " + next);
}
- next = readHmsg(readresult);
+ Hmsg hmsg = gfCapsule.readHmsg(readresult);
+ next = hmsg.lastline;
//in case there comes sth. unexpected before <linearizations>
//usually the while body is never entered
// %%%
while ((next!=null)&&((next.length()==0)||(!next.trim().equals("<linearizations>")))) {
- next = fromProc.readLine();
+ next = gfCapsule.fromProc.readLine();
if (next!=null){
if (logger.isLoggable(Level.FINER)) {
logger.finer("1 " + next);
@@ -128,7 +133,7 @@ abstract class AbstractProber {
readMenu();
for (int i=0; i<3 && !next.equals(""); i++){
- next = fromProc.readLine();
+ next = gfCapsule.fromProc.readLine();
if (logger.isLoggable(Level.FINER)) {
logger.finer("1 " + next);
}
@@ -141,31 +146,6 @@ abstract class AbstractProber {
}
/**
- * Reads the output from GF until the ending tag corresponding to the
- * given opening tag is read.
- * @param opening tag in the format of &gt;gfinit&lt;
- */
- protected void skipChild(String opening) {
- String closing = (new StringBuffer(opening)).insert(1, '/').toString();
- try {
- String nextRead = fromProc.readLine();
- if (logger.isLoggable(Level.FINER)) {
- logger.finer("3 " + nextRead);
- }
- while (!nextRead.trim().equals(closing)) {
- nextRead = fromProc.readLine();
- if (logger.isLoggable(Level.FINER)) {
- logger.finer("3 " + nextRead);
- }
- }
- } catch (IOException e) {
- System.err.println("Could not read from external process:\n" + e);
- }
-
-
- }
-
- /**
* send a command to GF
* @param text the command, exactly the string that is going to be sent
*/
@@ -173,29 +153,26 @@ abstract class AbstractProber {
if (logger.isLoggable(Level.FINE)) {
logger.fine("## send: '" + text + "'");
}
- try {
- toProc.write(text, 0, text.length());
- toProc.newLine();
- toProc.flush();
- } catch (IOException e) {
- System.err.println("Could not write to external process " + e);
- }
+ gfCapsule.realSend(text);
}
/**
* Just reads the complete output of a GF run and ignores it.
- * @param fromProc The process from which the GFEDIT should be read.
*/
- static void readAndIgnore(BufferedReader fromProc) {
- try {
- String readresult = fromProc.readLine();
- if (logger.isLoggable(Level.FINER)) logger.finer("14 "+readresult);
- while (readresult.indexOf("</gfedit>") == -1) {
- readresult = fromProc.readLine();
+ protected void readAndIgnore() {
+ try {
+ StringBuffer debugCollector = new StringBuffer();
+ String readresult = gfCapsule.fromProc.readLine();
+ debugCollector.append(readresult).append('\n');
+ if (logger.isLoggable(Level.FINER)) logger.finer("14 "+readresult);
+ while (readresult.indexOf("</gfedit>") == -1) {
+ readresult = gfCapsule.fromProc.readLine();
+ debugCollector.append(readresult).append('\n');
if (logger.isLoggable(Level.FINER)) logger.finer("14 "+readresult);
- }
+ }
//read trailing newline:
- readresult = fromProc.readLine();
+ readresult = gfCapsule.fromProc.readLine();
+ debugCollector.append(readresult).append('\n');
if (logger.isLoggable(Level.FINER)) logger.finer("14 "+readresult);
} catch (IOException e) {
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/AstNodeData.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/AstNodeData.java
index df86fa936..9a4c48911 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/AstNodeData.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/AstNodeData.java
@@ -22,6 +22,8 @@ import java.util.logging.*;
* An object of this type knows how it self should be rendered,
* via Printname how its children should be rendered.
* This means the tooltip information it got from there.
+ * Knows nothing directly of the type of the node, which an object of this class
+ * represents. That's whats GfAstNode is for.
*/
abstract class AstNodeData {
protected static Logger logger = Logger.getLogger(DynamicTree2.class.getName());
@@ -37,19 +39,67 @@ abstract class AstNodeData {
public abstract String getParamTooltip();
/**
- *
- * @return true iff this node represents an open leaf
- */
- public abstract boolean isMeta();
- /**
* keeps track of the number of children of this node.
* It has to be increased whenever a new child of this node is
* added.
*/
public int childNum = 0;
/**
- * @return The position String in the GF AST for this node
+ * The position String in the GF AST for this node
* in Haskell notation.
*/
- public abstract String getPosition();
+ public final String position;
+ /**
+ * the GF node connected to this NodeData, not the JTree node
+ */
+ public final GfAstNode node;
+
+ /**
+ * If a subtyping witness is missing, then this flag is false
+ */
+ public boolean subtypingStatus = true;
+
+ /**
+ * if this is the active, selected, focused node
+ */
+ public final boolean selected;
+
+ /**
+ * The constraint, that is valid on this node.
+ * If this node introduced a node itself and did not just inherit
+ * one, they are just concatenated.
+ * Until now, only the presence of a non-empty string here is used,
+ * so that is not important yet.
+ */
+ public final String constraint;
+
+ /**
+ * some nodes like coerce should, if possible, be covered from the
+ * users eyes. If this variable is greater than -1, the child
+ * with that number is shown instead of this node.
+ * This node will not appear in the tree.
+ */
+ public int showInstead = -1;
+
+ /**
+ * A simple setter constructor, that sets the fields of this class (except showInstead)
+ * @param node the GF node connected to this NodeData, not the JTree node
+ * @param pos The position String in the GF AST for this node
+ * in Haskell notation.
+ * @param selected if this is the active, selected, focused node
+ * @param constraint The GF constraint introduced in this node
+ */
+ protected AstNodeData(GfAstNode node, String pos, boolean selected, String constraint) {
+ this.node = node;
+ this.position = pos;
+ this.selected = selected;
+ // I have no better idea, how to clutch them together, since
+ // I don't need the content of this field right now.
+ this.constraint = node.constraint + constraint;
+ }
+
+ public String toString() {
+ return this.node.getLine();
+ }
+
}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/ChainCommandTuple.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/ChainCommandTuple.java
new file mode 100644
index 000000000..c0f6f0c0d
--- /dev/null
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/ChainCommandTuple.java
@@ -0,0 +1,60 @@
+//Copyright (c) Hans-Joachim Daniels 2005
+//
+//This program is free software; you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation; either version 2 of the License, or
+//(at your option) any later version.
+//
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU General Public License for more details.
+//
+//You can either finde the file LICENSE or LICENSE.TXT in the source
+//distribution or in the .jar file of this application
+package de.uka.ilkd.key.ocl.gf;
+
+/**
+ * @author hdaniels
+ * For chain commands, it is not just enough, to save the command sent to GF
+ * and the respective show text.
+ * Then it would be unclear, which fun should determine the used printname.
+ * If none is given, the last one of a chain command is taken.
+ * But if a solve for example is to follow, this does not work.
+ * Thus, this class has some other fields to define the appearance of a
+ * chain command.
+ */
+class ChainCommandTuple extends StringTuple {
+ /**
+ * the fun, that selects the printname
+ */
+ final public String fun;
+ /**
+ * Here the subcat of fun can be overwritten.
+ * Is used for the attributes of self.
+ */
+ final public String subcat;
+ /**
+ * normally, the ';;' are counted. But if we know, how many commands we
+ * chain to each other, we can skip that step and use undoSteps instead
+ */
+ final public int undoSteps;
+
+ /**
+ * A simple setter constructor
+ * @param command The command sent to GF
+ * @param showtext The text, that GF would display if no matching
+ * printname is found.
+ * @param fun The fun that selects the used printname
+ * @param subcat the subcategory for the refinement menu, overwrites
+ * the one defined in the printname
+ * @param undoSteps how many undos are needed to undo this command
+ */
+ public ChainCommandTuple(String command, String showtext, String fun, String subcat, int undoSteps) {
+ super(command, showtext);
+ this.fun = fun;
+ this.subcat = subcat;
+ this.undoSteps = undoSteps;
+ }
+
+}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/ConstraintCallback.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/ConstraintCallback.java
index a9fa6570d..3a9432960 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/ConstraintCallback.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/ConstraintCallback.java
@@ -21,8 +21,7 @@ import java.util.logging.*;
* @author daniels
* Offers the interface that GFEditor2 uses to send back the constraint after editing.
* Has no dependancies on KeY or TogetherCC.
- *
- */
+ */
abstract class ConstraintCallback {
/**
@@ -30,6 +29,9 @@ abstract class ConstraintCallback {
*/
protected static Logger logger = Logger.getLogger(ConstraintCallback.class.getName());
+ /**
+ * The path name of the directory where the grammars reside
+ */
String grammarsDir;
/**
* sets the directory where the grammars reside
@@ -38,6 +40,7 @@ abstract class ConstraintCallback {
void setGrammarsDir(final String grammarsDir) {
this.grammarsDir = grammarsDir;
}
+
/**
* gets the directory where the grammars reside
*/
@@ -51,5 +54,11 @@ abstract class ConstraintCallback {
* @param constraint The OCL constraint in question.
*/
abstract void sendConstraint(String constraint);
-
+
+ /**
+ * Sends the unfinished OCL constraint back to Together to save it
+ * as a GF tree as a JavaDoc comment.
+ * @param abs The GF tree in question
+ */
+ abstract void sendAbstract(String abs);
}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Display.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Display.java
index e28febb86..9ca39fc49 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Display.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Display.java
@@ -25,8 +25,14 @@ import javax.swing.JEditorPane;
* Takes care of collecting the linearized text and the length calculations
*/
class Display {
- private final boolean doText;
- private final boolean doHtml;
+ /**
+ * If the linearization should be displayed as pure text
+ */
+ private boolean doText;
+ /**
+ * If the linearization should be displayed as HTML
+ */
+ private boolean doHtml;
/**
* collects the linearization after each append.
* what's in here are Strings
@@ -46,33 +52,49 @@ class Display {
*/
private JEditorPane htmlLengthPane = new JEditorPane();
- /** initializes this object, nothing special
+ /**
+ * initializes this object, nothing special
* @param dt 1 if only text is to be shown, 2 for only HTML, 3 for both.
* Other values are forbidden.
*/
public Display(int dt) {
+ setDisplayType(dt);
+ this.htmlLengthPane.setContentType("text/html");
+ this.htmlLengthPane.setEditable(false);
+ }
+
+ /**
+ * (de-)activates display of text and HTML according to dt
+ * @param dt 1 if only text is to be shown, 2 for only HTML, 3 for both.
+ */
+ protected void setDisplayType(int dt) {
switch (dt) {
case 1:
doText = true;
- doHtml = false;
- break;
+ doHtml = false;
+ break;
case 2:
doText = false;
- doHtml = true;
- break;
+ doHtml = true;
+ break;
case 3:
doText = true;
- doHtml = true;
- break;
- default:
- doText = true;
- doHtml = true;
- break;
+ doHtml = true;
+ break;
+ default:
+ doText = true;
+ doHtml = true;
+ break;
}
- this.htmlLengthPane.setContentType("text/html");
- this.htmlLengthPane.setEditable(false);
}
-
+ /**
+ * Resets the stored text, but leaves the scroll markers untouched.
+ */
+ public void resetLin() {
+ linStagesHtml.clear();
+ linStagesText.clear();
+ htmlLengthPane.setText("");
+ }
/**
* @param font The Font, that is to be used. If null, the default of JTextPane is taken.
@@ -157,7 +179,7 @@ class Display {
* @return the HtmlMarkedArea object that represents the given information
* and knows about its beginning and end in the display areas.
*/
- protected HtmlMarkedArea addAsMarked(String toAdd, LinPosition position, String language) {
+ protected MarkedArea addAsMarked(String toAdd, LinPosition position, String language) {
/** the length of the displayed HTML before the current append */
int oldLengthHtml = 0;
if (doHtml) {
@@ -187,7 +209,7 @@ class Display {
if (doHtml) {
final String newStageHtml = this.linStagesHtml.lastElement().toString();
final String newHtml = Printname.htmlPrepend(newStageHtml, "");
- //yeah, daniels admits, this IS probably expensive
+ //yeah, daniels admits, this IS expensive
this.htmlLengthPane.setText(newHtml);
newLengthHtml = htmlLengthPane.getDocument().getLength();
if (newLengthHtml < oldLengthHtml) {
@@ -199,7 +221,7 @@ class Display {
if (doText) {
newLengthText = this.linStagesText.lastElement().toString().length();
}
- final HtmlMarkedArea hma = new HtmlMarkedArea(oldLengthText, newLengthText, position, toAdd, oldLengthHtml, newLengthHtml, language);
+ final MarkedArea hma = new MarkedArea(oldLengthText, newLengthText, position, toAdd, oldLengthHtml, newLengthHtml, language);
return hma;
}
/**
@@ -210,6 +232,15 @@ class Display {
* To store the scroll state of the HTML linearization area
*/
Rectangle recHtml = new Rectangle();
+ /**
+ * To store the scroll state of the pure text linearization area
+ */
+ int scrollText = 0;
+ /**
+ * To store the scroll state of the HTML linearization area
+ */
+ int scrollHtml = 0;
+
public String toString() {
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/DynamicTree2.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/DynamicTree2.java
index 59616034a..5c88955d3 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/DynamicTree2.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/DynamicTree2.java
@@ -29,21 +29,28 @@ import java.util.logging.*;
//import de.uka.ilkd.key.util.KeYResourceManager;
import java.awt.event.*;
-//import java.net.URL;
-public class DynamicTree2 extends JPanel implements KeyListener,
-ActionListener{
+/**
+ * A GUI class, does store the tree, but does not create it.
+ * The tree is created in GFEditor2.
+ * This class displays the tree and let the user interact with it via mouse clicks.
+ */
+public class DynamicTree2 extends JPanel implements KeyListener {
protected static Logger logger = Logger.getLogger(DynamicTree2.class.getName());
-
+
public DefaultMutableTreeNode rootNode;
- protected DefaultTreeModel treeModel;
+ private DefaultTreeModel treeModel;
public JTree tree;
- public int oldSelection = 0;
private Toolkit toolkit = Toolkit.getDefaultToolkit();
- public JPopupMenu popup = new JPopupMenu();
- JMenuItem menuItem;
private GFEditor2 gfeditor;
+ protected TreePath oldSelection = null;
+ /**
+ * Initializes the display state of the tree panel, sets up the
+ * event handlers.
+ * Does not initialize the tree.
+ * @param gfe The editor object this object belongs to.
+ */
public DynamicTree2(GFEditor2 gfe) {
this.gfeditor = gfe;
@@ -54,12 +61,8 @@ ActionListener{
tree = new JTree(treeModel);
tree.setRootVisible(false);
tree.setEditable(false);
- tree.getSelectionModel().setSelectionMode
- (TreeSelectionModel.SINGLE_TREE_SELECTION);
+ tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
tree.addKeyListener(this);
- menuItem = new JMenuItem("Paste");
- menuItem.addActionListener(this);
- popup.add(menuItem);
//Add listener to components that can bring up popup menus.
MouseListener popupListener = new PopupListener();
@@ -72,33 +75,29 @@ ActionListener{
* gfeditor.nodeTable contains the positions for all selectionPathes.
*/
public void valueChanged(TreeSelectionEvent e) {
+ if ((tree.getSelectionPath() != null) && tree.getSelectionPath().equals(oldSelection)) {
+ //nothing to be done here, probably
+ //triggered by showTree
+ return;
+ }
if (tree.getSelectionRows() != null) {
- if (gfeditor.nodeTable == null) {
- if (GFEditor2.treeLogger.isLoggable(Level.FINER)) {
- GFEditor2.treeLogger.finer("null node table");
- }
- } else {
- if (GFEditor2.treeLogger.isLoggable(Level.FINER)) {
- GFEditor2.treeLogger.finer("node table: " + gfeditor.nodeTable.contains(new Integer(0)) + " " + gfeditor.nodeTable.keys().nextElement());
- }
- }
if (tree.getSelectionPath() == null) {
- if (GFEditor2.treeLogger.isLoggable(Level.FINER)) {
- GFEditor2.treeLogger.finer("null root path");
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("null root path");
}
} else {
- if (GFEditor2.treeLogger.isLoggable(Level.FINER)) {
- GFEditor2.treeLogger.finer("selected path" + tree.getSelectionPath());
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("selected path" + tree.getSelectionPath());
}
}
- String pos = (String)gfeditor.nodeTable.get(tree.getSelectionPath());
+ String pos = gfeditor.getNodePosition(tree.getSelectionPath());
if (pos == null || "".equals(pos)) {
//default to sth. sensible
pos = "[]";
}
- gfeditor.treeChanged = true;
- gfeditor.send("mp " + pos);
+ gfeditor.send("[t] mp " + pos);
}
+ oldSelection = tree.getSelectionPath();
}
});
@@ -112,10 +111,20 @@ ActionListener{
add(scrollPane);
}
+ /**
+ * Remove all nodes in the tree and
+ * form a dummy tree in treePanel
+ */
+ protected void resetTree() {
+ ((DefaultTreeModel)(tree.getModel())).setRoot(new DefaultMutableTreeNode("Root"));
+ ((DefaultTreeModel)(tree.getModel())).reload();
+ }
+
/** Remove all nodes except the root node. */
public void clear() {
- rootNode.removeAllChildren();
- treeModel.reload();
+ ((DefaultTreeModel)(tree.getModel())).setRoot(null);
+ oldSelection = null;
+ //((DefaultTreeModel)(tree.getModel())).reload();
}
/** Remove the currently selected node. */
@@ -218,9 +227,9 @@ ActionListener{
exc.printStackTrace();
}
- if (GFEditor2.treeLogger.isLoggable(Level.FINER)) {
- GFEditor2.treeLogger.finer("The user has finished editing the node.");
- GFEditor2.treeLogger.finer("New value: " + node.getUserObject());
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("The user has finished editing the node.");
+ logger.finer("New value: " + node.getUserObject());
}
}
public void treeNodesInserted(TreeModelEvent e) {
@@ -234,6 +243,10 @@ ActionListener{
}
}
+ /**
+ * This tree cell renderer got overwritten to make it possible to show
+ * tooltips according to the user object
+ */
private class MyRenderer extends DefaultTreeCellRenderer {
//int counter = 0;
//final ImageIcon iconFilled;
@@ -245,7 +258,11 @@ ActionListener{
// iconOpen = new ImageIcon(urlOpen);
// iconFilled = new ImageIcon(urlFilled);
// }
-
+
+ /**
+ * The heart of this class, sets display and tooltip text
+ * depending on the user data
+ */
public Component getTreeCellRendererComponent(
JTree tree,
Object value,
@@ -264,6 +281,10 @@ ActionListener{
if (node.getUserObject() instanceof AstNodeData) {
AstNodeData and = (AstNodeData)node.getUserObject();
String ptt = and.getParamTooltip();
+ if (!and.subtypingStatus ) {
+ this.setForeground(Color.RED);
+ ptt = Printname.htmlAppend(ptt, "<p>Subtyping proof is missing. <br>If no refinements are offered here, then there is a subtyping error.");
+ }
this.setToolTipText(ptt);
this.setText(and.toString());
// if (and.isMeta()) {
@@ -309,12 +330,6 @@ ActionListener{
class PopupListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
- int selRow = tree.getRowForLocation(e.getX(), e.getY());
- tree.setSelectionRow(selRow);
- if (GFEditor2.treeLogger.isLoggable(Level.FINER)) {
- GFEditor2.treeLogger.finer("selection changed!");
- }
- //for the popup or parse field, do the same as for the linearization areas
gfeditor.maybeShowPopup(e);
}
@@ -323,11 +338,9 @@ ActionListener{
}
}
- public void actionPerformed(ActionEvent ae) {
- //nothing to be done here
- }
-
- /** Handle the key pressed event. */
+ /**
+ * Handle the key pressed event.
+ */
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
switch (keyCode){
@@ -335,11 +348,15 @@ ActionListener{
case KeyEvent.VK_DELETE : gfeditor.send("d"); break;
}
}
- /** Handle the key typed event. */
+ /**
+ * Handle the key typed event.
+ */
public void keyTyped(KeyEvent e) {
//nothing to be done here
}
- /** Handle the key released event. */
+ /**
+ * Handle the key released event.
+ */
public void keyReleased(KeyEvent e) {
//nothing to be done here
}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/ExportFormatMenu.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/ExportFormatMenu.java
new file mode 100644
index 000000000..076a9778f
--- /dev/null
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/ExportFormatMenu.java
@@ -0,0 +1,67 @@
+// This file is part of KeY - Integrated Deductive Software Design
+// Copyright (C) 2001-2005 Universitaet Karlsruhe, Germany
+// Universitaet Koblenz-Landau, Germany
+// Chalmers University of Technology, Sweden
+//
+// The KeY system is protected by the GNU General Public License.
+// See LICENSE.TXT for details.
+//
+
+package de.uka.ilkd.key.ocl.gf;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+
+/** Provide a choice of output formats: OCL or Natural Language. NL can be
+ * formatted using either HTML or LaTeX.
+ */
+public class ExportFormatMenu extends JPanel
+{
+ public static int OCL = 0, HTML=1, LATEX=2;
+
+ private static String[] menuStrings = { "OCL",
+ "Natural Language/HTML (requires GF)",
+ "Natural Language/LaTeX (requires GF)"
+ };
+
+ private JComboBox formatMenu;
+ private int selection;
+
+ private ActionListener al = new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ JComboBox cb = (JComboBox) e.getSource();
+ String s = (String) cb.getSelectedItem();
+ if (s.equals("OCL")) {
+ selection = OCL;
+ } else if (s.equals("Natural Language/HTML (requires GF)")) {
+ selection = HTML;
+ } else if (s.equals("Natural Language/LaTeX (requires GF)")) {
+ selection = LATEX;
+ } else { // should never occur
+ selection = OCL;
+ };
+ }
+ };
+
+ public ExportFormatMenu()
+ {
+ super();
+ this.setLayout(new BoxLayout(this,BoxLayout.Y_AXIS));
+ formatMenu = new JComboBox(menuStrings);
+ formatMenu.setSelectedIndex(0);
+ formatMenu.addActionListener(al);
+ this.add(Box.createVerticalGlue());
+ JLabel text = new JLabel("Choose output format:");
+ this.add(text);
+ text.setAlignmentX(Component.CENTER_ALIGNMENT);
+ this.add(formatMenu);
+ }
+
+
+ public int getSelection()
+ {
+ return selection;
+ }
+}
+
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GFCommand.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GFCommand.java
index 93e4f8b83..6e420a62b 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GFCommand.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GFCommand.java
@@ -29,51 +29,78 @@ package de.uka.ilkd.key.ocl.gf;
*/
abstract class GFCommand implements Comparable{
- /** the subcategory of this command */
+ /**
+ * the subcategory of this command
+ */
public abstract String getSubcat();
- /** the type of the command, r,w,ch,d,ac,... */
+ /**
+ * the type of the command, r,w,ch,d,ac,...
+ */
protected String commandType;
- /** the type of the command, r,w,ch,d,ac,... */
+ /**
+ * the type of the command, r,w,ch,d,ac,...
+ */
public String getCommandType(){
return commandType;
}
- /** for wrap, the number of the argument the current node should become */
+ /**
+ * for wrap, the number of the argument the current node should become
+ */
protected int argument;
- /**the actual command that this object should represent */
+ /**
+ * the actual command that this object should represent
+ */
protected String command;
- /**the actual command that this object should represent */
+ /**
+ * the actual command that this object should represent
+ */
public String getCommand() {
return command;
}
- /**the Printname corresponding to the GF fun of this command*/
+ /**
+ * the Printname corresponding to the GF fun of this command
+ */
protected Printname printname;
- /**the Printname corresponding to the GF fun of this command*/
+ /**
+ * the Printname corresponding to the GF fun of this command
+ */
public Printname getPrintname(){
return printname;
}
- /**the text that is to be displayed as the tooltip */
+ /**
+ * the text that is to be displayed as the tooltip
+ */
public abstract String getTooltipText();
- /** the text that is to be displayed in the refinement lists */
+ /**
+ * the text that is to be displayed in the refinement lists
+ */
public abstract String getDisplayText();
- /** the name of the fun that is used in this command */
+ /**
+ * the name of the fun that is used in this command
+ */
protected String funName;
- /** if this is the first occurence of the current subcat */
+ /**
+ * if this is the first occurence of the current subcat
+ */
protected boolean newSubcat;
- /** if this is the first occurence of the current subcat */
+
+ /**
+ * if this is the first occurence of the current subcat
+ */
public boolean isNewSubcat() {
return newSubcat;
}
/**
* Compares two GFCommands.
- * LinkCommands are the least. InputCommands the greatest. If that does not decide,
- * the display name as a String does.
+ * LinkCommands are the least. Then the InputCommand (more than one
+ * does not happen). If that does not decide, the display name as a String does.
* @param o the other command.
* @return see above.
*/
@@ -87,11 +114,12 @@ abstract class GFCommand implements Comparable{
if (!(this instanceof LinkCommand) && (o instanceof LinkCommand)) {
return 1;
}
+ //LinkCommands are dealt with, so from now on, they don't occur
if (this instanceof InputCommand && !(o instanceof InputCommand)) {
- return 1;
+ return -1;
}
if (!(this instanceof InputCommand) && (o instanceof InputCommand)) {
- return -1;
+ return 1;
}
if (! (o instanceof GFCommand)) {
//This should never occur!
@@ -100,7 +128,6 @@ abstract class GFCommand implements Comparable{
GFCommand ocmd = (GFCommand)o;
return this.getDisplayText().compareTo(ocmd.getDisplayText());
}
-
}
public String toString() {
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GFEditor2.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GFEditor2.java
index 0e781ddaa..cdda74168 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GFEditor2.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GFEditor2.java
@@ -14,7 +14,7 @@
//You can either finde the file LICENSE or LICENSE.TXT in the source
//distribution or in the .jar file of this application
-package de.uka.ilkd.key.ocl.gf;
+package de.uka.ilkd.key.ocl.gf;
import java.awt.*;
import java.awt.event.*;
@@ -31,33 +31,37 @@ import java.util.logging.*;
import jargs.gnu.CmdLineParser;
public class GFEditor2 extends JFrame {
-
- /** the main logger for this class */
- protected static Logger logger = Logger.getLogger(GFEditor2.class.getName());
/**
- * logs the time at several stages when starting the editor.
- * For calibrating the ProgressMonitor
+ * the main logger for this class
+ */
+ private static Logger logger = Logger.getLogger(GFEditor2.class.getName());
+ /**
+ * debug stuff for the tree
+ */
+ private static Logger treeLogger = Logger.getLogger(DynamicTree2.class.getName());
+ /**
+ * red mark-up && html debug messages
+ */
+ private static Logger redLogger = Logger.getLogger(GFEditor2.class.getName() + "_Red");
+ /**
+ * pop-up/mouse handling debug messages
+ */
+ private static Logger popUpLogger = Logger.getLogger(GFEditor2.class.getName() + "_PopUp");
+ /**
+ * linearization marking debug messages
+ */
+ private static Logger linMarkingLogger = Logger.getLogger(GFEditor2.class.getName() + "_LinMarking");
+ /**
+ * keyPressedEvents & Co.
+ */
+ private static Logger keyLogger = Logger.getLogger(GFEditor2.class.getName() + "_key");
+ /**
+ * everything that is sent to GF
+ */
+ private static Logger sendLogger = Logger.getLogger(GFEditor2.class.getName() + ".send");
+ /**
+ * the first part of the name of the GF grammar file
*/
- protected static Logger timeLogger = Logger.getLogger("de.uka.ilkd.key.ocl.gf.Timer");
- /** print MarkedAreas */
- protected static Logger markedAreaLogger = Logger.getLogger(GFEditor2.class.getName() + "_MarkedArea");
- /** print MarkedAreas */
- protected static Logger htmlLogger = Logger.getLogger(GFEditor2.class.getName() + "_HTML");
- /** debug stuff for the tree */
- public static Logger treeLogger = Logger.getLogger(GFEditor2.class.getName() + "_Tree");
- /** red mark-up && html debug messages */
- protected static Logger redLogger = Logger.getLogger(GFEditor2.class.getName() + "_Red");
- /** pop-up/mouse handling debug messages */
- protected static Logger popUpLogger = Logger.getLogger(GFEditor2.class.getName() + "_PopUp");
- /** linearization marking debug messages */
- protected static Logger linMarkingLogger = Logger.getLogger(GFEditor2.class.getName() + "_LinMarking");
- /** XML parsing debug messages */
- protected static Logger xmlLogger = Logger.getLogger(GFEditor2.class.getName() + "_XML");
- /** keyPressedEvents & Co. */
- protected static Logger keyLogger = Logger.getLogger(GFEditor2.class.getName() + "_key");
- /** keyPressedEvents & Co. */
- protected static Logger sendLogger = Logger.getLogger(GFEditor2.class.getName() + ".send");
-
public final static String modelModulName = "FromUMLTypes";
/**
* Does the saving of constraints in Together.
@@ -65,50 +69,46 @@ public class GFEditor2 extends JFrame {
* Only its subclasses. That way it can be compiled without KeY.
*/
final private ConstraintCallback callback;
+ /**
+ * if the OCL features should be switched on
+ */
+ final private boolean oclMode;
- /** to collect the linearization strings */
- private HashMap linearizations = new HashMap();
- /** current Font */
+ /**
+ * does all direct interaction with GF
+ * (except for the probers)
+ */
+ private GfCapsule gfCapsule = null;
+ /**
+ * current Font
+ */
private Font font;
- /** contains the offered fonts by name */
+ /**
+ * contains the offered fonts by name
+ */
private JMenu fontMenu;
- /** offers a list of font sizes */
+ /**
+ * offers a list of font sizes
+ */
private JMenu sizeMenu;
-
- public JPopupMenu popup2 = new JPopupMenu();
+
/**
* what is written here is parsed and the result inserted instead of tbe selection.
* No idea how this element is displayed
*/
- public JTextField parseField = new JTextField("textField!");
+ private JTextField parseField = new JTextField("textField!");
/**
* The position of the focus, that is, the currently selected node in the AST
*/
- public LinPosition focusPosition ;
- /**
- * stack for storing the current position:
- * When displaying, we start with the root of the AST.
- * Whenever we start to display a node, it is pushed, and when it is completely displayed, we pop it.
- * Only LinPositions are stored in here
- * local in formLin?
- * */
- public Vector currentPosition = new Vector();
-
+ private LinPosition focusPosition ;
/**
* When a new category is chosen, it is set to true.
* In the reset or a completely new state it is falsed.
* The structure of the GF output is different then and this must be taken
* care of.
*/
- public boolean newObject = false;
- /**
- * the opposite of newObject
- * is only true, when we don't have a chosen category.
- * false: reading lins and tree
- * true: reading categories from GF
- */
- public boolean finished = false;
+ private boolean newObject = false;
/**
* if the user enters text for the alpha conversion, he perhaps wants to input the same text again.
* Therefore it is saved.
@@ -128,13 +128,7 @@ public class GFEditor2 extends JFrame {
/**
* the language the possible actions are displayed
*/
- protected String selectedMenuLanguage = "Abstract";
- /**
- * the GF-output between <linearization> </linearization> tags is stored here.
- * Must be saved in case the displayed languages are changed.
- * Only written in readLin
- */
- private String linearization = "";
+ private String selectedMenuLanguage = "Abstract";
/**
* write-only variable, stores the current import paths
* reset after each reset.
@@ -144,42 +138,40 @@ public class GFEditor2 extends JFrame {
* The mapping between Java tree pathes and GF AST positions
* is stored here.
*/
- public Hashtable nodeTable = new Hashtable();
- /**this FileChooser gets enriched with the Term/Text option */
- JFileChooser saveFc = new JFileChooser("./");
+ private Hashtable nodeTable = new Hashtable();
+ /**
+ * This is necessary to map clicks in the tree, where in the event handler
+ * only the selection path is availble, to AST positions which can be
+ * sent to GF.
+ * @param key The TreeSelectionPath, that identifies the wanted node
+ * @return The AST position string of the given TreePath in the table
+ * of stored nodes.
+ */
+ protected String getNodePosition(Object key) {
+ return nodeTable.get(key).toString();
+ }
+ /**
+ * this FileChooser gets enriched with the Term/Text option
+ */
+ private JFileChooser saveFc = new JFileChooser("./");
/** used for new Topic, Import and Browse (readDialog) */
- JFileChooser fc = new JFileChooser("./");
+ private JFileChooser fc = new JFileChooser("./");
private final static String [] modifyMenu = {"Modify", "identity","transfer",
"compute", "paraphrase", "generate","typecheck", "solve", "context" };
private static final String [] newMenu = {"New"};
- /**
- * if treeChanged is false, we don't have to rebuild it.
- * Avoids a time-consuming reconstruction and flickering.
- */
- public boolean treeChanged = true;
/**
- * The output from GF is in here.
- * Only the read methods, initializeGF and the prober objects access this.
- */
- private BufferedReader fromProc;
- /** Used to leave messages for GF here.
- * But <b>only</b> in send and special probers that clean up with undo
- * after them (or don't change the state like PrintnameLoader).
+ * Linearizations' display area
*/
- private BufferedWriter toProc;
- /** Linearizations' display area */
private JTextArea linearizationArea = new JTextArea();
- /** the content of the refinementMenu */
- public DefaultListModel listModel= new DefaultListModel();
- /** The list of current refinement options */
- private JList refinementList = new JList(this.listModel);
/**
* The abstract syntax tree representation of the current editing object
*/
private DynamicTree2 tree = new DynamicTree2(this);
- /** Current Topic */
+ /**
+ * Current Topic
+ */
private JLabel grammar = new JLabel("No topic ");
/**
* Writing the current editing object to file in the term or text
@@ -214,8 +206,6 @@ public class GFEditor2 extends JFrame {
private JLabel subtermDescLabel = new JLabel();
/** Refining with term or linearization from typed string or file */
private JButton read = new JButton("Read");
- // private JButton parse = new JButton("Parse");
- // private JButton term = new JButton("Term");
/** Performing alpha-conversion of bound variables */
private JButton alpha;
/** Generating random refinement */
@@ -231,7 +221,6 @@ public class GFEditor2 extends JFrame {
private JComboBox newCategoryMenu = new JComboBox(newMenu);
/** Choosing a linearization method */
private JComboBox modify = new JComboBox(modifyMenu);
- // private JComboBox mode = new JComboBox(modeMenu);
/** the panel with the more general command buttons */
private JPanel downPanel = new JPanel();
/** the splitpane containing tree on the left and linearization area on the right*/
@@ -252,8 +241,6 @@ public class GFEditor2 extends JFrame {
private JPanel centerPanel2= new JPanel();
/** contains refinment list and navigation buttons */
private JPanel centerPanelDown = new JPanel();
- /** the scrollpane containing the refinements */
- private JScrollPane refinementPanel = new JScrollPane(this.refinementList);
/** only contains the linearization area */
private JScrollPane outputPanelText = new JScrollPane(this.linearizationArea);
/** HTML Linearizations' display area */
@@ -270,7 +257,6 @@ public class GFEditor2 extends JFrame {
private JLabel statusLabel = new JLabel(status);
/** the main menu in the top */
private JMenuBar menuBar= new JMenuBar();
- //private ButtonGroup menuGroup = new ButtonGroup();
/** View settings */
private JMenu viewMenu= new JMenu("View");
/**
@@ -288,7 +274,6 @@ public class GFEditor2 extends JFrame {
private JRadioButtonMenuItem rbMenuItemLong;
/** stores whether the refinement list should be in 'short' format */
private JRadioButtonMenuItem rbMenuItemShort;
- // private JRadioButtonMenuItem rbMenuItemAbs;
/** stores whether the refinement list should be in 'untyped' format */
private JRadioButtonMenuItem rbMenuItemUnTyped;
/**
@@ -308,7 +293,6 @@ public class GFEditor2 extends JFrame {
private JMenu filterMenu = new JMenu("Filter");
/** for managing the filter menu entries*/
private ButtonGroup filterButtonGroup = new ButtonGroup();
- //now for stuff that is more or less OCL specific
/** Some usability things can be switched off here for testing */
private JMenu usabilityMenu= new JMenu("Usability");
@@ -321,6 +305,18 @@ public class GFEditor2 extends JFrame {
private JCheckBoxMenuItem subcatCbMenuItem;
/** to switch sorting of entries in the refinement menu on and off */
private JCheckBoxMenuItem sortCbMenuItem;
+ /** to switch autocoercing */
+ private JCheckBoxMenuItem coerceCbMenuItem;
+ /** to switch reducing the argument 3 refinement menu of coerce on or off */
+ private JCheckBoxMenuItem coerceReduceCbMenuItem;
+ /** to switch highlighting subtyping errors on or off */
+ private JCheckBoxMenuItem highlightSubtypingErrorsCbMenuItem;
+ /** to switch hiding coerce on or off */
+ private JCheckBoxMenuItem hideCoerceCbMenuItem;
+ /** to switch hiding coerce even if parts are unrefined on or off */
+ private JCheckBoxMenuItem hideCoerceAggressiveCbMenuItem;
+ /** to switch the attributes of self in the refinement menu on or off */
+ private JCheckBoxMenuItem easyAttributesCbMenuItem;
/**
* if true, self and result are only shown if applicable,
@@ -329,42 +325,66 @@ public class GFEditor2 extends JFrame {
private boolean showSelfResult = true;
/**
* if true, refinements are grouped by subcat
- * tied to @see subcatCbMenuItem
+ * tied to @see subcatCbMenuItem.
*/
private boolean groupSubcat = true;
+ /**
+ * @return Returns whether subcategories should be grouped or not
+ */
+ protected boolean isGroupSubcat() {
+ return groupSubcat;
+ }
/**
- * if true, refinements are grouped by subcat
- * tied to @see subcatCbMenuItem
+ * if true, refinements are grouped by subcat.
+ * tied to @see subcatCbMenuItem.
*/
private boolean sortRefinements = true;
/**
- * to store the Vectors which contain the display names for the
- * ListModel for refinementSubcatList for the different
- * subcategory menus.
- * The key is the shortname String, the value the Vector with the
- * display Strings
+ * @return Returns if the refinements should get sorted.
*/
- private Hashtable subcatListModelHashtable = new Hashtable();
- /**
- * this ListModel gets refilled every time a %WHATEVER command,
- * which stands for a shortname for a subcategory of commands
- * in the ListModel of refinementList, is selected there
+ protected boolean isSortRefinements() {
+ return sortRefinements;
+ }
+ /**
+ * if true, then Instances will automatically get wrapped with a coerce
+ * if encountered as meta in the active node
+ */
+ private boolean autoCoerce = false;
+ /**
+ * If this is true, the refinementmenu for argument 3 of coerce
+ * will be populated only with suiting refinements.
+ */
+ private boolean coerceReduceRM = false;
+ /**
+ * If true, then the AST will be checked for missing subtyping witnesses
+ */
+ private boolean highlightSubtypingErrors = false;
+ /**
+ * if true, filled in coercions will be hidden from the user
+ */
+ private boolean hideCoerce = false;
+ /**
+ * if true, filled in coercions will be hidden from the user
+ * even if they lack filled in type arguments
*/
- private DefaultListModel refinementSubcatListModel = new DefaultListModel();
- /** The list of current refinement options in the subcategory menu*/
- private JList refinementSubcatList = new JList(this.refinementSubcatListModel);
- /** the scrollpane containing the refinement subcategory*/
- private JScrollPane refinementSubcatPanel = new JScrollPane(this.refinementSubcatList);
- /** store what the shorthand name for the current subcat is */
- private String whichSubcat;
- /** stores the two refinement JLists */
- private JSplitPane refinementListsContainer;
+ private boolean hideCoerceAggressive = false;
+ /**
+ * offer the attributes of self directly in the refinement menu
+ */
+ private boolean easyAttributes = false;
- /** here the GFCommand objects are stored*/
- private Vector gfcommands = new Vector();
- /** handles all the Printname naming a.s.o */
+ /**
+ * handles all the Printname naming and so on.
+ */
private PrintnameManager printnameManager;
+ /**
+ * @return Returns the printnameManager.
+ */
+ protected PrintnameManager getPrintnameManager() {
+ return printnameManager;
+ }
+
/**
* stores the current type. Since the parsing often fails, this is
@@ -374,21 +394,6 @@ public class GFEditor2 extends JFrame {
/** stores the displayed parts of the linearization */
private Display display = new Display(3);
- /**
- * contains all the linearization pieces as HtmlMarkedArea
- * Needed to know to which node in the AST a word in the linHtmlPane
- * area belongs.
- */
- public Vector htmlOutputVector = new Vector();
- /**
- * contains all the linearization pieces as MarkedArea
- * Needed to know to which node in the AST a word in the linearization
- * area belongs.
- * At the moment, this is double effort, but the old way of generating
- * MarkedAreas should go away.
- */
- public Vector textOutputVector = new Vector();
-
/** takes care of the menus that display the available languages */
private LangMenuModel langMenuModel = new LangMenuModel();
@@ -408,6 +413,7 @@ public class GFEditor2 extends JFrame {
public void actionPerformed(ActionEvent ae) {
int oldDisplayType = displayType;
displayType = 1;
+ display.setDisplayType(displayType);
outputPanelUp.removeAll();
outputPanelUp.add(outputPanelText, BorderLayout.CENTER);
outputPanelUp.add(statusPanel, BorderLayout.SOUTH);
@@ -424,6 +430,7 @@ public class GFEditor2 extends JFrame {
public void actionPerformed(ActionEvent ae) {
int oldDisplayType = displayType;
displayType = 2;
+ display.setDisplayType(displayType);
outputPanelUp.removeAll();
outputPanelUp.add(outputPanelHtml, BorderLayout.CENTER);
outputPanelUp.add(statusPanel, BorderLayout.SOUTH);
@@ -441,6 +448,7 @@ public class GFEditor2 extends JFrame {
public void actionPerformed(ActionEvent ae) {
int oldDisplayType = displayType;
displayType = 3;
+ display.setDisplayType(displayType);
linSplitPane.setLeftComponent(outputPanelText);
linSplitPane.setRightComponent(outputPanelHtml);
outputPanelUp.removeAll();
@@ -452,16 +460,30 @@ public class GFEditor2 extends JFrame {
outputPanelUp.validate();
}
});
+
/**
* Since the user will be able to send chain commands to GF,
- * the editor has to keep track of them, sinve GF does not undo
+ * the editor has to keep track of them, since GF does not undo
* all parts with one undo, instead 'u n' with n as the number of
* individual commands, has to be sent.
- * This array keeps track of the last 21 such chain commands.
- * Farther back does the memory of the user probably not reach,
- * after that only 'u 1' is offered.
*/
- final private int[] undoRecord = new int[21];
+ private final Stack undoStack = new Stack();
+
+ /**
+ * for starting a SubtypingProber run
+ */
+ private JButton checkSubtyping;
+
+ /**
+ * handles the commands and how they are presented to the user
+ */
+ private RefinementMenu refinementMenu;
+ /**
+ * handles parsing and preparing for display
+ * of the linearization XML from GF.
+ * Also takes care of the click-in functionality.
+ */
+ private Linearization linearization;
/**
* Initializes GF with the given command, sets up the GUI
@@ -470,9 +492,11 @@ public class GFEditor2 extends JFrame {
* that is to be executed. Will set up the GF side of this session.
* @param isHtml true iff the editor should start in HTML mode.
* @param baseURL the URL that is the base for all relative links in HTML
+ * @param isOcl if the OCL special features should be available
*/
- public GFEditor2(String gfcmd, boolean isHtml, URL baseURL) {
+ public GFEditor2(String gfcmd, boolean isHtml, URL baseURL, boolean isOcl) {
this.callback = null;
+ this.oclMode = isOcl;
Image icon = null;
try {
final URL iconURL = ClassLoader.getSystemResource("gf-icon.gif");
@@ -482,7 +506,6 @@ public class GFEditor2 extends JFrame {
}
initializeGUI(baseURL, isHtml, icon);
initializeGF(gfcmd, null);
- //readAndDisplay();
}
/**
@@ -496,6 +519,7 @@ public class GFEditor2 extends JFrame {
* @param pm to monitor the loading progress. May be null
*/
public GFEditor2(String gfcmd, ConstraintCallback callback, String initAbs, ProgressMonitor pm) {
+ this.oclMode = true;
this.callback = callback;
Utils.tickProgress(pm, 5220, "Loading grammars");
@@ -507,8 +531,8 @@ public class GFEditor2 extends JFrame {
//The initial GF constraint has until now always been
//automatically solvable. So don't startle the user
//with painting everything red.
- send(initAbs + " ;; c solve ", false);
- readAndDisplay();
+ send(initAbs + " ;; c solve ", false, 2);
+ processGfedit();
Utils.tickProgress(pm, 9700, "Loading finished");
pm.close();
logger.finer("GFEditor2 constructor finished");
@@ -524,42 +548,23 @@ public class GFEditor2 extends JFrame {
* @param pm to monitor the loading progress. May be null
*/
private void initializeGF(String gfcmd, ProgressMonitor pm){
- try {
Utils.tickProgress(pm, 5250, "Starting GF");
logger.fine("Trying: "+gfcmd);
- Process extProc = Runtime.getRuntime().exec(gfcmd);
- InputStreamReader isr = new InputStreamReader(
- extProc.getInputStream(),"UTF8");
- this.fromProc = new BufferedReader (isr);
- String defaultEncoding = isr.getEncoding();
- if (logger.isLoggable(Level.FINER)) {
- logger.finer("encoding "+defaultEncoding);
- }
- this.toProc = new BufferedWriter(new OutputStreamWriter(extProc.getOutputStream(),"UTF8"));
-
- readInit(pm, true);
+ gfCapsule = new GfCapsule(gfcmd);
+ processInit(pm, true);
resetPrintnames(false);
- } catch (IOException e) {
- JOptionPane.showMessageDialog(new JFrame(), "Could not start " + gfcmd+
- "\nCheck your $PATH", "Error",
- JOptionPane.ERROR_MESSAGE);
- throw new RuntimeException("Could not start " + gfcmd+
- "\nCheck your $PATH");
- }
-
}
-
+
/**
* (re-)initializes this.printnameManager and loads the printnames from
* GF.
* @param replayState If GF should be called to give the same state as before,
* but without the message. Is needed, when this function is started by the user.
* If sth. else is sent to GF automatically, this is not needed.
- *
*/
private void resetPrintnames(boolean replayState) {
this.printnameManager = new PrintnameManager();
- PrintnameLoader pl = new PrintnameLoader(this.fromProc, this.toProc, this.printnameManager, this.typedMenuItems);
+ PrintnameLoader pl = new PrintnameLoader(gfCapsule, this.printnameManager, this.typedMenuItems);
if (!selectedMenuLanguage.equals("Abstract")) {
String sendString = selectedMenuLanguage;
pl.readPrintnames(sendString);
@@ -567,7 +572,7 @@ public class GFEditor2 extends JFrame {
//are not printed again when for example a 'ml' command comes
//next
if (replayState) {
- send("gf ");
+ send("gf ", true, 0);
}
}
}
@@ -581,6 +586,7 @@ public class GFEditor2 extends JFrame {
* instead.
*/
private void initializeGUI(URL baseURL, boolean showHtml, Image icon) {
+ refinementMenu = new RefinementMenu(this);
this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
@@ -785,6 +791,7 @@ public class GFEditor2 extends JFrame {
viewMenu.addSeparator();
viewMenu.add(filterMenu);
+ mlMenu.setToolTipText("the language of the entries in the refinement menu");
modeMenu.add(mlMenu);
/**
* switches GF to either display the refinement menu commands
@@ -805,11 +812,13 @@ public class GFEditor2 extends JFrame {
modeMenu.addSeparator();
menuGroup = new ButtonGroup();
rbMenuItemLong = new JRadioButtonMenuItem("long");
+ rbMenuItemLong.setToolTipText("long format in the refinement menu, e.g. 'refine' instead of 'r'");
rbMenuItemLong.setActionCommand("long");
rbMenuItemLong.addActionListener(longShortListener);
menuGroup.add(rbMenuItemLong);
modeMenu.add(rbMenuItemLong);
rbMenuItemShort = new JRadioButtonMenuItem("short");
+ rbMenuItemShort.setToolTipText("short format in the refinement menu, e.g. 'r' instead of 'refine'");
rbMenuItemShort.setActionCommand("short");
rbMenuItemShort.setSelected(true);
rbMenuItemShort.addActionListener(longShortListener);
@@ -840,35 +849,25 @@ public class GFEditor2 extends JFrame {
};
menuGroup = new ButtonGroup();
rbMenuItem = new JRadioButtonMenuItem("typed");
+ rbMenuItem.setToolTipText("append the respective types to the entries of the refinement menu");
rbMenuItem.setActionCommand("typed");
rbMenuItem.addActionListener(unTypedListener);
rbMenuItem.setSelected(false);
menuGroup.add(rbMenuItem);
modeMenu.add(rbMenuItem);
rbMenuItemUnTyped = new JRadioButtonMenuItem("untyped");
+ rbMenuItemUnTyped.setToolTipText("omit the types of the entries of the refinement menu");
rbMenuItemUnTyped.setSelected(true);
rbMenuItemUnTyped.setActionCommand("untyped");
rbMenuItemUnTyped.addActionListener(unTypedListener);
menuGroup.add(rbMenuItemUnTyped);
modeMenu.add(rbMenuItemUnTyped);
- //OCL specific stuff
- selfresultCbMenuItem = new JCheckBoxMenuItem("skip self&result if possible");
- selfresultCbMenuItem.setActionCommand("selfresult");
- selfresultCbMenuItem.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- showSelfResult = selfresultCbMenuItem.isSelected();
- send("gf");
- }
- });
- selfresultCbMenuItem.setSelected(showSelfResult);
- if (this.callback != null || this.linearizations.containsKey("FromUMLTypesOCL")) {
- // only visible, if we really do OCL constraints
- usabilityMenu.add(selfresultCbMenuItem);
- }
+ //usability menu
subcatCbMenuItem = new JCheckBoxMenuItem("group possible refinements");
subcatCbMenuItem.setActionCommand("subcat");
+ subcatCbMenuItem.setToolTipText("group the entries of the refinement menus as defined in the printnames for the selected menu language");
subcatCbMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
groupSubcat = subcatCbMenuItem.isSelected();
@@ -880,6 +879,7 @@ public class GFEditor2 extends JFrame {
sortCbMenuItem = new JCheckBoxMenuItem("sort refinements");
sortCbMenuItem.setActionCommand("sortRefinements");
+ sortCbMenuItem.setToolTipText("sort the entries of the refinement menu");
sortCbMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
sortRefinements = sortCbMenuItem.isSelected();
@@ -888,13 +888,134 @@ public class GFEditor2 extends JFrame {
});
sortCbMenuItem.setSelected(sortRefinements);
usabilityMenu.add(sortCbMenuItem);
+
+ //OCL specific stuff
+
+ if (oclMode) {
+ usabilityMenu.addSeparator();
+ }
+ selfresultCbMenuItem = new JCheckBoxMenuItem("skip self&result if possible");
+ selfresultCbMenuItem.setToolTipText("do not display self and result in the refinement menu, if they don't fit");
+ selfresultCbMenuItem.setActionCommand("selfresult");
+ selfresultCbMenuItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ showSelfResult = selfresultCbMenuItem.isSelected();
+ send("gf");
+ }
+ });
+ selfresultCbMenuItem.setSelected(showSelfResult);
+ if (oclMode) {
+ // only visible, if we really do OCL constraints
+ usabilityMenu.add(selfresultCbMenuItem);
+ }
+ coerceReduceCbMenuItem = new JCheckBoxMenuItem("only suiting subtype instances for coerce");
+ coerceReduceCbMenuItem.setToolTipText("For coerce, where the target type is already known, show only the functions that return a subtype of this type.");
+ coerceReduceCbMenuItem.setActionCommand("coercereduce");
+ coerceReduceCbMenuItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ coerceReduceRM = coerceReduceCbMenuItem.isSelected();
+ }
+ });
+ if (oclMode) {
+ // only visible, if we really do OCL constraints
+ usabilityMenu.add(coerceReduceCbMenuItem);
+ coerceReduceRM = true;
+ }
+ coerceReduceCbMenuItem.setSelected(coerceReduceRM);
- //now for the other elements
+ coerceCbMenuItem = new JCheckBoxMenuItem("coerce automatically");
+ coerceCbMenuItem.setToolTipText("Fill in coerce automatically where applicable");
+ coerceCbMenuItem.setActionCommand("autocoerce");
+ coerceCbMenuItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ autoCoerce = coerceCbMenuItem.isSelected();
+ }
+ });
+ if (oclMode) {
+ // only visible, if we really do OCL constraints
+ usabilityMenu.add(coerceCbMenuItem);
+ autoCoerce = true;
+ }
+ coerceCbMenuItem.setSelected(autoCoerce);
- //HTML components
+ highlightSubtypingErrorsCbMenuItem = new JCheckBoxMenuItem("highlight suptyping errors");
+ highlightSubtypingErrorsCbMenuItem.setToolTipText("Mark nodes in situations, if where a non-existing subtyping is expected.");
+ highlightSubtypingErrorsCbMenuItem.setActionCommand("highlightsubtypingerrors");
+ highlightSubtypingErrorsCbMenuItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ highlightSubtypingErrors = highlightSubtypingErrorsCbMenuItem.isSelected();
+ send("[t] gf");
+ }
+ });
+ if (oclMode) {
+ // only visible, if we really do OCL constraints
+ usabilityMenu.add(highlightSubtypingErrorsCbMenuItem);
+ highlightSubtypingErrors = true;
+ }
+ highlightSubtypingErrorsCbMenuItem.setSelected(highlightSubtypingErrors);
+
+ hideCoerceCbMenuItem = new JCheckBoxMenuItem("hide coerce if completely refined");
+ hideCoerceCbMenuItem.setToolTipText("<html>Hide coerce functions when all arguments are filled in.<br>Note that, when a subtyping error is introduced, they will be shown.</html>");
+ hideCoerceCbMenuItem.setActionCommand("hideCoerce");
+ hideCoerceCbMenuItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ hideCoerce = hideCoerceCbMenuItem.isSelected();
+ //hideCoerceAggressiveCbMenuItem can only be used,
+ //if hideCoerce is active. But its state should survive.
+ hideCoerceAggressiveCbMenuItem.setEnabled(hideCoerce);
+ if (hideCoerce) {
+ hideCoerceAggressive = hideCoerceAggressiveCbMenuItem.isSelected();
+ } else {
+ hideCoerceAggressive = false;
+ }
+ send("[t] gf ", true, 0);
+ }
+ });
+ if (oclMode) {
+ // only visible, if we really do OCL constraints
+ usabilityMenu.add(hideCoerceCbMenuItem);
+ hideCoerce = true;
+ }
+ hideCoerceCbMenuItem.setSelected(hideCoerce);
+ hideCoerceAggressiveCbMenuItem = new JCheckBoxMenuItem("hide coerce always");
+ hideCoerceAggressiveCbMenuItem.setActionCommand("hideCoerceAggressive");
+ hideCoerceAggressiveCbMenuItem.setToolTipText("<html>Hide coerce functions even if the type arguments are incomplete.<br>Note that, when a subtyping error is introduced, they will be shown.</html>");
+ hideCoerceAggressiveCbMenuItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ hideCoerceAggressive = hideCoerceAggressiveCbMenuItem.isSelected();
+ send("[t] gf ", true, 0);
+ }
+ });
+ if (oclMode) {
+ // only visible, if we really do OCL constraints
+ usabilityMenu.add(hideCoerceAggressiveCbMenuItem);
+ hideCoerceAggressive = true;
+ }
+ hideCoerceAggressiveCbMenuItem.setSelected(hideCoerceAggressive);
+
+
+ easyAttributesCbMenuItem = new JCheckBoxMenuItem("directly offer attributes of 'self'");
+ easyAttributesCbMenuItem.setActionCommand("easyAttributes");
+ easyAttributesCbMenuItem.setToolTipText("list suiting attributes of self directly in the refinement menu");
+ easyAttributesCbMenuItem.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ easyAttributes = easyAttributesCbMenuItem.isSelected();
+ send("[t] gf ", true, 0);
+ }
+ });
+ if (oclMode) {
+ // only visible, if we really do OCL constraints
+ usabilityMenu.add(easyAttributesCbMenuItem);
+ easyAttributes = true;
+ }
+ easyAttributesCbMenuItem.setSelected(easyAttributes);
+
+ //now for the other elements
+
+ //HTML components
this.htmlLinPane.setContentType("text/html");
this.htmlLinPane.setEditable(false);
if (this.htmlLinPane.getStyledDocument() instanceof HTMLDocument) {
@@ -921,11 +1042,6 @@ public class GFEditor2 extends JFrame {
* The corresponding tree node is selected.
*/
public void caretUpdate(CaretEvent e) {
- String jPosition ="", iPosition="", position="";
- HtmlMarkedArea jElement = null;
- HtmlMarkedArea iElement = null;
- int j = 0;
- int i = htmlOutputVector.size()-1;
int start = htmlLinPane.getSelectionStart();
int end = htmlLinPane.getSelectionEnd();
if (popUpLogger.isLoggable(Level.FINER)) {
@@ -943,94 +1059,14 @@ public class GFEditor2 extends JFrame {
}
}
// not null selection:
- if ((i > -1) && (start < htmlLinPane.getDocument().getLength())) {
- if (linMarkingLogger.isLoggable(Level.FINER))
- for (int k=0; k < htmlOutputVector.size(); k++) {
- linMarkingLogger.finer("element: "+k+" begin "+((HtmlMarkedArea)htmlOutputVector.elementAt(k)).htmlBegin+" "
- + "\n-> end: "+((HtmlMarkedArea)htmlOutputVector.elementAt(k)).htmlEnd+" "
- + "\n-> position: "+(((HtmlMarkedArea)htmlOutputVector.elementAt(k)).position).position+" "
- + "\n-> words: "+((HtmlMarkedArea)htmlOutputVector.elementAt(k)).words);
- }
- // localizing end:
- while ((j < htmlOutputVector.size()) && (((HtmlMarkedArea)htmlOutputVector.elementAt(j)).htmlEnd < end)) {
- j++;
- }
- // localising start:
- while ((i >= 0) && (((HtmlMarkedArea)htmlOutputVector.elementAt(i)).htmlBegin > start)) {
- i--;
- }
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("i: "+i+" j: "+j);
- }
- if ((j < htmlOutputVector.size())) {
- jElement = (HtmlMarkedArea)htmlOutputVector.elementAt(j);
- jPosition = jElement.position.position;
- // less & before:
- if (i == -1) { // less:
- if (end>=jElement.htmlBegin) {
- iElement = (HtmlMarkedArea)htmlOutputVector.elementAt(0);
- iPosition = iElement.position.position;
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("Less: "+jPosition+" and "+iPosition);
- }
- position = findMax(0,j);
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("SELECTEDTEXT: "+position+"\n");
- }
- treeChanged = true;
- send("mp "+position);
- } else { // before:
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("BEFORE vector of size: "+htmlOutputVector.size());
- }
- }
- } else { // just:
- iElement = (HtmlMarkedArea)htmlOutputVector.elementAt(i);
- iPosition = iElement.position.position;
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("SELECTED TEXT Just: "+iPosition +" and "+jPosition+"\n");
- }
- position = findMax(i,j);
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("SELECTEDTEXT: "+position+"\n");
- }
- treeChanged = true;
- send("mp "+position);
- }
- } else if (i>=0) { // more && after:
- iElement = (HtmlMarkedArea)htmlOutputVector.elementAt(i);
- iPosition = iElement.position.position;
- // more
- if (start<=iElement.htmlEnd) {
- jElement = (HtmlMarkedArea)htmlOutputVector.elementAt(htmlOutputVector.size()-1);
- jPosition = jElement.position.position;
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("MORE: "+iPosition+ " and "+jPosition);
- }
- position = findMax(i,htmlOutputVector.size()-1);
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("SELECTEDTEXT: "+position+"\n");
- }
- treeChanged = true;
- send("mp "+position);
- // after:
- } else if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("AFTER vector of size: "+htmlOutputVector.size());
- }
- } else { // bigger:
- iElement = (HtmlMarkedArea)htmlOutputVector.elementAt(0);
- iPosition = iElement.position.position;
- jElement = (HtmlMarkedArea)htmlOutputVector.elementAt(htmlOutputVector.size()-1);
- jPosition = jElement.position.position;
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("BIGGER: "+iPosition +" and "+jPosition+"\n"
- + "\n-> SELECTEDTEXT: []\n");
- }
- treeChanged = true;
- send("mp []");
+ if (start < htmlLinPane.getDocument().getLength()) {
+ String position = linearization.markedAreaForPosHtml(start, end);
+ if (position != null) {
+ send("[t] mp " + position);
}
}//not null selection
}
+
});
this.linSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
this.outputPanelText, outputPanelHtml);
@@ -1046,11 +1082,6 @@ public class GFEditor2 extends JFrame {
* The corresponding tree node is selected.
*/
public void caretUpdate(CaretEvent e) {
- String jPosition ="", iPosition="", position="";
- MarkedArea jElement = null;
- MarkedArea iElement = null;
- int j = 0;
- int i = htmlOutputVector.size() - 1;
int start = linearizationArea.getSelectionStart();
int end = linearizationArea.getSelectionEnd();
if (popUpLogger.isLoggable(Level.FINER)) {
@@ -1058,95 +1089,18 @@ public class GFEditor2 extends JFrame {
+ "\n-> SELECTION START POSITION: "+start
+ "\n-> SELECTION END POSITION: "+end);
}
+ final int displayedTextLength = linearizationArea.getText().length();
if (linMarkingLogger.isLoggable(Level.FINER)) {
- if (end>0&&(end<linearizationArea.getText().length())) {
+ if (end>0&&(end<displayedTextLength)) {
linMarkingLogger.finer("CHAR: "+linearizationArea.getText().charAt(end));
}
}
// not null selection:
- if ((i>-1)&&(start<linearizationArea.getText().length()-1)) {
- if (linMarkingLogger.isLoggable(Level.FINER))
- for (int k = 0; k < htmlOutputVector.size(); k++) {
- linMarkingLogger.finer("element: " + k + " begin " + ((MarkedArea)htmlOutputVector.elementAt(k)).begin + " "
- + "\n-> end: " + ((MarkedArea)htmlOutputVector.elementAt(k)).end+" "
- + "\n-> position: " + (((MarkedArea)htmlOutputVector.elementAt(k)).position).position+" "
- + "\n-> words: " + ((MarkedArea)htmlOutputVector.elementAt(k)).words);
- }
- // localizing end:
- while ((j < htmlOutputVector.size()) && (((MarkedArea)htmlOutputVector.elementAt(j)).end < end)) {
- j++;
- }
- // localising start:
- while ((i >= 0) && (((MarkedArea)htmlOutputVector.elementAt(i)).begin > start))
- i--;
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("i: " + i + " j: " + j);
+ if (start < displayedTextLength) { //TODO was -1 before, why?
+ String position = linearization.markedAreaForPosPureText(start, end);
+ if (position != null) {
+ send("[t] mp " + position);
}
- if ((j < htmlOutputVector.size())) {
- jElement = (MarkedArea)htmlOutputVector.elementAt(j);
- jPosition = jElement.position.position;
- // less & before:
- if (i==-1) { // less:
- if (end>=jElement.begin) {
- iElement = (MarkedArea)htmlOutputVector.elementAt(0);
- iPosition = iElement.position.position;
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("Less: "+jPosition+" and "+iPosition);
- }
- position = findMax(0,j);
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("SELECTEDTEXT: "+position+"\n");
- }
- treeChanged = true;
- send("mp "+position);
- } else if (linMarkingLogger.isLoggable(Level.FINER)) { // before:
- linMarkingLogger.finer("BEFORE vector of size: " + htmlOutputVector.size());
- }
- } else { // just:
- iElement = (MarkedArea)htmlOutputVector.elementAt(i);
- iPosition = iElement.position.position;
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("SELECTED TEXT Just: "+iPosition +" and "+jPosition+"\n");
- }
- position = findMax(i,j);
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("SELECTEDTEXT: "+position+"\n");
- }
- treeChanged = true;
- send("mp "+position);
- }
- } else if (i>=0) { // more && after:
- iElement = (MarkedArea)htmlOutputVector.elementAt(i);
- iPosition = iElement.position.position;
- // more
- if (start<=iElement.end) {
- jElement = (MarkedArea)htmlOutputVector.elementAt(htmlOutputVector.size() - 1);
- jPosition = jElement.position.position;
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("MORE: "+iPosition+ " and "+jPosition);
- }
- position = findMax(i, htmlOutputVector.size()-1);
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("SELECTEDTEXT: "+position+"\n");
- }
- treeChanged = true;
- send("mp "+position);
- } else if (linMarkingLogger.isLoggable(Level.FINER)) { // after:
- linMarkingLogger.finer("AFTER vector of size: " + htmlOutputVector.size());
- }
- } else {
- // bigger:
- iElement = (MarkedArea)htmlOutputVector.elementAt(0);
- iPosition = iElement.position.position;
- jElement = (MarkedArea)htmlOutputVector.elementAt(htmlOutputVector.size()-1);
- jPosition = jElement.position.position;
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("BIGGER: "+iPosition +" and "+jPosition+"\n"
- + "\n-> SELECTEDTEXT: []\n");
- }
- treeChanged = true;
- send("mp []");
- }
}//not null selection
}
@@ -1166,9 +1120,8 @@ public class GFEditor2 extends JFrame {
if (keyCode == KeyEvent.VK_ENTER) {
getLayeredPane().remove(parseField);
- treeChanged = true;
- send("p "+parseField.getText());
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("sending parse string: "+parseField.getText());
+ send("[t] p "+parseField.getText());
+ if (logger.isLoggable(Level.FINE)) logger.fine("sending parse string: "+parseField.getText());
repaint();
} else if (keyCode == KeyEvent.VK_ESCAPE) {
getLayeredPane().remove(parseField);
@@ -1199,6 +1152,7 @@ public class GFEditor2 extends JFrame {
}
});
// System.out.println(output.getFont().getFontName());
+
//Now for the command buttons in the lower part
gfCommand = new JButton(gfCommandAction);
@@ -1207,14 +1161,17 @@ public class GFEditor2 extends JFrame {
alpha = new JButton(alphaAction);
random = new JButton(randomAction);
undo = new JButton(undoAction);
+ checkSubtyping = new JButton(new SubtypeAction());
downPanel.add(gfCommand);
downPanel.add(read);
downPanel.add(modify);
downPanel.add(alpha);
downPanel.add(random);
downPanel.add(undo);
- //downPanel.add(parse);
- //downPanel.add(term);
+ if (oclMode) {
+ // only visible, if we really do OCL constraints
+ downPanel.add(checkSubtyping);
+ }
//now for the navigation buttons
leftMeta.setToolTipText("Moving the focus to the previous metavariable");
@@ -1247,13 +1204,9 @@ public class GFEditor2 extends JFrame {
upPanel.add(newTopic);
statusLabel.setToolTipText("The current focus type");
- refinementList.setToolTipText("The list of current refinement options");
- refinementList.setCellRenderer(new ToolTipCellRenderer());
- refinementSubcatList.setToolTipText("The list of current refinement options");
- refinementSubcatList.setCellRenderer(new ToolTipCellRenderer());
tree.setToolTipText("The abstract syntax tree representation of the current editing object");
- resetTree(tree);
+ tree.resetTree();
bgDisplayType.add(rbText);
bgDisplayType.add(rbHtml);
@@ -1271,6 +1224,7 @@ public class GFEditor2 extends JFrame {
viewMenu.add(rbHtml);
viewMenu.add(rbTextHtml);
display = new Display(displayType);
+ linearization = new Linearization(display);
statusPanel.setLayout(new GridLayout(1,1));
statusPanel.add(statusLabel);
@@ -1290,112 +1244,20 @@ public class GFEditor2 extends JFrame {
centerPanel.addKeyListener(tree);
centerPanel.setOneTouchExpandable(true);
- refinementListsContainer = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,refinementPanel, refinementSubcatPanel);
+
centerPanelDown.add(middlePanel, BorderLayout.NORTH);
- centerPanelDown.add(refinementListsContainer, BorderLayout.CENTER);
- //centerPanelDown.add(refinementSubcatPanel, BorderLayout.EAST);
+ centerPanelDown.add(refinementMenu.getRefinementListsContainer(), BorderLayout.CENTER);
coverPanel.add(centerPanel, BorderLayout.CENTER);
coverPanel.add(upPanel, BorderLayout.NORTH);
coverPanel.add(downPanel, BorderLayout.SOUTH);
- refinementList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-
- final MouseListener mlRefinementList = new MouseAdapter() {
- public void mouseClicked(MouseEvent e) {
- refinementList.setSelectionBackground(refinementSubcatList.getSelectionBackground());
- boolean doubleClick = (e.getClickCount() == 2);
- listAction(refinementList, refinementList.locationToIndex(e.getPoint()), doubleClick);
- }
- };
- refinementList.addMouseListener(mlRefinementList);
- refinementList.addKeyListener(new KeyListener() {
- /** Handle the key pressed event for the refinement list. */
- public void keyPressed(KeyEvent e) {
- int keyCode = e.getKeyCode();
- if (keyLogger.isLoggable(Level.FINER)) {
- keyLogger.finer("Key pressed: " + e.toString());
- }
-
- int index = refinementList.getSelectedIndex();
- if (index == -1) {
- //nothing selected, so nothing to be seen here, please move along
- } else if (keyCode == KeyEvent.VK_ENTER) {
- listAction(refinementList, refinementList.getSelectedIndex(), true);
- } else if (keyCode == KeyEvent.VK_DOWN && index < listModel.getSize() - 1) {
- listAction(refinementList, index + 1, false);
- } else if (keyCode == KeyEvent.VK_UP && index > 0) {
- listAction(refinementList, index - 1, false);
- } else if (keyCode == KeyEvent.VK_RIGHT) {
- if (refinementSubcatList.getModel().getSize() > 0) {
- refinementSubcatList.requestFocusInWindow();
- refinementSubcatList.setSelectedIndex(0);
- refinementList.setSelectionBackground(Color.GRAY);
- }
- }
- }
-
- /**
- * Handle the key typed event.
- * We are not really interested in typed characters, thus empty
- */
- public void keyTyped(KeyEvent e) {
- //needed for KeyListener, but not used
- }
-
- /** Handle the key released event. */
- public void keyReleased(KeyEvent e) {
- //needed for KeyListener, but not used
- }
- });
-
- refinementSubcatList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-
- final MouseListener mlRefinementSubcatList = new MouseAdapter() {
- public void mouseClicked(MouseEvent e) {
- boolean doubleClick = (e.getClickCount() == 2);
- listAction(refinementSubcatList, refinementSubcatList.locationToIndex(e.getPoint()), doubleClick);
- refinementList.setSelectionBackground(Color.GRAY);
- }
- };
- refinementSubcatList.addMouseListener(mlRefinementSubcatList);
- refinementSubcatList.addKeyListener(new KeyListener() {
- /** Handle the key pressed event. */
- public void keyPressed(KeyEvent e) {
- int keyCode = e.getKeyCode();
- if (keyLogger.isLoggable(Level.FINER)) {
- keyLogger.finer("Key pressed: " + e.toString());
- }
- if (keyCode == KeyEvent.VK_ENTER) {
- listAction(refinementSubcatList, refinementSubcatList.getSelectedIndex(), true);
- } else if (keyCode == KeyEvent.VK_LEFT) {
- refinementList.requestFocusInWindow();
- refinementSubcatList.clearSelection();
- refinementList.setSelectionBackground(refinementSubcatList.getSelectionBackground());
- }
- }
-
- /**
- * Handle the key typed event.
- * We are not really interested in typed characters, thus empty
- */
- public void keyTyped(KeyEvent e) {
- //needed for KeyListener, but not used
- }
-
- /** Handle the key released event. */
- public void keyReleased(KeyEvent e) {
- //needed for KeyListener, but not used
- }
- });
newCategoryMenu.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if (!newCategoryMenu.getSelectedItem().equals("New")) {
- treeChanged = true;
- newObject = true;
- send("n " + newCategoryMenu.getSelectedItem());
+ send("[nt] n " + newCategoryMenu.getSelectedItem());
newCategoryMenu.setSelectedIndex(0);
}
}
@@ -1421,24 +1283,19 @@ public class GFEditor2 extends JFrame {
public void actionPerformed(ActionEvent ae) {
Object obj = ae.getSource();
if ( obj == leftMeta ) {
- treeChanged = true;
- send("<<");
+ send("[t] <<");
}
if ( obj == left ) {
- treeChanged = true;
- send("<");
+ send("[t] <");
}
if ( obj == top ) {
- treeChanged = true;
- send("'");
+ send("[t] '");
}
if ( obj == right ) {
- treeChanged = true;
- send(">");
+ send("[t] >");
}
if ( obj == rightMeta ) {
- treeChanged = true;
- send(">>");
+ send("[t] >>");
}
}
};
@@ -1451,8 +1308,7 @@ public class GFEditor2 extends JFrame {
modify.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if (!modify.getSelectedItem().equals("Modify")) {
- treeChanged = true;
- send("c " + modify.getSelectedItem());
+ send("[t] c " + modify.getSelectedItem());
modify.setSelectedIndex(0);
}
}
@@ -1461,20 +1317,17 @@ public class GFEditor2 extends JFrame {
top.setFocusable(false);
right.setFocusable(false);
rightMeta.setFocusable(false);
- //parse.setFocusable(false);
- //term.setFocusable(false);
read.setFocusable(false);
modify.setFocusable(false);
- //mode.setFocusable(false);
alpha.setFocusable(false);
random.setFocusable(false);
undo.setFocusable(false);
linearizationArea.addKeyListener(tree);
- this.setSize(800,600);
+ this.setSize(800, 600);
outputPanelUp.setPreferredSize(new Dimension(400,230));
treePanel.setDividerLocation(0.3);
- nodeTable.put(new TreePath(tree.rootNode.getPath()), "");
+ //nodeTable.put(new TreePath(tree.rootNode.getPath()), "");
JRadioButton termButton = new JRadioButton("Term");
termButton.setActionCommand("term");
@@ -1501,274 +1354,154 @@ public class GFEditor2 extends JFrame {
* @param text the command, exacltly the string that is going to be sent
*/
protected void send(String text){
- send(text, true);
+ send(text, true, 1);
}
/**
- * send a command to GF.
- * @param text the command, exacltly the string that is going to be sent
+ * send a command to GF (indirectly).
+ * @param text the command, exactly the string that is going to be sent
* @param andRead if true, the returned XML will be read an displayed accordingly
+ * @param undoSteps How many undo steps need to be done to undo this command.
+ * If undoSteps == 0, then nothing is done. If it is &lt; 0, it gets
+ * subtracted from the last number on the undoStack. That way, both
+ * this command and the last one get undone together (since the undo
+ * value is actually increased).
*/
- protected void send(String text, boolean andRead) {
- if (sendLogger.isLoggable(Level.FINER)) {
- sendLogger.finer("## send: '" + text + "'");
+ protected void send(String text, boolean andRead, int undoSteps) {
+ if (sendLogger.isLoggable(Level.FINE)) {
+ sendLogger.fine("## send: '" + text + "', undo steps: " + undoSteps);
}
- try {
- this.display = new Display(displayType);
- display(true, false);
- if (xmlLogger.isLoggable(Level.FINER)) {
- xmlLogger.finer("output cleared\n\n\n");
- }
- this.htmlOutputVector = new Vector();
- this.textOutputVector = new Vector();
- toProc.write(text, 0, text.length());
- toProc.newLine();
- toProc.flush();
- if (andRead) {
- readAndDisplay();
+ this.display.resetLin();
+ display(false, true, false);
+ linearization.reset();
+ if (undoSteps > 0) { //undo itself should not push sth. on the stack, only pop
+ undoStack.push(new Integer(undoSteps));
+ } else if (undoSteps < 0) {
+ final int oldUndo = ((Integer)undoStack.pop()).intValue();
+ final int newUndo = oldUndo - undoSteps;
+ if (sendLogger.isLoggable(Level.FINER)) {
+ sendLogger.finer("modified undoStack, top was " + oldUndo + ", but is now: " + newUndo);
}
- } catch (IOException e) {
- System.err.println("Could not write to external process " + e);
- }
+ undoStack.push(new Integer(newUndo));
+ }
+ gfCapsule.realSend(text);
+
+ if (andRead) {
+ processGfedit();
+ }
}
- /**
- * a simple wrapper around readGfedit that also probes
- * for unneccessary commands
- */
- protected void readAndDisplay() {
- readGfedit();
- probeCompletability();
- refinementList.requestFocusInWindow();
- }
+
/**
- * reads the front matter that GF returns when freshly started and loading a grammar.
- * When &lt;gfinit&gt; is read, the function returns.
+ * Asks the respective read methods to read the front matter of GF.
+ * That can be the greetings and loading messages.
+ * The latter are always read.
+ * When &lt;gfinit&gt; is read, the function returns.
* @param pm to monitor the loading progress. May be null
* @param greetingsToo if the greeting text from GF is expected
*/
- protected void readInit(ProgressMonitor pm, boolean greetingsToo) {
- String next = "";
+ private void processInit(ProgressMonitor pm, boolean greetingsToo) {
+ String next = null;
if (greetingsToo) {
- next = readGfGreetings();
- } else {
- try {
- next = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("1 " + next);
- } catch (IOException e) {
- System.err.println("Could not read from external process:\n" + e);
- }
+ StringTuple greetings = gfCapsule.readGfGreetings();
+ next = greetings.first;
+ this.display.addToStages(greetings.second, greetings.second.replaceAll("\\n", "<br>"));
+ display(true, true, false);
}
Utils.tickProgress(pm, 5300, null);
- next = readGfLoading(next, pm);
+ StringTuple loading = gfCapsule.readGfLoading(next, pm);
+ next = loading.first;
+ this.display.addToStages(loading.second, Utils.replaceAll(loading.second, "\n", "<br>\n"));
+ display(true, true, false);
+
if (next.equals("<gfinit>")) {
- readGfinit();
+ processGfinit();
}
}
/**
- * reads the greeting text from GF
- * @return the last read GF line, which should be the first loading line
+ * Takes care of reading the &lt;gfinit&gt; part
+ * Fills the new category menu.
*/
- protected String readGfGreetings() {
- try {
- String readresult = "";
- StringBuffer outputStringBuffer = new StringBuffer();
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("1 "+readresult);
- while ((readresult.indexOf("gf")==-1) && (readresult.trim().indexOf("<") < 0)){
- outputStringBuffer.append(readresult).append("\n");
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("1 "+readresult);
- }
- this.display.addToStages(outputStringBuffer.toString(), outputStringBuffer.toString().replaceAll("\\n", "<br>"));
- display(true, false);
- return readresult;
- } catch (IOException e) {
- System.err.println("Could not read from external process:\n" + e);
- return "";
- }
-
- }
-
- /**
- * reads the loading and compiling messages from GF
- * @param readresult the first loading line
- * @param pm to monitor the loading progress. May be null
- * @return the first line from &gt;gfinit&lt; or &gt;gfedit&lt;
- */
- protected String readGfLoading(String readresult, ProgressMonitor pm) {
- try {
- StringBuffer textPure = new StringBuffer();
- StringBuffer textHtml = new StringBuffer();
- int progress = 5300;
- while (!(readresult.indexOf("<gfinit>") > -1 || (readresult.indexOf("<gfmenu>") > -1))){
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("1 "+readresult);
- textPure.append(readresult).append("\n");
- textHtml.append(readresult).append("<br>\n");
- progress += 12;
- Utils.tickProgress(pm, progress, null);
- }
- //when old grammars are loaded, the first line looks like
- //"reading grammar of old format letter.Abs.gfreading old file letter.Abs.gf<gfinit>"
- //without newlines
- final int beginInit = readresult.indexOf("<gfinit>");
- if (beginInit > 0) {
- textPure.append(readresult.substring(0, beginInit)).append("\n");
- textPure.append(readresult.substring(0, beginInit)).append("<br>\n");
- //that is the expected result
- readresult = "<gfinit>";
- }
- this.display.addToStages(textPure.toString(), textHtml.toString());
- display(true, false);
- return readresult;
- } catch (IOException e) {
- System.err.println("Could not read from external process:\n" + e);
- return "";
- }
-
- }
-
- /**
- * reads the part between &gt;gfinit&lt; and &gt;/gfinit&lt;
- * and feeds the editor with what was read
- */
- protected void readGfinit() {
- try {
- //read <hmsg> or <newcat> or <topic> (in case of no grammar loaded)
- String readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("12 "+readresult);
- //when old grammars are loaded, the first line looks like
- //"reading grammar of old format letter.Abs.gfreading old file letter.Abs.gf<gfinit>"
- if (readresult.indexOf("<gfinit>") > -1) {
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("12 "+readresult);
- }
- String next = readHmsg(readresult);
-
- if ((next!=null) && ((next.indexOf("newcat") > -1) || (next.indexOf("topic") > -1))) {
- formNewMenu();
- }
-
- } catch (IOException e) {
- System.err.println("Could not read from external process:\n" + e);
+ private void processGfinit() {
+ NewCategoryMenuResult ncmr = gfCapsule.readGfinit();
+ if (ncmr != null) {
+ formNewMenu(ncmr);
}
-
}
/**
- * reads the output from GF starting with &gt;gfedit&lt; and last reads &gt;/gfedit&lt;.
+ * Takes care of reading the output from GF starting with
+ * &gt;gfedit&lt; and last reads &gt;/gfedit&lt;.
* Feeds the editor with what was read.
- */
- protected void readGfedit() {
- try {
- String next = "";
- //read <gfedit>
- String readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("11 "+readresult);
- //read either <hsmg> or <lineatization>
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("11 "+readresult);
+ * This makes this method nearly the central method of the editor.
+ */
+ private void processGfedit() {
+ final GfeditResult gfedit = gfCapsule.readGfedit(newObject);
+ formHmsg(gfedit.hmsg);
+ //now the form methods are called:
+ DefaultMutableTreeNode topNode = null;
+ TreeAnalysisResult tar = new TreeAnalysisResult(null, -1, false, true, false, false, null, null);
+ TreeAnalyser treeAnalyser = new TreeAnalyser(autoCoerce, coerceReduceRM, easyAttributes, hideCoerce, hideCoerceAggressive, highlightSubtypingErrors, showSelfResult);
+ if (gfedit.hmsg.treeChanged && newObject) {
+ topNode = formTree(gfedit.treeString);
+ tar = treeAnalyser.analyseTree(topNode);
+ focusPosition = tar.focusPosition;
+ currentNode = tar.currentNode;
+ }
+ //only sent sth. to GF directly, if we have sth. to send, and if it is not forbidden
+ if (tar.command == null || !gfedit.hmsg.recurse) {
+ //for normal grammars (not the OCL ones),
+ //the nextCommand feature is not used, thus
+ //only this branch is executed.
- //hmsg stuff
- next = readHmsg(readresult);
+ // nothing special is to be done here,
+ // the tree analysis has
+ // not told us to send sth. to GF,
+ // so display the rest and do most of the
+ // expensive stuff
- //reading <linearizations>
- //seems to be the only line read here
- //this is here to give as some sort of catch clause.
- while ((next!=null)&&((next.length()==0)||(next.indexOf("<linearizations>")==-1))) {
- next = fromProc.readLine();
- if (next!=null){
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("10 "+next);
- } else {
- System.exit(0);
- }
- }
- readresult = next;
- readLin();
- final String treeString = readTree();
- final String message = readMessage();
- //read the menu stuff
- Vector gfCommandVector;
- if (newObject) {
- gfCommandVector = readRefinementMenu();
- } else {
- while(readresult.indexOf("</menu")==-1) {
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("12 " + readresult);
- }
- gfCommandVector = null;
- }
- // "" should occur quite fast, but it has not already been read,
- // since the last read line is "</menu>"
- for (int i = 0; i < 3 && !readresult.equals(""); i++){
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("11 " + readresult);
+ if (topNode != null) { //the case of !treeChanged or !newObject
+ DefaultMutableTreeNode transformedTreeRoot = TreeAnalyser.transformTree(topNode);
+ showTree(tree, transformedTreeRoot);
}
- //now the form methods are called:
- if (treeChanged && (newObject)) {
- formTree(tree, treeString);
- }
- if (gfCommandVector != null) {
- formRefinementMenu(gfCommandVector);
+
+ if (gfedit.gfCommands != null) {
+ final Vector usedCommandVector = RefinementMenuTransformer.transformRefinementMenu(tar, gfedit.gfCommands, gfCapsule);
+ final boolean isAbstract = "Abstract".equals(selectedMenuLanguage);
+ refinementMenu.formRefinementMenu(usedCommandVector, gfedit.hmsg.appendix, currentNode, isAbstract, tar.easyAttributes && tar.reduceCoerce, focusPosition, gfCapsule);
}
if (newObject) {
- //MUST come after readLin, but since formLin is called later too,
+ //MUST come after readLin, but since formLin is called later on too,
//this cannot be enforced with a local this.linearization
+ String linString = gfedit.linearizations;
+ //is set only here, when it is fresh
+ linearization.setLinearization(linString);
formLin();
}
- if (message != null && message.length()>1) {
- this.display.addToStages("\n-------------\n" + message, "<br><hr>" + message);
+ if (gfedit.message != null && gfedit.message.length()>1) {
+ logger.fine("message found: '" + gfedit.message + "'");
+ this.display.addToStages("\n-------------\n" + gfedit.message, "<br><hr>" + gfedit.message);
//in case no language is displayed
- display(false, false);
- }
-
-
- } catch (IOException e) {
- System.err.println("Could not read from external process:\n" + e);
- }
-
- }
-
- /**
- * checks if result and self make sense in the current context.
- * if not, they are removed from the list
- */
- protected void probeCompletability() {
- if (!showSelfResult || (this.focusPosition == null)) {
- return;
- }
- /**
- * self and result both take two arguments.
- * The first is the type, which is fixed
- * if the second argument is refineable.
- * Important is the second.
- * This only is refineable for the real type of self/result
- */
- final String childPos = this.focusPosition.childPosition(1);
- final AutoCompletableProber cp = new AutoCompletableProber(fromProc, toProc);
- for (int i = 0; i < listModel.size(); i++) {
- String cmd = ((GFCommand)listModel.elementAt(i)).getCommand();
- if ((cmd != null) && ((cmd.indexOf("r core.self") > -1) || (cmd.indexOf("r core.result") > -1))) {
- String newCommand = cmd + " ;; mp " + childPos;
- if (!cp.isAutoCompletable(newCommand, 2)) {
- listModel.remove(i);
- i -=1;
- }
+ display(true, false, false);
}
+ } else {
+ // OK, sth. has to be sent to GF without displaying
+ // the linearization of this run
+ send(tar.command, true, - tar.undoSteps);
}
+ refinementMenu.requestFocus();
}
-
+
/**
* prints the available command line options
*/
private static void printUsage() {
- System.err.println("Usage: java -jar [-h/--html] [-b/--base baseURL] [grammarfile(s)]");
+ System.err.println("Usage: java -jar [-h/--html] [-b/--base baseURL] [-o/--ocl] [grammarfile(s)]");
System.err.println("where -h activates the HTML mode");
System.err.println("and -b sets the base location to which links in HTML are relative to. "
+ "Default is the current directory.");
@@ -1784,6 +1517,7 @@ public class GFEditor2 extends JFrame {
CmdLineParser parser = new CmdLineParser();
CmdLineParser.Option optHtml = parser.addBooleanOption('h', "html");
CmdLineParser.Option optBase = parser.addStringOption('b', "base");
+ CmdLineParser.Option optOcl = parser.addBooleanOption('o', "ocl");
CmdLineParser.Option gfBin = parser.addStringOption('g', "gfbin");
// Parse the command line options.
@@ -1798,6 +1532,7 @@ public class GFEditor2 extends JFrame {
Boolean isHtml = (Boolean)parser.getOptionValue(optHtml, Boolean.FALSE);
String baseString = (String)parser.getOptionValue(optBase, null);
String gfBinString = (String)parser.getOptionValue(gfBin, null);
+ Boolean isOcl = (Boolean)parser.getOptionValue(optOcl, Boolean.FALSE);
String[] otherArgs = parser.getRemainingArgs();
URL myBaseURL;
@@ -1824,7 +1559,7 @@ public class GFEditor2 extends JFrame {
}
Locale.setDefault(Locale.US);
logger.info("call to GF: " + gfCall);
- GFEditor2 gui = new GFEditor2(gfCall, isHtml.booleanValue(), myBaseURL);
+ GFEditor2 gui = new GFEditor2(gfCall, isHtml.booleanValue(), myBaseURL, isOcl.booleanValue());
if (logger.isLoggable(Level.FINER)) {
logger.finer("main finished");
}
@@ -1854,12 +1589,17 @@ public class GFEditor2 extends JFrame {
* we should not end the program, just close the GF editor
* possibly sending something back to KeY
*/
- protected void endProgram(){
+ private void endProgram(){
String saveQuestion;
if (this.callback == null) {
saveQuestion = "Save text before exiting?";
} else {
- saveQuestion = "Save constraint before exiting?";
+ send("' ;; >>");
+ if (this.currentNode.isMeta()) {
+ saveQuestion = "Incomplete OCL found.\nThis can only be saved (and loaded again) in an internal representation.\nStill save before exiting?";
+ } else {
+ saveQuestion = "Save constraint before exiting?";
+ }
}
int returnStatus;
if (this.newObject) {
@@ -1879,16 +1619,29 @@ public class GFEditor2 extends JFrame {
// back to Together/KeY.
// Hence this try-catch
if (returnStatus == JOptionPane.YES_OPTION) {
- String ocl = (String)linearizations.get(modelModulName + "OCL");
- if (ocl == null) {
- //OCL not present, so switch it on
- langMenuModel.setActive(modelModulName + "OCL", true);
- send("on " + modelModulName + "OCL");
- ocl = (String)linearizations.get(modelModulName + "OCL");
- }
- ocl = compactSpaces(ocl.trim()).trim();
-
- this.callback.sendConstraint(ocl);
+ //check, if there are open metavariables
+ //send("' ;; >>"); already done above
+ if (!this.currentNode.isMeta()) {
+ logger.info("No metavariables found, saving OCL");
+ //no open nodes, we can save OCL
+ String ocl = (String)linearization.getLinearizations().get(modelModulName + "OCL");
+ if (ocl == null) {
+ //OCL not present, so switch it on
+ langMenuModel.setActive(modelModulName + "OCL", true);
+ send("on " + modelModulName + "OCL");
+ ocl = (String)linearization.getLinearizations().get(modelModulName + "OCL");
+ }
+ ocl = Utils.compactSpaces(ocl.trim()).trim();
+
+ this.callback.sendConstraint(ocl);
+ } else {
+ logger.info("Metavariables found, saving AST");
+ //Abstract is always present
+ String abs = (String)linearization.getLinearizations().get("Abstract");
+ //then remove duplicate white space
+ abs = removeMetavariableNumbers(abs).replaceAll("\\s+", " ").trim();
+ this.callback.sendAbstract(abs);
+ }
}
} catch (Exception e) { // just print information about the exception
@@ -1910,13 +1663,25 @@ public class GFEditor2 extends JFrame {
}
}
+ /**
+ * In the GF AST, all metavariables have numbers behind them,
+ * like ?4. But GF cannot parse these, so the numbers have to be
+ * removed.
+ * Be aware, that this method also replaces ?n inside String literals!
+ * @param abs The GF AST
+ * @return abs, but without numbers behind the '?'
+ */
+ private static String removeMetavariableNumbers(String abs) {
+ return abs.replaceAll("\\?\\d+", "\\?");
+ }
+
/**
* Shuts down GF and terminates the edior
*/
private void shutDown() {
try {
- send("q", false); // tell external GF process to quit
+ send("q", false, 1); // tell external GF process to quit
} finally {
removeAll();
dispose();
@@ -1924,636 +1689,139 @@ public class GFEditor2 extends JFrame {
}
/**
- * just replace sequences of spaces with one space
- * @param s The string to be compacted
- * @return the compacted result
+ * Performs some global settings like setting treeChanged and newObject,
+ * which can depend on the hmsg.
+ * Also the display gets cleared of wished so.
+ * @param hmsg The parsed hmsg.
*/
- static String compactSpaces(String s) {
- String localResult = new String();
- boolean spaceIncluded = false;
-
- for (int i = 0; i < s.length(); i++) {
- char c = s.charAt(i);
- if (c != ' ') { // include all non-spaces
- localResult += String.valueOf(c);
- spaceIncluded = false;
- } else {// we have a space
- if (!spaceIncluded) {
- localResult += " ";
- spaceIncluded = true;
- } // else just skip
- }
+ private void formHmsg(Hmsg hmsg){
+ if (hmsg.clear) {
+ //clear output before linearization
+ this.display.resetLin();
+ display(true, false, false);
+ linearization.reset();
}
- return localResult;
- }
+ if (hmsg.newObject) {
+ this.newObject = true;
+ }
+ }
/**
- * fills the menu with the possible actions like refinements
- * with the available ones.
- * Parses the GF-output between <menu> and </menu> tags
- * and fills the corrsponding GUI list -"Select Action".
- * seems to expect the starting menu tag to be already read
- * @return A Vector of GfCommand, that contains all commands,
- * already parsed, but not grouped or otherwise treated.
- */
- protected Vector readRefinementMenu (){
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("list model changing! ");
- String s ="";
- Vector printnameVector = new Vector();
- Vector commandVector = new Vector();
- Vector gfCommandVector = new Vector();
- HashSet processedSubcats = new HashSet();
- try {
- //read <menu>
- String readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("7 " + readresult);
- //read item
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("8 " + readresult);
- while (readresult.indexOf("/menu")==-1){
- //read show
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("8 " + readresult);
- while (readresult.indexOf("/show") == -1){
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("9 " + readresult);
- if (readresult.indexOf("/show") == -1) {
- if (readresult.length()>8)
- s += readresult.trim();
- else
- s += readresult;
- }
- }
- // if (s.charAt(0)!='d')
- // listModel.addElement("Refine " + s);
- // else
- String showText = s;
- printnameVector.addElement(s);
- s = "";
- //read /show
- //read send
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("8 " + readresult);
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("8 " + readresult);
- String myCommand = readresult;
- commandVector.add(readresult);
- //read /send (discarded)
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("8 " + readresult);
-
- // read /item
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("8 " + readresult);
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("8 " + readresult);
-
- final boolean isAbstract = "Abstract".equals(this.selectedMenuLanguage);
- RealCommand gfc = new RealCommand(myCommand, processedSubcats, this.printnameManager, showText, isAbstract);
- gfCommandVector.addElement(gfc);
+ * Fills the new category menu and sets the label 'grammar' to
+ * display the name of the abstract grammar.
+ * Fills langMenuModel and registers the presence of the
+ * loaded languages in linearization.linearizations.
+ */
+ private void formNewMenu (NewCategoryMenuResult nmr) {
+ //fill newCategoryMenu
+ for (int i = 0; i < nmr.menuContent.length; i++) {
+ newCategoryMenu.addItem(nmr.menuContent[i]);
+ }
+ //add the languages to the menu
+ for (int i = 0; i < nmr.languages.length; i++) {
+ final boolean active;
+ if (nmr.languages[i].equals("Abstract")) {
+ active = false;
+ } else {
+ active = true;
}
- } catch(IOException e){
- System.err.println(e.getMessage());
- e.printStackTrace();
- }
- return gfCommandVector;
- }
-
- /**
- * Goes through the list of possible refinements and groups them
- * according to their subcategory tag (which starts with %)
- * If there is a "(" afterwards, everything until the before last
- * character in the printname will be used as the display name
- * for this subcategory. If this displayname is defined a second time,
- * it will get overwritten.
- * Sorting is also done here.
- * Adding additional special commands like InputCommand happens here too.
- * @param gfCommandVector contains all RealCommands, that are available
- * at the moment
- */
- protected void formRefinementMenu(Vector gfCommandVector) {
- this.listModel.clear();
- this.refinementSubcatListModel.clear();
- this.gfcommands.clear();
- this.subcatListModelHashtable.clear();
- this.whichSubcat = null;
- this.popup2.removeAll();
- Vector prelListModel = new Vector();
-
- //at the moment, we don't know yet, which subcats are
- //nearly empty
- for (Iterator it = gfCommandVector.iterator(); it.hasNext();) {
- GFCommand gfcommand = (GFCommand)it.next();
- if ((!this.groupSubcat) || (gfcommand.getSubcat() == null)) {
- prelListModel.addElement(gfcommand);
- } else {
- //put stuff in the correct Vector for the refinementSubcatListModel
- Vector lm;
- if (subcatListModelHashtable.containsKey(gfcommand.getSubcat())) {
- lm = (Vector)this.subcatListModelHashtable.get(gfcommand.getSubcat());
- } else {
- lm = new Vector();
- this.subcatListModelHashtable.put(gfcommand.getSubcat(), lm);
- }
- lm.addElement(gfcommand);
- if (gfcommand.isNewSubcat()) {
- GFCommand linkCmd = new LinkCommand(gfcommand.getSubcat(), this.printnameManager);
- prelListModel.addElement(linkCmd);
- }
+ this.langMenuModel.add(nmr.languages[i], active);
+
+ //select FromUMLTypesOCL by default
+ if (nmr.languages[i].equals(modelModulName + "OCL")) {
+ this.selectedMenuLanguage = modelModulName + "OCL";
+ //TODO select OCL also in the menu
}
- }
-
- //so we remove empty subcats now and replace them by their RealCommand
- for (int i = 0; i < prelListModel.size(); i++) {
- if (prelListModel.get(i) instanceof LinkCommand) {
- LinkCommand lc = (LinkCommand) prelListModel.get(i);
- Vector subcatMenu = (Vector)this.subcatListModelHashtable.get(lc.getSubcat());
- if (subcatMenu.size() == 1) {
- RealCommand rc = (RealCommand)subcatMenu.get(0);
- prelListModel.set(i, rc);
- }
+ //'register' the presence of this language if possible
+ if (linearization != null) {
+ linearization.getLinearizations().put(nmr.languages[i], null);
}
}
-
-
- // Some types invite special treatment, like Int and String
- // which can be read from the user.
- if (this.currentNode.isMeta()) {
- if (this.currentNode.getType().equals("Int")) {
- prelListModel.addElement(InputCommand.intInputCommand);
- } if (this.currentNode.getType().equals("String")) {
- prelListModel.addElement(InputCommand.stringInputCommand);
- }
+ //tell the user, which abstract grammar is used
+ //and save the import path
+ grammar.setText(nmr.grammarName);
+ for (int i = 0; i < nmr.paths.length; i++) {
+ fileString +="--" + nmr.paths[i] +"\n";
+ if (nmr.paths[i].lastIndexOf('.')!=nmr.paths[i].indexOf('.'))
+ grammar.setText(nmr.paths[i].substring(0,
+ nmr.paths[i].indexOf('.')).toUpperCase()+" ");
}
- //now sort the preliminary listmodel
- if (sortRefinements) {
- Collections.sort(prelListModel);
- }
- //now fill this.listModel
- for (Iterator it = prelListModel.iterator(); it.hasNext();) {
- Object next = it.next();
- this.listModel.addElement(next);
- }
- //select the first command in the refinement menu, if available
- if (this.listModel.size() > 0) {
- this.refinementList.setSelectedIndex(0);
- } else {
- this.refinementList.setSelectedIndex(-1);
- }
- this.refinementList.setSelectionBackground(refinementSubcatList.getSelectionBackground());
- }
-
- /**
- * Reads the hmsg part of the XML that is put out from GF.
- * Everything in [] given in front of a GF command will be rewritten here.
- * This method does nothing when no hmsg part is present.
- * @param prevreadresult The last line read from GF
- * @return the last line this method has read
- */
- protected String readHmsg(String prevreadresult){
- if ((prevreadresult!=null)&&(prevreadresult.indexOf("<hmsg>") > -1)) {
- StringBuffer s =new StringBuffer("");
- try {
- String readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("7 "+readresult);
- while (readresult.indexOf("/hmsg")==-1){
- s.append(readresult).append('\n');
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("7 "+readresult);
- }
- if (s.indexOf("c") > -1) {
- //clear output before linearization
- this.display = new Display(displayType);
- display(false, false);
- this.htmlOutputVector = new Vector();
- this.textOutputVector = new Vector();
- }
- if (s.indexOf("t") > -1) {
- //tree has changed
- this.treeChanged = true;
- }
- if (s.indexOf("n") > -1) {
- //a new object has been created
- this.newObject = true;
- }
- return readresult;
- } catch(IOException e){
- System.err.println(e.getMessage());
- e.printStackTrace();
- return "";
- }
- } else {
- return prevreadresult;
- }
- }
-
-
- /**
- * reads the linearizations in all language.
- * seems to expect the first line of the XML structure
- * (< lin) already to be read
- * Accumulates the GF-output between <linearization> </linearization> tags
- */
- protected void readLin(){
- try {
- linearization="";
- //read <linearizations>
- String readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("7 " + readresult);
- linearization += readresult + "\n";
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("6 " + readresult);
- while ((readresult != null) && (readresult.indexOf("/linearization") == -1)){
- linearization += readresult + "\n";
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("6 " + readresult);
- }
- } catch(IOException e){
- System.err.println(e.getMessage());
- e.printStackTrace();
- }
}
- /**
- * reads in the tree and calls formTree without start end end tag of tree
- * expects the first starting XML tag tree to be already read
- * @return the read tags for the tree or null if a read error occurs
- */
- protected String readTree(){
- String treeString = "";
- try {
- //read <tree>
- String readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("6 " + readresult);
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("6 " + readresult);
- while (readresult.indexOf("/tree") == -1){
- treeString += readresult + "\n";
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("6 " + readresult);
- }
- return treeString;
- } catch(IOException e){
- System.err.println(e.getMessage());
- e.printStackTrace();
- return null;
- }
- }
- /**
- * Parses the GF-output between <message> </message> tags
- * and returns it.
- * @return The read message.
- */
- protected String readMessage(){
- String s ="";
- try {
- // read <message>
- String readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("6 " + readresult);
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("7 " + readresult);
- while (readresult.indexOf("/message") == -1){
- s += readresult + "\n";
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("7 " + readresult);
- }
- return s;
- } catch(IOException e){
- System.err.println(e.getLocalizedMessage());
- e.printStackTrace();
- return e.getLocalizedMessage();
- }
- }
-
- /**
- * reads the cat entries and puts them into menu, and after that reads
- * the names of the languages and puts them into the language menu
- * Parses the GF-output between <gfinit> tags
- * and fill the New combobox in the GUI.
- * Reading and forming is mixed, since forming is quite primitive.
- */
- protected void formNewMenu () {
- boolean more = true;
- try {
- //read first cat
- String readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) {
- xmlLogger.finer("2 " + readresult);
- }
- if (readresult.indexOf("(none)") > -1) {
- //no topics present
- more = false;
- }
-
- while (more){
- //adds new cat s to the menu
- if (readresult.indexOf("topic") == -1) {
- newCategoryMenu.addItem(readresult.substring(6));
- }
- else
- more = false;
- //read </newcat
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("2 " + readresult);
- //read <newcat (normally)
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("3 " + readresult);
- if (readresult.indexOf("topic") != -1) {
- //no more categories
- more = false;
- }
- //read next cat / topic
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("4 " + readresult);
- }
- //set topic
- grammar.setText(readresult.substring(4)+" ");
- //read </topic>
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("2 " + readresult);
- //read <language>
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("3 " + readresult);
- //read actual language
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("4 " + readresult);
-
- //read the languages and select the last non-abstract
- more = true;
- while (more){
- if ((readresult.indexOf("/gfinit") == -1) && (readresult.indexOf("lin") == -1)) {
- //form lang and Menu menu:
- final String langName = readresult.substring(4);
- final boolean active;
- if (langName.equals("Abstract")) {
- active = false;
- } else {
- active = true;
- }
- this.langMenuModel.add(langName, active);
- //select FromUMLTypesOCL by default
- if (langName.equals(modelModulName + "OCL")) {
- this.selectedMenuLanguage = modelModulName + "OCL";
- }
- //'register' the presence of this language.
- this.linearizations.put(langName, null);
- } else {
- more = false;
- }
- // read </language>
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("2 " + readresult);
- // read <language> or </gfinit...>
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("3 " + readresult);
- if ((readresult.indexOf("/gfinit") != -1) || (readresult.indexOf("lin") != -1))
- more = false;
- if (readresult.indexOf("/gfinit") != -1)
- finished = true;
- // registering the file name:
- if (readresult.indexOf("language") != -1) {
- String path = readresult.substring(readresult.indexOf('=') + 1,
- readresult.indexOf('>'));
- path = path.substring(path.lastIndexOf('/') + 1);
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("name: " + path);
- fileString +="--" + path +"\n";
- if (path.lastIndexOf('.')!=path.indexOf('.'))
- grammar.setText(path.substring(0,
- path.indexOf('.')).toUpperCase()+" ");
- }
- // in case of finished, read the final "" after </gfinit>,
- // otherwise the name of the next language
- readresult = fromProc.readLine();
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("4 " + readresult);
- }
- } catch(IOException e){
- logger.warning(e.getMessage());
- }
- }
- /**
- * Parses the GF-output between &lt;lin&gt; &lt;/lin&gt; tags.
- * Sets the current focusPosition, then changes all &lt;focus&gt; tags
- * into regular &lt;subtree&gt; tags.
- *
- * Then control is given to appendMarked, which does the display
- * @param readLin The text between &lt;lin&gt; &lt;/lin&gt; tags.
- * @param clickable true iff the correspondent display area should be clickable
- * @param doDisplay true iff the linearization should be displayed.
- * @param language the current linearization language
- */
- protected StringBuffer outputAppend(String readLin, boolean clickable, boolean doDisplay, String language){
- final StringBuffer linCollector = new StringBuffer();
- //result=result.replace('\n',' ');
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("INPUT:" + readLin);
- }
- int focusTagBegin = readLin.indexOf("<focus");
- int typeBegin=readLin.indexOf("type=",focusTagBegin);
- int focusTagEnd = readLin.indexOf('>',typeBegin);
- // status incorrect ?:
- final int typeEnd;
- if ((typeBegin > -1) && (readLin.substring(typeBegin,focusTagEnd).indexOf("incorrect")!=-1)) {
- typeEnd = readLin.indexOf("status");
- } else {
- typeEnd = focusTagEnd;
- }
- int focusTextBegin = readLin.indexOf("focus");
- if (focusTagBegin!=-1){
- // in case focus tag is cut into two lines:
- if (focusTagBegin==-1){
- focusTagBegin = focusTextBegin - 7;
- }
- final int positionBegin=readLin.indexOf("position",focusTagBegin);
- final int positionEnd=readLin.indexOf("]",positionBegin);
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("POSITION START: "+positionBegin
- + "\n-> POSITION END: "+positionEnd);
- }
- if (xmlLogger.isLoggable(Level.FINER)) {
- xmlLogger.finer("form Lin1: " + readLin);
- }
- this.focusPosition = new LinPosition(readLin.substring(positionBegin + 9, positionEnd+1),
- readLin.substring(positionBegin, focusTagEnd).indexOf("incorrect") == -1);
- statusLabel.setText(" " + readLin.substring(typeBegin + 5, typeEnd));
- //changing <focus> to <subtree>
- readLin = replaceNotEscaped(readLin, "<focus", "<subtree");
- readLin = replaceNotEscaped(readLin, "</focus", "</subtree");
-
- String appended = appendMarked(readLin + '\n', clickable, doDisplay, language);
- linCollector.append(appended);
- } else {//no focus at all (message?):
- this.focusPosition = null;
-// beware the side-effects! They are, what counts
- linCollector.append(appendMarked(readLin + '\n', clickable, doDisplay, language));
- }
-// if (logger.isLoggable(Level.FINER)) {
-// logger.finer("collected appended linearizations:\n" + linCollector.toString());
-// }
- return linCollector;
- }
-
/**
- * Replaces all occurances of toBeReplaced, that are not escaped by '\'
- * with replacement
- * @param working the String in which substrings should be replaced
- * @param toBeReplaced The substring, that should be replaced by replacement
- * @param replacement well, the replacement string
- * @return The String with the replaced parts
- */
- private static String replaceNotEscaped(String working, String toBeReplaced, String replacement) {
- StringBuffer w = new StringBuffer(working);
- for (int i = w.indexOf(toBeReplaced); i > -1 && i < w.length(); i = w.indexOf(toBeReplaced, i)) {
- if (i == 0 || w.charAt(i - 1) != '\\') {
- w.replace(i, i + toBeReplaced.length(), replacement);
- i += replacement.length();
- } else {
- i += 1;
- }
- }
- return w.toString();
- }
-
-
- /**
* Parses the GF-output between <linearization> </linearization> tags
*
- * pseudo-parses the XML lins and fills the output text area
- * with the lin in all enabled languages.
- *
- * Expects the linearization string to be in this.linearization.
+ * Expects the linearization string to be given to this.linearization.
*/
- protected void formLin(){
+ private void formLin(){
//reset previous output
- this.display = new Display(displayType);
- this.linearizations.clear();
+ this.display.resetLin();
- boolean firstLin=true;
- //read first line like ' <lin lang=Abstract>'
- String readResult = linearization.substring(0,linearization.indexOf('\n'));
- //the rest of the linearizations
- String lin = linearization.substring(linearization.indexOf('\n')+1);
- //extract the language from readResult
- int ind = Utils.indexOfNotEscaped(readResult, "=");
- int ind2 = Utils.indexOfNotEscaped(readResult, ">");
- /** The language of the linearization */
- String language = readResult.substring(ind+1,ind2);
- //the first direct linearization
- readResult = lin.substring(0,lin.indexOf("</lin>"));
- //the rest
- lin = lin.substring(lin.indexOf("</lin>"));
- while (readResult.length()>1) {
- this.langMenuModel.add(language,true);
- // selected?
- boolean visible = this.langMenuModel.isLangActive(language);
- if (visible && !firstLin) {
- // appending sth. linearizationArea
- this.display.addToStages("\n************\n", "<br><hr><br>");
- }
- if (xmlLogger.isLoggable(Level.FINER)) {
- xmlLogger.finer("linearization for the language: "+readResult);
- }
- // we want the side-effects of outputAppend
- final boolean isAbstract = "Abstract".equals(language);
- String linResult = outputAppend(readResult, !isAbstract, visible, language).toString();
- if (visible) {
- firstLin = false;
- }
- linearizations.put(language, linResult);
- // read </lin>
- lin = lin.substring(lin.indexOf('\n')+1);
- // read lin or 'end'
- if (lin.length()<1) {
- break;
- }
-
- readResult = lin.substring(0,lin.indexOf('\n'));
- lin = lin.substring(lin.indexOf('\n')+1);
- if (readResult.indexOf("<lin ")!=-1){
- //extract the language from readResult
- ind = readResult.indexOf('=');
- ind2 = readResult.indexOf('>');
- language = readResult.substring(ind+1,ind2);
- readResult = lin.substring(0,lin.indexOf("</lin>"));
- lin = lin.substring(lin.indexOf("</lin>"));
- }
- }
- display(true, true);
+ linearization.parseLin(langMenuModel);
+ display(true, false, true);
//do highlighting
this.linearizationArea.getHighlighter().removeAllHighlights();
this.htmlLinPane.getHighlighter().removeAllHighlights();
- final HashSet incorrectMA = new HashSet();
- for (int i = 0; i<htmlOutputVector.size(); i++) {
- final HtmlMarkedArea ma = (HtmlMarkedArea)this.htmlOutputVector.elementAt(i);
- //check, if and how ma should be highlighted
- boolean incorrect = false;
- boolean focused = false;
- if (redLogger.isLoggable(Level.FINER)) {
- redLogger.finer("Highlighting: " + ma);
- }
- if (!ma.position.correctPosition) {
- incorrectMA.add(ma);
- incorrect = true;
- } else {
- //This could be quadratic, but normally on very
- //few nodes constraints are introduced, so
- //incorrectMA should not contain many elements.
- HtmlMarkedArea incMA;
- for (Iterator it = incorrectMA.iterator(); !incorrect && it.hasNext();) {
- incMA = (HtmlMarkedArea)it.next();
- if (LinPosition.isSubtreePosition(incMA.position, ma.position)) {
- incorrect = true;
- }
- }
- }
- if (LinPosition.isSubtreePosition(this.focusPosition, ma.position)) {
- focused = true;
- }
+ Vector mahsVector = linearization.calculateHighlights(focusPosition);
+ for (Iterator it = mahsVector.iterator(); it.hasNext();) {
+ MarkedAreaHighlightingStatus mahs = (MarkedAreaHighlightingStatus)it.next();
//now highlight
- if (focused && incorrect) {
- highlight(ma, Color.ORANGE);
- highlightHtml(ma, Color.ORANGE);
- } else if (focused) {
- highlight(ma, linearizationArea.getSelectionColor());
- highlightHtml(ma, linearizationArea.getSelectionColor());
- } else if (incorrect) {
- highlight(ma, Color.RED);
- highlightHtml(ma, Color.RED);
+ if (mahs.focused && mahs.incorrect) {
+ highlight(mahs.ma, Color.ORANGE);
+ highlightHtml(mahs.ma, Color.ORANGE);
+ } else if (mahs.focused) {
+ highlight(mahs.ma, linearizationArea.getSelectionColor());
+ highlightHtml(mahs.ma, linearizationArea.getSelectionColor());
+ } else if (mahs.incorrect) {
+ highlight(mahs.ma, Color.RED);
+ highlightHtml(mahs.ma, Color.RED);
}
}
}
+
+
/**
* Small method that takes this.display and displays its content
* accordingly to what it is (pure text/HTML)
+ * @param doDisplay If the text should get displayed
* @param saveScroll if the old scroll state should be saved
* @param restoreScroll if the old scroll state should be restored
*/
- private void display(boolean saveScroll, boolean restoreScroll) {
+ private void display(boolean doDisplay, boolean saveScroll, boolean restoreScroll) {
//Display the pure text
final String text = this.display.getText();
- this.linearizationArea.setText(text);
+ if (doDisplay) {
+ this.linearizationArea.setText(text);
+ }
if (restoreScroll) {
+ //this.outputPanelText.getVerticalScrollBar().setValue(this.display.scrollText);
this.linearizationArea.scrollRectToVisible(this.display.recText);
}
if (saveScroll) {
+ //this.display.scrollText = this.outputPanelText.getVerticalScrollBar().getValue();
this.display.recText = this.linearizationArea.getVisibleRect();
}
//Display the HTML
final String html = this.display.getHtml(this.font);
- this.htmlLinPane.setText(html);
+ if (doDisplay) {
+ this.htmlLinPane.setText(html);
+ }
if (restoreScroll) {
+ //this.outputPanelHtml.getVerticalScrollBar().setValue(this.display.scrollHtml);
this.htmlLinPane.scrollRectToVisible(this.display.recHtml);
}
if (saveScroll) {
+ //this.display.scrollHtml = this.outputPanelHtml.getVerticalScrollBar().getValue();
this.display.recHtml = this.htmlLinPane.getVisibleRect();
}
}
@@ -2563,7 +1831,7 @@ public class GFEditor2 extends JFrame {
* @param ma the MarkedArea
* @param color the color the highlight should get
*/
- private void highlightHtml(final HtmlMarkedArea ma, Color color) {
+ private void highlightHtml(final MarkedArea ma, Color color) {
try {
int begin = ma.htmlBegin;
int end = ma.htmlEnd;
@@ -2590,7 +1858,7 @@ public class GFEditor2 extends JFrame {
try {
int begin = ma.begin;
int end = ma.end ;
- //When creating the HtmlMarkedArea, we don't know, if
+ //When creating the MarkedArea, we don't know, if
//it is going to be the last or not.
if (end > this.linearizationArea.getText().length()) {
end = this.linearizationArea.getText().length() + 1;
@@ -2609,14 +1877,12 @@ public class GFEditor2 extends JFrame {
* Sets the font on all the GUI-elements to font.
* @param newFont the font everything should have afterwards
*/
- protected void fontEveryWhere(Font newFont) {
+ private void fontEveryWhere(Font newFont) {
linearizationArea.setFont(newFont);
htmlLinPane.setFont(newFont);
parseField.setFont(newFont);
- tree.tree.setFont(newFont);
- refinementList.setFont(newFont);
- refinementSubcatList.setFont(newFont);
- popup2.setFont(newFont);
+ tree.tree.setFont(newFont);
+ refinementMenu.setFont(newFont);
save.setFont(newFont);
grammar.setFont(newFont);
open.setFont(newFont);
@@ -2633,29 +1899,30 @@ public class GFEditor2 extends JFrame {
alpha.setFont(newFont);
random.setFont(newFont);
undo.setFont(newFont);
+ checkSubtyping.setFont(newFont);
filterMenu.setFont(newFont);
- setFontRecursive(filterMenu, newFont, false);
+ setSubmenuFont(filterMenu, newFont, false);
modify.setFont(newFont);
statusLabel.setFont(newFont);
menuBar.setFont(newFont);
newCategoryMenu.setFont(newFont);
readDialog.setFont(newFont);
mlMenu.setFont(newFont);
- setFontRecursive(mlMenu, newFont, false);
+ setSubmenuFont(mlMenu, newFont, false);
modeMenu.setFont(newFont);
- setFontRecursive(modeMenu, newFont, false);
+ setSubmenuFont(modeMenu, newFont, false);
langMenu.setFont(newFont);
- setFontRecursive(langMenu, newFont, false);
+ setSubmenuFont(langMenu, newFont, false);
fileMenu.setFont(newFont);
- setFontRecursive(fileMenu, newFont, false);
+ setSubmenuFont(fileMenu, newFont, false);
usabilityMenu.setFont(newFont);
- setFontRecursive(usabilityMenu, newFont, false);
+ setSubmenuFont(usabilityMenu, newFont, false);
viewMenu.setFont(newFont);
- setFontRecursive(viewMenu, newFont, false);
- setFontRecursive(sizeMenu, newFont, false);
- setFontRecursive(fontMenu, newFont, true);
+ setSubmenuFont(viewMenu, newFont, false);
+ setSubmenuFont(sizeMenu, newFont, false);
+ setSubmenuFont(fontMenu, newFont, true);
//update also the HTML with the new size
- display(false, true);
+ display(true, false, true);
}
/**
@@ -2666,8 +1933,7 @@ public class GFEditor2 extends JFrame {
* @param onlySize If only the font size or the whole font should
* be changed
*/
- private void setFontRecursive(JMenu subMenu, Font font, boolean onlySize)
- {
+ private void setSubmenuFont(JMenu subMenu, Font font, boolean onlySize) {
for (int i = 0; i<subMenu.getItemCount(); i++)
{
JMenuItem item = subMenu.getItem(i);
@@ -2704,44 +1970,33 @@ public class GFEditor2 extends JFrame {
}
/**
- * Remove all nodes in the tree and
- * form a dummy tree in treePanel
- * @param myTreePanel the aforementioned treePanel
- */
- protected void resetTree(DynamicTree2 myTreePanel) {
- tree.clear();
- String p1Name = new String("Root");
- myTreePanel.addObject(null, p1Name);
- }
-
- /**
* Parses the GF-output between <tree> </tree> tags
* and build the corresponding tree.
*
* parses the already read XML for the tree and stores the tree nodes
* in nodeTable with their numbers as keys
- * @param myTreePanel the panel of GFEditor2
+ *
+ * Also does some tree analyzing, if other actions have to be taken.
+ *
* @param treeString the string representation for the XML tree
+ * @return null, if no commands have to be executed afterwards.
+ * If the result is non-null, then result.s should be sent to GF
+ * afterwards, and no other form-method on this read-run is to be executed.
+ * result.i is the amount of undo steps that this command needs.
*/
- protected void formTree(DynamicTree2 myTreePanel, String treeString) {
+ private DefaultMutableTreeNode formTree(String treeString) {
if (treeLogger.isLoggable(Level.FINER)) {
treeLogger.finer("treeString: "+ treeString);
}
-
+
/**
* stores the nodes and the indention of their children.
- * Works stack like, so when all children of a node are read,
+ * When all children of a node are read,
* the next brethren / uncle node 'registers' with the same
* indention depth to show that the next children are his.
*/
Hashtable parentNodes = new Hashtable();
- /**
- * the path in the JTree (not in GF repesentation!) to the
- * current new node.
- */
- TreePath path=null;
String s = treeString;
- myTreePanel.clear();
/** consecutive node numbering */
int index = 0;
/** the node that gets created from the current line */
@@ -2751,6 +2006,7 @@ public class GFEditor2 extends JFrame {
if (s.indexOf('*')!=-1) {
star = 1;
}
+ DefaultMutableTreeNode topNode = null;
while (s.length()>0) {
/**
* every two ' ' indicate one tree depth level
@@ -2767,34 +2023,33 @@ public class GFEditor2 extends JFrame {
shift++;
}
if (s.length()>0) {
-
+ /** to save the top node*/
+ boolean isTop = false;
int j = s.indexOf("\n");
//is sth like "andS : Sent ", i.e. "fun : type " before trimming
String gfline = s.substring(0, j).trim();
GfAstNode node = new GfAstNode(gfline);
- if (selected) {
- this.currentNode = node;
- }
// use indentation to calculate the parent
index++;
s = s.substring(j+1);
shift = (shift - star)/2;
- /*
+ /**
* we know the parent, so we can ask it for the param information
* for the next child (the parent knows how many it has already)
* and save it in an AstNodeData
*/
DefaultMutableTreeNode parent = (DefaultMutableTreeNode)parentNodes.get(new Integer(shift));
- // compute the now childs position
+ /** compute the now child's position */
String newPos;
if ((parent != null) && (parent.getUserObject() instanceof AstNodeData) && parent.getUserObject() != null) {
AstNodeData pand = (AstNodeData)parent.getUserObject();
- newPos = LinPosition.calculateChildPosition(pand.getPosition(), pand.childNum++);
+ newPos = LinPosition.calculateChildPosition(pand.position, pand.childNum++);
} else {
//only the case for the root node
newPos = "[]";
+ isTop = true;
}
//default case, if we can get more information, this is overwritten
@@ -2804,12 +2059,19 @@ public class GFEditor2 extends JFrame {
childPrintname = this.printnameManager.getPrintname(node.getFun());
}
Printname parentPrintname = null;
+ AstNodeData parentAnd = null;
+ String parentConstraint = "";
+ if (parent != null) {
+ parentAnd = (AstNodeData)parent.getUserObject();
+ if (parentAnd != null) {
+ parentConstraint = parentAnd.constraint;
+ }
+ }
if (childPrintname != null) {
//we know this one
- and = new RefinedAstNodeData(childPrintname, node, newPos);
+ and = new RefinedAstNodeData(childPrintname, node, newPos, selected, parentConstraint);
} else if (parent != null && node.isMeta()) {
//new child without refinement
- AstNodeData parentAnd = (AstNodeData)parent.getUserObject();
if (parentAnd != null) {
parentPrintname = parentAnd.getPrintname();
}
@@ -2824,37 +2086,89 @@ public class GFEditor2 extends JFrame {
// if (logger.isLoggable(Level.FINER)) {
// logger.finer("new node-parsing: '" + name + "', fun: '" + fun + "', type: '" + paramType + "'");
// }
- and = new UnrefinedAstNodeData(paramTooltip, node, newPos);
+ and = new UnrefinedAstNodeData(paramTooltip, node, newPos, selected, parentConstraint);
} else {
- and = new RefinedAstNodeData(null, node, newPos);
+ and = new RefinedAstNodeData(null, node, newPos, selected, parentConstraint);
}
} else {
//something unparsable, bad luck
//or refined and not described
- and = new RefinedAstNodeData(null, node, newPos);
+ and = new RefinedAstNodeData(null, node, newPos, selected, parentConstraint);
}
- newChildNode = myTreePanel.addObject(parent, and);
+ //add to the parent node
+ newChildNode = new DefaultMutableTreeNode(and);
+ if ((parent != null) && (newChildNode != null)) {
+ parent.add(newChildNode);
+ }
parentNodes.put(new Integer(shift+1), newChildNode);
- path = new TreePath(newChildNode.getPath());
- nodeTable.put(path, newPos);
-
- if (selected) {
- //show the selected as the 'selected' one in the JTree
- myTreePanel.tree.setSelectionPath(path);
- myTreePanel.oldSelection = index;
- if (treeLogger.isLoggable(Level.FINER)) {
- treeLogger.finer("new selected index "+ index);
+ if (isTop) {
+ topNode = newChildNode;
+ }
+ }
+ }
+ //to be deferred to later step in readGfEdit
+ return topNode;
+ }
+
+ /**
+ * Shows the tree, scrolls to the selected node and updates the
+ * mapping table between displayed node paths and AST positions.
+ * @param myTreePanel the panel of GFEditor2
+ * @param topNode The root node of the tree, that has the other nodes
+ * already as its children
+ */
+ private void showTree(DynamicTree2 myTreePanel, DefaultMutableTreeNode topNode) {
+ myTreePanel.clear();
+ nodeTable.clear();
+ //the rootNode is not shown, therefore, a dummy node plays this role
+ final DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode();
+ rootNode.add(topNode);
+ ((DefaultTreeModel)(myTreePanel.tree.getModel())).setRoot(rootNode);
+ /**
+ * the path in the JTree (not in GF repesentation!) to the
+ * current new node.
+ */
+ TreePath path=null;
+ TreePath selectionPath = null;
+ // now fill nodeTable
+ for (Enumeration e = rootNode.breadthFirstEnumeration() ; e.hasMoreElements() ;) {
+ DefaultMutableTreeNode currNode = (DefaultMutableTreeNode)e.nextElement();
+ AstNodeData and = (AstNodeData)currNode.getUserObject();
+
+ path = new TreePath(currNode.getPath());
+ if (and == null) {
+ //only the case for the root node
+ nodeTable.put(path, "[]");
+ } else {
+ nodeTable.put(path, and.position);
+ if (and.selected) {
+ selectionPath = path;
+ if (treeLogger.isLoggable(Level.FINE)) {
+ treeLogger.fine("new selectionPath: " + selectionPath);
}
+ DefaultMutableTreeNode parent = null;
+ if (currNode.getParent() instanceof DefaultMutableTreeNode) {
+ parent = (DefaultMutableTreeNode)currNode.getParent();
+ }
+ Printname parentPrintname = null;
+ //display the current refinement description
+ if ((parent != null)
+ && (parent.getUserObject() != null)
+ && (parent.getUserObject() instanceof AstNodeData)
+ ) {
+ AstNodeData parentAnd = (AstNodeData)parent.getUserObject();
+ parentPrintname = parentAnd.getPrintname();
+ }
// set the description of the current parameter to a more
// prominent place
String paramName = null;
int paramPosition = -1;
if (parentPrintname != null) {
- paramPosition = parent.getChildCount() - 1;
- paramName = parentPrintname.getParamName(paramPosition);
+ paramPosition = parent.getIndex(currNode);
+ paramName = parentPrintname.getParamName(paramPosition);
}
if (paramName == null) {
subtermNameLabel.setText(actionOnSubtermString);
@@ -2868,352 +2182,39 @@ public class GFEditor2 extends JFrame {
subtermDescLabel.setText("<html>" + paramDesc + "</html>");
}
}
+ statusLabel.setText(and.node.getType());
}
}
}
- if ((newChildNode!=null)) {
- myTreePanel.tree.makeVisible(path);
- gui2.toFront();
- index = 0;
- }
- treeChanged = false;
+ //also set the old selectionPath since we know that we do know,
+ //that the selectionChanged event is bogus.
+ myTreePanel.oldSelection = selectionPath;
+ myTreePanel.tree.setSelectionPath(selectionPath);
+ myTreePanel.tree.scrollPathToVisible(selectionPath);
+ //show the selected as the 'selected' one in the JTree
+ myTreePanel.tree.makeVisible(selectionPath);
+ gui2.toFront();
}
- /**
- * Returns the widest position (see comments to comparePositions)
- * covered in the string from begin to end in the
- * linearization area.
- * @param begin The index in htmlOutputVector of the first MarkedArea, that is possibly the max
- * @param end The index in htmlOutputVector of the last MarkedArea, that is possibly the max
- * @return the position in GF Haskell notation (hdaniels guesses)
- */
- private String findMax(int begin, int end) {
- String max = (((MarkedArea)this.htmlOutputVector.elementAt(begin)).position).position;
- for (int i = begin+1; i <= end; i++)
- max = LinPosition.maxPosition(max,(((MarkedArea)this.htmlOutputVector.elementAt(i)).position).position);
- return max;
- }
/**
- * Appends the string s to the text in the linearization area
- * on the screen. It parses the subtree tags and registers them.
- * The focus tag is expected to be replaced by subtree.
- * @param restString string to append, with tags in it.
- * @param clickable if true, the text is appended and the subtree tags are
- * parsed. If false, the text is appended, but the subtree tags are ignored.
- * @param doDisplay true iff the output is to be displayed.
- * Implies, if false, that clickable is treated as false.
- * @param language the current linearization language
+ * Removes anything but the "new" from the new category menu
*/
- protected String appendMarked(String restString, final boolean clickable, boolean doDisplay, String language) {
- String appendedPureText = "";
- if (restString.length()>0) {
- /**
- * the length of what is already displayed of the linearization.
- * Alternatively: What has been processed in restString since
- * subtreeBegin
- */
- int currentLength = 0;
- /** position of &lt;subtree */
- int subtreeBegin;
- /** position of &lt;/subtree */
- int subtreeEnd;
-
- if (clickable && doDisplay) {
- subtreeBegin = Utils.indexOfNotEscaped(restString, "<subtree");
- subtreeEnd = Utils.indexOfNotEscaped(restString, "</subtree");
- // cutting subtree-tags:
- while ((subtreeEnd>-1)||(subtreeBegin>-1)) {
- /**
- * length of the portion that is to be displayed
- * in the current run of appendMarked.
- * For HTML this would have to be calculated
- * in another way.
- */
- final int newLength;
-
- if ((subtreeEnd==-1)||((subtreeBegin<subtreeEnd)&&(subtreeBegin>-1))) {
- final int subtreeTagEnd = Utils.indexOfNotEscaped(restString, ">",subtreeBegin);
- final int nextOpeningTagBegin = Utils.indexOfNotEscaped(restString, "<", subtreeTagEnd);
-
- //getting position:
- final int posStringBegin = Utils.indexOfNotEscaped(restString, "[",subtreeBegin);
- final int posStringEnd = Utils.indexOfNotEscaped(restString, "]",subtreeBegin);
- final LinPosition position = new LinPosition(restString.substring(posStringBegin,posStringEnd+1),
- restString.substring(subtreeBegin,subtreeTagEnd).indexOf("incorrect")==-1);
-
- // is something before the tag?
- // is the case in the first run
- if (subtreeBegin-currentLength>1) {
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("SOMETHING BEFORE THE TAG");
- }
- if (this.currentPosition.size()>0)
- newLength = register(currentLength, subtreeBegin, (LinPosition)this.currentPosition.elementAt(this.currentPosition.size()-1), restString, language);
- else
- newLength = register(currentLength, subtreeBegin, new LinPosition("[]",
- restString.substring(subtreeBegin,subtreeTagEnd).indexOf("incorrect")==-1), restString, language);
- } else { // nothing before the tag:
- //the case in the beginning
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("NOTHING BEFORE THE TAG");
- }
- if (nextOpeningTagBegin>0) {
- newLength = register(subtreeTagEnd+2, nextOpeningTagBegin, position, restString, language);
- } else {
- newLength = register(subtreeTagEnd+2, restString.length(), position, restString, language);
- }
- restString = removeSubTreeTag(restString,subtreeBegin, subtreeTagEnd+1);
- }
- currentLength += newLength ;
- } else {// l<l2
- // something before the </subtree> tag:
- if (subtreeEnd-currentLength>1) {
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("SOMETHING BEFORE THE </subtree> TAG");
- }
- if (this.currentPosition.size()>0)
- newLength = register(currentLength, subtreeEnd, (LinPosition)this.currentPosition.elementAt(this.currentPosition.size()-1), restString, language);
- else
- newLength = register(currentLength, subtreeEnd, new LinPosition("[]",
- restString.substring(subtreeBegin,subtreeEnd).indexOf("incorrect")==-1), restString, language);
- currentLength += newLength ;
- }
- // nothing before the tag:
- else
- // punctuation after the </subtree> tag:
- if (restString.substring(subtreeEnd+10,subtreeEnd+11).trim().length()>0)
- {
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("PUNCTUATION AFTER THE </subtree> TAG"
- + "/n" + "STRING: " + restString);
- }
- //cutting the tag first!:
- if (subtreeEnd>0) {
- restString = removeSubTreeTag(restString,subtreeEnd-1, subtreeEnd+9);
- } else {
- restString = removeSubTreeTag(restString,subtreeEnd, subtreeEnd+9);
- }
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("STRING after cutting the </subtree> tag: "+restString);
- }
- // cutting the space in the last registered component:
- if (this.htmlOutputVector.size()>0) {
- ((MarkedArea)this.htmlOutputVector.elementAt(this.htmlOutputVector.size()-1)).end -=1;
- if (currentLength>0) {
- currentLength -=1;
- }
- }
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("currentLength: " + currentLength);
- }
- // register the punctuation:
- if (this.currentPosition.size()>0) {
- newLength = register(currentLength, currentLength+2, (LinPosition)this.currentPosition.elementAt(this.currentPosition.size()-1), restString, language);
- } else {
- newLength = register(currentLength, currentLength+2, new LinPosition("[]",
- true), restString, language);
- }
- currentLength += newLength ;
- } else {
- // just cutting the </subtree> tag:
- restString = removeSubTreeTag(restString,subtreeEnd, subtreeEnd+10);
- }
- }
- subtreeEnd = Utils.indexOfNotEscaped(restString, "</subtree");
- subtreeBegin = Utils.indexOfNotEscaped(restString, "<subtree");
- // if (debug2)
- // System.out.println("/subtree index: "+l2 + "<subtree"+l);
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("<-POSITION: "+subtreeBegin+" CURRLENGTH: "+currentLength
- + "\n STRING: "+restString.substring(currentLength));
- }
- } //while
- } else { //no focus, no selection enabled (why ever)
- //that means, that all subtree tags are removed here.
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("NO SELECTION IN THE TEXT TO BE APPENDED!");
- }
- //cutting tags from previous focuses if any:
- int r = Utils.indexOfNotEscaped(restString, "</subtree>");
- while (r>-1) {
- // check if punktualtion marks like . ! ? are at the end of a sentence:
- if (restString.charAt(r+10)==' ')
- restString = restString.substring(0,r)+restString.substring(r+11);
- else
- restString = restString.substring(0,r)+restString.substring(r+10);
- r = Utils.indexOfNotEscaped(restString, "</subtree>");
- }
- r = Utils.indexOfNotEscaped(restString, "<subtree");
- while (r>-1) {
- int t = Utils.indexOfNotEscaped(restString, ">", r);
- if (t<restString.length()-2)
- restString = restString.substring(0,r)+restString.substring(t+2);
- else
- restString = restString.substring(0,r);
- r = Utils.indexOfNotEscaped(restString, "<subtree");
- }
- }
- // appending:
- restString = unescapeTextFromGF(restString);
- if (redLogger.isLoggable(Level.FINER)) {
- redLogger.finer(restString);
- }
- appendedPureText = restString.replaceAll("&-","\n ");
- //display the text if not already done in case of clickable
- if (!clickable && doDisplay) {
- // the text has only been pruned from markup, but still needs
- // to be displayed
- this.display.addToStages(appendedPureText, appendedPureText);
- }
- } // else: nothing to append
- return appendedPureText;
- }
-
- /**
- * Replaces a number of escaped characters by an unescaped version
- * of the same length
- * @param string The String with '\' as the escape character
- * @return the same String, but with escaped characters removed
- *
- */
- static String unescapeTextFromGF(String string) {
- final String more = "\\"+">";
- final String less = "\\"+"<";
- //%% by daniels, linearization output will be changed drastically
- //(or probably will), so for now some hacks for -> and >=
- string = Utils.replaceAll(string, "-" + more, "-> ");
- string = Utils.replaceAll(string, "-" + more,"-> ");
- string = Utils.replaceAll(string, more," >");
- string = Utils.replaceAll(string, less," <");
- //an escaped \ becomes a single \
- string = Utils.replaceAll(string, "\\\\"," \\");
- return string;
+ private void resetNewCategoryMenu() {
+ //remove everything except "New"
+ while (1< newCategoryMenu.getItemCount())
+ newCategoryMenu.removeItemAt(1);
}
-
-
- /**
- * The substring from start to end in workingString, together with
- * position is saved as a MarkedArea in this.htmlOutputVector.
- * The information from where to where the to be created MarkedArea
- * extends, is calculated in this method.
- * @param start The position of the first character in workingString
- * of the part, that is to be registered.
- * @param end The position of the last character in workingString
- * of the part, that is to be registered.
- * @param position the position in the tree that corresponds to
- * the to be registered text
- * @param workingString the String from which the displayed
- * characters are taken from
- * @param language the current linearization language
- * @return newLength, the difference between end and start
- */
- private int register(int start, int end, LinPosition position, String workingString, String language) {
- /**
- * the length of the piece of text that is to be appended now
- */
- final int newLength = end-start;
- // the tag has some words to register:
- if (newLength>0) {
- final String stringToAppend = workingString.substring(start,end);
- //if (stringToAppend.trim().length()>0) {
-
- //get oldLength and add the new text
- String toAdd = unescapeTextFromGF(stringToAppend);
- final HtmlMarkedArea hma = this.display.addAsMarked(toAdd, position, language);
- this.htmlOutputVector.add(hma);
- if (htmlLogger.isLoggable(Level.FINER)) {
- htmlLogger.finer("HTML added : " + hma);
- } //} else if (linMarkingLogger.isLoggable(Level.FINER)) {
- // linMarkingLogger.finer("whiteSpaces: " + newLength);
- //}
- } //some words to register
- return newLength;
- }
-
- /**
- * removing subtree-tag in the interval start-end
- * and updating the coordinates after that
- * basically part of appendMarked
- * No subtree is removed, just the tag.
- * @param s The String in which the subtree tag should be removed
- * @param start position in restString
- * @param end position in restString
- * @return the String without the subtree-tags in the given interval
- */
- private String removeSubTreeTag (final String s, final int start, final int end) {
- String restString = s;
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("removing: "+ start +" to "+ end);
- }
- int difference =end-start+1;
- int positionStart, positionEnd;
- if (difference>20) {
- positionStart = Utils.indexOfNotEscaped(restString, "[", start);
- positionEnd = Utils.indexOfNotEscaped(restString, "]", start);
-
- currentPosition.addElement(new LinPosition(
- restString.substring(positionStart, positionEnd+1),
- restString.substring(start,end).indexOf("incorrect")==-1));
- } else if (currentPosition.size()>0) {
- currentPosition.removeElementAt(currentPosition.size()-1);
- }
- if (start>0) {
- restString = restString.substring(0,start)+restString.substring(end+1);
- } else{
- restString = restString.substring(end+1);
- }
- return restString;
- }
-
- /**
- * handling the event of choosing the action at index from the list.
- * That is either giving commands to GF or displaying the subcat menus
- * @param list The list that generated this action
- * @param index the index of the selected element in list
- * @param doubleClick true iff a command should be sent to GF,
- * false if only a new subcat menu should be opened.
- */
- protected void listAction(JList list, int index, boolean doubleClick) {
- if (index == -1) {
- if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("no selection");
- } else {
- GFCommand command;
- if (list == refinementList) {
- command = (GFCommand)listModel.elementAt(index);
- } else {
- Vector cmdvector = (Vector)this.subcatListModelHashtable.get(this.whichSubcat);
- command = (GFCommand)(cmdvector.get(index));
- }
- if (command instanceof LinkCommand) {
- this.whichSubcat = command.getSubcat();
- refinementSubcatListModel.clear();
- Vector currentCommands = (Vector)this.subcatListModelHashtable.get(this.whichSubcat);
- for (Iterator it = currentCommands.iterator(); it.hasNext();) {
- this.refinementSubcatListModel.addElement(it.next());
- }
- } else if (doubleClick && command instanceof InputCommand) {
- InputCommand ic = (InputCommand)command;
- executeInputCommand(ic);
-
- } else if (doubleClick){
- refinementSubcatListModel.clear();
- treeChanged = true;
- send(command.getCommand());
- } else if (list == refinementList){
- refinementSubcatListModel.clear();
- }
- }
- }
/**
* Pops up a window for input of the wanted data and asks ic
* afterwards, if the data has the right format.
- * Then gives that to GF
+ * Then gives that to GF.
+ * TODO Is called from RefinementMenu, but uses display. Where to put?
* @param ic the InputCommand that specifies the wanted format/type
*/
- private void executeInputCommand(InputCommand ic) {
+ protected void executeInputCommand(InputCommand ic) {
String s = (String)JOptionPane.showInputDialog(
this,
ic.getTitleText(),
@@ -3225,107 +2226,17 @@ public class GFEditor2 extends JFrame {
StringBuffer reason = new StringBuffer();
Object value = ic.validate(s, reason);
if (value != null) {
- treeChanged = true;
- send("g "+value);
+ send("[t] g "+value);
if (logger.isLoggable(Level.FINER)) {
logger.finer("sending string " + value);
}
} else {
this.display.addToStages("\n" + reason.toString(), "<p>" + reason.toString() + "</p>");
- display(false, false);
+ display(true, false, false);
}
}
- /**
- * Produces the popup menu that represents the current refinements.
- * An alternative to the refinement list.
- * @return s.a.
- */
- JPopupMenu producePopup() {
- if (popup2.getComponentCount() > 0) {
- return popup2;
- }
- for (int i = 0; i < this.listModel.size(); i++) {
- GFCommand gfcmd = (GFCommand)this.listModel.get(i);
- if (gfcmd instanceof LinkCommand) {
- LinkCommand lc = (LinkCommand)gfcmd;
- Vector subcatMenu = (Vector)this.subcatListModelHashtable.get(lc.getSubcat());
- JMenu tempMenu = new JMenu(lc.getDisplayText());
- tempMenu.setToolTipText(lc.getTooltipText());
- tempMenu.setFont(font);
- JMenuItem tempMenuItem;
- for (Iterator it = subcatMenu.iterator(); it.hasNext();) {
- GFCommand subgfcmd = (GFCommand)it.next();
- tempMenuItem = menuForCommand(subgfcmd);
- if (tempMenuItem != null) {
- tempMenu.add(tempMenuItem);
- }
- }
- popup2.add(tempMenu);
- } else {
- JMenuItem tempMenu = menuForCommand(gfcmd);
- if (tempMenu != null) {
- popup2.add(tempMenu);
- }
- }
- }
- return popup2;
- }
-
- /**
- * takes a GFCommand and "transforms" it in a JMenuItem.
- * These JMenuItems have their own listeners that take care of
- * doing what is right ...
- * @param gfcmd a RealCommand or an InputCommand
- * (LinkCommand is ignored and produces null as the result)
- * @return either the correspondend JMenuItem or null.
- */
- private JMenuItem menuForCommand(GFCommand gfcmd) {
- JMenuItem tempMenu = null;
- if (gfcmd instanceof RealCommand){
- tempMenu = new JMenuItem(gfcmd.getDisplayText());
- tempMenu.setFont(font);
- tempMenu.setActionCommand(gfcmd.getCommand());
- tempMenu.setToolTipText(gfcmd.getTooltipText());
- tempMenu.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent ae) {
- JMenuItem mi = (JMenuItem)ae.getSource();
- refinementSubcatListModel.clear();
- treeChanged = true;
- String command = mi.getActionCommand();
- send(command);
- }
- });
- } else if (gfcmd instanceof InputCommand) {
- tempMenu = new JMenuItem(gfcmd.getDisplayText());
- tempMenu.setFont(font);
- tempMenu.setActionCommand(gfcmd.getCommand());
- tempMenu.setToolTipText(gfcmd.getTooltipText());
- tempMenu.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent ae) {
- JMenuItem mi = (JMenuItem)ae.getSource();
- String command = mi.getActionCommand();
- InputCommand ic = InputCommand.forTypeName(command);
- if (ic != null) {
- executeInputCommand(ic);
- }
- }
- });
-
- }
- return tempMenu;
- }
-
-
- /**
- *
- */
- private void resetNewCategoryMenu() {
- //remove everything except "New"
- while (1< newCategoryMenu.getItemCount())
- newCategoryMenu.removeItemAt(1);
- }
/**
* Handles the showing of the popup menu and the parse field
@@ -3338,7 +2249,7 @@ public class GFEditor2 extends JFrame {
if (popUpLogger.isLoggable(Level.FINER)) {
popUpLogger.finer("changing pop-up menu2!");
}
- popup2 = producePopup();
+ JPopupMenu popup2 = refinementMenu.producePopup();
popup2.show(e.getComponent(), e.getX(), e.getY());
}
// middle click
@@ -3358,41 +2269,12 @@ public class GFEditor2 extends JFrame {
if (e.getComponent() instanceof JTextComponent) {
JTextComponent jtc = (JTextComponent)e.getComponent();
int pos = jtc.viewToModel(e.getPoint());
- MarkedArea ma = null;
- if (jtc instanceof JTextPane) {
- //HTML
- for (int i = 0; i < htmlOutputVector.size(); i++) {
- if ((pos >= ((HtmlMarkedArea)htmlOutputVector.get(i)).htmlBegin) && (pos <= ((HtmlMarkedArea)htmlOutputVector.get(i)).htmlEnd)) {
- ma = (HtmlMarkedArea)htmlOutputVector.get(i);
- break;
- }
- }
- } else {
- //assumably pure text
- for (int i = 0; i < htmlOutputVector.size(); i++) {
- if ((pos >= ((MarkedArea)htmlOutputVector.get(i)).begin) && (pos <= ((MarkedArea)htmlOutputVector.get(i)).end)) {
- ma = (MarkedArea)htmlOutputVector.get(i);
- break;
- }
- }
-
- }
- if (ma != null && ma.language != null) {
- language = ma.language;
- } else {
- language = "Abstract";
- }
+ final boolean htmlClicked = (jtc instanceof JTextPane);
+ language = linearization.getLanguageForPos(pos, htmlClicked);
} else {
language = "Abstract";
}
- StringBuffer sel = new StringBuffer();
- for (int i = 0; i<htmlOutputVector.size(); i++) {
- final HtmlMarkedArea ma = (HtmlMarkedArea)htmlOutputVector.elementAt(i);
- if (language.equals(ma.language) && LinPosition.isSubtreePosition(focusPosition, ma.position)) {
- sel.append(ma.words);
- }
- }
- selectedText = sel.toString();
+ selectedText = linearization.getSelectedLinearization(language, focusPosition);
}
//compute the size of parseField
@@ -3411,158 +2293,22 @@ public class GFEditor2 extends JFrame {
parseField.requestFocusInWindow();
}
}
-
- /**
- * gets the LinPosition according to the given start and end of
- * the selection in comp.
- * Is meant as a unified replacement of large parts of caretUpdate
- * @param start start of the selection in comp
- * @param end end of the selection in comp
- * @param comp either a JTextArea or a JTextPane
- * @return s.a.
- */
- String getLinPosition(int start, int end, JTextComponent comp) {
- final int maType;
- if (comp instanceof JTextPane) {
- //if a JTextPane is given, calculate for HTML
- maType = 1;
- } else {
- maType = 0;
- }
- String jPosition ="", iPosition="", position="", resultPosition = null;
- MarkedArea jElement = null;
- MarkedArea iElement = null;
- int j = 0;
- int i = htmlOutputVector.size() - 1;
- if (popUpLogger.isLoggable(Level.FINER)) {
- popUpLogger.finer("CARET POSITION: "+comp.getCaretPosition()
- + "\n-> SELECTION START POSITION: "+start
- + "\n-> SELECTION END POSITION: "+end);
- }
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- if (end > 0 && (end < comp.getDocument().getLength())) {
- try {
- linMarkingLogger.finer("CHAR: "+comp.getDocument().getText(end, 1));
- } catch (BadLocationException ble) {
- linMarkingLogger.fine(ble.getLocalizedMessage());
- ble.printStackTrace();
- }
- }
- }
- // not null selection:
- if ((i>-1)&&(start<comp.getDocument().getLength()-1)) {
- if (linMarkingLogger.isLoggable(Level.FINER))
- for (int k = 0; k < htmlOutputVector.size(); k++) {
- MarkedArea kma = normalizeMarkedArea((MarkedArea)htmlOutputVector.elementAt(k), maType);
- linMarkingLogger.finer("element: " + k + " begin " + kma.begin + " "
- + "\n-> end: " + kma.end+" "
- + "\n-> position: " + (kma.position).position+" "
- + "\n-> words: " + kma.words);
- }
- // localizing end:
- while ((j < htmlOutputVector.size()) && (normalizeMarkedArea((MarkedArea)htmlOutputVector.elementAt(j), maType).end < end)) {
- j++;
- }
- // localising start:
- while ((i >= 0) && (normalizeMarkedArea((MarkedArea)htmlOutputVector.elementAt(i), maType).begin > start))
- i--;
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("i: " + i + " j: " + j);
- }
- if ((j < htmlOutputVector.size())) {
- jElement = normalizeMarkedArea((MarkedArea)htmlOutputVector.elementAt(j), maType);
- jPosition = jElement.position.position;
- // less & before:
- if (i == -1) { // less:
- if (end >= jElement.begin) {
- iElement = normalizeMarkedArea((MarkedArea)htmlOutputVector.elementAt(0), maType);
- iPosition = iElement.position.position;
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("Less: "+jPosition+" and "+iPosition);
- }
- position = findMax(0,j);
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("SELECTEDTEXT: "+position+"\n");
- }
- treeChanged = true;
- resultPosition = position;
- } else if (linMarkingLogger.isLoggable(Level.FINER)) { // before:
- linMarkingLogger.finer("BEFORE vector of size: " + htmlOutputVector.size());
- }
- } else { // just:
- iElement = normalizeMarkedArea((MarkedArea)htmlOutputVector.elementAt(i), maType);
- iPosition = iElement.position.position;
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("SELECTED TEXT Just: "+iPosition +" and "+jPosition+"\n");
- }
- position = findMax(i,j);
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("SELECTEDTEXT: "+position+"\n");
- }
- treeChanged = true;
- resultPosition = position;
- }
- } else if (i>=0) { // more && after:
- iElement = normalizeMarkedArea((MarkedArea)htmlOutputVector.elementAt(i), maType);
- iPosition = iElement.position.position;
- // more
- if (start<=iElement.end) {
- jElement = normalizeMarkedArea((MarkedArea)htmlOutputVector.elementAt(htmlOutputVector.size() - 1), maType);
- jPosition = jElement.position.position;
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("MORE: "+iPosition+ " and "+jPosition);
- }
- position = findMax(i, htmlOutputVector.size()-1);
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("SELECTEDTEXT: "+position+"\n");
- }
- treeChanged = true;
- resultPosition = position;
- } else if (linMarkingLogger.isLoggable(Level.FINER)) { // after:
- linMarkingLogger.finer("AFTER vector of size: " + htmlOutputVector.size());
- }
- } else {
- // bigger:
- iElement = normalizeMarkedArea((MarkedArea)htmlOutputVector.elementAt(0), maType);
- iPosition = iElement.position.position;
- jElement = normalizeMarkedArea((MarkedArea)htmlOutputVector.elementAt(htmlOutputVector.size() - 1), maType);
- jPosition = jElement.position.position;
- if (linMarkingLogger.isLoggable(Level.FINER)) {
- linMarkingLogger.finer("BIGGER: "+iPosition +" and "+jPosition+"\n"
- + "\n-> SELECTEDTEXT: []\n");
- }
- treeChanged = true;
- resultPosition = "[]";
- }
- }//not null selection
- return resultPosition;
- }
/**
- * Takes a MarkedArea and transforms it into a MarkedArea,
- * that has begin and and set as the valid fields.
- * If a HtmlMarkedArea is given and type == 1, then the htmlBegin
- * and htmlEnd fields are used as begin and end.
- * For type == 0, the normal begin and end fields are used.
- * @param ma The MarkedArea to 'normalize'
- * @param type 0 for pure text, 1 for HTML. begin and end will be -1 for other values.
- * @return a MarkedArea as described above
+ * Adds toHmsg to the [hmsg] part of command, if that is present.
+ * If not, prepends toHmsg in square brackets to command
+ * @param command The command for GF
+ * @param toHmsg the text, that should occur inside [] before the command
+ * @return the updated command (s.a.)
*/
- private MarkedArea normalizeMarkedArea(MarkedArea ma, int type) {
- int begin, end;
- if (type == 0) {
- begin = ma.begin;
- end = ma.end;
- } else if (type == 1 && (ma instanceof HtmlMarkedArea)) {
- HtmlMarkedArea hma = (HtmlMarkedArea)ma;
- begin = hma.htmlBegin;
- end = hma.htmlEnd;
+ private static String addToHmsg(String command, String toHmsg) {
+ command = command.trim();
+ if (command.startsWith("[")) {
+ command = "[" + toHmsg + command.substring(1);
} else {
- begin = -1;
- end = -1;
- linMarkingLogger.info("Illegal number-code of MarkedArea encountered: " + type + "\nor alternatively, HTML is expected, but a " + ma.getClass().getName() + " was given");
+ command = "[" + toHmsg + "] " + command;
}
- return new MarkedArea(begin, end, ma.position, ma.words, ma.language);
+ return command;
}
/**
@@ -3602,20 +2348,6 @@ public class GFEditor2 extends JFrame {
saveFc.addChoosableFileFilter(new GrammarFilter());
int returnVal = saveFc.showOpenDialog(GFEditor2.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
-
- /* "sending" should be fixed on the GF side:
- rbMenuItemLong.setSelected(true);
- send("ms long");
- rbMenuItemUnTyped.setSelected(true);
- send("mt untyped");
- selectedMenuLanguage = "Abstract";
- rbMenuItemAbs.setSelected(true);
- send("ml Abs");
- */
-
- treeChanged = true;
- newObject = true;
-
resetNewCategoryMenu();
langMenuModel.resetLanguages();
@@ -3624,11 +2356,11 @@ public class GFEditor2 extends JFrame {
if (logger.isLoggable(Level.FINER)) logger.finer("opening: "+ file.getPath().replace('\\', File.separatorChar));
if (saveTypeGroup.getSelection().getActionCommand().equals("term")) {
if (logger.isLoggable(Level.FINER)) logger.finer(" opening as a term ");
- send("open "+ file.getPath().replace('\\', File.separatorChar));
+ send("[nt] open "+ file.getPath().replace('\\', File.separatorChar));
}
else {
if (logger.isLoggable(Level.FINER)) logger.finer(" opening as a linearization ");
- send("openstring "+ file.getPath().replace('\\', File.separatorChar));
+ send("[nt] openstring "+ file.getPath().replace('\\', File.separatorChar));
}
fileString ="";
@@ -3657,24 +2389,24 @@ public class GFEditor2 extends JFrame {
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = saveFc.getSelectedFile();
if (logger.isLoggable(Level.FINER)) logger.finer("saving as " + file);
- final String abstractLin = linearizations.get("Abstract").toString();
+ final String abstractLin = linearization.getLinearizations().get("Abstract").toString();
if (saveTypeGroup.getSelection().getActionCommand().equals("term")) {
// saving as a term
- writeOutput(abstractLin, file.getPath());
+ writeOutput(removeMetavariableNumbers(abstractLin), file.getPath());
} else {
// saving as a linearization:
/** collects the show linearizations */
StringBuffer text = new StringBuffer();
/** if sth. at all is shown already*/
boolean sthAtAll = false;
- for (Iterator it = linearizations.keySet().iterator(); it.hasNext();) {
+ for (Iterator it = linearization.getLinearizations().keySet().iterator(); it.hasNext();) {
Object key = it.next();
if (!key.equals("Abstract")) {
if (sthAtAll) {
text.append("\n\n");
}
- text.append(linearizations.get(key));
+ text.append(linearization.getLinearizations().get(key));
sthAtAll = true;
}
}
@@ -3683,7 +2415,7 @@ public class GFEditor2 extends JFrame {
if (logger.isLoggable(Level.FINER)) logger.finer(file + " saved.");
} else {
if (logger.isLoggable(Level.FINER)) logger.warning("no concrete language shown, saving abstract");
- writeOutput(abstractLin, file.getPath());
+ writeOutput(removeMetavariableNumbers(abstractLin), file.getPath());
if (logger.isLoggable(Level.FINER)) logger.finer(file + " saved.");
}
}
@@ -3718,9 +2450,10 @@ public class GFEditor2 extends JFrame {
// importing a new language :
if (logger.isLoggable(Level.FINER)) logger.finer("importing: "+ file.getPath().replace('\\','/'));
fileString ="";
- send("i "+ file.getPath().replace('\\',File.separatorChar), false);
- readGfinit();
- readAndDisplay();
+ //TODO does that load paths in UNIX-notation under windows?
+ send("i "+ file.getPath().replace('\\',File.separatorChar), false, 1);
+ processGfinit();
+ processGfedit();
}
}
@@ -3754,8 +2487,8 @@ public class GFEditor2 extends JFrame {
statusLabel.setText(status);
subtermDescLabel.setText("");
subtermNameLabel.setText("");
- listModel.clear();
- resetTree(tree);
+ refinementMenu.reset();
+ tree.resetTree();
resetNewCategoryMenu();
langMenuModel.resetLanguages();
selectedMenuLanguage = "Abstract";
@@ -3765,11 +2498,12 @@ public class GFEditor2 extends JFrame {
fileString="";
grammar.setText("No Topic ");
- display = new Display(displayType);
- display(true, false);
- send(" e "+ file.getPath().replace('\\',File.separatorChar), false);
- readInit(null, false);
- readAndDisplay();
+ display.resetLin();
+ display(true, true, false);
+ undoStack.clear();
+ send(" e "+ file.getPath().replace('\\',File.separatorChar), false, 1);
+ processInit(null, false);
+ processGfedit();
resetPrintnames(true);
}
}
@@ -3795,8 +2529,8 @@ public class GFEditor2 extends JFrame {
statusLabel.setText(status);
subtermDescLabel.setText("");
subtermNameLabel.setText("");
- listModel.clear();
- resetTree(tree);
+ refinementMenu.reset();
+ tree.resetTree();
langMenuModel.resetLanguages();
resetNewCategoryMenu();
selectedMenuLanguage = "Abstract";
@@ -3807,8 +2541,9 @@ public class GFEditor2 extends JFrame {
fileString="";
grammar.setText("No Topic ");
- send("e", false);
- readGfinit();
+ undoStack.clear();
+ send("e", false, 1);
+ processGfinit();
}
}
@@ -3846,8 +2581,7 @@ public class GFEditor2 extends JFrame {
}
public void actionPerformed(ActionEvent e) {
- treeChanged = true;
- send("a");
+ send("[t] a");
}
}
@@ -3866,8 +2600,11 @@ public class GFEditor2 extends JFrame {
}
public void actionPerformed(ActionEvent e) {
- treeChanged = true;
- send("u");
+ int undoSteps = 1;
+ if (!undoStack.empty()) {
+ undoSteps = ((Integer)undoStack.pop()).intValue();
+ }
+ send("[t] u " + undoSteps, true, 0);
}
}
@@ -3888,8 +2625,7 @@ public class GFEditor2 extends JFrame {
String s = JOptionPane.showInputDialog("Type string:", alphaInput);
if (s!=null) {
alphaInput = s;
- treeChanged = true;
- send("x "+s);
+ send("[t] x "+s);
}
}
@@ -3912,12 +2648,11 @@ public class GFEditor2 extends JFrame {
String s = JOptionPane.showInputDialog("Command:", commandInput);
if (s!=null) {
commandInput = s;
- //s = "gf "+s; This is for debugging, otherwise shift the comment to the next line.
- treeChanged = true;
+ s = addToHmsg(s, "t");
if (logger.isLoggable(Level.FINER)) logger.finer("sending: "+ s);
send(s);
- } }
-
+ }
+ }
}
/**
@@ -3962,7 +2697,7 @@ public class GFEditor2 extends JFrame {
centerPanel2.add(outputPanelUp, BorderLayout.CENTER);
}
coverPanel.add(centerPanel2, BorderLayout.CENTER);
- gui2.getContentPane().add(refinementListsContainer);
+ gui2.getContentPane().add(refinementMenu.getRefinementListsContainer());
gui2.setVisible(true);
pack();
repaint();
@@ -3994,20 +2729,51 @@ public class GFEditor2 extends JFrame {
gui2.setVisible(false);
}
coverPanel.add(centerPanel, BorderLayout.CENTER);
- centerPanelDown.add(refinementListsContainer, BorderLayout.CENTER);
- centerPanelDown.add(refinementSubcatPanel, BorderLayout.EAST);
+ centerPanelDown.add(refinementMenu.getRefinementListsContainer(), BorderLayout.CENTER);
+ //centerPanelDown.add(refinementMenu.refinementSubcatPanel, BorderLayout.EAST);
pack();
repaint();
}
}
+ /**
+ * Starts a run on the AST to hunt down open subtyping witnesses
+ * Is not local in initializeGUI because jswat cannot have active breakpoints in such a class, whyever.
+ * @author daniels
+ */
+ class SubtypeAction extends AbstractAction {
+ public SubtypeAction() {
+ super("Close Subtypes", null);
+ putValue(SHORT_DESCRIPTION, "try to automatically refine Subtype relations");
+ //putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_U));
+ putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_T, ActionEvent.CTRL_MASK));
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ String resetCommand;
+ int usteps ;
+ if (focusPosition != null) {
+ //go back to where we come from
+ resetCommand = "[t] mp " + focusPosition.position;
+ usteps = 1;
+ } else {
+ resetCommand = "[t] gf";
+ usteps = 0;
+ }
+ SubtypingProber sp = new SubtypingProber(gfCapsule);
+ int undos = sp.checkSubtyping();
+ send(resetCommand , true, undos + usteps);
+ }
+ }
+
+
/**
* Takes care, which classes are present and which states they have.
* @author daniels
*/
- class LangMenuModel {
+ class LangMenuModel implements LanguageManager{
Logger menuLogger = Logger.getLogger("de.uka.ilkd.key.ocl.gf.GFEditor2.MenuModel");
/**
* Just a mutable tuple of language name and whether this language
@@ -4065,8 +2831,8 @@ public class GFEditor2 extends JFrame {
}
}
//stolen from fontEverywhere
- setFontRecursive(langMenu, font, false);
- setFontRecursive(mlMenu, font, false);
+ setSubmenuFont(langMenu, font, false);
+ setSubmenuFont(mlMenu, font, false);
}
/**
@@ -4095,7 +2861,7 @@ public class GFEditor2 extends JFrame {
* @param myLang The name of the language
* @param myActive whether the language is displayed or not
*/
- void add(String myLang, boolean myActive) {
+ public void add(String myLang, boolean myActive) {
boolean alreadyThere = false;
for (Iterator it = this.languages.iterator(); it.hasNext(); ) {
LangActiveTuple current = (LangActiveTuple)it.next();
@@ -4118,7 +2884,7 @@ public class GFEditor2 extends JFrame {
* @return true iff the language is present and set to active,
* false otherwise.
*/
- boolean isLangActive(String myLang) {
+ public boolean isLangActive(String myLang) {
for (Iterator it = this.languages.iterator(); it.hasNext(); ) {
LangActiveTuple current = (LangActiveTuple)it.next();
if (current.lang.equals(myLang)) {
@@ -4171,14 +2937,10 @@ public class GFEditor2 extends JFrame {
} else {
sendLang = action;
}
- if (xmlLogger.isLoggable(Level.FINER)){
- xmlLogger.finer("sending "+sendLang);
- }
send("ml " + sendLang);
resetPrintnames(true);
return;
-
}
};
@@ -4190,8 +2952,8 @@ public class GFEditor2 extends JFrame {
public void actionPerformed(ActionEvent e) {
if (newObject) {
//clear display of text and HTML
- display = new Display(displayType);
- display(true, true);
+ display.resetLin();
+ display(true, false, true);
formLin();
}
final String lang = ((JCheckBoxMenuItem)e.getSource()).getText();
@@ -4212,13 +2974,5 @@ public class GFEditor2 extends JFrame {
return;
}
};
-
-
-
}
-
}
-
-
-
-
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GfAstNode.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GfAstNode.java
index 48b00b8ed..8912d0778 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GfAstNode.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GfAstNode.java
@@ -18,11 +18,21 @@ package de.uka.ilkd.key.ocl.gf;
/**
* @author daniels
* This Class represents a parsed node in the GF AST.
+ * It knows about types, bound variables, funs.
+ * But nothing about printnames. That's what AstNodeData is for.
*/
class GfAstNode {
+ /**
+ * contains the types of the bound variables in the order of their occurence
+ */
protected final String[] boundTypes;
+ /**
+ * contains the names of the bound variables in the order of their occurence
+ */
protected final String[] boundNames;
- /** The type of this AST node */
+ /**
+ * The type of this AST node
+ */
private final String type;
/**
* @return The type of this AST node
@@ -30,8 +40,11 @@ class GfAstNode {
protected String getType() {
return type;
}
- /** the fun represented in this AST node */
+ /**
+ * the fun represented in this AST node
+ */
private final String fun;
+
/**
* @return the fun represented in this AST node.
* Can be a metavariable like "?1"
@@ -39,6 +52,7 @@ class GfAstNode {
protected String getFun() {
return fun;
}
+
/**
* @return true iff the node is a metavariable, i.e. open and not
* yet refined.
@@ -46,7 +60,9 @@ class GfAstNode {
protected boolean isMeta() {
return fun.startsWith("?");
}
- /** the line that was used to build this node */
+ /**
+ * the line that was used to build this node
+ */
private final String line;
/**
* @return the line that was used to build this node
@@ -54,6 +70,11 @@ class GfAstNode {
protected String getLine() {
return line;
}
+
+ /**
+ * The constraint attached to this node
+ */
+ public final String constraint;
/**
* feed this constructor the line that appears in the GF AST and
@@ -63,7 +84,15 @@ class GfAstNode {
protected GfAstNode(final String line) {
this.line = line.trim();
final int index = this.line.lastIndexOf(" : ");
- this.type = this.line.substring(index + 3);
+ String typeString = this.line.substring(index + 3);
+ final int constraintIndex = typeString.indexOf(" {");
+ if (constraintIndex > -1) {
+ this.constraint = typeString.substring(constraintIndex + 1).trim();
+ this.type = typeString.substring(0, constraintIndex).trim();
+ } else {
+ this.constraint = "";
+ this.type = typeString;
+ }
String myFun = this.line.substring(0, index);
if (myFun.startsWith("\\(")) {
final int end = myFun.lastIndexOf(") -> ");
@@ -89,46 +118,4 @@ class GfAstNode {
public String toString() {
return this.line;
}
-
- public static void main(String[] args) {
- String[] lines = {"?1 : Sent",
- "Two : Instance Integer",
- "?3 : Instance (Collection (?{this:=this{-0-}}))",
- "NOPACKAGEP_StartC_Constr : Constraint {Constraint<>NOPACKAGEP_StartC_Constr (\\this -> invCt ?)}",
- "\\(this : VarSelf NOPACKAGEP_StartC) -> invCt : ClassConstraintBody",
- "\\(x_0 : Instance Integer) -> ?6 : Sent",
- "\\(selfGF : VarSelf NOPACKAGEP_PayCardC),(amount : Instance Integer) -> preC : OperConstraintBody",
- "\\(selfGF : VarSelf NOPACKAGEP_PayCardC),(amount : Instance Integer) -> ?0 : OperConstraintBody"
- };
- String[] funs = {"?1",
- "Two",
- "?3",
- "NOPACKAGEP_StartC_Constr",
- "invCt",
- "?6",
- "preC",
- "?0"
- };
- String[] types = {"Sent",
- "Instance Integer",
- "Instance (Collection (?{this:=this{-0-}}))",
- "Constraint {Constraint<>NOPACKAGEP_StartC_Constr (\\this -> invCt ?)}",
- "ClassConstraintBody",
- "Sent",
- "OperConstraintBody",
- "OperConstraintBody"
- };
-
- for (int i = 0; i < lines.length; i++) {
- System.out.println("* " + lines[i]);
- GfAstNode gfa = new GfAstNode(lines[i]);
- if (!gfa.getFun().equals(funs[i])) {
- System.out.println(" fun mismatch: expected '" + funs[i] + "', got '" + gfa.getFun() + "'");
- }
- if (!gfa.getType().equals(types[i])) {
- System.out.println(" type mismatch: expected '" + types[i] + "', got '" + gfa.getType() + "'");
- }
-
- }
- }
}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GfCapsule.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GfCapsule.java
new file mode 100644
index 000000000..c1d012a02
--- /dev/null
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GfCapsule.java
@@ -0,0 +1,621 @@
+//Copyright (c) Janna Khegai 2004, Hans-Joachim Daniels 2005
+//
+//This program is free software; you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation; either version 2 of the License, or
+//(at your option) any later version.
+//
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU General Public License for more details.
+//
+//You can either finde the file LICENSE or LICENSE.TXT in the source
+//distribution or in the .jar file of this application
+
+package de.uka.ilkd.key.ocl.gf;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.util.Vector;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+import javax.swing.ProgressMonitor;
+
+class GfCapsule {
+ /**
+ * XML parsing debug messages
+ */
+ private static Logger xmlLogger = Logger.getLogger(GfCapsule.class.getName() + ".xml");
+ /**
+ * generic logging of this class
+ */
+ private static Logger logger = Logger.getLogger(GfCapsule.class.getName());
+ /**
+ * The output from GF is in here.
+ * Only the read methods, initializeGF and the prober objects access this.
+ */
+ BufferedReader fromProc;
+ /**
+ * Used to leave messages for GF here.
+ * But <b>only</b> in send and special probers that clean up with undo
+ * after them (or don't change the state like PrintnameLoader).
+ */
+ BufferedWriter toProc;
+
+ /**
+ * Starts GF with the given command gfcmd in another process.
+ * Sets up the reader and writer to that process.
+ * Does in it self not read anything from GF.
+ * @param gfcmd The complete command to start GF, including 'gf' itself.
+ */
+ public GfCapsule(String gfcmd){
+ try {
+ Process extProc = Runtime.getRuntime().exec(gfcmd);
+ InputStreamReader isr = new InputStreamReader(
+ extProc.getInputStream(),"UTF8");
+ this.fromProc = new BufferedReader (isr);
+ String defaultEncoding = isr.getEncoding();
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("encoding "+defaultEncoding);
+ }
+ this.toProc = new BufferedWriter(new OutputStreamWriter(extProc.getOutputStream(),"UTF8"));
+ } catch (IOException e) {
+ JOptionPane.showMessageDialog(new JFrame(), "Could not start " + gfcmd+
+ "\nCheck your $PATH", "Error",
+ JOptionPane.ERROR_MESSAGE);
+ throw new RuntimeException("Could not start " + gfcmd+
+ "\nCheck your $PATH");
+ }
+ }
+
+
+ /**
+ * Does the actual writing of command to the GF process via STDIN
+ * @param command exactly the string that is going to be sent
+ */
+ protected void realSend(String command) {
+ try {
+ toProc.write(command, 0, command.length());
+ toProc.newLine();
+ toProc.flush();
+ } catch (IOException e) {
+ System.err.println("Could not write to external process " + e);
+ }
+
+ }
+
+ /**
+ * reads the part between &gt;gfinit&lt; and &gt;/gfinit&lt;
+ * @return the data for the new category menu
+ */
+ protected NewCategoryMenuResult readGfinit() {
+ try {
+ //read <hmsg> or <newcat> or <topic> (in case of no grammar loaded)
+ String readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("12 "+readresult);
+ //when old grammars are loaded, the first line looks like
+ //"reading grammar of old format letter.Abs.gfreading old file letter.Abs.gf<gfinit>"
+ if (readresult.indexOf("<gfinit>") > -1) {
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("12 "+readresult);
+ }
+ //no command appendix expected or applicable here, so appendix is discarded
+ Hmsg hmsg = readHmsg(readresult);
+ String next = hmsg.lastline;
+ //no hmsg supported here. Wouldn't be applicable.
+ //the reading above is to silently ignore it intead of failing.
+ //formHmsg(hmsg);
+
+ if ((next!=null) && ((next.indexOf("newcat") > -1)
+ || (next.indexOf("topic") > -1))) {
+ NewCategoryMenuResult ncmr = readNewMenu();
+ return ncmr;
+ }
+
+ } catch (IOException e) {
+ System.err.println("Could not read from external process:\n" + e);
+ }
+ return null;
+ }
+
+ /**
+ * reads the greeting text from GF
+ * @return S tuple with first = the last read GF line,
+ * which should be the first loading line
+ * and second = The greetings string
+ */
+ protected StringTuple readGfGreetings() {
+ try {
+ String readresult = "";
+ StringBuffer outputStringBuffer = new StringBuffer();
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("1 "+readresult);
+ while ((readresult.indexOf("gf")==-1) && (readresult.trim().indexOf("<") < 0)){
+ outputStringBuffer.append(readresult).append("\n");
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("1 "+readresult);
+ }
+ return new StringTuple(readresult, outputStringBuffer.toString());
+ } catch (IOException e) {
+ System.err.println("Could not read from external process:\n" + e);
+ return new StringTuple("", e.getLocalizedMessage());
+ }
+
+ }
+
+ /**
+ * reads the loading and compiling messages from GF
+ * @param readresult the first loading line
+ * @param pm to monitor the loading progress. May be null
+ * @return A tuple with first = the first line from &gt;gfinit&lt; or &gt;gfedit&lt;
+ * and second = the loading message as pure text
+ */
+ protected StringTuple readGfLoading(String readresult, ProgressMonitor pm) {
+ try {
+ // in case nothing has been loaded first, the that has to be done now
+ if (readresult == null) {
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("1 " + readresult);
+ }
+ StringBuffer textPure = new StringBuffer();
+ int progress = 5300;
+ while (!(readresult.indexOf("<gfinit>") > -1 || (readresult.indexOf("<gfmenu>") > -1))){
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("1 "+readresult);
+ textPure.append(readresult).append("\n");
+ progress += 12;
+ Utils.tickProgress(pm, progress, null);
+ }
+ //when old grammars are loaded, the first line looks like
+ //"reading grammar of old format letter.Abs.gfreading old file letter.Abs.gf<gfinit>"
+ //without newlines
+ final int beginInit = readresult.indexOf("<gfinit>");
+ if (beginInit > 0) {
+ textPure.append(readresult.substring(0, beginInit)).append("\n");
+ //that is the expected result
+ readresult = "<gfinit>";
+ }
+ return new StringTuple(readresult, textPure.toString());
+ } catch (IOException e) {
+ System.err.println("Could not read from external process:\n" + e);
+ return new StringTuple("", e.getLocalizedMessage());
+ }
+
+ }
+
+
+ /**
+ * Reads the &lt;gfedit&gt; part from GF's XML output.
+ * The different subtags are put into the result
+ * @param newObj If a new object in the editor has been started.
+ * If the to-be-read hmsg contains the newObject flag,
+ * that overwrites this parameter
+ * @return the read tags, partially halfy parsed, partially raw.
+ * The way the different form methods expect it.
+ */
+ protected GfeditResult readGfedit(boolean newObj) {
+ try {
+ String next = "";
+ //read <gfedit>
+ String readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("11 "+readresult);
+ //read either <hsmg> or <lineatization>
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("11 "+readresult);
+
+ //hmsg stuff
+ final Hmsg hmsg = readHmsg(readresult);
+ next = hmsg.lastline;
+
+ //reading <linearizations>
+ //seems to be the only line read here
+ //this is here to give as some sort of catch clause.
+ while ((next!=null)&&((next.length()==0)||(next.indexOf("<linearizations>")==-1))) {
+ next = fromProc.readLine();
+ if (next!=null){
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("10 "+next);
+ } else {
+ System.exit(0);
+ }
+ }
+ readresult = next;
+ String lin = readLin();
+ final String treeString = readTree();
+ final String message = readMessage();
+ //read the menu stuff
+ Vector gfCommandVector;
+ if (newObj || hmsg.newObject) {
+ gfCommandVector = readRefinementMenu();
+ } else {
+ while(readresult.indexOf("</menu")==-1) {
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("12 " + readresult);
+ }
+ gfCommandVector = null;
+ }
+ // "" should occur quite fast, but it has not already been read,
+ // since the last read line is "</menu>"
+ for (int i = 0; i < 3 && !readresult.equals(""); i++){
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("11 " + readresult);
+ }
+ //all well, return the read stuff
+ return new GfeditResult(gfCommandVector, hmsg, lin, message, treeString);
+
+ } catch (IOException e) {
+ System.err.println("Could not read from external process:\n" + e);
+ }
+ //nothing well, return bogus stuff
+ return new GfeditResult(new Vector(), new Hmsg("", "", false, false, false, false, true), "", "", "");
+
+ }
+
+ /**
+ * reads the linearizations in all language.
+ * seems to expect the first line of the XML structure
+ * (< lin) already to be read
+ * Accumulates the GF-output between <linearization> </linearization> tags
+ */
+ protected String readLin(){
+ StringBuffer lins = new StringBuffer();
+ try {
+ //read <linearizations>
+ String readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("7 " + readresult);
+ lins.append(readresult).append('\n');
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("6 " + readresult);
+ while ((readresult != null) && (readresult.indexOf("/linearization") == -1)){
+ lins.append(readresult).append('\n');
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("6 " + readresult);
+ }
+ } catch(IOException e){
+ System.err.println(e.getMessage());
+ e.printStackTrace();
+ }
+ return lins.toString();
+ }
+
+ /**
+ * reads in the tree and calls formTree without start end end tag of tree
+ * expects the first starting XML tag tree to be already read
+ * @return the read tags for the tree or null if a read error occurs
+ */
+ protected String readTree(){
+ String treeString = "";
+ try {
+ //read <tree>
+ String readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("6 " + readresult);
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("6 " + readresult);
+ while (readresult.indexOf("/tree") == -1){
+ treeString += readresult + "\n";
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("6 " + readresult);
+ }
+ return treeString;
+ } catch(IOException e){
+ System.err.println(e.getMessage());
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Parses the GF-output between <message> </message> tags
+ * and returns it.
+ * @return The read message.
+ */
+ protected String readMessage(){
+ String s ="";
+ try {
+ // read <message>
+ String readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("6 " + readresult);
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("7 " + readresult);
+ while (readresult.indexOf("/message") == -1){
+ s += readresult + "\n";
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("7 " + readresult);
+ }
+ return s;
+ } catch(IOException e){
+ System.err.println(e.getLocalizedMessage());
+ e.printStackTrace();
+ return e.getLocalizedMessage();
+ }
+ }
+
+ /**
+ * reads the cat entries and puts them into result.menuContent,
+ * after that reads
+ * the names of the languages and puts them into the result.languages
+ * The loaded grammar files are put into result.paths,
+ * a guessed grammar name into result.grammarName
+ * Parses the GF-output between <gfinit> tags
+ */
+ protected NewCategoryMenuResult readNewMenu () {
+ //here the read stuff is sorted into
+ String grammarName = "";
+ final Vector languages = new Vector();
+ final Vector menuContent = new Vector();
+ final Vector paths = new Vector();
+
+ boolean more = true;
+ try {
+ //read first cat
+ String readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) {
+ xmlLogger.finer("2 " + readresult);
+ }
+ if (readresult.indexOf("(none)") > -1) {
+ //no topics present
+ more = false;
+ }
+
+ while (more){
+ //adds new cat s to the menu
+ if (readresult.indexOf("topic") == -1) {
+ final String toAdd = readresult.substring(6);
+ menuContent.add(toAdd);
+ } else {
+ more = false;
+ }
+ //read </newcat
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("2 " + readresult);
+ //read <newcat (normally)
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("3 " + readresult);
+ if (readresult.indexOf("topic") != -1) {
+ //no more categories
+ more = false;
+ }
+ //read next cat / topic
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("4 " + readresult);
+ }
+ //set topic
+ grammarName = readresult.substring(4) + " ";
+ //read </topic>
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("2 " + readresult);
+ //read <language>
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("3 " + readresult);
+ //read actual language
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("4 " + readresult);
+
+ //read the languages and select the last non-abstract
+ more = true;
+ while (more){
+ if ((readresult.indexOf("/gfinit") == -1)
+ && (readresult.indexOf("lin") == -1)) {
+ //form lang and Menu menu:
+ final String langName = readresult.substring(4);
+ languages.add(langName);
+ } else {
+ more = false;
+ }
+ // read </language>
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("2 " + readresult);
+ // read <language> or </gfinit...>
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("3 " + readresult);
+ if ((readresult.indexOf("/gfinit") != -1)
+ || (readresult.indexOf("lin") != -1)) {
+ more = false;
+ }
+ // registering the file name:
+ if (readresult.indexOf("language") != -1) {
+ String path = readresult.substring(readresult.indexOf('=') + 1,
+ readresult.indexOf('>'));
+ path = path.substring(path.lastIndexOf(File.separatorChar) + 1);
+ if (xmlLogger.isLoggable(Level.FINE)) xmlLogger.fine("language: " + path);
+ paths.add(path);
+ }
+ // in case of finished, read the final "" after </gfinit>,
+ // otherwise the name of the next language
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("4 " + readresult);
+ }
+ } catch(IOException e){
+ xmlLogger.warning(e.getMessage());
+ }
+ String[] menuContentArray = Utils.vector2Array(menuContent);
+ String[] languagesArray = Utils.vector2Array(languages);
+ String[] pathsArray = Utils.vector2Array(paths);
+ NewCategoryMenuResult result = new NewCategoryMenuResult(grammarName, menuContentArray, languagesArray, pathsArray);
+ return result;
+ }
+
+ /**
+ * Reads the hmsg part of the XML that is put out from GF.
+ * Everything in [] given in front of a GF command will be rewritten here.
+ * This method does nothing when no hmsg part is present.
+ *
+ * If a '$' appears in this string, everything that comes after it
+ * will be in result.second.
+ * ;; and [] don't work in the [] for the hmsg,
+ * therfore the following replacements are done:
+ * %% for ;;
+ * ( for [
+ * ) for ]
+ *
+ * If one of the characters c,t,n comes before, the following is done:
+ * c The output will be cleared before the linearization (TODO: done anyway?)
+ * t The treeChanged flag will be set to true
+ * n The newObject flag will be set to true
+ * p No other probing run should be done (avoid cycles)
+ * r To prevent the execution of automatically triggered commands to prevent recursion
+ *
+ * @param prevreadresult The last line read from GF
+ * @return first: the last line this method has read;
+ * second: the string after $, null if that is not present
+ */
+ protected Hmsg readHmsg(String prevreadresult){
+ if ((prevreadresult!=null)&&(prevreadresult.indexOf("<hmsg>") > -1)) {
+ StringBuffer s =new StringBuffer("");
+ String commandAppendix = null;
+ try {
+ boolean onceAgain = true;
+ boolean recurse = true;
+ boolean newObj = false;
+ boolean treeCh = false;
+ boolean clear = false;
+ String readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("7 "+readresult);
+ while (readresult.indexOf("/hmsg")==-1){
+ s.append(readresult).append('\n');
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("7 "+readresult);
+ }
+ int commandAppendixStart = s.indexOf("$");
+ if (commandAppendixStart > -1 && commandAppendixStart < s.length() - 1) { //present, but not the last character
+ commandAppendix = s.substring(commandAppendixStart + 1, s.indexOf("\n")); //two \n trail the hmsg
+ //;; and [] don't work in the [] for the hmsg
+ commandAppendix = Utils.replaceAll(commandAppendix, "%%", ";;");
+ commandAppendix = Utils.replaceAll(commandAppendix, "(", "[");
+ commandAppendix = Utils.replaceAll(commandAppendix, ")", "]");
+ } else {
+ commandAppendixStart = s.length();
+ }
+ if (s.indexOf("c") > -1 && s.indexOf("c") < commandAppendixStart) {
+ //clear output before linearization
+ clear = true;
+ }
+ if (s.indexOf("t") > -1 && s.indexOf("t") < commandAppendixStart) {
+ //tree has changed
+ treeCh = true;
+ }
+ if (s.indexOf("p") > -1 && s.indexOf("p") < commandAppendixStart) {
+ //we must not probe again
+ onceAgain = false;
+ }
+ if (s.indexOf("r") > -1 && s.indexOf("r") < commandAppendixStart) {
+ //we must not probe again
+ recurse = false;
+ }
+
+ if (s.indexOf("n") > -1 && s.indexOf("n") < commandAppendixStart) {
+ //a new object has been created
+ newObj = true;
+ }
+ if (logger.isLoggable(Level.FINE)) {
+ if (commandAppendix != null) {
+ logger.fine("command appendix read: '" + commandAppendix + "'");
+ }
+ }
+ return new Hmsg(readresult, commandAppendix, onceAgain, recurse, newObj, treeCh, clear);
+ } catch(IOException e){
+ System.err.println(e.getMessage());
+ e.printStackTrace();
+ return new Hmsg("", null, false, true, false, true, false);
+ }
+ } else {
+ return new Hmsg(prevreadresult, null, true, true, false, true, false);
+ }
+ }
+
+ /**
+ * Parses the GF-output between <menu> and </menu> tags
+ * and puts a StringTuple for each show/send pair into the
+ * return vector.
+ * @return A Vector of StringTuple as described above
+ */
+ protected Vector readRefinementMenu (){
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("list model changing! ");
+ String s ="";
+ Vector printnameVector = new Vector();
+ Vector commandVector = new Vector();
+ Vector gfCommandVector = new Vector();
+ try {
+ //read <menu>
+ String readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("7 " + readresult);
+ //read item
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("8 " + readresult);
+ while (readresult.indexOf("/menu")==-1){
+ //read show
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("8 " + readresult);
+ while (readresult.indexOf("/show") == -1){
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("9 " + readresult);
+ if (readresult.indexOf("/show") == -1) {
+ if (readresult.length()>8)
+ s += readresult.trim();
+ else
+ s += readresult;
+ }
+ }
+ // if (s.charAt(0)!='d')
+ // listModel.addElement("Refine " + s);
+ // else
+ String showText = s;
+ printnameVector.addElement(s);
+ s = "";
+ //read /show
+ //read send
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("8 " + readresult);
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("8 " + readresult);
+ String myCommand = readresult;
+ commandVector.add(readresult);
+ //read /send (discarded)
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("8 " + readresult);
+
+ // read /item
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("8 " + readresult);
+ readresult = fromProc.readLine();
+ if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("8 " + readresult);
+
+ StringTuple st = new StringTuple(myCommand.trim(), showText);
+ gfCommandVector.addElement(st);
+ }
+ } catch(IOException e){
+ System.err.println(e.getMessage());
+ e.printStackTrace();
+ }
+ return gfCommandVector;
+ }
+ /**
+ * Reads the output from GF until the ending tag corresponding to the
+ * given opening tag is read.
+ * @param opening tag in the format of &gt;gfinit&lt;
+ */
+ protected void skipChild(String opening) {
+ String closing = (new StringBuffer(opening)).insert(1, '/').toString();
+ try {
+ String nextRead = fromProc.readLine();
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("3 " + nextRead);
+ }
+ while (!nextRead.trim().equals(closing)) {
+ nextRead = fromProc.readLine();
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("3 " + nextRead);
+ }
+ }
+ } catch (IOException e) {
+ System.err.println("Could not read from external process:\n" + e);
+ }
+ }
+}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GfeditResult.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GfeditResult.java
new file mode 100644
index 000000000..ccc75ff26
--- /dev/null
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/GfeditResult.java
@@ -0,0 +1,61 @@
+//Copyright (c) Hans-Joachim Daniels 2005
+//
+//This program is free software; you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation; either version 2 of the License, or
+//(at your option) any later version.
+//
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU General Public License for more details.
+//
+//You can either finde the file LICENSE or LICENSE.TXT in the source
+//distribution or in the .jar file of this application
+
+package de.uka.ilkd.key.ocl.gf;
+
+import java.util.Vector;
+/**
+ * Encapsulates the &lt;gfedit&gt; XML tree from GF.
+ * @author hdaniels
+ */
+class GfeditResult {
+ /**
+ * The fully parsed &lt;hmsg&gt; subtree
+ */
+ final Hmsg hmsg;
+ /**
+ * A Vector of StringTuple where first is the command for GF
+ * and second is the show text
+ */
+ final Vector gfCommands;
+ /**
+ * The tree from GF isn't XML anyway, so here it is in all its raw glory
+ */
+ final String treeString;
+ /**
+ * if GF had something extra to tell, it can be found here
+ */
+ final String message;
+ /**
+ * The XML for the linearizations in all languages
+ */
+ final String linearizations;
+ /**
+ * A simple setter constructor
+ * @param gfCommands A Vector of StringTuple where first is the command for GF
+ * and second is the show text
+ * @param hmsg The fully parsed &lt;hmsg&gt; subtree
+ * @param linearizations The XML for the linearizations in all languages
+ * @param message the GF message
+ * @param treeString The tree from GF
+ */
+ public GfeditResult(Vector gfCommands, Hmsg hmsg, String linearizations, String message, String treeString) {
+ this.gfCommands = gfCommands;
+ this.hmsg = hmsg;
+ this.linearizations = linearizations;
+ this.message = message;
+ this.treeString = treeString;
+ }
+}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Hmsg.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Hmsg.java
new file mode 100644
index 000000000..0a640f787
--- /dev/null
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Hmsg.java
@@ -0,0 +1,77 @@
+//Copyright (c) Hans-Joachim Daniels 2005
+//
+//This program is free software; you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation; either version 2 of the License, or
+//(at your option) any later version.
+//
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU General Public License for more details.
+//
+//You can either finde the file LICENSE or LICENSE.TXT in the source
+//distribution or in the .jar file of this application
+
+package de.uka.ilkd.key.ocl.gf;
+
+/**
+ * The parsed format of the hmsg, that GF sents, if a command in java mode
+ * was prefixed with [something].
+ * And that something gets parsed and stored in this representation.
+ * @author daniels
+ */
+class Hmsg {
+ /**
+ * The last read line
+ */
+ String lastline = "";
+ /**
+ * the String that should be appended to all commands of the
+ * next refinement menu
+ */
+ String appendix = null;
+ /**
+ * If the editor shall probe once again for missing subtyping witnesses.
+ * Unused.
+ */
+ boolean onceAgain = false;
+ /**
+ * If false, no commands are executed automatically
+ * in the next GF reading run
+ */
+ boolean recurse = false;
+ /**
+ * if the newObject flag should be set
+ */
+ boolean newObject = false;
+ /**
+ * if the command changed the tree, so that it has to be rebuilt
+ */
+ boolean treeChanged = false;
+ /**
+ * if the display should be cleared
+ */
+ boolean clear = false;
+ /**
+ * A simple setter constructor
+ * @param lastRead The last read line
+ * @param appendix the String that should be appended to all commands of the
+ * next refinement menu
+ * @param onceAgain
+ * @param recurse If false, no commands are executed automatically
+ * in the next GF reading run
+ * @param newObject if the newObject flag should be set
+ * @param treeChanged if the command changed the tree, so that it has to be rebuilt
+ * @param clear if the display should get cleared
+ */
+ public Hmsg(String lastRead, String appendix, boolean onceAgain, boolean recurse, boolean newObject, boolean treeChanged, boolean clear) {
+ this.lastline = lastRead;
+ this.appendix = appendix;
+ this.onceAgain = onceAgain;
+ this.recurse = recurse;
+ this.newObject = newObject;
+ this.treeChanged = treeChanged;
+ this.clear = clear;
+ }
+}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/HtmlMarkedArea.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/HtmlMarkedArea.java
deleted file mode 100644
index 6e0424f55..000000000
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/HtmlMarkedArea.java
+++ /dev/null
@@ -1,63 +0,0 @@
-//Copyright (c) Hans-Joachim Daniels 2005
-//
-//This program is free software; you can redistribute it and/or modify
-//it under the terms of the GNU General Public License as published by
-//the Free Software Foundation; either version 2 of the License, or
-//(at your option) any later version.
-//
-//This program is distributed in the hope that it will be useful,
-//but WITHOUT ANY WARRANTY; without even the implied warranty of
-//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-//GNU General Public License for more details.
-//
-//You can either finde the file LICENSE or LICENSE.TXT in the source
-//distribution or in the .jar file of this application
-
-package de.uka.ilkd.key.ocl.gf;
-
-/**
- * @author daniels
- *
- * An extender of MarkedArea that adds additional fields for the click-in
- * functionality for HTML
- */
-class HtmlMarkedArea extends MarkedArea {
-
- /** the start index in the HTML area */
- final public int htmlBegin;
- /** the end index in the HTML area */
- final public int htmlEnd;
-
- /**
- * A stand-alone constuctor which takes all values as arguments
- * @param b The starting position of the stored words
- * @param e The ending position of the stored words
- * @param p The position in the AST
- * @param w The actual text of this area
- * @param hb the start index in the HTML area
- * @param he the end index in the HTML area
- * @param lang the language of the current linearization
- */
- public HtmlMarkedArea(int b, int e, LinPosition p, String w, int hb, int he, String lang) {
- super(b, e, p, w, lang);
- this.htmlBegin = hb;
- this.htmlEnd = he;
- }
-
- /**
- * Creates a copy of orig, but with additional fields for the click-
- * in functionality for HTML
- * @param orig the original MarkedArea that should be extended
- * @param hb the start index in the HTML area
- * @param he the end index in the HTML area
- */
- HtmlMarkedArea(final MarkedArea orig, final int hb, final int he) {
- super(orig.begin, orig.end, orig.position, orig.words, orig.language);
- this.htmlBegin = hb;
- this.htmlEnd = he;
- }
-
- public String toString() {
- return begin + " - " + end + " : " + position + " = '" + words + "' ; HTML: " + htmlBegin + " - " + htmlEnd;
- }
-}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/InputCommand.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/InputCommand.java
index 3d19ddcc8..d047b943b 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/InputCommand.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/InputCommand.java
@@ -14,13 +14,14 @@
//distribution or in the .jar file of this application
package de.uka.ilkd.key.ocl.gf;
+import java.util.HashSet;
/**
* @author daniels
*
- * This class represents a fake command, i.e. nothing is send to GF here.
- * Instead this class acts more like a placeholder for the input dialog.
- * This dialog is handled in GFEditor2 when a InputCommand is executed.
+ * This class represents a fake command, i.e. nothing is send to GF here.
+ * Instead this class acts more like a placeholder for the input dialog.
+ * This dialog is handled in GFEditor2 when a InputCommand is executed.
* Reason: No GUI stuff in the command.
*/
class InputCommand extends GFCommand {
@@ -43,35 +44,56 @@ class InputCommand extends GFCommand {
protected Class type;
- /**the text that is to be displayed as the title in the input window */
+ /**
+ * the text that is to be displayed as the title in the input window
+ */
protected final String titleText;
- /**the text that is to be displayed as the title in the input window */
+ /**
+ * the text that is to be displayed as the title in the input window
+ */
public String getTitleText() {
return titleText;
}
+ /**
+ * stores the entered values, so they can be offered to the user
+ * the next time, in case, he wants them again.
+ */
+ protected final HashSet enteredValues = new HashSet();
- /**the text that is to be displayed as the tooltip */
+ /**
+ * the text that is to be displayed as the tooltip
+ */
protected final String tooltipText;
- /**the text that is to be displayed as the tooltip */
+ /**
+ * the text that is to be displayed as the tooltip
+ */
public String getTooltipText() {
return tooltipText;
}
- /** the text that is to be displayed in the refinement lists */
+ /**
+ * the text that is to be displayed in the refinement lists
+ */
protected final String displayText;
- /** the text that is to be displayed in the refinement lists */
+ /**
+ * the text that is to be displayed in the refinement lists
+ */
public String getDisplayText() {
return displayText;
}
- /** the subcategory of this command */
+ /**
+ * the subcategory of this command
+ */
public String getSubcat() {
return null;
}
/**
* Checks if the given String can be converted into
- * the Type of this InputCommand (int or String)
+ * the Type of this InputCommand (int or String).
+ * If that is possible, the converted object is saved
+ * in enteredValues for later redisplay for the user.
* @param o The String the user has typed
* @param reason If the entered String is not parseable as the expected
* type, an error message is appended to this StringBuffer, so better
@@ -95,6 +117,9 @@ class InputCommand extends GFCommand {
result = "\"" + o.toString() + "\"";
}
}
+ if (result != null) {
+ this.enteredValues.add(result);
+ }
return result;
}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/LanguageManager.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/LanguageManager.java
new file mode 100644
index 000000000..39e3e6fb1
--- /dev/null
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/LanguageManager.java
@@ -0,0 +1,39 @@
+//Copyright (c) Hans-Joachim Daniels 2005
+//
+//This program is free software; you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation; either version 2 of the License, or
+//(at your option) any later version.
+//
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU General Public License for more details.
+//
+//You can either finde the file LICENSE or LICENSE.TXT in the source
+//distribution or in the .jar file of this application
+
+package de.uka.ilkd.key.ocl.gf;
+
+/**
+ * Sadly, this class is a hack.
+ * It serves as the pointer type to an inner class of GFEditor2.
+ * Two of its methods are needed outside after refactoring.
+ * @author daniels
+ *
+ */
+interface LanguageManager {
+ /**
+ * @param myLang The language in question
+ * @return true iff the language is present and set to active,
+ * false otherwise.
+ */
+ public boolean isLangActive(String myLang);
+ /**
+ * Checks if myLang is already present, and if not,
+ * adds it. In that case, myActive is ignored.
+ * @param myLang The name of the language
+ * @param myActive whether the language is displayed or not
+ */
+ public void add(String myLang, boolean myActive);
+}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/LinPosition.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/LinPosition.java
index 0c2c51309..cf2963210 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/LinPosition.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/LinPosition.java
@@ -63,11 +63,31 @@ class LinPosition {
if ("[]".equals(pos)) {
return "[" + nr + "]";
} else {
- return pos.substring(0, pos.length() - 1) + "," + nr + "]";
+ return pos.trim().substring(0, pos.length() - 1) + "," + nr + "]";
}
}
/**
+ * Creates a position string in Haskell notation for the argument
+ * number nr for the position pos' parent, i.e. brethren number nr.
+ * Example: calculateBrethrenPosition("[0,0,1]", 3).equals("[0,0,3]")
+ * @param pos The position of a brethren of the wanted
+ * @param nr The number of the wanted brethren
+ * @return the position string for the nrth brother of pos
+ */
+ protected static String calculateBrethrenPosition(String pos, int nr) {
+ if ("[]".equals(pos)) {
+ return "[]"; //no brethren possible here
+ } else if (pos.lastIndexOf(',') == -1) {
+ return "[" + nr + "]"; //one below top
+ } else {
+ final String newPos = pos.substring(0, pos.lastIndexOf(',') + 1) + nr + "]";
+ return newPos;
+ }
+
+ }
+
+ /**
* compares two position strings and returns true, if superPosition is
* a prefix of subPosition, that is, if subPosition is in a subtree of
* superPosition
@@ -115,6 +135,21 @@ class LinPosition {
}
}
+ /**
+ * @return The Haskell position string for the parent of this position.
+ * If self is already the top node, [] is returned.
+ */
+ public String parentPosition() {
+ if (this.position.equals("[]")) {
+ return this.position;
+ } else if (this.position.lastIndexOf(',') == -1) {
+ return "[]"; //one below top
+ } else {
+ final String newPos = this.position.substring(0, this.position.lastIndexOf(',')) + "]";
+ return newPos;
+ }
+ }
+
public String toString() {
return position + (correctPosition ? " correct" : " incorrect");
}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Linearization.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Linearization.java
new file mode 100644
index 000000000..5ff78202b
--- /dev/null
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Linearization.java
@@ -0,0 +1,760 @@
+//Copyright (c) Janna Khegai 2004, Hans-Joachim Daniels 2005
+//
+//This program is free software; you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation; either version 2 of the License, or
+//(at your option) any later version.
+//
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU General Public License for more details.
+//
+//You can either finde the file LICENSE or LICENSE.TXT in the source
+//distribution or in the .jar file of this application
+
+package de.uka.ilkd.key.ocl.gf;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Encapsulates everything that has to do with the linearization.
+ * It is parsed here, and also the indices for click-in for pure text and HTML
+ * are managed here. They get calculated in GfCapsule.
+ * The result can be directly displayed, and this class has methods to translate
+ * the indices back to the respective tree positions.
+ * @author daniels
+ */
+class Linearization {
+ /**
+ * linearization marking debug messages
+ */
+ protected static Logger logger = Logger.getLogger(Linearization.class.getName());
+
+ /**
+ * contains all the linearization pieces as HtmlMarkedArea
+ * Needed to know to which node in the AST a word in the linHtmlPane
+ * area belongs.
+ */
+ private Vector htmlOutputVector = new Vector();
+ /**
+ * the GF-output between <linearization> </linearization> tags is stored here.
+ * Must be saved in case the displayed languages are changed.
+ * Only written in readLin
+ */
+ private String linearization = "";
+ /**
+ * stack for storing the current position:
+ * When displaying, we start with the root of the AST.
+ * Whenever we start to display a node, it is pushed, and when it is completely displayed, we pop it.
+ * Only LinPositions are stored in here
+ * local in formLin?
+ * */
+ private Vector currentPosition = new Vector();
+
+ /**
+ * Must be the same Display as GFEditor2 uses
+ */
+ private Display display;
+ /**
+ * to collect the linearization strings
+ */
+ private HashMap linearizations = new HashMap();
+
+
+
+ /**
+ * Initializes this object and binds it to the given Display
+ * @param display The display, that the editor uses
+ */
+ public Linearization(Display display) {
+ this.display = display;
+ }
+
+ /**
+ * @return Returns the linearizations.
+ */
+ HashMap getLinearizations() {
+ return linearizations;
+ }
+
+ /**
+ * @param linearization The linearization to set.
+ */
+ void setLinearization(String linearization) {
+ this.linearization = linearization;
+ }
+
+ /**
+ * resets the output mechanism.
+ */
+ void reset() {
+ htmlOutputVector = new Vector();
+ }
+
+ /**
+ * Returns the widest position (see comments to comparePositions)
+ * covered in the string from begin to end in the
+ * linearization area.
+ * @param begin The index in htmlOutputVector of the first MarkedArea, that is possibly the max
+ * @param end The index in htmlOutputVector of the last MarkedArea, that is possibly the max
+ * @return the position in GF Haskell notation (hdaniels guesses)
+ */
+ private String findMax(int begin, int end) {
+ String max = (((MarkedArea)this.htmlOutputVector.elementAt(begin)).position).position;
+ for (int i = begin+1; i <= end; i++)
+ max = LinPosition.maxPosition(max,(((MarkedArea)this.htmlOutputVector.elementAt(i)).position).position);
+ return max;
+ }
+
+ /**
+ * Appends the string restString to display.
+ * It parses the subtree tags and registers them.
+ * The focus tag is expected to be replaced by subtree.
+ * @param restString string to append, with tags in it.
+ * @param clickable if true, the text is appended and the subtree tags are
+ * parsed. If false, the text is appended, but the subtree tags are ignored.
+ * @param doDisplay true iff the output is to be displayed.
+ * Implies, if false, that clickable is treated as false.
+ * @param language the current linearization language
+ */
+ private String appendMarked(String restString, final boolean clickable, boolean doDisplay, String language) {
+ String appendedPureText = "";
+ if (restString.length()>0) {
+ /**
+ * the length of what is already displayed of the linearization.
+ * Alternatively: What has been processed in restString since
+ * subtreeBegin
+ */
+ int currentLength = 0;
+ /** position of &lt;subtree */
+ int subtreeBegin;
+ /** position of &lt;/subtree */
+ int subtreeEnd;
+
+ if (clickable && doDisplay) {
+ subtreeBegin = Utils.indexOfNotEscaped(restString, "<subtree");
+ subtreeEnd = Utils.indexOfNotEscaped(restString, "</subtree");
+ // cutting subtree-tags:
+ while ((subtreeEnd>-1)||(subtreeBegin>-1)) {
+ /**
+ * length of the portion that is to be displayed
+ * in the current run of appendMarked.
+ * For HTML this would have to be calculated
+ * in another way.
+ */
+ final int newLength;
+
+ if ((subtreeEnd==-1)||((subtreeBegin<subtreeEnd)&&(subtreeBegin>-1))) {
+ final int subtreeTagEnd = Utils.indexOfNotEscaped(restString, ">",subtreeBegin);
+ final int nextOpeningTagBegin = Utils.indexOfNotEscaped(restString, "<", subtreeTagEnd);
+
+ //getting position:
+ final int posStringBegin = Utils.indexOfNotEscaped(restString, "[",subtreeBegin);
+ final int posStringEnd = Utils.indexOfNotEscaped(restString, "]",subtreeBegin);
+ final LinPosition position = new LinPosition(restString.substring(posStringBegin,posStringEnd+1),
+ restString.substring(subtreeBegin,subtreeTagEnd).indexOf("incorrect")==-1);
+
+ // is something before the tag?
+ // is the case in the first run
+ if (subtreeBegin-currentLength>1) {
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("SOMETHING BEFORE THE TAG");
+ }
+ if (this.currentPosition.size()>0)
+ newLength = register(currentLength, subtreeBegin, (LinPosition)this.currentPosition.elementAt(this.currentPosition.size()-1), restString, language);
+ else
+ newLength = register(currentLength, subtreeBegin, new LinPosition("[]",
+ restString.substring(subtreeBegin,subtreeTagEnd).indexOf("incorrect")==-1), restString, language);
+ } else { // nothing before the tag:
+ //the case in the beginning
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("NOTHING BEFORE THE TAG");
+ }
+ if (nextOpeningTagBegin>0) {
+ newLength = register(subtreeTagEnd+2, nextOpeningTagBegin, position, restString, language);
+ } else {
+ newLength = register(subtreeTagEnd+2, restString.length(), position, restString, language);
+ }
+ restString = removeSubTreeTag(restString,subtreeBegin, subtreeTagEnd+1);
+ }
+ currentLength += newLength ;
+ } else {
+ // something before the </subtree> tag:
+ if (subtreeEnd-currentLength>1) {
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("SOMETHING BEFORE THE </subtree> TAG");
+ }
+ if (this.currentPosition.size()>0)
+ newLength = register(currentLength, subtreeEnd, (LinPosition)this.currentPosition.elementAt(this.currentPosition.size()-1), restString, language);
+ else
+ newLength = register(currentLength, subtreeEnd, new LinPosition("[]",
+ restString.substring(subtreeBegin,subtreeEnd).indexOf("incorrect")==-1), restString, language);
+ currentLength += newLength ;
+ }
+ // nothing before the tag:
+ else
+ // punctuation after the </subtree> tag:
+ if (restString.substring(subtreeEnd+10,subtreeEnd+11).trim().length()>0)
+ {
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("PUNCTUATION AFTER THE </subtree> TAG"
+ + "/n" + "STRING: " + restString);
+ }
+ //cutting the tag first!:
+ if (subtreeEnd>0) {
+ restString = removeSubTreeTag(restString,subtreeEnd-1, subtreeEnd+9);
+ } else {
+ restString = removeSubTreeTag(restString,subtreeEnd, subtreeEnd+9);
+ }
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("STRING after cutting the </subtree> tag: "+restString);
+ }
+ // cutting the space in the last registered component:
+ if (this.htmlOutputVector.size()>0) {
+ ((MarkedArea)this.htmlOutputVector.elementAt(this.htmlOutputVector.size()-1)).end -=1;
+ if (currentLength>0) {
+ currentLength -=1;
+ }
+ }
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("currentLength: " + currentLength);
+ }
+ // register the punctuation:
+ if (this.currentPosition.size()>0) {
+ newLength = register(currentLength, currentLength+2, (LinPosition)this.currentPosition.elementAt(this.currentPosition.size()-1), restString, language);
+ } else {
+ newLength = register(currentLength, currentLength+2, new LinPosition("[]",
+ true), restString, language);
+ }
+ currentLength += newLength ;
+ } else {
+ // just cutting the </subtree> tag:
+ restString = removeSubTreeTag(restString,subtreeEnd, subtreeEnd+10);
+ }
+ }
+ subtreeEnd = Utils.indexOfNotEscaped(restString, "</subtree");
+ subtreeBegin = Utils.indexOfNotEscaped(restString, "<subtree");
+ // if (debug2)
+ // System.out.println("/subtree index: "+l2 + "<subtree"+l);
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("<-POSITION: "+subtreeBegin+" CURRLENGTH: "+currentLength
+ + "\n STRING: "+restString.substring(currentLength));
+ }
+ } //while
+ } else { //no focus, no selection enabled (why ever)
+ //that means, that all subtree tags are removed here.
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("NO SELECTION IN THE TEXT TO BE APPENDED!");
+ }
+ //cutting tags from previous focuses if any:
+ int r = Utils.indexOfNotEscaped(restString, "</subtree>");
+ while (r>-1) {
+ // check if punktualtion marks like . ! ? are at the end of a sentence:
+ if (restString.charAt(r+10)==' ')
+ restString = restString.substring(0,r)+restString.substring(r+11);
+ else
+ restString = restString.substring(0,r)+restString.substring(r+10);
+ r = Utils.indexOfNotEscaped(restString, "</subtree>");
+ }
+ r = Utils.indexOfNotEscaped(restString, "<subtree");
+ while (r>-1) {
+ int t = Utils.indexOfNotEscaped(restString, ">", r);
+ if (t<restString.length()-2)
+ restString = restString.substring(0,r)+restString.substring(t+2);
+ else
+ restString = restString.substring(0,r);
+ r = Utils.indexOfNotEscaped(restString, "<subtree");
+ }
+ }
+ // appending:
+ restString = unescapeTextFromGF(restString);
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer(restString);
+ }
+ appendedPureText = restString.replaceAll("&-","\n ");
+ //display the text if not already done in case of clickable
+ if (!clickable && doDisplay) {
+ // the text has only been pruned from markup, but still needs
+ // to be displayed
+ this.display.addToStages(appendedPureText, appendedPureText);
+ }
+ } // else: nothing to append
+ return appendedPureText;
+ }
+
+ /**
+ * Replaces a number of escaped characters by an unescaped version
+ * of the same length
+ * @param string The String with '\' as the escape character
+ * @return the same String, but with escaped characters removed
+ *
+ */
+ static String unescapeTextFromGF(String string) {
+ final String more = "\\"+">";
+ final String less = "\\"+"<";
+ //%% by daniels, linearization output will be changed drastically
+ //(or probably will), so for now some hacks for -> and >=
+ string = Utils.replaceAll(string, "-" + more, "-> ");
+ string = Utils.replaceAll(string, "-" + more,"-> ");
+ string = Utils.replaceAll(string, more," >");
+ string = Utils.replaceAll(string, less," <");
+ //an escaped \ becomes a single \
+ string = Utils.replaceAll(string, "\\\\"," \\");
+ return string;
+ }
+
+
+
+ /**
+ * The substring from start to end in workingString, together with
+ * position is saved as a MarkedArea in this.htmlOutputVector.
+ * The information from where to where the to be created MarkedArea
+ * extends, is calculated in this method.
+ * @param start The position of the first character in workingString
+ * of the part, that is to be registered.
+ * @param end The position of the last character in workingString
+ * of the part, that is to be registered.
+ * @param position the position in the tree that corresponds to
+ * the to be registered text
+ * @param workingString the String from which the displayed
+ * characters are taken from
+ * @param language the current linearization language
+ * @return newLength, the difference between end and start
+ */
+ private int register(int start, int end, LinPosition position, String workingString, String language) {
+ /**
+ * the length of the piece of text that is to be appended now
+ */
+ final int newLength = end-start;
+ // the tag has some words to register:
+ if (newLength>0) {
+ final String stringToAppend = workingString.substring(start,end);
+ //if (stringToAppend.trim().length()>0) {
+
+ //get oldLength and add the new text
+ String toAdd = unescapeTextFromGF(stringToAppend);
+ final MarkedArea hma = this.display.addAsMarked(toAdd, position, language);
+ this.htmlOutputVector.add(hma);
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("HTML added : " + hma);
+ }
+ } //some words to register
+ return newLength;
+ }
+
+ /**
+ * removing subtree-tag in the interval start-end
+ * and updating the coordinates after that
+ * basically part of appendMarked
+ * No subtree is removed, just the tag.
+ * @param s The String in which the subtree tag should be removed
+ * @param start position in restString
+ * @param end position in restString
+ * @return the String without the subtree-tags in the given interval
+ */
+ private String removeSubTreeTag (final String s, final int start, final int end) {
+ String restString = s;
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("removing: "+ start +" to "+ end);
+ }
+ int difference =end-start+1;
+ int positionStart, positionEnd;
+ if (difference>20) {
+ positionStart = Utils.indexOfNotEscaped(restString, "[", start);
+ positionEnd = Utils.indexOfNotEscaped(restString, "]", start);
+
+ currentPosition.addElement(new LinPosition(
+ restString.substring(positionStart, positionEnd+1),
+ restString.substring(start,end).indexOf("incorrect")==-1));
+ } else if (currentPosition.size()>0) {
+ currentPosition.removeElementAt(currentPosition.size()-1);
+ }
+ if (start>0) {
+ restString = restString.substring(0,start)+restString.substring(end+1);
+ } else{
+ restString = restString.substring(end+1);
+ }
+ return restString;
+ }
+
+ /**
+ * Goes through the list of MarkedAreas and creates MarkedAreaHighlightingStatus
+ * objects for them, which contain fields for incorrect constraints
+ * and if they belong to the selected subtree.
+ * @param focusPosition The AST position of the selected node
+ * @return a Vector of MarkedAreaHighlightingStatus
+ */
+ Vector calculateHighlights(LinPosition focusPosition) {
+ Vector result = new Vector();
+ final HashSet incorrectMA = new HashSet();
+ for (int i = 0; i<htmlOutputVector.size(); i++) {
+ final MarkedArea ma = (MarkedArea)this.htmlOutputVector.elementAt(i);
+ //check, if and how ma should be highlighted
+ boolean incorrect = false;
+ boolean focused = false;
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("Highlighting: " + ma);
+ }
+ if (!ma.position.correctPosition) {
+ incorrectMA.add(ma);
+ incorrect = true;
+ } else {
+ //This could be quadratic, but normally on very
+ //few nodes constraints are introduced, so
+ //incorrectMA should not contain many elements.
+ MarkedArea incMA;
+ for (Iterator it = incorrectMA.iterator(); !incorrect && it.hasNext();) {
+ incMA = (MarkedArea)it.next();
+ if (LinPosition.isSubtreePosition(incMA.position, ma.position)) {
+ incorrect = true;
+ }
+ }
+ }
+ if (LinPosition.isSubtreePosition(focusPosition, ma.position)) {
+ focused = true;
+ }
+ MarkedAreaHighlightingStatus mahs = new MarkedAreaHighlightingStatus(focused, incorrect, ma);
+ result.add(mahs);
+ }
+ return result;
+ }
+
+ /**
+ * Parses the linearization XML and calls outputAppend
+ * @param langMan The LangMenuModel, but that is an inner class and only
+ * the methods in the Interface LanguageManager are used here.
+ */
+ void parseLin(LanguageManager langMan) {
+ linearizations.clear();
+ boolean firstLin=true;
+ //read first line like ' <lin lang=Abstract>'
+ String readResult = linearization.substring(0,linearization.indexOf('\n'));
+ //the rest of the linearizations
+ String lin = linearization.substring(linearization.indexOf('\n')+1);
+ //extract the language from readResult
+ int ind = Utils.indexOfNotEscaped(readResult, "=");
+ int ind2 = Utils.indexOfNotEscaped(readResult, ">");
+ /** The language of the linearization */
+ String language = readResult.substring(ind+1,ind2);
+ //the first direct linearization
+ readResult = lin.substring(0,lin.indexOf("</lin>"));
+ //the rest
+ lin = lin.substring(lin.indexOf("</lin>"));
+ while (readResult.length()>1) {
+ langMan.add(language,true);
+ // selected?
+ boolean visible = langMan.isLangActive(language);
+ if (visible && !firstLin) {
+ // appending sth. linearizationArea
+ this.display.addToStages("\n************\n", "<br><hr><br>");
+ }
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("linearization for the language: "+readResult);
+ }
+
+ // change the focus tag into a subtree tag.
+ // focus handling now happens in GFEditor2::formTree
+ String readLin = readResult;
+ readLin = Utils.replaceNotEscaped(readLin, "<focus", "<subtree");
+ readLin = Utils.replaceNotEscaped(readLin, "</focus", "</subtree");
+
+ final boolean isAbstract = "Abstract".equals(language);
+ // now do appending and registering
+ String linResult = appendMarked(readLin + '\n', !isAbstract, visible, language);
+
+ if (visible) {
+ firstLin = false;
+ }
+ linearizations.put(language, linResult);
+ // read </lin>
+ lin = lin.substring(lin.indexOf('\n')+1);
+ // read lin or 'end'
+ if (lin.length()<1) {
+ break;
+ }
+
+ readResult = lin.substring(0,lin.indexOf('\n'));
+ lin = lin.substring(lin.indexOf('\n')+1);
+ if (readResult.indexOf("<lin ")!=-1){
+ //extract the language from readResult
+ ind = readResult.indexOf('=');
+ ind2 = readResult.indexOf('>');
+ language = readResult.substring(ind+1,ind2);
+ readResult = lin.substring(0,lin.indexOf("</lin>"));
+ lin = lin.substring(lin.indexOf("</lin>"));
+ }
+ }
+ }
+
+ /**
+ *
+ * @param language The concrete language of choice
+ * @return The linearization of the subtree starting with the currently
+ * selected node in the given language.
+ */
+ String getSelectedLinearization(final String language, final LinPosition focusPosition) {
+ StringBuffer sel = new StringBuffer();
+ for (int i = 0; i<htmlOutputVector.size(); i++) {
+ final MarkedArea ma = (MarkedArea)htmlOutputVector.elementAt(i);
+ if (language.equals(ma.language) && LinPosition.isSubtreePosition(focusPosition, ma.position)) {
+ sel.append(ma.words);
+ }
+ }
+ return sel.toString();
+ }
+
+ /**
+ * Takes the index of a caret position in the linearization area
+ * and returns the language of the clicked linearization.
+ * GF lists the different concrete languages one after the other,
+ * and this method looks at the linearization snipplets to get
+ * the language.
+ * If somehow no language can be found out, 'Abstract' is returned
+ * @param pos The index of the caret position
+ * @param htmlClicked If the HTML JTextPane has been clicked,
+ * false for the JTextArea
+ * @return the name of the concrete grammar (language) or Abstract
+ * (see above).
+ */
+ String getLanguageForPos(int pos, final boolean htmlClicked) {
+ final String language;
+ MarkedArea ma = null;
+ if (htmlClicked) {
+ //HTML
+ for (int i = 0; i < htmlOutputVector.size(); i++) {
+ if ((pos >= ((MarkedArea)htmlOutputVector.get(i)).htmlBegin) && (pos <= ((MarkedArea)htmlOutputVector.get(i)).htmlEnd)) {
+ ma = (MarkedArea)htmlOutputVector.get(i);
+ break;
+ }
+ }
+ } else {
+ //assumably pure text
+ for (int i = 0; i < htmlOutputVector.size(); i++) {
+ if ((pos >= ((MarkedArea)htmlOutputVector.get(i)).begin) && (pos <= ((MarkedArea)htmlOutputVector.get(i)).end)) {
+ ma = (MarkedArea)htmlOutputVector.get(i);
+ break;
+ }
+ }
+
+ }
+ if (ma != null && ma.language != null) {
+ language = ma.language;
+ } else {
+ language = "Abstract";
+ }
+ return language;
+ }
+
+ /**
+ * The user has either just clicked in the linearization area,
+ * which means start == end, or he has selected a text, so that
+ * start < end.
+ * This method figures out the smallest subtree whose linearization
+ * completely encompasses the area from start to end.
+ * This method is for the HTML linearization area.
+ * @param start The index of the caret position at the begin of the selection
+ * @param end The index of the caret position at the end of the selection
+ * @return The 'root' of the subtree described above
+ */
+ String markedAreaForPosHtml(int start, int end) {
+ if (htmlOutputVector.isEmpty()) {
+ return null;
+ }
+ String position = null; //the result
+ String jPosition ="", iPosition="";
+ MarkedArea jElement = null;
+ MarkedArea iElement = null;
+ int j = 0;
+ int i = htmlOutputVector.size()-1;
+
+ if (logger.isLoggable(Level.FINER))
+ for (int k=0; k < htmlOutputVector.size(); k++) {
+ logger.finer("element: "+k+" begin "+((MarkedArea)htmlOutputVector.elementAt(k)).htmlBegin+" "
+ + "\n-> end: "+((MarkedArea)htmlOutputVector.elementAt(k)).htmlEnd+" "
+ + "\n-> position: "+(((MarkedArea)htmlOutputVector.elementAt(k)).position).position+" "
+ + "\n-> words: "+((MarkedArea)htmlOutputVector.elementAt(k)).words);
+ }
+ // localizing end:
+ while ((j < htmlOutputVector.size()) && (((MarkedArea)htmlOutputVector.elementAt(j)).htmlEnd < end)) {
+ j++;
+ }
+ // localising start:
+ while ((i >= 0) && (((MarkedArea)htmlOutputVector.elementAt(i)).htmlBegin > start)) {
+ i--;
+ }
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("i: "+i+" j: "+j);
+ }
+ if ((j < htmlOutputVector.size())) {
+ jElement = (MarkedArea)htmlOutputVector.elementAt(j);
+ jPosition = jElement.position.position;
+ // less & before:
+ if (i == -1) { // less:
+ if (end>=jElement.htmlBegin) {
+ iElement = (MarkedArea)htmlOutputVector.elementAt(0);
+ iPosition = iElement.position.position;
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("Less: "+jPosition+" and "+iPosition);
+ }
+ position = findMax(0,j);
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("SELECTEDTEXT: "+position+"\n");
+ }
+ } else { // before:
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("BEFORE vector of size: "+htmlOutputVector.size());
+ }
+ }
+ } else { // just:
+ iElement = (MarkedArea)htmlOutputVector.elementAt(i);
+ iPosition = iElement.position.position;
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("SELECTED TEXT Just: "+iPosition +" and "+jPosition+"\n");
+ }
+ position = findMax(i,j);
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("SELECTEDTEXT: "+position+"\n");
+ }
+ }
+ } else if (i>=0) { // more && after:
+ iElement = (MarkedArea)htmlOutputVector.elementAt(i);
+ iPosition = iElement.position.position;
+ // more
+ if (start<=iElement.htmlEnd) {
+ jElement = (MarkedArea)htmlOutputVector.elementAt(htmlOutputVector.size()-1);
+ jPosition = jElement.position.position;
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("MORE: "+iPosition+ " and "+jPosition);
+ }
+ position = findMax(i,htmlOutputVector.size()-1);
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("SELECTEDTEXT: "+position+"\n");
+ }
+ // after:
+ } else if (logger.isLoggable(Level.FINER)) {
+ logger.finer("AFTER vector of size: "+htmlOutputVector.size());
+ }
+ } else { // bigger:
+ iElement = (MarkedArea)htmlOutputVector.elementAt(0);
+ iPosition = iElement.position.position;
+ jElement = (MarkedArea)htmlOutputVector.elementAt(htmlOutputVector.size()-1);
+ jPosition = jElement.position.position;
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("BIGGER: "+iPosition +" and "+jPosition+"\n"
+ + "\n-> SELECTEDTEXT: []\n");
+ }
+ position = "[]";
+ }
+ return position;
+ }
+
+ /**
+ * The user has either just clicked in the linearization area,
+ * which means start == end, or he has selected a text, so that
+ * start < end.
+ * This method figures out the smallest subtree whose linearization
+ * completely encompasses the area from start to end.
+ * This method is for the pure text linearization area.
+ * @param start The index of the caret position at the begin of the selection
+ * @param end The index of the caret position at the end of the selection
+ * @return The 'root' of the subtree described above
+ */
+ String markedAreaForPosPureText(int start, int end) {
+ if (htmlOutputVector.isEmpty()) {
+ return null;
+ }
+ //the result
+ String position = null;
+ //variables for confining the searched MarkedArea from
+ //start and end (somehow ...)
+ int j = 0;
+ int i = htmlOutputVector.size() - 1;
+ String jPosition ="", iPosition="";
+ MarkedArea jElement = null;
+ MarkedArea iElement = null;
+
+ if (logger.isLoggable(Level.FINER))
+ for (int k = 0; k < htmlOutputVector.size(); k++) {
+ logger.finer("element: " + k + " begin " + ((MarkedArea)htmlOutputVector.elementAt(k)).begin + " "
+ + "\n-> end: " + ((MarkedArea)htmlOutputVector.elementAt(k)).end+" "
+ + "\n-> position: " + (((MarkedArea)htmlOutputVector.elementAt(k)).position).position+" "
+ + "\n-> words: " + ((MarkedArea)htmlOutputVector.elementAt(k)).words);
+ }
+ // localizing end:
+ while ((j < htmlOutputVector.size()) && (((MarkedArea)htmlOutputVector.elementAt(j)).end < end)) {
+ j++;
+ }
+ // localising start:
+ while ((i >= 0) && (((MarkedArea)htmlOutputVector.elementAt(i)).begin > start))
+ i--;
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("i: " + i + " j: " + j);
+ }
+ if ((j < htmlOutputVector.size())) {
+ jElement = (MarkedArea)htmlOutputVector.elementAt(j);
+ jPosition = jElement.position.position;
+ // less & before:
+ if (i==-1) { // less:
+ if (end>=jElement.begin) {
+ iElement = (MarkedArea)htmlOutputVector.elementAt(0);
+ iPosition = iElement.position.position;
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("Less: "+jPosition+" and "+iPosition);
+ }
+ position = findMax(0,j);
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("SELECTEDTEXT: "+position+"\n");
+ }
+ } else if (logger.isLoggable(Level.FINER)) { // before:
+ logger.finer("BEFORE vector of size: " + htmlOutputVector.size());
+ }
+ } else { // just:
+ iElement = (MarkedArea)htmlOutputVector.elementAt(i);
+ iPosition = iElement.position.position;
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("SELECTED TEXT Just: "+iPosition +" and "+jPosition+"\n");
+ }
+ position = findMax(i,j);
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("SELECTEDTEXT: "+position+"\n");
+ }
+ }
+ } else if (i>=0) { // more && after:
+ iElement = (MarkedArea)htmlOutputVector.elementAt(i);
+ iPosition = iElement.position.position;
+ // more
+ if (start<=iElement.end) {
+ jElement = (MarkedArea)htmlOutputVector.elementAt(htmlOutputVector.size() - 1);
+ jPosition = jElement.position.position;
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("MORE: "+iPosition+ " and "+jPosition);
+ }
+ position = findMax(i, htmlOutputVector.size()-1);
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("SELECTEDTEXT: "+position+"\n");
+ }
+ } else if (logger.isLoggable(Level.FINER)) { // after:
+ logger.finer("AFTER vector of size: " + htmlOutputVector.size());
+ }
+ } else {
+ // bigger:
+ iElement = (MarkedArea)htmlOutputVector.elementAt(0);
+ iPosition = iElement.position.position;
+ jElement = (MarkedArea)htmlOutputVector.elementAt(htmlOutputVector.size()-1);
+ jPosition = jElement.position.position;
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("BIGGER: "+iPosition +" and "+jPosition+"\n"
+ + "\n-> SELECTEDTEXT: []\n");
+ }
+ position = "[]";
+ }
+ return position;
+ }
+
+}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/LinkCommand.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/LinkCommand.java
index b4af88d4f..fb12c79b7 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/LinkCommand.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/LinkCommand.java
@@ -23,6 +23,14 @@ package de.uka.ilkd.key.ocl.gf;
*/
public class LinkCommand extends GFCommand {
+ /**
+ * Since LinkCommand is not a real command, that is sent to GF,
+ * most fields are given dummy values here.
+ * The subcat is assigned its full display name and tooltip
+ * @param subcat The subcategory of the menu behind this command
+ * @param manager The PrintnameManager, that can map subcat to its
+ * full name
+ */
public LinkCommand(final String subcat, final PrintnameManager manager) {
this.command = subcat;
this.newSubcat = false;
@@ -46,20 +54,30 @@ public class LinkCommand extends GFCommand {
}
- /**the text that is to be displayed as the tooltip */
+ /**
+ * the text that is to be displayed as the tooltip
+ */
protected final String tooltipText;
- /**the text that is to be displayed as the tooltip */
+ /**
+ * the text that is to be displayed as the tooltip
+ */
public String getTooltipText() {
return tooltipText;
}
- /** the text that is to be displayed in the refinement lists */
+ /**
+ * the text that is to be displayed in the refinement lists
+ */
protected final String displayText;
- /** the text that is to be displayed in the refinement lists */
+ /**
+ * the text that is to be displayed in the refinement lists
+ */
public String getDisplayText() {
return displayText;
}
- /** the subcategory of this command */
+ /**
+ * the subcategory of this command
+ */
public String getSubcat() {
return this.command;
}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/MarkedArea.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/MarkedArea.java
index ec53847d8..0f4422978 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/MarkedArea.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/MarkedArea.java
@@ -20,7 +20,7 @@ package de.uka.ilkd.key.ocl.gf;
* and an end in the linearization area and a position in the AST. It is used
* for clicking in the text
*
- * @author janna
+ * @author janna, daniels
*/
class MarkedArea {
/**
@@ -46,24 +46,39 @@ class MarkedArea {
* this MarkedArea belongs to
*/
final public String language;
+
+ /**
+ * the start index in the HTML area
+ */
+ final public int htmlBegin;
+ /**
+ * the end index in the HTML area
+ */
+ final public int htmlEnd;
+
/**
- * Creates a new MarkedArea and initializes the fields with the parameters
- * @param b The starting position of the stored words
- * @param e The ending position of the stored words
- * @param p The position in the AST
- * @param w The actual text of this area
- * @param lang the language of the current linearization
+ * A stand-alone constuctor which takes all values as arguments
+ * @param begin The starting position of the stored words
+ * @param end The ending position of the stored words
+ * @param position The position in the AST
+ * @param words The actual text of this area
+ * @param htmlBegin the start index in the HTML area
+ * @param htmlEnd the end index in the HTML area
+ * @param language the language of the current linearization
*/
- MarkedArea(int b, int e, LinPosition p, String w, String lang) {
- begin = b;
- end = e;
- position = p;
- words = w;
- language = lang;
+ public MarkedArea(int begin, int end, LinPosition position, String words, int htmlBegin, int htmlEnd, String language) {
+ this.begin = begin;
+ this.end = end;
+ this.position = position;
+ this.words = words;
+ this.language = language;
+ this.htmlBegin = htmlBegin;
+ this.htmlEnd = htmlEnd;
}
+
public String toString() {
- return begin + " - " + end + " : " + position + " = '" + words + "'";
+ return begin + " - " + end + " : " + position + " = '" + words + "' ; HTML: " + htmlBegin + " - " + htmlEnd;
}
}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/MarkedAreaHighlightingStatus.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/MarkedAreaHighlightingStatus.java
new file mode 100644
index 000000000..f2c712a75
--- /dev/null
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/MarkedAreaHighlightingStatus.java
@@ -0,0 +1,48 @@
+//Copyright (c) Hans-Joachim Daniels 2005
+//
+//This program is free software; you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation; either version 2 of the License, or
+//(at your option) any later version.
+//
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU General Public License for more details.
+//
+//You can either finde the file LICENSE or LICENSE.TXT in the source
+//distribution or in the .jar file of this application
+
+package de.uka.ilkd.key.ocl.gf;
+
+/**
+ * Stores a MarkedArea together with some status fields, which tell
+ * how it should get highlighted.
+ * No direct highlighting stuff in here, that's done in GFEditor2
+ * @author daniels
+ */
+class MarkedAreaHighlightingStatus {
+ /**
+ * The MarkedArea, which contains the highlighting information
+ */
+ final MarkedArea ma;
+ /**
+ * whether this MarkedArea is a subnode of the currently focused node
+ */
+ final boolean focused;
+ /**
+ * whether this MarkedArea has (inherited) a GF constraint
+ */
+ final boolean incorrect;
+ /**
+ * Initializes this immutable record class
+ * @param focused whether this MarkedArea is a subnode of the currently focused node
+ * @param incorrect whether this MarkedArea has (inherited) a GF constraint
+ * @param ma The MarkedArea, which contains the highlighting information
+ */
+ public MarkedAreaHighlightingStatus(boolean focused, boolean incorrect, MarkedArea ma) {
+ this.focused = focused;
+ this.incorrect = incorrect;
+ this.ma = ma;
+ }
+}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/NewCategoryMenuResult.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/NewCategoryMenuResult.java
new file mode 100644
index 000000000..44880a00a
--- /dev/null
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/NewCategoryMenuResult.java
@@ -0,0 +1,57 @@
+//Copyright (c) Hans-Joachim Daniels 2005
+//
+//This program is free software; you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation; either version 2 of the License, or
+//(at your option) any later version.
+//
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU General Public License for more details.
+//
+//You can either finde the file LICENSE or LICENSE.TXT in the source
+//distribution or in the .jar file of this application
+
+package de.uka.ilkd.key.ocl.gf;
+
+/**
+ * GF sends the new menu as XML.
+ * After this has been parsed by GfCapsule, it is sent in this representation
+ * to GFEditor2.
+ * @author daniels
+ *
+ */
+class NewCategoryMenuResult {
+ /**
+ * The actual entries of the newMenu
+ */
+ final String[] menuContent;
+ /**
+ * The languages, that GF sent
+ */
+ final String[] languages;
+ /**
+ * the constituents of the import path?
+ */
+ final String[] paths;
+ /**
+ * the name of the abstract grammar, also called topic
+ */
+ final String grammarName;
+
+ /**
+ * Just sets the attributes of this class
+ * @param grammarName the name of the abstract grammar, also called topic
+ * @param menuContent The actual entries of the newMenu
+ * @param languages The languages, that GF sent
+ * @param paths the constituents of the import path?
+ */
+ public NewCategoryMenuResult(String grammarName, String[] menuContent, String[] languages, String paths[]) {
+ this.grammarName = grammarName;
+ this.menuContent = menuContent;
+ this.languages = languages;
+ this.paths = paths;
+ }
+
+}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Printname.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Printname.java
index 774566e7e..68feb6dd9 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Printname.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Printname.java
@@ -34,12 +34,31 @@ import java.util.logging.*;
* HTML can be used inside the descriptions and the tooltip text
*/
class Printname {
- protected static Logger subcatLogger = Logger.getLogger(Printname.class.getName());
+ private static Logger subcatLogger = Logger.getLogger(Printname.class.getName());
- public static final Printname delete = new Printname("d", "delete current sub-tree");
- public static final Printname addclip = new Printname("ac", "add to clipboard\\$<html>adds the current subtree to the clipboard.<br>It is offered in the refinement menu if the expected type fits to the one of the current sub-tree.</html>");
- public static final Printname printhistory = new Printname("ph", "peel head\\$removes this fun and moves its first argument at its place instead");
+ /**
+ * delete is always the same and only consists of one letter, therefore static.
+ */
+ public static final Printname delete = new Printname("d", "delete current sub-tree", false);
+ /**
+ * The ac command i always the same, therefore static
+ */
+ public static final Printname addclip = new Printname("ac", "add to clipboard\\$<html>adds the current subtree to the clipboard.<br>It is offered in the refinement menu if the expected type fits to the one of the current sub-tree.</html>", false);
+
+ /**
+ * @param arg The number of the argument,
+ * that will take the place of the selected fun
+ * @return a Printname for the 'ph arg' command
+ */
+ public static Printname peelHead(int arg) {
+ final String cmd = "ph " + arg;
+ final String show = "peel head " + arg + "\\$removes this fun and moves its " + (arg + 1) + ". argument at its place instead";
+ return new Printname(cmd, show, true);
+ }
+ /**
+ * the type of the fun behind that printname (if applicable)
+ */
protected final String type;
/**
@@ -61,18 +80,26 @@ class Printname {
* The string that is followed by a new parameter to the GF function
*/
public final static String PARAM = "\\#";
+ /**
+ * If that follows "\#" in the parameter descriptions, then do an
+ * auto-coerce when this param is meta and selected
+ */
+ public final static String AUTO_COERCE = "!";
-
- /** the name of the fun that is used in this command */
+ /**
+ * the name of the fun that is used in this command
+ */
protected final String fun;
- /** the printname of this function */
+ /**
+ * the printname of this function
+ */
protected final String printname;
- /** to cache the printname, once it is constructed */
+ /**
+ * to cache the printname, once it is constructed
+ */
protected String displayedPrintname = null;
-
-
/**
* the name of the module the fun belongs to
* null means that the function is saved without module information,
@@ -100,9 +127,13 @@ class Printname {
}
*/
- /** the subcategory of this command */
+ /**
+ * the subcategory of this command
+ */
protected final String subcat;
- /** the subcategory of this command */
+ /**
+ * the subcategory of this command
+ */
public String getSubcat() {
return subcat;
}
@@ -131,7 +162,7 @@ class Printname {
public String getParamName(int n) {
String name = null;
try {
- name = (String)this.paramNames.get(n);
+ name = (String)this.paramNames.get(n);
} catch (ArrayIndexOutOfBoundsException e) {
subcatLogger.fine(e.getLocalizedMessage());
}
@@ -143,6 +174,26 @@ class Printname {
*/
protected final Vector paramTexts = new Vector();
+ /**
+ * tells, whether the nth parameter should be auto-coerced
+ * @param n the number of the parameter in question
+ * @return whether the nth parameter should be auto-coerced
+ */
+ public boolean getParamAutoCoerce(int n) {
+ boolean result = false;
+ try {
+ result = ((Boolean)this.paramAutoCoerce.get(n)).booleanValue();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ subcatLogger.fine(e.getLocalizedMessage());
+ }
+ return result;
+ }
+
+ /**
+ * stores for the parameters whether they should be auto-coerced or not.
+ * parallel with paramNames
+ */
+ protected final Vector paramAutoCoerce = new Vector();
/**
* Creates a Printname for a normal GF function
@@ -166,81 +217,88 @@ class Printname {
} else {
this.funPresent = false;
}
-
+
//parse the fun name
{
- int index = myFun.indexOf('.');
- if (index > -1) {
- //a valid fun name must not be empty
- this.fun = myFun.substring(index + 1);
- this.module = myFun.substring(0, index);
- } else {
- this.fun = myFun;
- this.module = null;
- }
+ int index = myFun.indexOf('.');
+ if (index > -1) {
+ //a valid fun name must not be empty
+ this.fun = myFun.substring(index + 1);
+ this.module = myFun.substring(0, index);
+ } else {
+ this.fun = myFun;
+ this.module = null;
+ }
}
//parse the parameters and cut that part
{
- int index = Utils.indexOfNotEscaped(myPrintname, PARAM);
- if (index > -1) {
- String paramPart = myPrintname.substring(index);
- String splitString;
- //split takes a regexp as an argument. So we have to escape the '\' again.
- if (PARAM.startsWith("\\")) {
- splitString = "\\" + PARAM;
- } else {
- splitString = PARAM;
- }
- String[] params = paramPart.split(splitString);
- //don't use the first split part, since it's empty
- for (int i = 1; i < params.length; i++) {
- String current = params[i];
- int nameEnd = current.indexOf(' ');
- int nameEnd2 = Utils.indexOfNotEscaped(current, PARAM);
- if (nameEnd == -1) {
- nameEnd = current.length();
- }
- String name = current.substring(0, nameEnd);
- String description;
- if (nameEnd < current.length() - 1) {
- description = current.substring(nameEnd + 1).trim();
+ int index = Utils.indexOfNotEscaped(myPrintname, PARAM);
+ if (index > -1) {
+ String paramPart = myPrintname.substring(index);
+ String splitString;
+ //split takes a regexp as an argument. So we have to escape the '\' again.
+ if (PARAM.startsWith("\\")) {
+ splitString = "\\" + PARAM;
} else {
- description = "";
+ splitString = PARAM;
}
- this.paramNames.addElement(name);
- this.paramTexts.addElement(description);
+ String[] params = paramPart.split(splitString);
+ //don't use the first split part, since it's empty
+ for (int i = 1; i < params.length; i++) {
+ String current = params[i];
+ boolean autocoerce = false;
+ if (AUTO_COERCE.equals(current.substring(0,1))) {
+ autocoerce = true;
+ //cut the !
+ current = current.substring(1);
+ }
+ int nameEnd = current.indexOf(' ');
+ int nameEnd2 = Utils.indexOfNotEscaped(current, PARAM);
+ if (nameEnd == -1) {
+ nameEnd = current.length();
+ }
+ String name = current.substring(0, nameEnd);
+ String description;
+ if (nameEnd < current.length() - 1) {
+ description = current.substring(nameEnd + 1).trim();
+ } else {
+ description = "";
+ }
+ this.paramNames.addElement(name);
+ this.paramTexts.addElement(description);
+ this.paramAutoCoerce.addElement(new Boolean(autocoerce));
+ }
+ myPrintname = myPrintname.substring(0, index);
}
- myPrintname = myPrintname.substring(0, index);
- }
}
//extract the subcategory part and cut that part
{
- int index = Utils.indexOfNotEscaped(myPrintname, SUBCAT);
- if (index > -1) {
- String subcatPart = myPrintname.substring(index);
- myPrintname = myPrintname.substring(0, index);
- int indFull = subcatPart.indexOf('{');
- if (indFull > -1) {
- int indFullEnd = subcatPart.indexOf('}', indFull + 1);
- if (indFullEnd == -1) {
- indFullEnd = subcatPart.length();
- }
- String fullName = subcatPart.substring(indFull + 1, indFullEnd);
- this.subcat = subcatPart.substring(0, indFull).trim();
- this.subcatNameHashtable.put(this.subcat, fullName);
- if (subcatLogger.isLoggable(Level.FINER)) {
- subcatLogger.finer("new fullname '" + fullName + "' for category (shortname) '" + this.subcat + "'");
+ int index = Utils.indexOfNotEscaped(myPrintname, SUBCAT);
+ if (index > -1) {
+ String subcatPart = myPrintname.substring(index);
+ myPrintname = myPrintname.substring(0, index);
+ int indFull = subcatPart.indexOf('{');
+ if (indFull > -1) {
+ int indFullEnd = subcatPart.indexOf('}', indFull + 1);
+ if (indFullEnd == -1) {
+ indFullEnd = subcatPart.length();
+ }
+ String fullName = subcatPart.substring(indFull + 1, indFullEnd);
+ this.subcat = subcatPart.substring(0, indFull).trim();
+ this.subcatNameHashtable.put(this.subcat, fullName);
+ if (subcatLogger.isLoggable(Level.FINER)) {
+ subcatLogger.finer("new fullname '" + fullName + "' for category (shortname) '" + this.subcat + "'");
+ }
+ } else {
+ subcat = subcatPart.trim();
}
+
} else {
- subcat = subcatPart.trim();
+ this.subcat = null;
}
-
- } else {
- this.subcat = null;
- }
}
}
@@ -249,15 +307,17 @@ class Printname {
* like d, ph, ac
* @param command the GF command
* @param explanation an explanatory text what this command does
+ * @param funPresent If explanation already contains the fun.
+ * If true, the fun won't be printed in the refinement menu.
*/
- protected Printname(String command, String explanation) {
+ protected Printname(String command, String explanation, boolean funPresent) {
this.fun = command;
this.subcatNameHashtable = null;
this.subcat = null;
this.module = "";
this.printname = explanation;
this.type = null;
- this.funPresent = false;
+ this.funPresent = funPresent;
}
/**
@@ -276,7 +336,9 @@ class Printname {
this.funPresent = false;
}
- /** the text that is to be displayed in the refinement lists */
+ /**
+ * the text that is to be displayed in the refinement lists
+ */
public String getDisplayText() {
String result;
result = extractDisplayText(this.printname);
@@ -376,7 +438,12 @@ class Printname {
* @return the aforementioned result.
*/
public static String htmlAppend(String original, String insertion) {
- StringBuffer result = new StringBuffer(original);
+ StringBuffer result;
+ if (original != null) {
+ result = new StringBuffer(original);
+ } else {
+ result = new StringBuffer();
+ }
int htmlindex = result.indexOf("</html>");
if (htmlindex > -1) {
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/PrintnameLoader.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/PrintnameLoader.java
index 842a72eeb..2cf5e9daa 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/PrintnameLoader.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/PrintnameLoader.java
@@ -15,8 +15,6 @@
package de.uka.ilkd.key.ocl.gf;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
import java.io.IOException;
import java.util.Hashtable;
import java.util.logging.*;
@@ -26,20 +24,30 @@ import java.util.logging.*;
* the suiting Printname objects.
*/
public class PrintnameLoader extends AbstractProber {
- protected final PrintnameManager printnameManager;
- protected final static Logger nogger = Logger.getLogger(Printname.class.getName());
- protected final Hashtable funTypes = new Hashtable();
- protected final boolean loadTypes;
+ private final static Logger nogger = Logger.getLogger(Printname.class.getName());
/**
- * @param fromGf The GF process
- * @param toGf The GF process
+ * The PrintnameManager on which the read Printnames
+ * will be registered with their fun name.
+ */
+ private final PrintnameManager printnameManager;
+ /**
+ * Here, the funs with their types get stored
+ */
+ private final Hashtable funTypes = new Hashtable();
+ /**
+ * if the Printnames should have their type appended to their display names
+ */
+ private final boolean loadTypes;
+ /**
+ * an initializing constructor, does nothing except setting fields
+ * @param gfCapsule the read/write encapsulation of GF
* @param pm The PrintnameManager on which the read Printnames
* will be registered with their fun name.
* @param withTypes true iff the Printnames should have their type
* appended to their display names
*/
- public PrintnameLoader(BufferedReader fromGf, BufferedWriter toGf, PrintnameManager pm, boolean withTypes) {
- super(fromGf, toGf);
+ public PrintnameLoader(GfCapsule gfCapsule, PrintnameManager pm, boolean withTypes) {
+ super(gfCapsule);
this.printnameManager = pm;
this.loadTypes = withTypes;
}
@@ -50,7 +58,7 @@ public class PrintnameLoader extends AbstractProber {
*/
protected void readMessage() {
try {
- String result = this.fromProc.readLine();
+ String result = gfCapsule.fromProc.readLine();
if (nogger.isLoggable(Level.FINER)) {
nogger.finer("1 " + result);
}
@@ -59,11 +67,11 @@ public class PrintnameLoader extends AbstractProber {
result = result.trim();
if (result.startsWith("printname fun ")) {
//unescape backslashes. Probably there are more
- result = GFEditor2.unescapeTextFromGF(result);
+ result = Linearization.unescapeTextFromGF(result);
this.printnameManager.addNewPrintnameLine(result, this.funTypes);
}
- result = this.fromProc.readLine();
+ result = gfCapsule.fromProc.readLine();
if (nogger.isLoggable(Level.FINER)) {
nogger.finer("1 " + result);
}
@@ -84,10 +92,10 @@ public class PrintnameLoader extends AbstractProber {
* @param lang The module for which the grammars should be printed.
* If lang is "" or null, the last read grammar module is used.
*/
- public void readPrintnames(String lang) {
+ protected void readPrintnames(String lang) {
//before, we want the types to be read.
if (this.loadTypes) {
- TypesLoader tl = new TypesLoader(fromProc, toProc, this.funTypes);
+ TypesLoader tl = new TypesLoader(gfCapsule, this.funTypes);
tl.readTypes();
}
//prints the printnames of the last loaded grammar,
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/PrintnameManager.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/PrintnameManager.java
index 23c058a12..685dcf000 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/PrintnameManager.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/PrintnameManager.java
@@ -25,7 +25,24 @@ import java.util.logging.*;
* counterpart is done here.
*/
class PrintnameManager {
- protected static Logger logger = Logger.getLogger(Printname.class.getName());
+ /**
+ * This constructor is a bit of a hack.
+ * It puts the \%SELF subcat into this.printnames.
+ * This subcat does not appear in the grammars and thus is
+ * introduced here. If it is defined there although, this
+ * definition is used. So it does not hurt.
+ */
+ public PrintnameManager() {
+ this.subcatNames.put(SELF_SUBCAT, "properties of self\\$shortcuts to the properties of self, that have a fitting type");
+ }
+
+ /**
+ * The name of the subcat, that is used for the easy property access
+ * of self.
+ */
+ static final String SELF_SUBCAT = "\\%SELF";
+
+ private static Logger logger = Logger.getLogger(Printname.class.getName());
protected final static String frontMatter = "printname fun ";
@@ -39,7 +56,9 @@ class PrintnameManager {
*/
protected final Hashtable subcatNames = new Hashtable();
- /** contains all the Printnames with the fun names as keys */
+ /**
+ * contains all the Printnames with the fun names as keys
+ */
protected final Hashtable printnames = new Hashtable();
/**
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/ReadDialog.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/ReadDialog.java
index 330444afb..3a0ea34f4 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/ReadDialog.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/ReadDialog.java
@@ -41,11 +41,11 @@ import java.util.logging.*;
*/
class ReadDialog implements ActionListener{
/** XML parsing debug messages */
- protected static Logger xmlLogger = Logger.getLogger(GFEditor2.class.getName() + "_XML");
+ private static Logger xmlLogger = Logger.getLogger(GFEditor2.class.getName() + "_XML");
/** The window to which this class belongs */
- protected final GFEditor2 owner;
+ private final GFEditor2 owner;
/** is the main thing of this class */
- protected final JDialog readDialog;
+ private final JDialog readDialog;
/** main area of the Read dialog (content pane)*/
private final JPanel inputPanel = new JPanel();
/** OK, Cancel, Browse in the Read dialog */
@@ -69,7 +69,7 @@ class ReadDialog implements ActionListener{
/** to select to input a String in the Read dialog */
private final JRadioButton stringReadButton = new JRadioButton("String");
/** used for new Topic, Import and Browse (readDialog) */
- protected final JFileChooser fc = new JFileChooser("./");
+ private final JFileChooser fc = new JFileChooser("./");
/**
* if a user sends a custom command to GF, he might want to do this
* again with the same command.
@@ -170,15 +170,13 @@ class ReadDialog implements ActionListener{
}
if ( obj == ok ) {
- owner.treeChanged = true;
if (termReadButton.isSelected()) {
termInput = inputField.getText();
if (termInput.indexOf(File.separatorChar)==-1){
- owner.send("g "+termInput);
+ owner.send("[t] g "+termInput);
if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("sending term string");
- }
- else {
- owner.send("tfile "+termInput);
+ } else {
+ owner.send("[t] tfile "+termInput);
if (xmlLogger.isLoggable(Level.FINER)) {
xmlLogger.finer("sending file term: "+termInput);
}
@@ -186,11 +184,11 @@ class ReadDialog implements ActionListener{
} else { //String selected
parseInput = inputField.getText();
if (parseInput.indexOf(File.separatorChar)==-1){
- owner.send("p "+parseInput);
+ owner.send("[t] p "+parseInput);
if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("sending parse string: "+parseInput);
}
else {
- owner.send("pfile "+parseInput);
+ owner.send("[t] pfile "+parseInput);
if (xmlLogger.isLoggable(Level.FINER)) xmlLogger.finer("sending file parse string: "+parseInput);
}
}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RealCommand.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RealCommand.java
index c2ba33955..8d9b4f3f8 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RealCommand.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RealCommand.java
@@ -21,13 +21,49 @@ import java.util.logging.*;
/**
* @author daniels
- * This class represents a command, that is sent to GF
+ * This class represents a command, that is sent to GF.
+ * TODO Refactor the chain command stuff out of this class and make it a subclass
*/
class RealCommand extends GFCommand {
+ /**
+ * maps shorthands to fullnames
+ */
private final static HashMap fullnames = new HashMap();
- protected final static Logger logger = Logger.getLogger(Printname.class.getName());
+ private final static Logger logger = Logger.getLogger(Printname.class.getName());
+
+ /**
+ * The number of undo steps that is needed to undo this fun call
+ */
+ public final int undoSteps;
+
+ /**
+ * The text that GF sent to describe the command
+ */
+ protected final String showText;
+
+ protected final String subcat;
+
+ /**
+ * Creates a Command that stands for a GF command, no link command
+ * sets all the attributes of this semi-immutable class.
+ * @param myCommand the actual GF command
+ * @param processedSubcats
+ * @param manager maps funs to previously read Printnames.
+ * Thus needs to be the same object.
+ * @param myShowText The text GF prints in the show part of the XML
+ * which should be the command followed by the printname
+ * @param mlAbstract is true, iff the menu language is set to Abstract
+ * Then no preloaded printnames are used.
+ * @param toAppend will be appended to the command, that is sent to GF.
+ * Normally, toAppend will be the empty String "".
+ * But it can be a chain command's second part.
+ * It will not be shown to the user.
+ */
+ public RealCommand(final String myCommand, final HashSet processedSubcats, final PrintnameManager manager, final String myShowText, final boolean mlAbstract, final String toAppend) {
+ this(myCommand, processedSubcats, manager, myShowText, mlAbstract, toAppend, 1, null, null);
+ }
/**
* Creates a Command that stands for a GF command, no link command
@@ -40,33 +76,65 @@ class RealCommand extends GFCommand {
* which should be the command followed by the printname
* @param mlAbstract is true, iff the menu language is set to Abstract
* Then no preloaded printnames are used.
+ * @param toAppend will be appended to the command, that is sent to GF.
+ * Normally, toAppend will be the empty String "".
+ * But it can be a chain command's second part.
+ * It will not be shown to the user.
+ * @param undoSteps The number of undo steps that is needed to undo this fun call
+ * @param printnameFun If the fun, that selects the printname, should not be read from
+ * myCommand. For single commands, this is the only fun. For chain command, the last is
+ * taken. With this parameter, this behaviour can be overwritten
+ * @param subcat Normally, every fun has its own Printname, which has a fixed
+ * category. Sometimes, for the properies of self for example,
+ * this should be overwritten. If null, the subcat from the printname is used.
*/
- public RealCommand(final String myCommand, final HashSet processedSubcats, final PrintnameManager manager, final String myShowText, final boolean mlAbstract) {
+ public RealCommand(final String myCommand, final HashSet processedSubcats, final PrintnameManager manager, final String myShowText, final boolean mlAbstract, String toAppend, int undoSteps, String printnameFun, String subcat) {
if (fullnames.isEmpty()) {
fullnames.put("w", "wrap");
fullnames.put("r", "refine");
fullnames.put("ch", "change head");
fullnames.put("rc", "refine from history:");
+ fullnames.put("ph", "peel head");
}
if (logger.isLoggable(Level.FINEST)) {
logger.finest("new RealCommand: " + myCommand);
}
+ //if we have a ChainCommand, but undoSteps is just 1, count the undoSteps.
+ if ((undoSteps == 1) && (myCommand.indexOf(";;") > -1)) {
+ int occ = Utils.countOccurances(Utils.removeQuotations(myCommand), ";;") + 1;
+ this.undoSteps = occ;
+ } else {
+ this.undoSteps = undoSteps;
+ }
this.command = myCommand.trim();
this.showText = myShowText;
+ this.subcat = subcat;
+
+ //handle chain commands.
+ //Only the last command counts for the printname selection
+ final String lastCommand;
+ if (this.undoSteps > 1) {
+ //TODO: sth. like refine " f ;;d" ;; mp [2] will break here.
+ final int chainIndex = this.command.lastIndexOf(";;");
+ lastCommand = this.command.substring(chainIndex + 2).trim();
+ } else {
+ lastCommand = this.command;
+ }
+
//extract command type
- int ind = this.command.indexOf(' ');
+ int ind = lastCommand.indexOf(' ');
if (ind > -1) {
- this.commandType = this.command.substring(0, ind);
+ this.commandType = lastCommand.substring(0, ind);
} else {
- this.commandType = this.command;
+ this.commandType = lastCommand;
}
//extract the argument position for wrapping commands and cut that part
- if (this.commandType.equals("w")) {
- int beforeNumber = this.command.lastIndexOf(' ');
+ if (this.commandType.equals("w") || this.commandType.equals("ph")) {
+ int beforeNumber = lastCommand.lastIndexOf(' ');
int protoarg;
try {
- String argumentAsString = this.command.substring(beforeNumber + 1);
+ String argumentAsString = lastCommand.substring(beforeNumber + 1);
protoarg = Integer.parseInt(argumentAsString);
} catch (Exception e) {
protoarg = -1;
@@ -78,17 +146,17 @@ class RealCommand extends GFCommand {
//extract the fun of the GF command
if (this.commandType.equals("w")) {
- int beforePos = this.command.indexOf(' ');
- int afterPos = this.command.lastIndexOf(' ');
+ int beforePos = lastCommand.indexOf(' ');
+ int afterPos = lastCommand.lastIndexOf(' ');
if (beforePos > -1 && afterPos > beforePos) {
- this.funName = this.command.substring(beforePos + 1, afterPos);
+ this.funName = lastCommand.substring(beforePos + 1, afterPos);
} else {
this.funName = null;
}
} else {
- int beforePos = this.command.indexOf(' ');
+ int beforePos = lastCommand.indexOf(' ');
if (beforePos > -1) {
- this.funName = this.command.substring(beforePos + 1);
+ this.funName = lastCommand.substring(beforePos + 1);
} else {
this.funName = null;
}
@@ -99,17 +167,23 @@ class RealCommand extends GFCommand {
this.printname = Printname.delete;
} else if (this.commandType.equals("ac")) {
this.printname = Printname.addclip;
- } else if (this.commandType.equals("ph")) {
- this.printname = Printname.printhistory;
} else if (this.commandType.equals("rc")) {
String subtree = this.showText.substring(3);
- this.printname = new Printname(this.getCommand(), subtree + "\\$paste the previously copied subtree here<br>" + subtree);
+ this.printname = new Printname(this.getCommand(), subtree + "\\$paste the previously copied subtree here<br>" + subtree, false);
+ } else if (this.commandType.equals("ph")) {
+ this.printname = Printname.peelHead(this.argument);
} else if (mlAbstract) {
//create a new Printname
this.printname = new Printname(funName, myShowText, null, null);
- } else {
- this.printname = manager.getPrintname(funName);
+ } else { //standard case
+ if (printnameFun == null) {
+ this.printname = manager.getPrintname(funName);
+ } else {
+ //overwrite mode. Until now, only for properties of self.
+ this.printname = manager.getPrintname(printnameFun);
+ }
}
+
if (this.getSubcat() != null) {
if (processedSubcats.contains(this.getSubcat())) {
newSubcat = false;
@@ -120,9 +194,17 @@ class RealCommand extends GFCommand {
} else {
newSubcat = false;
}
+
+ //now append toAppend before it is too late.
+ //Only now, since it must not interfere with the things above.
+ if (toAppend != null) {
+ this.command += toAppend;
+ }
}
- /** the text that is to be displayed in the refinement lists */
+ /**
+ * the text that is to be displayed in the refinement lists
+ */
public String getDisplayText() {
String result = "";
if (this.printname.funPresent) {
@@ -146,7 +228,9 @@ class RealCommand extends GFCommand {
return result;
}
- /**the text that is to be displayed as the tooltip */
+ /**
+ * the text that is to be displayed as the tooltip
+ */
public String getTooltipText() {
String result;
result = this.printname.getTooltipText();
@@ -157,9 +241,15 @@ class RealCommand extends GFCommand {
return result;
}
+ /**
+ * returns the subcat of this command
+ */
public String getSubcat() {
- return this.printname.getSubcat();
+ if (this.subcat == null) {
+ return this.printname.getSubcat();
+ } else {
+ //special case, only for properties of self so far
+ return this.subcat;
+ }
}
-
- protected final String showText;
}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RefinedAstNodeData.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RefinedAstNodeData.java
index a1bff105b..bfd526593 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RefinedAstNodeData.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RefinedAstNodeData.java
@@ -26,8 +26,6 @@ import java.util.logging.*;
class RefinedAstNodeData extends AstNodeData {
protected final Printname printname;
- protected final GfAstNode node;
- protected final String position;
/**
* all we have to know about an already refined node is its Printname
@@ -36,13 +34,15 @@ class RefinedAstNodeData extends AstNodeData {
* not be parsed
* @param node the GfAstNode for the current line
* @param pos The position in the GF AST of this node in Haskell notation
+ * @param selected if this is the selected node in the GF AST
+ * @param constraint A constraint from a parent node, that also
+ * applies for this node.
*/
- public RefinedAstNodeData(Printname pname, GfAstNode node, String pos) {
+ public RefinedAstNodeData(Printname pname, GfAstNode node, String pos, boolean selected, String constraint) {
+ super(node, pos, selected, constraint);
this.printname = pname;
- this.node = node;
- this.position = pos;
if (logger.isLoggable(Level.FINEST)) {
- logger.finest(this.toString() + " - " + getPosition());
+ logger.finest(this.toString() + " - " + position);
}
}
@@ -65,17 +65,4 @@ class RefinedAstNodeData extends AstNodeData {
}
}
- public boolean isMeta() {
- return this.node.isMeta();
- }
-
- public String getPosition() {
- return this.position;
- }
-
-
- public String toString() {
- return this.node.getLine();
- }
-
}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RefinementMenu.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RefinementMenu.java
new file mode 100644
index 000000000..46e4a2443
--- /dev/null
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RefinementMenu.java
@@ -0,0 +1,518 @@
+//Copyright (c) Hans-Joachim Daniels 2005
+//
+//This program is free software; you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation; either version 2 of the License, or
+//(at your option) any later version.
+//
+//You can either finde the file LICENSE or LICENSE.TXT in the source
+//distribution or in the .jar file of this applicationpackage de.uka.ilkd.key.ocl.gf;
+
+package de.uka.ilkd.key.ocl.gf;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.swing.DefaultListModel;
+import javax.swing.JList;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.ListSelectionModel;
+
+/**
+ * Takes care of managing the commands, that GF sent,
+ * including subcategories and their menus.
+ * Manages the graphical lists. To display them, they are reachable
+ * via getRefinementListsContainer().
+ * @author hdaniels
+ */
+class RefinementMenu {
+ /**
+ * logs things like selections and key events
+ */
+ private static Logger logger = Logger.getLogger(RefinementMenu.class.getName());
+
+ /**
+ * the editor of which this menu is part of
+ */
+ final private GFEditor2 editor;
+ /**
+ * the content of the refinementMenu
+ */
+ public DefaultListModel listModel= new DefaultListModel();
+ /**
+ * The list of current refinement options
+ */
+ private JList refinementList = new JList(this.listModel);
+ /**
+ * to store the Vectors which contain the display names for the
+ * ListModel for refinementSubcatList for the different
+ * subcategory menus.
+ * The key is the shortname String, the value the Vector with the
+ * display Strings
+ */
+ private Hashtable subcatListModelHashtable = new Hashtable();
+ /**
+ * this ListModel gets refilled every time a %WHATEVER command,
+ * which stands for a shortname for a subcategory of commands
+ * in the ListModel of refinementList, is selected there
+ */
+ private DefaultListModel refinementSubcatListModel = new DefaultListModel();
+ /**
+ * The list of current refinement options in the subcategory menu
+ */
+ private JList refinementSubcatList = new JList(this.refinementSubcatListModel);
+ /**
+ * the scrollpane containing the refinement subcategory
+ */
+ private JScrollPane refinementSubcatPanel = new JScrollPane(this.refinementSubcatList);
+ /**
+ * store what the shorthand name for the current subcat is
+ */
+ private String whichSubcat;
+ /**
+ * stores the two refinement JLists
+ */
+ private JSplitPane refinementListsContainer;
+ /**
+ * the scrollpane containing the refinements
+ */
+ private JScrollPane refinementPanel = new JScrollPane(this.refinementList);
+ /**
+ * here the GFCommand objects are stored
+ */
+ private Vector gfcommands = new Vector();
+ /**
+ * The cached popup menu containing the same stuff as the refinement list
+ */
+ public JPopupMenu popup2 = new JPopupMenu();
+
+ /**
+ * Creates the panels for the refinement (subcat) menu
+ * @param editor the editor, that the refinement menu is part of
+ */
+ protected RefinementMenu(GFEditor2 editor) {
+ this.editor = editor;
+ refinementListsContainer = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,refinementPanel, refinementSubcatPanel);
+ refinementList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+ final MouseListener mlRefinementList = new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ refinementList.setSelectionBackground(refinementSubcatList.getSelectionBackground());
+ boolean doubleClick = (e.getClickCount() == 2);
+ listAction(refinementList, refinementList.locationToIndex(e.getPoint()), doubleClick);
+ }
+ };
+ refinementList.addMouseListener(mlRefinementList);
+ refinementList.addKeyListener(new KeyListener() {
+ /** Handle the key pressed event for the refinement list. */
+ public void keyPressed(KeyEvent e) {
+ int keyCode = e.getKeyCode();
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("Key pressed: " + e.toString());
+ }
+
+ int index = refinementList.getSelectedIndex();
+ if (index == -1) {
+ //nothing selected, so nothing to be seen here, please move along
+ } else if (keyCode == KeyEvent.VK_ENTER) {
+ listAction(refinementList, refinementList.getSelectedIndex(), true);
+ } else if (keyCode == KeyEvent.VK_DOWN && index < listModel.getSize() - 1) {
+ listAction(refinementList, index + 1, false);
+ } else if (keyCode == KeyEvent.VK_UP && index > 0) {
+ listAction(refinementList, index - 1, false);
+ } else if (keyCode == KeyEvent.VK_RIGHT) {
+ if (refinementSubcatList.getModel().getSize() > 0) {
+ refinementSubcatList.requestFocusInWindow();
+ refinementSubcatList.setSelectedIndex(0);
+ refinementList.setSelectionBackground(Color.GRAY);
+ }
+ }
+ }
+
+ /**
+ * Handle the key typed event.
+ * We are not really interested in typed characters, thus empty
+ */
+ public void keyTyped(KeyEvent e) {
+ //needed for KeyListener, but not used
+ }
+
+ /** Handle the key released event. */
+ public void keyReleased(KeyEvent e) {
+ //needed for KeyListener, but not used
+ }
+ });
+
+ refinementSubcatList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+ final MouseListener mlRefinementSubcatList = new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ boolean doubleClick = (e.getClickCount() == 2);
+ listAction(refinementSubcatList, refinementSubcatList.locationToIndex(e.getPoint()), doubleClick);
+ refinementList.setSelectionBackground(Color.GRAY);
+ }
+ };
+ refinementSubcatList.addMouseListener(mlRefinementSubcatList);
+ refinementSubcatList.addKeyListener(new KeyListener() {
+ /** Handle the key pressed event. */
+ public void keyPressed(KeyEvent e) {
+ int keyCode = e.getKeyCode();
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("Key pressed: " + e.toString());
+ }
+ if (keyCode == KeyEvent.VK_ENTER) {
+ listAction(refinementSubcatList, refinementSubcatList.getSelectedIndex(), true);
+ } else if (keyCode == KeyEvent.VK_LEFT) {
+ refinementList.requestFocusInWindow();
+ refinementSubcatList.clearSelection();
+ refinementList.setSelectionBackground(refinementSubcatList.getSelectionBackground());
+ }
+ }
+
+ /**
+ * Handle the key typed event.
+ * We are not really interested in typed characters, thus empty
+ */
+ public void keyTyped(KeyEvent e) {
+ //needed for KeyListener, but not used
+ }
+
+ /** Handle the key released event. */
+ public void keyReleased(KeyEvent e) {
+ //needed for KeyListener, but not used
+ }
+ });
+ refinementList.setToolTipText("The list of current refinement options");
+ refinementList.setCellRenderer(new ToolTipCellRenderer());
+ refinementSubcatList.setToolTipText("The list of current refinement options");
+ refinementSubcatList.setCellRenderer(new ToolTipCellRenderer());
+
+ }
+
+ /**
+ * @return Returns the refinementListsContainer,
+ * which will contain both JLists.
+ */
+ protected JSplitPane getRefinementListsContainer() {
+ return refinementListsContainer;
+ }
+
+ /**
+ * handling the event of choosing the action at index from the list.
+ * That is either giving commands to GF or displaying the subcat menus
+ * @param list The list that generated this action
+ * @param index the index of the selected element in list
+ * @param doubleClick true iff a command should be sent to GF,
+ * false if only a new subcat menu should be opened.
+ */
+ private void listAction(JList list, int index, boolean doubleClick) {
+ if (index == -1) {
+ if (logger.isLoggable(Level.FINER)) logger.finer("no selection");
+ } else {
+ Object o;
+ if (list == refinementList) {
+ o = listModel.elementAt(index);
+ } else {
+ if (whichSubcat == null) {
+ //this is probably the case when no fitting properties of self
+ //are available and only a string is displayed in the submenu.
+ //clicking that string should do exactly nothing.
+ return;
+ }
+ Vector cmdvector = (Vector)this.subcatListModelHashtable.get(this.whichSubcat);
+ o = (cmdvector.get(index));
+ }
+ GFCommand command = null;
+ if (o instanceof GFCommand) {
+ command = (GFCommand)o;
+ } else {
+ return;
+ }
+ if (command instanceof SelfPropertiesCommand) {
+ SelfPropertiesCommand spc = (SelfPropertiesCommand)command;
+ Vector selfs = spc.produceSubmenu();
+ if (selfs.size() == 0) {
+ listModel.remove(index);
+ refinementSubcatListModel.clear();
+ refinementSubcatListModel.addElement("No properties fit here");
+ return;
+ } else {
+ this.subcatListModelHashtable.put(command.getSubcat(), selfs);
+ listModel.remove(index);
+ LinkCommand newLink = new LinkCommand(PrintnameManager.SELF_SUBCAT, editor.getPrintnameManager());
+ listModel.add(index, newLink);
+ command = newLink;
+ }
+ }
+ if (command instanceof LinkCommand) { //includes SelfPropertiesCommand, which is intended
+ this.whichSubcat = command.getSubcat();
+ refinementSubcatListModel.clear();
+ Vector currentCommands = (Vector)this.subcatListModelHashtable.get(this.whichSubcat);
+ for (Iterator it = currentCommands.iterator(); it.hasNext();) {
+ this.refinementSubcatListModel.addElement(it.next());
+ }
+ } else if (doubleClick && command instanceof InputCommand) {
+ InputCommand ic = (InputCommand)command;
+ editor.executeInputCommand(ic);
+
+ } else if (doubleClick){
+ refinementSubcatListModel.clear();
+ if (command instanceof RealCommand) {
+ editor.send("[t] " + command.getCommand(), true, ((RealCommand)command).undoSteps);
+ } else {
+ //that shouldn't be the case ...
+ editor.send("[t] " + command.getCommand());
+ }
+ } else if (list == refinementList){
+ refinementSubcatListModel.clear();
+ }
+ }
+ }
+ /**
+ * Produces the popup menu that represents the current refinements.
+ * An alternative to the refinement list.
+ * @return s.a.
+ */
+ protected JPopupMenu producePopup() {
+ if (popup2.getComponentCount() > 0) {
+ return popup2;
+ }
+ for (int i = 0; i < this.listModel.size(); i++) {
+ GFCommand gfcmd = (GFCommand)this.listModel.get(i);
+ if (gfcmd instanceof LinkCommand) {
+ LinkCommand lc = (LinkCommand)gfcmd;
+ Vector subcatMenu = (Vector)this.subcatListModelHashtable.get(lc.getSubcat());
+ JMenu tempMenu = new JMenu(lc.getDisplayText());
+ tempMenu.setToolTipText(lc.getTooltipText());
+ tempMenu.setFont(popup2.getFont());
+ JMenuItem tempMenuItem;
+ for (Iterator it = subcatMenu.iterator(); it.hasNext();) {
+ GFCommand subgfcmd = (GFCommand)it.next();
+ tempMenuItem = menuForCommand(subgfcmd);
+ if (tempMenuItem != null) {
+ tempMenu.add(tempMenuItem);
+ }
+ }
+ popup2.add(tempMenu);
+ } else {
+ JMenuItem tempMenu = menuForCommand(gfcmd);
+ if (tempMenu != null) {
+ popup2.add(tempMenu);
+ }
+ }
+ }
+ return popup2;
+ }
+
+ /**
+ * takes a GFCommand and "transforms" it in a JMenuItem.
+ * These JMenuItems have their own listeners that take care of
+ * doing what is right ...
+ * @param gfcmd a RealCommand or an InputCommand
+ * (LinkCommand is ignored and produces null as the result)
+ * @return either the correspondend JMenuItem or null.
+ */
+ private JMenuItem menuForCommand(GFCommand gfcmd) {
+ JMenuItem tempMenu = null;
+ if (gfcmd instanceof RealCommand){
+ tempMenu = new JMenuItem(gfcmd.getDisplayText());
+ tempMenu.setFont(popup2.getFont());
+ tempMenu.setActionCommand(gfcmd.getCommand());
+ tempMenu.setToolTipText(gfcmd.getTooltipText());
+ tempMenu.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent ae) {
+ JMenuItem mi = (JMenuItem)ae.getSource();
+ refinementSubcatListModel.clear();
+ String command = "[t] " + mi.getActionCommand();
+ editor.send(command);
+ }
+ });
+ } else if (gfcmd instanceof InputCommand) {
+ tempMenu = new JMenuItem(gfcmd.getDisplayText());
+ tempMenu.setFont(popup2.getFont());
+ tempMenu.setActionCommand(gfcmd.getCommand());
+ tempMenu.setToolTipText(gfcmd.getTooltipText());
+ tempMenu.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent ae) {
+ JMenuItem mi = (JMenuItem)ae.getSource();
+ String command = mi.getActionCommand();
+ InputCommand ic = InputCommand.forTypeName(command);
+ if (ic != null) {
+ editor.executeInputCommand(ic);
+ }
+ }
+ });
+
+ }
+ return tempMenu;
+ }
+ /**
+ * Takes the StringTuples in gfCommandVector, creates the RealCommand
+ * objects for them.
+ * Goes through this list and groups the RealCommands
+ * according to their subcategory tag (which starts with %)
+ * If there is a "(" afterwards, everything until the before last
+ * character in the printname will be used as the display name
+ * for this subcategory. If this displayname is defined a second time,
+ * it will get overwritten.
+ * Sorting is also done here.
+ * Adding additional special commands like InputCommand happens here too.
+ * @param gfCommandVector contains all RealCommands, that are available
+ * at the moment
+ * @param toAppend will be appended to every command, that is sent to GF.
+ * Normally, toAppend will be the empty String "".
+ * But it can be a chain command's second part.
+ * @param isAbstract If the selected menu language is abstract or not
+ * @param easyAttributes if true, attributes of self will be added.
+ * @param focusPosition The current position of the focus in the AST.
+ * Needed for easy access to properties of self.
+ * @param gfCapsule The read/write encapsulation of the GF process.
+ * Needed for easy access to properties of self.
+ */
+ protected void formRefinementMenu(final Vector gfCommandVector, final String toAppend, GfAstNode currentNode, final boolean isAbstract, boolean easyAttributes, LinPosition focusPosition, GfCapsule gfCapsule) {
+ this.listModel.clear();
+ this.refinementSubcatListModel.clear();
+ this.gfcommands.clear();
+ this.subcatListModelHashtable.clear();
+ this.whichSubcat = null;
+ this.popup2.removeAll();
+ Vector prelListModel = new Vector();
+ /** to keep track of subcats and their names */
+ HashSet processedSubcats = new HashSet();
+ //at the moment, we don't know yet, which subcats are
+ //nearly empty
+ for (Iterator it = gfCommandVector.iterator(); it.hasNext();) {
+ final StringTuple st = (StringTuple)it.next();
+ GFCommand gfcommand;
+ if (st instanceof ChainCommandTuple) {
+ ChainCommandTuple cct = (ChainCommandTuple)st;
+ gfcommand = new RealCommand(st.first, processedSubcats, editor.getPrintnameManager(), st.second, isAbstract, toAppend, cct.undoSteps, cct.fun, cct.subcat);
+ } else {
+ gfcommand = new RealCommand(st.first, processedSubcats, editor.getPrintnameManager(), st.second, isAbstract, toAppend);
+ }
+ if ((!editor.isGroupSubcat()) || (gfcommand.getSubcat() == null)) {
+ prelListModel.addElement(gfcommand);
+ } else {
+ //put stuff in the correct Vector for the refinementSubcatListModel
+ Vector lm;
+ if (subcatListModelHashtable.containsKey(gfcommand.getSubcat())) {
+ lm = (Vector)this.subcatListModelHashtable.get(gfcommand.getSubcat());
+ } else {
+ lm = new Vector();
+ this.subcatListModelHashtable.put(gfcommand.getSubcat(), lm);
+ }
+ lm.addElement(gfcommand);
+ if (gfcommand.isNewSubcat()) {
+ GFCommand linkCmd = new LinkCommand(gfcommand.getSubcat(), editor.getPrintnameManager());
+ prelListModel.addElement(linkCmd);
+ }
+ }
+ }
+
+ //so we remove empty subcats now and replace them by their RealCommand
+ for (int i = 0; i < prelListModel.size(); i++) {
+ if (prelListModel.get(i) instanceof LinkCommand) {
+ LinkCommand lc = (LinkCommand) prelListModel.get(i);
+ Vector subcatMenu = (Vector)this.subcatListModelHashtable.get(lc.getSubcat());
+ if (subcatMenu.size() == 1) {
+ RealCommand rc = (RealCommand)subcatMenu.get(0);
+ prelListModel.set(i, rc);
+ }
+ }
+ }
+
+
+ // Some types invite special treatment, like Int and String
+ // which can be read from the user.
+ if (currentNode.isMeta()) {
+ InputCommand usedInputCommand = null;
+ if (currentNode.getType().equals("Int")) {
+ usedInputCommand = InputCommand.intInputCommand;
+ prelListModel.addElement(usedInputCommand);
+ } if (currentNode.getType().equals("String")) {
+ usedInputCommand = InputCommand.stringInputCommand;
+ prelListModel.addElement(usedInputCommand);
+ }
+ if (usedInputCommand != null) {
+ for (Iterator it = usedInputCommand.enteredValues.iterator(); it.hasNext();) {
+ Object o = it.next();
+ //for GF it seems to make no difference,
+ //if we use 'g' or 'r' as the command to send
+ //Int and String. 'r' is already supported
+ //by RealCommand, so I chose that.
+ RealCommand rc = new RealCommand("r " + o, processedSubcats, editor.getPrintnameManager(), "r " + o, isAbstract, toAppend);
+ prelListModel.addElement(rc);
+ }
+ }
+ }
+
+ //add the special entry for the properties of self
+ if (easyAttributes) {
+ final SelfPropertiesCommand spc = new SelfPropertiesCommand(editor.getPrintnameManager(), gfCapsule, focusPosition, isAbstract, toAppend, processedSubcats);
+ prelListModel.add(spc);
+ }
+
+ //now sort the preliminary listmodels
+ if (editor.isSortRefinements()) {
+ Collections.sort(prelListModel);
+ for (Iterator it = subcatListModelHashtable.values().iterator(); it.hasNext();) {
+ Vector slm = (Vector)it.next();
+ Collections.sort(slm);
+ }
+ }
+ //now fill this.listModel
+ for (Iterator it = prelListModel.iterator(); it.hasNext();) {
+ Object next = it.next();
+ this.listModel.addElement(next);
+ }
+ //select the first command in the refinement menu, if available
+ if (this.listModel.size() > 0) {
+ this.refinementList.setSelectedIndex(0);
+ } else {
+ this.refinementList.setSelectedIndex(-1);
+ }
+ this.refinementList.setSelectionBackground(refinementSubcatList.getSelectionBackground());
+ }
+
+ /**
+ * Requests the focus for the refinement list
+ */
+ protected void requestFocus() {
+ refinementList.requestFocusInWindow();
+ }
+
+ /**
+ * clears the list model
+ */
+ protected void reset() {
+ listModel.clear();
+ }
+
+ /**
+ * Applies newFont to the visible elements
+ * @param newFont The new font, what else?
+ */
+ protected void setFont(Font newFont) {
+ refinementList.setFont(newFont);
+ refinementSubcatList.setFont(newFont);
+ popup2.setFont(newFont);
+ }
+}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RefinementMenuCollector.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RefinementMenuCollector.java
new file mode 100644
index 000000000..4d7df9dac
--- /dev/null
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RefinementMenuCollector.java
@@ -0,0 +1,51 @@
+package de.uka.ilkd.key.ocl.gf;
+
+import java.util.Vector;
+
+/**
+ * Asks GF the Vector of RefinementMenu entries.
+ *
+ * This class can be reused.
+ * @author daniels
+ */
+class RefinementMenuCollector extends AbstractProber {
+ /**
+ * here the result of this run is saved
+ */
+ Vector refinementMenuContent = null;
+ /**
+ * Standard fill-in-the-parameters constructor
+ * @param gfCapsule The reader/writer to GF
+ */
+ public RefinementMenuCollector(GfCapsule gfCapsule) {
+ super(gfCapsule);
+ }
+
+ /**
+ * Asks GF (the same GF as the one editor has) to execute a command
+ * and returns the read refinement menu that is offered then.
+ * Uses the readRefinementMenu method from GFEditor2 which does not
+ * change any global variable besides GF itself. So that is safe.
+ *
+ * Note: This method does not do undo automatically, since it is
+ * intended to run several times in a row, so the u should be part of
+ * next command.
+ * @param command The command that is sent to GF. Should contain a mp
+ * to make sure that the command at the right position in the AST
+ * is read
+ * @return a Vector of StringTuple like readRefinementMenu does it.
+ */
+ public Vector readRefinementMenu(String command) {
+ send(command);
+ readGfedit();
+ return this.refinementMenuContent;
+ }
+
+ /**
+ * parses the refinement menu part and stores it in this.refinementMenuContent
+ */
+ protected void readMenu() {
+ this.refinementMenuContent = gfCapsule.readRefinementMenu();
+ }
+
+}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RefinementMenuTransformer.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RefinementMenuTransformer.java
new file mode 100644
index 000000000..ba1263db8
--- /dev/null
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/RefinementMenuTransformer.java
@@ -0,0 +1,223 @@
+//Copyright (c) Hans-Joachim Daniels 2005
+//
+//This program is free software; you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation; either version 2 of the License, or
+//(at your option) any later version.
+//
+//You can either finde the file LICENSE or LICENSE.TXT in the source
+//distribution or in the .jar file of this application
+
+package de.uka.ilkd.key.ocl.gf;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * This class is completely static and cannot be instantiated.
+ * @see #transformRefinementMenu(de.uka.ilkd.key.ocl.gf.TreeAnalysisResult, java.util.Vector, de.uka.ilkd.key.ocl.gf.GfCapsule)
+ * @author hdaniels
+ */
+class RefinementMenuTransformer {
+ /**
+ * if things are added to or removed from the refinement menu
+ */
+ protected static Logger logger = Logger.getLogger(RefinementMenuTransformer.class.getName());
+
+ private RefinementMenuTransformer() {
+ //A private constructor enforces the noninstantiability
+ //of "RefinementMenuTransformer".
+ //(See item 3 of "Effective Java".)
+ }
+
+ /**
+ * Depending on tar, the refinement menu given in raw form in oldMenu
+ * is transformed.
+ * That includes:
+ * - adding properties of self
+ * - producing a reduced version for subtyping below a coerce
+ * where only Instances of subtypes are listed
+ * - probes, if self and result are really applicable
+ * - changes the delete command, when an unrefined Instance
+ * argument of coerce is clicked on, to first delete the
+ * whole coerce to avoid sticking with wrong type arguments.
+ * @param tar TreeAnalyser has decided what to do here. That is followed.
+ * @param oldMenu The original content of the refinement menu.
+ * Is a Vector of StringTuple
+ * @param gfCapsule The encapsulation of GF regarding read/write access
+ * @return The refinement menu in its new form
+ */
+ protected static Vector transformRefinementMenu(TreeAnalysisResult tar, Vector oldMenu, GfCapsule gfCapsule) {
+ //now do fill (or partially empty) the offered commands list
+ final Vector usedCommandVector;
+ if (tar.reduceCoerce) {
+ //is only true if switched on globally.
+ //And if conditions are right.
+ usedCommandVector = produceReducedCoerceRefinementMenu(tar.focusPosition.position, gfCapsule);
+ } else {
+ usedCommandVector = oldMenu;
+ }
+ if (tar.deleteAlsoAbove) {
+ String newPos = tar.focusPosition.parentPosition();
+ StringTuple newDelete = new StringTuple("mp " + newPos + " ;; d", "delete current subtree\\$also delete the encompassing coercion ");
+ exchangeCommand(usedCommandVector, "d", newDelete);
+ }
+ if (tar.probeSelfResult) {
+ probeCompletability(usedCommandVector, tar.focusPosition, gfCapsule);
+ }
+ if (tar.easyAttributes && !tar.reduceCoerce) {
+ addSelfProperties(usedCommandVector, tar.focusPosition, gfCapsule);
+ }
+ return usedCommandVector;
+ }
+
+ /**
+ * Looks at the subtyping witness of the same coerce as currentPos
+ * and collects the possible refinements for all offered subtypes.
+ * It assumes that argument 0 of coerce is automatically filled in.
+ *
+ * This method is surely <b>slow</b> since a lot of calls to GF is made
+ * here.
+ * @param currentPos musst point to a child of a coerce.
+ * @param gfCapsule The encapsulation of GF regarding read/write access
+ * @return a Vector of StringTuple as readRefinementMenu does.
+ * This Vector can be fed into formRefinementMenu.
+ */
+ private static Vector produceReducedCoerceRefinementMenu(String currentPos, GfCapsule gfCapsule) {
+ final HashSet commands = new HashSet();
+ RefinementMenuCollector rmc = new RefinementMenuCollector(gfCapsule);
+ //move to the subtype witness argument
+ final String collectSubtypesCommand = "mp " + LinPosition.calculateBrethrenPosition(currentPos, 2);
+ Vector possibleSubtypes = rmc.readRefinementMenu(collectSubtypesCommand);
+ String undoString = "";
+ final String undoTemplate = "u 2 ;; ";
+ for (Iterator it = possibleSubtypes.iterator(); it.hasNext(); ) {
+ StringTuple nextCommand = (StringTuple)it.next();
+// if (!nextCommand.first.trim().startsWith("r")) {
+// //no ac, d, rc or whatever wanted here. Only refine.
+// continue;
+// }
+ final String collectRefinementsCommand = undoString + nextCommand.first + " ;; mp " + currentPos;
+ undoString = undoTemplate; //for all following runs we want an undo before it
+ Vector nextRefinements = rmc.readRefinementMenu(collectRefinementsCommand);
+ commands.addAll(nextRefinements);
+ }
+ final String cleanupCommand = "u 3"; //undo the last command and also the first mp
+ rmc.readRefinementMenu(cleanupCommand); //no harm done here, collector won't get reused
+ Vector result = new Vector(commands);
+ return result;
+ }
+
+ /**
+ * checks if result and self make sense in the current context.
+ * if not, they are removed from oldMenu
+ * @param oldMenu A Vector of StringTuple that represents the
+ * commands for the refinement menu
+ * @param focusPos The current position in the AST
+ * @param gfCapsule The encapsulation of GF regarding read/write access
+ */
+ private static void probeCompletability(Vector oldMenu, LinPosition focusPos, GfCapsule gfCapsule) {
+ /**
+ * self and result both take two arguments.
+ * The first is the type, which is fixed
+ * if the second argument is refineable.
+ * Important is the second.
+ * This only is refineable for the real type of self/result
+ */
+ if (focusPos == null) {
+ //sadly, we can't do much
+ return;
+ }
+ final String childPos = focusPos.childPosition(1);
+ final SelfResultProber cp = new SelfResultProber(gfCapsule);
+ for (int i = 0; i < oldMenu.size(); i++) {
+ String cmd = ((StringTuple)oldMenu.elementAt(i)).first;
+ if ((cmd != null) && ((cmd.indexOf("r core.self") > -1) || (cmd.indexOf("r core.result") > -1))) {
+ //the first mp is necessary for the second of self/result.
+ //without, GF will jump to a stupid position
+ String newCommand = "mp " + focusPos.position + " ;; " + cmd + " ;; mp " + childPos;
+ if (!cp.isAutoCompletable(newCommand, 3)) {
+ oldMenu.remove(i);
+ i -=1;
+ }
+ }
+ }
+ }
+
+ /**
+ * Probes for the properties of self, that could be filled in at
+ * the current focus position.
+ * If it finds any, these are added to oldMenu
+ * This method will add all offered commands to the refinement menu,
+ * not only for suiting subtypes due to speed reasons.
+ * @param oldMenu A Vector of StringTuple. The menu with the commands
+ * and show texts as given by GF. Gets modified.
+ * @param focusPos The position of the GF focus in the AST
+ * @param gfCapsule The encapsulation of GF regarding read/write access
+ */
+ private static void addSelfProperties(Vector oldMenu, LinPosition focusPos, GfCapsule gfCapsule) {
+ //solve in between to avoid some typing errors by closing some type arguments
+ final String probeCommand = "r core.implPropCall ;; mp " + focusPos.childPosition(2) + " ;; r core.self ;; solve ;; mp " + focusPos.childPosition(3);
+ final String deleteAppendix = " ;; d";
+ final RefinementMenuCollector rmc = new RefinementMenuCollector(gfCapsule);
+ Vector futureRefinements = rmc.readRefinementMenu(probeCommand + deleteAppendix);
+ final int undos = 5;
+ final boolean singleRefinement;
+ if (futureRefinements.size() == 1) {
+ singleRefinement = true;
+ } else {
+ singleRefinement = false;
+ }
+ final String cleanupCommand = "u " + undos;
+ rmc.readRefinementMenu(cleanupCommand); //no harm done here
+ for (Iterator it = futureRefinements.iterator(); it.hasNext();) {
+ StringTuple st = (StringTuple)it.next();
+ if (st.first.startsWith("r")) { //is a refinement, no ac or d
+ String newCommand;
+ //add the command that came before
+ final int cmdUndos;
+ if (singleRefinement) {
+ //that is an exceptional case, but might happen.
+ //Here we don't have to refine the final property
+ //at all, since GF does that automatically
+ newCommand = probeCommand + " ;; c solve";
+ cmdUndos = 5;
+ } else {
+ //here the 'd' is not needed, since we know,
+ //that nothing is refined automatically
+ newCommand = probeCommand + " ;; " + st.first + " ;; c solve";
+ cmdUndos = 6;
+ }
+ // now extract the fun of the property
+ String fun = st.first.substring(1).trim();
+ ChainCommandTuple cct = new ChainCommandTuple(newCommand, st.second, fun, PrintnameManager.SELF_SUBCAT, cmdUndos);
+ if (logger.isLoggable(Level.FINER)) {
+ logger.finer("added " + cct);
+ }
+ oldMenu.add(cct);
+ }
+ }
+ }
+
+ /**
+ * Goes through oldMenu and if it finds a command in there, where
+ * first.equals(oldCommand), this command is replaced by newCommand.
+ * oldMenu's content thus gets modified.
+ * @param oldMenu a Vector of StringTuple
+ * @param oldCommand a GF command string (what is sent, not the show text)
+ * @param newCommand a StringTuple representing what could be a pait from GF
+ */
+ private static void exchangeCommand(Vector oldMenu, String oldCommand, StringTuple newCommand) {
+ for (int i = 0; i < oldMenu.size(); i++) {
+ StringTuple next = (StringTuple)oldMenu.get(i);
+ if (next.first.equals(oldCommand)) {
+ oldMenu.remove(i);
+ oldMenu.insertElementAt(newCommand, i);
+ }
+ }
+ }
+
+}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/SelfPropertiesCommand.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/SelfPropertiesCommand.java
new file mode 100644
index 000000000..60ee86c64
--- /dev/null
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/SelfPropertiesCommand.java
@@ -0,0 +1,175 @@
+//Copyright (c) Hans-Joachim Daniels 2005
+//
+//This program is free software; you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation; either version 2 of the License, or
+//(at your option) any later version.
+//
+//You can either finde the file LICENSE or LICENSE.TXT in the source
+//distribution or in the .jar file of this applicationpackage de.uka.ilkd.key.ocl.gf;
+
+package de.uka.ilkd.key.ocl.gf;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Vector;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * This class is an unclean hack.
+ * The whole refinement menu architecture expected, that everything is probed,
+ * when the refinement menu is getting created.
+ * But for getting only subtype correct properties of self needs a number of
+ * calls to GF, which could be deferred to not make things slower than they
+ * already are.
+ * This deferred probing is done in this class.
+ * @author daniels
+ *
+ */
+class SelfPropertiesCommand extends LinkCommand {
+ private final static Logger logger = Logger.getLogger(SelfPropertiesCommand.class.getName());
+ private final GfCapsule gfCapsule;
+ private final LinPosition focusPos;
+ private final String toAppend;
+ private final boolean isAbstract;
+ private final HashSet processedSubcats;
+ private final PrintnameManager printnameManager;
+
+ /**
+ * A simple setter constructor, no calculation done here.
+ * @param manager The printname manager, that knows, how the properties
+ * of self should be listed in the refinement menu
+ * @param gfCapsule The reader/writer abstraction from GF
+ * @param focusPos The position of the GF focus
+ * @param isAbstract if Abstract is the current menu language
+ * @param toAppend If something should be appended to the command
+ * @param processedSubcats Here, the subcat for self is put into
+ */
+ public SelfPropertiesCommand(final PrintnameManager manager, GfCapsule gfCapsule, LinPosition focusPos, boolean isAbstract, String toAppend, HashSet processedSubcats) {
+ super(PrintnameManager.SELF_SUBCAT, manager);
+ this.gfCapsule = gfCapsule;
+ this.printnameManager = manager;
+ this.focusPos = focusPos;
+ this.processedSubcats = processedSubcats;
+ this.toAppend = toAppend;
+ this.isAbstract = isAbstract;
+ }
+
+ /**
+ * @return a Vector of RealCommand containing the suitable properties
+ * of self at the current focus position.
+ * Subtyping is taken into account, so only properties with a subtype
+ * of the supertype of the coerce above (at other places this method
+ * is not applicable) show up in this menu.
+ * The method used is similiar to the one for Instances below a coerce.
+ */
+ Vector produceSubmenu() {
+ logger.fine("SelfPropertiesCommand asked to produce a menu");
+ //HashSet to prevent duplicates
+ final HashSet commands = new HashSet();
+ RefinementMenuCollector rmc = new RefinementMenuCollector(gfCapsule);
+ //move to the subtype witness argument
+ final String collectSubtypesCommand = "mp " + LinPosition.calculateBrethrenPosition(focusPos.position, 2);
+ final Vector possibleSubtypes = rmc.readRefinementMenu(collectSubtypesCommand);
+ String undoString = "";
+ int undos = 0;
+ //for the case, that there is only one possible refinement at all
+ //which gets automatically filled in
+ final StringBuffer singleReplacement = new StringBuffer();
+ //loop through the offered Subtype refinements
+ for (Iterator it = possibleSubtypes.iterator(); it.hasNext(); ) {
+ StringTuple nextCommand = (StringTuple)it.next();
+ if (!nextCommand.first.trim().startsWith("r")) {
+ //no ac, d, rc or whatever wanted here. Only refine.
+ continue;
+ }
+ final String commandPrefix = undoString + nextCommand.first + " ;; mp " + focusPos.position + " ;; ";
+ logger.finer("commandPrefix: " + commandPrefix);
+ Vector futureRefinements = new Vector();
+ undos = addSelfProperties(futureRefinements, commandPrefix, singleReplacement);
+ undos += 2; // to undo commandPrefix
+ undoString = "u " + undos + " ;; "; //for all following runs we want an undo before it
+// Vector nextRefinements = rmc.readRefinementMenu(collectRefinementsCommand);
+ commands.addAll(futureRefinements);
+ }
+ final String cleanupCommand = "u " + (undos + 1); //undo the last command and also the first mp
+ rmc.readRefinementMenu(cleanupCommand); //no harm done here, collector won't get reused
+ Vector result = new Vector();
+ for (Iterator it = commands.iterator(); it.hasNext();) {
+ StringTuple st = (StringTuple)it.next();
+ if ((commands.size() == 1) && (st instanceof ChainCommandTuple)) {
+ //the case when only one property is available at all.
+ //Then this will automatically be selected
+ //To compensate for that, singleRefinement is used.
+ //This will be just one refinement, otherwise, we
+ //wouldn't be in this branch.
+ //This refinement does not contain the actual r
+ //command and therefore needs one undo step less
+ ChainCommandTuple cct = (ChainCommandTuple)st;
+ st = new ChainCommandTuple(singleReplacement.toString(), cct.second, cct.fun, cct.subcat, cct.undoSteps - 1);
+ }
+ GFCommand gfcommand;
+ if (st instanceof ChainCommandTuple) {
+ ChainCommandTuple cct = (ChainCommandTuple)st;
+ gfcommand = new RealCommand(st.first, processedSubcats, printnameManager, st.second, isAbstract, toAppend, cct.undoSteps, cct.fun, cct.subcat);
+ } else {
+ gfcommand = new RealCommand(st.first, processedSubcats, printnameManager, st.second, isAbstract, toAppend);
+ }
+ result.add(gfcommand);
+ }
+ Collections.sort(result);
+ return result;
+ }
+
+ /**
+ * Probes for the properties of self, that could be filled in at
+ * the current focus position.
+ * If it finds any, these are added to result.
+ * @param result The Vector, that will get filled with the collected
+ * chain commands
+ * @param commandPrefix The prefix, that is to be prepended to the
+ * probing command. Used for refining with a Subtype witness and a
+ * mp to the Instance position, where this method expects to start.
+ * @param singleReplacement This is a hack for cases, when GF refines
+ * an refinement automatically. If that happens only for one subtype,
+ * then GF would fill that in automatically even when the supertype is
+ * open. Therefore, it must be omitted in the actual command.
+ * But this situation can only be checked after all subtypes have been
+ * probed.
+ * @return the number of undo steps needed to undo the probing command
+ * (without prefix, that is handled by the caller)
+ */
+ private int addSelfProperties(final Vector result, final String commandPrefix, final StringBuffer singleReplacement) {
+ //solve in between to avoid some typing errors by closing some type arguments
+ final String probeCommand = "r core.implPropCall ;; mp " + focusPos.childPosition(2) + " ;; r core.self ;; solve ;; mp " + focusPos.childPosition(3);
+ final String deleteAppendix = " ;; d";
+ final RefinementMenuCollector rmc = new RefinementMenuCollector(gfCapsule);
+ final String actualProbeCommand = commandPrefix + probeCommand + deleteAppendix;
+ logger.finer("&&& actual probe command:: " + actualProbeCommand);
+ Vector futureRefinements = rmc.readRefinementMenu(actualProbeCommand);
+ final int undos = 5;
+ for (Iterator it = futureRefinements.iterator(); it.hasNext();) {
+ StringTuple st = (StringTuple)it.next();
+ if (st.first.startsWith("r")) { //is a refinement, no ac or d
+ String newCommand;
+ //add the command that came before
+ final int cmdUndos;
+ if (futureRefinements.size() == 1) {
+ //the case, when only one property is defined in the grammar:
+ singleReplacement.append(probeCommand + " ;; c solve");
+ }
+ newCommand = probeCommand + " ;; " + st.first + " ;; c solve";
+ cmdUndos = 6;
+ // now extract the fun of the property
+ String fun = st.first.substring(1).trim();
+ ChainCommandTuple cct = new ChainCommandTuple(newCommand, st.second, fun, PrintnameManager.SELF_SUBCAT, cmdUndos);
+ if (logger.isLoggable(Level.FINE)) {
+ logger.finer("added " + cct);
+ }
+ result.add(cct);
+ }
+ }
+ return undos;
+ }
+}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/CompletableProber.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/SelfResultProber.java
index 55b228a63..664a9d918 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/CompletableProber.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/SelfResultProber.java
@@ -1,8 +1,5 @@
package de.uka.ilkd.key.ocl.gf;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.IOException;
import java.util.logging.*;
/**
@@ -11,22 +8,21 @@ import java.util.logging.*;
* This class is meant for self and result.
* @author daniels
*/
-class AutoCompletableProber extends AbstractProber {
+class SelfResultProber extends AbstractProber {
/**
* This field is true in the beginning of each run, and
* set to false, if the focus position when checking is found
* to be open.
*/
protected boolean autocompleted = true;
-
- protected static Logger nogger = Logger.getLogger(AutoCompletableProber.class.getName());
+
+ protected static Logger nogger = Logger.getLogger(SelfResultProber.class.getName());
/**
* A constructor which sets some fields
- * @param fromGf the stdout from the GF process
- * @param toGf the stdin from the GF process
+ * @param gfCapsule The encapsulation of the running GF process
*/
- public AutoCompletableProber(BufferedReader fromGf, BufferedWriter toGf) {
- super(fromGf, toGf);
+ public SelfResultProber(GfCapsule gfCapsule) {
+ super(gfCapsule);
}
/**
@@ -51,7 +47,7 @@ class AutoCompletableProber extends AbstractProber {
this.autocompleted = true;
//clean up and undo
send("u " + chainCount);
- readAndIgnore(fromProc);
+ readAndIgnore();
if (nogger.isLoggable(Level.FINE)) {
nogger.fine(result + " is the result for: '" + gfCommand +"'");
}
@@ -63,31 +59,26 @@ class AutoCompletableProber extends AbstractProber {
* Sets autocompleted to false, if the focus position is open.
*/
protected void readTree() {
- try {
- String result = fromProc.readLine();
- if (nogger.isLoggable(Level.FINER)) {
- nogger.finer("14 " + result);
- }
- while (result.indexOf("/tree")==-1){
- result = result.trim();
- if (result.startsWith("*")) {
- result = result.substring(1).trim();
- if (result.startsWith("?")) {
- this.autocompleted = false;
- }
- }
-
- result = fromProc.readLine();
- if (nogger.isLoggable(Level.FINER)) {
- nogger.finer("14 " + result);
+ String treeString = gfCapsule.readTree();
+ String[] treeArray = treeString.split("\\n");
+ for (int i = 0; i < treeArray.length; i++) {
+ String result = treeArray[i].trim();
+ if (result.startsWith("*")) {
+ result = result.substring(1).trim();
+ if (result.startsWith("?")) {
+ //the normal case, focus position open
+ this.autocompleted = false;
+ } else if ((i >= 6) //that we could be at the instance argument at all
+ && (treeArray[i - 6].indexOf("coerce") > -1) //we are below a coerce
+ && (treeArray[i - 3].trim().startsWith("?")) //the Subtype argument is not filled in
+ // The super argument cannot be OclAnyC or even unrefined, because then this
+ // method wouldn't have been called. Thus, the Subtype argument is unique.
+ ){
+ //we are below a coerce, but self would have a non-suiting subtype
+ this.autocompleted = false;
}
}
- } catch(IOException e){
- System.err.println(e.getMessage());
- e.printStackTrace();
- }
+ }
}
-
-
}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/StringTuple.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/StringTuple.java
new file mode 100644
index 000000000..67f4326e1
--- /dev/null
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/StringTuple.java
@@ -0,0 +1,54 @@
+//Copyright (c) Hans-Joachim Daniels 2005
+//
+//This program is free software; you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation; either version 2 of the License, or
+//(at your option) any later version.
+//
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU General Public License for more details.
+//
+//You can either finde the file LICENSE or LICENSE.TXT in the source
+//distribution or in the .jar file of this application
+
+package de.uka.ilkd.key.ocl.gf;
+
+/**
+ * Small tuple class for two Strings.
+ * The main use is grouping command and showname for GF commands before
+ * they are processed.
+ * This class is mutable.
+ * Equality is bound to the first argument.
+ * @author daniels
+ */
+class StringTuple {
+ String first;
+ String second;
+
+ /**
+ * Just sets both values.
+ * @param f Well, the first String
+ * @param s Well, the second String
+ * (if it is used at all)
+ */
+ public StringTuple(String f, String s) {
+ this.first = f;
+ this.second = s;
+ }
+
+ public int hashCode() {
+ return this.first.hashCode();
+ }
+ public boolean equals(Object o) {
+ if (o instanceof StringTuple) {
+ return this.first.equals(((StringTuple)o).first);
+ } else {
+ return false;
+ }
+ }
+ public String toString() {
+ return this.first;
+ }
+}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/SubtypingProber.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/SubtypingProber.java
new file mode 100644
index 000000000..9ff3c4f92
--- /dev/null
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/SubtypingProber.java
@@ -0,0 +1,107 @@
+package de.uka.ilkd.key.ocl.gf;
+
+import java.util.logging.Logger;
+import java.util.*;
+
+/**
+ * This class goes through the tree and tries to close all open Subtype lines.
+ *
+ * Makes heavy use of instance fields instead of parameters and return values.
+ * I justify that with the rather small size of this class.
+ * Because of this this class has to be reinitialized for each run.
+ * @author daniels
+ */
+class SubtypingProber extends RefinementMenuCollector {
+ private static Logger nogger = Logger.getLogger(SubtypingProber.class.getName());
+ /**
+ * how many undos are needed to clean up behind this probing
+ */
+ protected int undoSteps = 0;
+ /**
+ * the GF AST line by line
+ */
+ protected String[] treeArray = new String[0];
+ /**
+ * the pointer to the line, that has been read last
+ */
+ protected int currentLine;
+
+ /**
+ * Standard fill-in-the-parameters constructor
+ * @param gfCapsule The encapsulation of GF
+ */
+ public SubtypingProber(GfCapsule gfCapsule) {
+ super(gfCapsule);
+ this.currentLine = 0;
+ }
+
+ /**
+ * stores the read GF AST in treeArray
+ */
+ protected void readTree() {
+ String treeString = gfCapsule.readTree();
+ this.treeArray = treeString.split("\\n");
+ }
+
+ /**
+ * looks at the refinement menu for node number lineNumber in the AST
+ * and if there is only one refinement command offered, does
+ * execute this.
+ * @param lineNumber
+ */
+ protected void checkLine(int lineNumber) {
+ String command = "mp [] ;; > " + lineNumber;
+ this.undoSteps += 2;
+ send(command);
+ readGfedit();
+ Vector commands = new Vector();
+ for (Iterator it = this.refinementMenuContent.iterator(); it.hasNext(); ) {
+ StringTuple next = (StringTuple)it.next();
+ if (next.first.startsWith("r")) {
+ commands.add(next);
+ }
+ }
+ if (commands.size() == 0) {
+ //nothing can be done
+ nogger.fine("no refinement for '" + this.treeArray[lineNumber] + "'");
+ } else if (commands.size() == 1) {
+ StringTuple nextCommand = (StringTuple)commands.lastElement();
+ nogger.fine("one refinement for '" + this.treeArray[lineNumber] + "'");
+ send(nextCommand.first);
+ this.undoSteps += 1;
+ // now new things are in the state,
+ // but since we assume that nothing above lineNumber changes,
+ // that is wanted.
+ readGfedit();
+ } else {
+ nogger.fine(commands.size() + " refinements for '" + this.treeArray[lineNumber] + "'");
+ }
+ }
+
+ /**
+ * Asks GF for the AST and tries to hunt down all unrefined
+ * Subtype witnesses.
+ * @return the number of undo steps this run needed
+ */
+ public int checkSubtyping() {
+ //solve to try to eliminate many unrefined places
+ send("c solve ;; mp []"); //focus at the top where '*' does not disturb
+ readGfedit();
+ this.undoSteps += 2;
+ for (int i = 3; i < this.treeArray.length; i++) {
+ //the condition gets rechecked every run, and length will only grow
+ //We start at 3 since the witness is the third argument of coerce,
+ //before nothing can happen
+ //(sth. like "n core.Subtype" does not count!
+ //(starting with new category Subtype) )
+ if (this.treeArray[i].indexOf(": Subtype") > -1) {
+ if (!this.treeArray[i - 2].startsWith("?") //both Class arguments refined
+ && !this.treeArray[i - 1].startsWith("?")) {
+ checkLine(i);
+ }
+ }
+ }
+ nogger.fine(this.undoSteps + " individual commands sent");
+ return this.undoSteps;
+ }
+}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/TreeAnalyser.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/TreeAnalyser.java
new file mode 100644
index 000000000..5edf2a16b
--- /dev/null
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/TreeAnalyser.java
@@ -0,0 +1,387 @@
+//Copyright (c) Hans-Joachim Daniels 2005
+//
+//This program is free software; you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation; either version 2 of the License, or
+//(at your option) any later version.
+//
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU General Public License for more details.
+//
+//You can either finde the file LICENSE or LICENSE.TXT in the source
+//distribution or in the .jar file of this application
+
+package de.uka.ilkd.key.ocl.gf;
+
+import java.util.Enumeration;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+
+/**
+ * Goes through the AST and:
+ * Labels node according to the following:
+ * hidden, if they are a coerce without a constraint
+ * colored, if they are a coerce with a constraint
+ * Saves a reference to the currently selected node
+ * Finds out
+ * if attributes of self should be given an easy access,
+ * if the refinement menu below a coerce should be reduces,
+ * if it should be probed, if self and result are superfluous
+ * in the refinement menu.
+ * if a coerce should be introduced automatically.
+ * Takes a tree and hides the nodes labelled as hidden in another stage.
+ * @author hdaniels
+ */
+class TreeAnalyser {
+ /**
+ * debug stuff for the tree
+ */
+ private static Logger treeLogger = Logger.getLogger(TreeAnalyser.class.getName());
+ /**
+ * dealing with coerce, when it is inserted and so on
+ */
+ private static Logger coerceLogger = Logger.getLogger(TreeAnalyser.class.getName() + ".coerce");
+
+ /**
+ * if coerce should get hidden, if all their arguments are refined
+ */
+ private boolean hideCoerce;
+ /**
+ * if coerce should always be hidden,
+ */
+ private boolean hideCoerceAggressive;
+ /**
+ * if the refinement menu should get condensed at all
+ */
+ private boolean coerceReduceRM;
+ /**
+ * if coerce should get introduced automatically at all
+ */
+ private boolean autoCoerce;
+ /**
+ * if result and self should be shown always
+ */
+ private boolean showSelfResult;
+ /**
+ * if properties of self should be probed for
+ */
+ private boolean easyAttributes;
+ /**
+ * If coerces whith both Class arguments
+ */
+ private boolean highlightSubtypingErrors;
+
+ /**
+ * @param autoCoerce if coerce should get introduced automatically at all
+ * @param coerceReduceRM if the refinement menu should get condensed at all
+ * @param easyAttributes if properties of self should be probed for
+ * @param hideCoerce if coerce should get hidden, if all their arguments are refined
+ * @param hideCoerceAggressive if coerce should always be hidden,
+ * unless there is a GF constraint
+ * @param highlightSubtypingErrors If coerces whith both Class arguments
+ * refined, but not with the Subtype argument should get marked
+ * @param showSelfResult if result and self should be shown always
+ */
+ public TreeAnalyser(boolean autoCoerce, boolean coerceReduceRM, boolean easyAttributes, boolean hideCoerce, boolean hideCoerceAggressive, boolean highlightSubtypingErrors, boolean showSelfResult) {
+ this.autoCoerce = autoCoerce;
+ this.coerceReduceRM = coerceReduceRM;
+ this.easyAttributes = easyAttributes;
+ this.hideCoerce = hideCoerce;
+ this.hideCoerceAggressive = hideCoerceAggressive;
+ this.highlightSubtypingErrors = highlightSubtypingErrors;
+ this.showSelfResult = showSelfResult;
+ }
+
+
+ /**
+ * Takes the rootNode of the AST and does some small analysis on it:
+ * Check for missing Subtype witnesses,
+ * check if the Instance menu of a Coerce can be reduced
+ * @param topNode The root or top node of the AST
+ * @return an object that contains the result of this analysis.
+ * Currently this applies only to the selected node.
+ * @see TreeAnalysisResult
+ */
+ TreeAnalysisResult analyseTree(DefaultMutableTreeNode topNode) {
+ //just the initial values
+ String resultCommand = null;
+ int resultUndoSteps = -1;
+ boolean resultReduceCoerce = false;
+ boolean resultProbeSelfResult = false;
+ boolean resultDeleteAlsoAbove = false;
+ boolean resultEasyAttributes = false;
+ TreeAnalysisResult tar = new TreeAnalysisResult(resultCommand, resultUndoSteps, resultReduceCoerce, resultProbeSelfResult, resultDeleteAlsoAbove, resultEasyAttributes, null, null);
+
+ //doing it depth first, because we have to know the subtypingStatus
+ //of the children of coerce before we analyze coerce itself
+ for (Enumeration e = topNode.depthFirstEnumeration() ; e.hasMoreElements() ;) {
+ DefaultMutableTreeNode currNode = (DefaultMutableTreeNode)e.nextElement();
+ analyseTreeNode(currNode, tar);
+ }
+ AstNodeData and = (AstNodeData)tar.selectedNode.getUserObject();
+ if ((and.showInstead != -1) && (tar.command == null)) {
+ //if the current node is hidden, move up in the tree,
+ //until a visible node is found
+ DefaultMutableTreeNode tn = (DefaultMutableTreeNode)tar.selectedNode.getParent();
+ AstNodeData dand = null;
+ while (tn != null) {
+ dand = (AstNodeData)tn.getUserObject();
+ if (dand.showInstead == -1) {
+ //found a visible node
+ break;
+ }
+ tn = (DefaultMutableTreeNode)tn.getParent();
+ }
+ if (dand != null) {
+ tar.command = "[tr] mp " + dand.position;
+ tar.undoSteps = 1;
+ } //otherwise give up, can only occur, if coerce is the top node.
+ //And for that, one would have to do a "n Instance" first,
+ //which GF does not even offer.
+ }
+ return tar;
+ }
+
+ /**
+ * Takes the rootNode of the AST and does some small analysis on it:
+ * Check for missing Subtype witnesses,
+ * check if the Instance menu of a Coerce can be reduced
+ * @param nodeToCheck The node that is to be analysed
+ * @param tar The result, that gets modified
+ * @see TreeAnalysisResult
+ */
+ private void analyseTreeNode(DefaultMutableTreeNode nodeToCheck, TreeAnalysisResult tar) {
+ AstNodeData and = (AstNodeData)nodeToCheck.getUserObject();
+ DefaultMutableTreeNode parent = (DefaultMutableTreeNode)nodeToCheck.getParent();
+ Printname parentPrintname = null;
+ if ((parent != null) && (parent.getUserObject() != null) && (parent.getUserObject() instanceof AstNodeData)) {
+ AstNodeData parentAnd = (AstNodeData)parent.getUserObject();
+ parentPrintname = parentAnd.getPrintname();
+ }
+
+ if (and.selected) {
+ tar.selectedNode = nodeToCheck;
+ tar.currentNode = and.node;
+ //set the focusPosition to a preliminary value
+ tar.focusPosition = new LinPosition(and.position, true);
+ //rather check too much for null
+ if (this.autoCoerce
+ && (and.node != null)
+ && and.node.isMeta()
+ && (parent != null)
+ && (parent.getUserObject() != null)
+ && (and.node.getType() != null)
+ && (and.node.getType().startsWith("Instance"))) {
+ //check, if a coerce is needed
+ GfAstNode parentNode = ((AstNodeData)parent.getUserObject()).node;
+ if (parentPrintname.getParamAutoCoerce(parent.getIndex(nodeToCheck))) {
+ coerceLogger.fine("Coerceable fun found: " + and.node + " + " + parentNode);
+ //refine with coerce. Do not allow another GF run, so [r]
+ tar.command = "[tr] r core.coerce ;; mp " + LinPosition.calculateChildPosition(and.position, 3);
+ tar.undoSteps = 2; //move there is also sth. to be undone
+ } else if ((parentNode.getFun().indexOf("coerce") > -1)
+ //to avoid getting stuck below a coerce with wrong type arguments
+ //the coerce above is deleted and rerefined.
+
+ //coerce below a coerce is never done automatically, so the else if is justified,
+ //meaning, that introduced a coerce, we do not have to delete it right a away
+ && parent.getParent() != null
+ && (parent.getParent() instanceof DefaultMutableTreeNode)) {
+ DefaultMutableTreeNode grandParent = (DefaultMutableTreeNode)parent.getParent();
+ if (grandParent != null) {
+ AstNodeData grandParentAnd = (AstNodeData)grandParent.getUserObject();
+ Printname grandParentPrintname = grandParentAnd.getPrintname();
+
+ if (grandParentPrintname.getParamAutoCoerce(grandParent.getIndex(parent))) {
+ coerceLogger.fine("Auto-Coerce to be un- and redone: "
+ + and.node + " + " + parentNode
+ + " -- " + tar.focusPosition.position);
+ tar.command = "[tr] mp " + tar.focusPosition.parentPosition()
+ + " ;; d ;; mp " + tar.focusPosition.parentPosition()
+ + " ;; r core.coerce ;; mp " + tar.focusPosition.position;
+ tar.undoSteps = 6;
+ }
+ }
+ }
+ }
+
+ if (coerceReduceRM
+ && (and.node != null)
+ && (and.node.getType() != null)
+ && (parent != null)
+ && (parent.getUserObject() != null)
+ && (((AstNodeData)parent.getUserObject()).getPrintname() != null)
+ && (((AstNodeData)parent.getUserObject()).getPrintname().fun.endsWith("coerce"))
+ && (and.node.getType().startsWith("Instance")) //if coerce, than we are the Instance argument
+ && (((DefaultMutableTreeNode)(parent.getChildAt(2))).getUserObject() != null)
+ && (parent.getChildAt(2) != null)
+ && ((AstNodeData)((DefaultMutableTreeNode)(parent.getChildAt(2))).getUserObject()).node.isMeta()) {
+ AstNodeData superTypeAnd = ((AstNodeData)((DefaultMutableTreeNode)(parent.getChildAt(1))).getUserObject());
+ if (!superTypeAnd.node.isMeta() && (superTypeAnd.node.getFun().indexOf("OclAnyC") == -1)) {
+ //in these cases, everything goes. No sense in dozends of expensive GF runs then.
+ tar.reduceCoerce = true;
+ }
+ coerceLogger.fine("candidate for coerce reduction found: " + and.node + " + " + parent);
+ }
+
+ if (showSelfResult
+ && (and.node != null)
+ && (and.node.getType() != null)
+ && (and.node.getType().startsWith("Instance"))
+ && (tar.reduceCoerce //not everything is allowed here
+ // if not below a coerce (covered above) and no constraints
+ || (and.node.getType().indexOf("{") == -1))
+ ){
+ //if there are constraints present, there is no point in probing, since
+ //then either no or every instance is offered.
+ //We do not have to probe then.
+ tar.probeSelfResult = true;
+ }
+
+ if (easyAttributes
+ && (and.node != null)
+ && (and.node.getType() != null)
+ && (and.node.isMeta())
+ && (and.node.getType().startsWith("Instance"))
+ ) {
+ //not much to check here
+ tar.easyAttributes = true;
+ }
+ }
+
+ //check for subtyping errors
+ if (highlightSubtypingErrors
+ && (and.node != null)
+ && (and.node.getType() != null)
+ && (parent != null)
+ && (and.node.isMeta()) //otherwise GF would complain
+ && (and.node.getType().startsWith("Subtype")) //if coerce, than we are the Subtype argument
+ ) {
+ AstNodeData subtypeAnd = (AstNodeData)(((DefaultMutableTreeNode)(parent.getChildAt(0))).getUserObject());
+ AstNodeData supertypeAnd = (AstNodeData)(((DefaultMutableTreeNode)(parent.getChildAt(1))).getUserObject());
+ if ((subtypeAnd != null) && (supertypeAnd != null)) {
+ if (!supertypeAnd.node.isMeta() && !subtypeAnd.node.isMeta()) {
+ //if one of them is meta, then the situation is not fixed yet,
+ //so don't complain.
+ and.subtypingStatus = false;
+ }
+ }
+ }
+ //hide coerce if possible
+ //if coere is completely filled in (all children not meta),
+ //it will be replaced by child 3.
+ if (hideCoerce
+ && (and.node != null)
+ && (and.node.getType() != null)
+ && (and.node.getFun().endsWith("coerce"))
+ ) {
+ /**
+ * if true, then something is unfinished or constrained.
+ * So don't hide that node.
+ */
+ boolean metaChild = false;
+ //check if constraints hold for this node
+ if ((and.constraint != null) && (and.constraint.length() > 0)) {
+ //some constraint holds here.
+ //We must not shroud a possible source for that.
+ metaChild = true;
+ }
+ //This search will only be run once for each coerce:
+ for (int i = 0; i < 3 && !metaChild; i++) {
+ //This is for the more complicated collection
+ //subtyping witnesses.
+ //we do a depthFirst search to find meta nodes.
+ //If they exist, we know that we shouldn't hide this node.
+ for (Enumeration e = ((DefaultMutableTreeNode)nodeToCheck.getChildAt(i)).depthFirstEnumeration() ; e.hasMoreElements() ;) {
+ DefaultMutableTreeNode currNode = (DefaultMutableTreeNode)e.nextElement();
+ AstNodeData dand = (AstNodeData)currNode.getUserObject();
+ if (!dand.subtypingStatus
+ //hideCoerceAggressive means that just incomplete type arguments are no reason to not hide the node
+ //only subtypingStatus is one because then surely there is an error
+ || (!hideCoerceAggressive && dand.node.isMeta())) {
+ metaChild = true;
+ break; //no need to go further
+ }
+ }
+ if (metaChild) {
+ break;
+ }
+ }
+ //For the Instance argument, we do not have do to a deep search
+ AstNodeData childAnd = (AstNodeData)(((DefaultMutableTreeNode)(nodeToCheck.getChildAt(3))).getUserObject());
+ if (!hideCoerceAggressive && childAnd.node.isMeta()) {
+ //see reasons for hideCoerceAggressive above
+ metaChild = true;
+ }
+
+ if (!metaChild) {
+ and.showInstead = 3;
+ //now label the type nodes as hidden
+ for (int i = 0; i < 3 && !metaChild; i++) {
+ //This is for the more complicated collection
+ //subtyping witnesses.
+ for (Enumeration e = ((DefaultMutableTreeNode)nodeToCheck.getChildAt(i)).depthFirstEnumeration() ; e.hasMoreElements() ;) {
+ DefaultMutableTreeNode currNode = (DefaultMutableTreeNode)e.nextElement();
+ AstNodeData dand = (AstNodeData)currNode.getUserObject();
+ dand.showInstead = -2; // tag for hidden without replacement
+ }
+ }
+
+ }
+
+ //if we are at a coerce above the selected Instance node,
+ //we want to mark that, so that the d command can be modified
+ if ((and.node != null)
+ && (and.node.getFun().endsWith("coerce"))
+ && (and.showInstead > -1) //only hidden coerce
+ && (((AstNodeData)((DefaultMutableTreeNode)nodeToCheck.getChildAt(3)).getUserObject()).selected)
+ ) {
+ tar.deleteAlsoAbove = true;
+ }
+ }
+ }
+ /**
+ * Removes nodes from the tree that has topNode as its root.
+ * Affected are nodes in which the field showInstead in their
+ * AstNodeData is greater than -1
+ * @param topNode The root of the tree from which nodes should
+ * be removed.
+ * @return The root of the transformed tree.
+ * This might not be topNode, since that node might as well be
+ * removed.
+ */
+ protected static DefaultMutableTreeNode transformTree(DefaultMutableTreeNode topNode) {
+ DefaultMutableTreeNode nextNode = topNode;
+ while (nextNode != null) {
+ AstNodeData and = (AstNodeData)nextNode.getUserObject();
+ if (and.showInstead > -1) {
+ DefaultMutableTreeNode parent = (DefaultMutableTreeNode)nextNode.getParent();
+ if (parent == null) {
+ topNode = (DefaultMutableTreeNode)nextNode.getChildAt(and.showInstead);
+ if (treeLogger.isLoggable(Level.FINE)) {
+ //yeah, I know, variable naming is messed up here because of the assignment above
+ treeLogger.fine("hiding topNode ###" + nextNode + "###, showing instead ###" + topNode + "###");
+ }
+ nextNode = topNode;
+ } else {
+ final int index = parent.getIndex(nextNode);
+ parent.remove(index);
+ DefaultMutableTreeNode instead = (DefaultMutableTreeNode)nextNode.getChildAt(and.showInstead);
+ parent.insert(instead, index);
+ if (treeLogger.isLoggable(Level.FINE)) {
+ treeLogger.fine("hiding node ###" + nextNode + "###, showing instead ###" + instead + "###");
+ }
+ nextNode = instead;
+ }
+ } else {
+ nextNode = nextNode.getNextNode();
+ }
+ }
+ return topNode;
+ }
+
+}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/TreeAnalysisResult.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/TreeAnalysisResult.java
new file mode 100644
index 000000000..1bcae3421
--- /dev/null
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/TreeAnalysisResult.java
@@ -0,0 +1,92 @@
+//Copyright (c) Hans-Joachim Daniels 2005
+//
+//This program is free software; you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation; either version 2 of the License, or
+//(at your option) any later version.
+//
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//GNU General Public License for more details.
+//
+//You can either finde the file LICENSE or LICENSE.TXT in the source
+//distribution or in the .jar file of this application
+
+package de.uka.ilkd.key.ocl.gf;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+
+/**
+ * A class to store the result of the tree analysis done in formTree
+ * @author daniels
+ */
+class TreeAnalysisResult {
+ /**
+ * The command, that is to be executed next automatically
+ */
+ String command;
+ /**
+ * the number of undo steps needed to undo command
+ */
+ int undoSteps;
+ /**
+ * reduceCoerce Whether the mechanism to produce a reduced
+ * refinement menu for coerce's 4th argument should kick in or not.
+ */
+ boolean reduceCoerce;
+ /**
+ * If the editor should ask GF if self an result are applicable here or not
+ */
+ boolean probeSelfResult;
+ /**
+ * If we at the the Instance Argument of a hidden
+ * coerce, we mark that (to change the d command)
+ */
+ boolean deleteAlsoAbove;
+ /**
+ * if the attributes of self should be added to the refinement menu.
+ */
+ boolean easyAttributes;
+ DefaultMutableTreeNode selectedNode = null;
+ /**
+ * The currently selected node
+ */
+ GfAstNode currentNode;
+ /**
+ * Where the cursor in GF is.
+ * Correct is not yet known and thus always true.
+ */
+ LinPosition focusPosition;
+
+ /**
+ * Just sets both values.
+ * @param command The command, that is to be executed next automatically
+ * @param undoSteps the number of undo steps needed to undo command
+ * @param reduceCoerce Whether the mechanism to produce a reduced
+ * refinement menu for coerce's 4th argument should kick in or not.
+ * @param probeSelfResult If the editor should ask GF if self an result
+ * are applicable here or not
+ * @param deleteAlsoAbove If we at the the Instance Argument of a hidden
+ * coerce, we mark that (to change the d command)
+ * @param easyAttributes if the attributes of self should be added to the
+ * refinement menu.
+ * @param currentNode The currently selected node
+ * @param focusPosition Where the cursor in GF is.
+ * Correct is not yet known and thus always true.
+ */
+ public TreeAnalysisResult(String command, int undoSteps, boolean reduceCoerce, boolean probeSelfResult, boolean deleteAlsoAbove, boolean easyAttributes, GfAstNode currentNode, LinPosition focusPosition) {
+ this.command = command;
+ this.undoSteps = undoSteps;
+ this.reduceCoerce = reduceCoerce;
+ this.probeSelfResult = probeSelfResult;
+ this.deleteAlsoAbove = deleteAlsoAbove;
+ this.currentNode = currentNode;
+ this.easyAttributes = easyAttributes;
+ this.focusPosition = focusPosition;
+ }
+
+ public String toString() {
+ return this.command + "|" + this.reduceCoerce + "|" + this.undoSteps + "|" + this.probeSelfResult;
+ }
+}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/TypesLoader.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/TypesLoader.java
index 6700b29ea..5cf5c4bd5 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/TypesLoader.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/TypesLoader.java
@@ -15,28 +15,35 @@
package de.uka.ilkd.key.ocl.gf;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
import java.io.IOException;
import java.util.Hashtable;
import java.util.logging.*;
/**
* @author daniels
- * asks GF to print all available printnames, parses that list and generates
- * the suiting Printname objects.
+ * If the entries of the refinement menu should have to appear there with
+ * type information appended to them, then the printnames have to get this
+ * knowledge at the time of their creation.
+ * When the entries are displayed, the display text line of GF is *not* looked
+ * at. And even if it would be, it would mess up the architecture, that the
+ * printnames, and only they, are responsible for their linearization.
+ * Appending their type later on would break that architecture.
+ * So they have to be prepared.
*/
public class TypesLoader extends AbstractProber {
+ /**
+ * The hash in which the funs as keys and
+ * types as values get saved. Both are Strings.
+ */
protected final Hashtable hashtable;
- protected static Logger nogger = Logger.getLogger(TypesLoader.class.getName());
+ private static Logger nogger = Logger.getLogger(TypesLoader.class.getName());
/**
- * @param fromGf The GF process
- * @param toGf The GF process
+ * @param gfCapsule the read/write encapsulation of the running GF
* @param myHashMap The hash in which the funs as keys and
* types as values get saved. Both are Strings.
*/
- public TypesLoader(BufferedReader fromGf, BufferedWriter toGf, Hashtable myHashMap) {
- super(fromGf, toGf);
+ public TypesLoader(GfCapsule gfCapsule, Hashtable myHashMap) {
+ super(gfCapsule);
this.hashtable = myHashMap;
}
@@ -46,7 +53,7 @@ public class TypesLoader extends AbstractProber {
*/
protected void readMessage() {
try {
- String result = this.fromProc.readLine();
+ String result = gfCapsule.fromProc.readLine();
if (nogger.isLoggable(Level.FINER)) {
nogger.finer("7 " + result);
}
@@ -58,7 +65,7 @@ public class TypesLoader extends AbstractProber {
readType(result);
}
- result = this.fromProc.readLine();
+ result = gfCapsule.fromProc.readLine();
if (nogger.isLoggable(Level.FINER)) {
nogger.finer("7 " + result);
}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/UnrefinedAstNodeData.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/UnrefinedAstNodeData.java
index 2f2819290..0c12fc0fb 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/UnrefinedAstNodeData.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/UnrefinedAstNodeData.java
@@ -24,23 +24,26 @@ import java.util.logging.*;
* It knows, how it is called and described (tooltip).
*/
public class UnrefinedAstNodeData extends AstNodeData {
- protected final GfAstNode node;
+ /**
+ * The tooltip that this node as a parameter should get
+ */
protected final String paramTooltip;
- protected final String position;
/**
* For a child we have to know its name, its type and the tooltip
- * @param pTooltip
+ * @param pTooltip The tooltip that this node as a parameter should get
* @param node The GfAstNode for the current AST node, for which
* this AstNodeData is the data for.
* @param pos The position in the GF AST of this node in Haskell notation
+ * @param selected if this is the selected node in the GF AST
+ * @param constraint A constraint from a parent node, that also
+ * applies for this node.
*/
- public UnrefinedAstNodeData(String pTooltip, GfAstNode node, String pos) {
- this.node = node;
+ public UnrefinedAstNodeData(String pTooltip, GfAstNode node, String pos, boolean selected, String constraint) {
+ super(node, pos, selected, constraint);
this.paramTooltip = pTooltip;
- this.position = pos;
if (logger.isLoggable(Level.FINEST)) {
- logger.finest(this.toString() + " - " + getPosition());
+ logger.finest(this.toString() + " - " + position);
}
}
/**
@@ -57,18 +60,5 @@ public class UnrefinedAstNodeData extends AstNodeData {
public String getParamTooltip() {
return this.paramTooltip;
}
-
- public boolean isMeta() {
- return this.node.isMeta();
- }
-
- public String getPosition() {
- return this.position;
- }
-
-
- public String toString() {
- return this.node.toString();
- }
}
diff --git a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Utils.java b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Utils.java
index 0f7a9f724..076cc2308 100644
--- a/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Utils.java
+++ b/src/JavaGUI2/de/uka/ilkd/key/ocl/gf/Utils.java
@@ -20,11 +20,17 @@ package de.uka.ilkd.key.ocl.gf;
import java.io.File;
import java.util.logging.*;
import javax.swing.ProgressMonitor;
+import java.util.Vector;
+/**
+ * consists of a bunch of static methods, mostly for String
+ * @author daniels
+ *
+ */
public class Utils {
- protected static Logger timeLogger = Logger.getLogger(Utils.class.getName() + ".timer");
- protected static Logger deleteLogger = Logger.getLogger(Utils.class.getName() + ".delete");
- protected static Logger stringLogger = Logger.getLogger(Utils.class.getName() + ".string");
+ private static Logger timeLogger = Logger.getLogger(Utils.class.getName() + ".timer");
+ private static Logger deleteLogger = Logger.getLogger(Utils.class.getName() + ".delete");
+ private static Logger stringLogger = Logger.getLogger(Utils.class.getName() + ".string");
private Utils() {
//non-instantiability enforced
@@ -33,7 +39,7 @@ public class Utils {
public static final String gf = "gf";
public static final String gfcm = "gfcm";
- /*
+ /**
* Get the extension of a file.
*/
public static String getExtension(File f) {
@@ -131,7 +137,7 @@ public class Utils {
*/
public static String replaceAll(String original, String toReplace, String replacement) {
StringBuffer sb = new StringBuffer(original);
- for (int i = sb.indexOf(toReplace); i >= 0; i = sb.indexOf(toReplace)) {
+ for (int i = sb.indexOf(toReplace); i >= 0; i = sb.indexOf(toReplace, i + replacement.length())) {
sb.replace(i, i + toReplace.length(), replacement);
}
return sb.toString();
@@ -159,4 +165,79 @@ public class Utils {
}
return s;
}
+
+ /**
+ * counts the occurances of toSearch in s
+ * @param s The String in which the search shall take place
+ * @param toSearch The String that should be counted
+ * @return the number of occurances, 0 if s is null
+ */
+ public static int countOccurances(String s, String toSearch) {
+ if (s == null) {
+ return 0;
+ }
+ int result = 0;
+ for (int i = s.indexOf(toSearch); i > -1; i = s.indexOf(toSearch, i)) {
+ result++;
+ i += toSearch.length();
+ }
+ return result;
+ }
+
+ /**
+ * Takes an arbitrary Vector and executes toString on each element and
+ * puts these into a String[] of the same size as the Vector
+ * @param strings A Vector of Object, preferably String
+ * @return The Vector as a String[]
+ */
+ public static String[] vector2Array(Vector strings) {
+ String[] result = new String[strings.size()];
+ for (int i = 0; i < strings.size(); i++) {
+ result[i] = strings.get(i).toString();
+ }
+ return result;
+ }
+ /**
+ * just replace sequences of spaces with one space
+ * @param s The string to be compacted
+ * @return the compacted result
+ */
+ static String compactSpaces(String s) {
+ String localResult = new String();
+ boolean spaceIncluded = false;
+
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if (c != ' ') { // include all non-spaces
+ localResult += String.valueOf(c);
+ spaceIncluded = false;
+ } else {// we have a space
+ if (!spaceIncluded) {
+ localResult += " ";
+ spaceIncluded = true;
+ } // else just skip
+ }
+ }
+ return localResult;
+ }
+ /**
+ * Replaces all occurances of toBeReplaced, that are not escaped by '\'
+ * with replacement
+ * @param working the String in which substrings should be replaced
+ * @param toBeReplaced The substring, that should be replaced by replacement
+ * @param replacement well, the replacement string
+ * @return The String with the replaced parts
+ */
+ public static String replaceNotEscaped(String working, String toBeReplaced, String replacement) {
+ StringBuffer w = new StringBuffer(working);
+ for (int i = w.indexOf(toBeReplaced); i > -1 && i < w.length(); i = w.indexOf(toBeReplaced, i)) {
+ if (i == 0 || w.charAt(i - 1) != '\\') {
+ w.replace(i, i + toBeReplaced.length(), replacement);
+ i += replacement.length();
+ } else {
+ i += 1;
+ }
+ }
+ return w.toString();
+ }
}