Revision: 21248
http://jedit.svn.sourceforge.net/jedit/?rev=21248&view=rev
Author: kerik-sf
Date: 2012-03-05 19:37:01 +0000 (Mon, 05 Mar 2012)
Log Message:
-----------
fix XmlInsert for namespace support, code cleanup in XmlParsedData, ElementDecl
fix namespace support in completion (with prefixes)
mostly passing test cases
xml.parser.TagParser methods all use CharSequence now => no more copying the content of the buffer multiple times
Modified Paths:
--------------
plugins/XML/trunk/test/build.xml
plugins/XML/trunk/test/sidekick/html/HtmlParserTest.java
plugins/XML/trunk/test/xml/XMLTestUtils.java
plugins/XML/trunk/test/xml/XmlPluginFailingTest.java
plugins/XML/trunk/test/xml/XmlPluginTest.java
plugins/XML/trunk/test/xml/parser/TagParserTest.java
plugins/XML/trunk/test/xml/parser/XmlTagTest.java
plugins/XML/trunk/test_data/abstract_substitution/abstract_element.xsd
plugins/XML/trunk/test_data/abstract_substitution/abstract_element_instance.xml
plugins/XML/trunk/test_data/relax_ng/schemas.xml
plugins/XML/trunk/test_data/xinclude/conventions.xml
plugins/XML/trunk/xml/EditTagDialog.java
plugins/XML/trunk/xml/XmlActions.java
plugins/XML/trunk/xml/XmlInsert.java
plugins/XML/trunk/xml/XmlListCellRenderer.java
plugins/XML/trunk/xml/XmlParsedData.java
plugins/XML/trunk/xml/completion/ElementDecl.java
plugins/XML/trunk/xml/completion/XmlCompletion.java
plugins/XML/trunk/xml/completion/XsdElementDecl.java
plugins/XML/trunk/xml/parser/SchemaToCompletion.java
plugins/XML/trunk/xml/parser/TagParser.java
plugins/XML/trunk/xml/parser/XmlParser.java
Modified: plugins/XML/trunk/test/build.xml
===================================================================
--- plugins/XML/trunk/test/build.xml 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/test/build.xml 2012-03-05 19:37:01 UTC (rev 21248)
@@ -90,7 +90,7 @@
<!-- this selector holds just one test. This is optional. -->
<selector id="testcases.current">
- <filename name="xml/XmlPluginTest.java"/>
+ <filename name="sidekick/html/HtmlParserTest.java"/>
</selector>
<!-- this selector controls which tests to run, set the refid to either
Modified: plugins/XML/trunk/test/sidekick/html/HtmlParserTest.java
===================================================================
--- plugins/XML/trunk/test/sidekick/html/HtmlParserTest.java 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/test/sidekick/html/HtmlParserTest.java 2012-03-05 19:37:01 UTC (rev 21248)
@@ -62,17 +62,15 @@
public void testErrorInCss(){
File xml = new File(testData,"html/error_in_css.html");
- TestUtils.openFile(xml.getPath());
+ openParseAndWait(xml.getPath());
- parseAndWait();
-
action("sidekick-tree");
FrameFixture sidekick = TestUtils.findFrameByTitle("Sidekick");
JTreeFixture sourceTree = sidekick.tree();
// inspect the tree
- selectPath(sourceTree,"<html><html>/<head>/<STYLE>");
+ selectPath(sourceTree,",<html><html>,<head>,<STYLE type=\"text/css\">");
// ensure some coherence in the assets
JEditTextArea area = TestUtils.view().getTextArea();
@@ -82,6 +80,7 @@
action("error-list-show",1);
FrameFixture errorlist = TestUtils.findFrameByTitle("Error List");
+ errorlist.resizeWidthTo(1024);
errorlist.tree().selectRow(1);
assertEquals(";",area.getSelectedText());
assertEquals(2,area.getCaretLine());
Modified: plugins/XML/trunk/test/xml/XMLTestUtils.java
===================================================================
--- plugins/XML/trunk/test/xml/XMLTestUtils.java 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/test/xml/XMLTestUtils.java 2012-03-05 19:37:01 UTC (rev 21248)
@@ -114,6 +114,21 @@
,10000);
}
+ /** open, parse and wait for SideKickUpdate in one go, to be sure not to miss the message */
+ public static Buffer openParseAndWait(final String path){
+ final Buffer[] ret = new Buffer[1];
+ doInBetween(
+ new Runnable(){
+ public void run(){
+ ret[0] = openFile(path);
+ action("sidekick-parse");
+ }
+ },
+ messageOfClassCondition(sidekick.SideKickUpdate.class)
+ ,10000);
+ return ret[0];
+ }
+
public static void gotoPositionAndWait(int pos){
gotoPosition(pos);
Pause.pause(500);
Modified: plugins/XML/trunk/test/xml/XmlPluginFailingTest.java
===================================================================
--- plugins/XML/trunk/test/xml/XmlPluginFailingTest.java 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/test/xml/XmlPluginFailingTest.java 2012-03-05 19:37:01 UTC (rev 21248)
@@ -45,6 +45,9 @@
import java.awt.event.KeyEvent;
import java.awt.event.InputEvent;
+
+import junit.framework.AssertionFailedError;
+
import org.gjt.sp.jedit.gui.CompletionPopup;
/**
@@ -78,8 +81,11 @@
FrameFixture insert = TestUtils.findFrameByTitle("XML Insert");
// wait for end of parsing
+ try{
simplyWaitForMessageOfClass(sidekick.SideKickUpdate.class,10000);
-
+ }catch(AssertionFailedError e){
+ // no worry
+ }
action("error-list-show",1);
Modified: plugins/XML/trunk/test/xml/XmlPluginTest.java
===================================================================
--- plugins/XML/trunk/test/xml/XmlPluginTest.java 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/test/xml/XmlPluginTest.java 2012-03-05 19:37:01 UTC (rev 21248)
@@ -19,6 +19,7 @@
import org.junit.*;
import static org.junit.Assert.*;
+import org.fest.assertions.ObjectArrayAssert;
import org.fest.swing.fixture.*;
import org.fest.swing.core.*;
import org.fest.swing.finder.*;
@@ -78,28 +79,107 @@
public void testAbstractSubstitution() throws IOException{
File xml = new File(testData,"abstract_substitution/abstract_element_instance.xml");
- TestUtils.openFile(xml.getPath());
- parseAndWait();
+ final Buffer b = openParseAndWait(xml.getPath());
- action("xml-insert-float",1);
-
- FrameFixture insert = TestUtils.findFrameByTitle("XML Insert");
-
- // go into the file
- gotoPositionAndWait(530);
+ try{
+ gotoPositionAndWait(348);
+ GuiActionRunner.execute(new GuiTask(){
+ protected void executeInEDT(){
+ view().getTextArea().setSelectedText("<");
+ }
+ });
+
+ action("sidekick-complete",1);
+
+ JWindowFixture completion;
+
+ completion = XMLTestUtils.completionPopup();
+ completion.requireVisible();
+ ObjectArrayAssert al = assertThat(xmlListContents(completion.list()));
+
+ // reportTitle is in the report namespace. It's proposed without prefix
+ al.contains("reportTitle");
+ // comment is abstract: it's not proposed
+ al.excludes("ns0:comment");
+ // some concrete comments are proposed, in a generated prefix (ns0)
+ al.contains("ns0:customerComment");
+ JListFixture list = completion.list().cellReader(xmlListCellReader());
+
+ list.selectItem("reportTitle");
+
+ // inserted, without IPO namespace
+ assertTrue(b.getText().contains("<reportTitle></reportTitle>"));
+ assertFalse(b.getText(348,b.getLength()-348).contains("http://www.example.com/IPO"));
+
+ action("undo",1);
+
+ // now, try to insert element with generated prefix
+ GuiActionRunner.execute(new GuiTask(){
+ protected void executeInEDT(){
+ view().getTextArea().setSelectedText("<");
+ }
+ });
+
+ action("sidekick-complete",1);
- assertThat(xmlListContents(insert.list("elements"))).contains("ipo:shipComment");
- assertThat(xmlListContents(insert.list("elements"))).excludes("ipo:comment").excludes("comment");
- assertThat(xmlListContents(insert.list("elements"))).excludes("ipo:otherComment").excludes("otherComment");
- assertThat(xmlListContents(insert.list("elements"))).contains("ipo:concreteOtherComment");
-
- // go into the customerComment
- gotoPositionAndWait(483);
-
- Pause.pause(500);
- assertThat(xmlListContents(insert.list("elements"))).contains("customerId");
+ completion = XMLTestUtils.completionPopup();
+ completion.requireVisible();
+ assertThat(xmlListContents(completion.list())).contains("ns0:customerComment");
+
+ list = completion.list().cellReader(xmlListCellReader());
- insert.close();
+ int iRT = list.item("ns0:customerComment").index();
+ for(int i=0;i<iRT;i++){
+ list.pressAndReleaseKeys(KeyEvent.VK_DOWN);
+ }
+ list.pressAndReleaseKeys(KeyEvent.VK_SPACE);
+
+ assertTrue(b.getText().contains("<ns0:customerComment xmlns:ns0=\"http://www.example.com/IPO\""));
+
+ action("undo",1);
+
+ // now, try to insert element with chosen prefix
+ GuiActionRunner.execute(new GuiTask(){
+ protected void executeInEDT(){
+ view().getTextArea().setSelectedText("<ipo:");
+ }
+ });
+
+ action("sidekick-complete",1);
+
+ completion = XMLTestUtils.completionPopup();
+ completion.requireVisible();
+ // reportTitle can't be there because we chose a new prefix
+ assertThat(xmlListContents(completion.list())).contains("ipo:customerComment").excludes("reportTitle");
+
+ list = completion.list().cellReader(xmlListCellReader());
+
+ list.selectItem("ipo:customerComment");
+
+ assertTrue(b.getText().contains("<ipo:customerComment xmlns:ipo=\"http://www.example.com/IPO\""));
+
+ parseAndWait();
+
+ Pause.pause(1000);
+ // try to insert customerId
+ // now, try to insert element with chosen prefix
+ GuiActionRunner.execute(new GuiTask(){
+ protected void executeInEDT(){
+ view().getTextArea().setSelectedText("<");
+ }
+ });
+
+ action("sidekick-complete",1);
+
+ completion = XMLTestUtils.completionPopup();
+ completion.requireVisible();
+ assertThat(xmlListContents(completion.list())).contains("customerId");
+
+
+ }finally{
+ // discard changes
+ TestUtils.close(view(), b);
+ }
}
/** Tests XML Plugin's completion
@@ -109,10 +189,8 @@
public void testAttributesCompletion() throws IOException{
File xml = new File(testData,"attributes_completion/attributes.xml");
- TestUtils.openFile(xml.getPath());
+ openParseAndWait(xml.getPath());
- parseAndWait();
-
// aa, ab
gotoPositionAndWait(493);
@@ -219,11 +297,8 @@
public void testCompoundDocuments(){
File xml = new File(testData,"compound_documents/fragment1.xml");
- TestUtils.openFile(xml.getPath());
+ openParseAndWait(xml.getPath());
- // wait for end of parsing
- parseAndWait();
-
action("xml-insert-float",1);
@@ -237,7 +312,7 @@
// ids declared in other fragment appear heare
assertThat(xmlListContents(insert.list("ids"))).contains("testing [element: <chapter>]");
- insert.list("ids").item("testing [element: <chapter>]").click(MouseButton.RIGHT_BUTTON);
+ insert.list("ids").cellReader(xmlListCellReader()).item("testing [element: <chapter>]").click(MouseButton.RIGHT_BUTTON);
Pause.pause(1000);
@@ -576,10 +651,8 @@
public void testImportSchemaRNG(){
File xml = new File(testData,"import_schema/relax_ng/instance.xml");
- final Buffer b = TestUtils.openFile(xml.getPath());
+ final Buffer b = openParseAndWait(xml.getPath());
- parseAndWait();
-
action("xml-insert-float",1);
FrameFixture insert = TestUtils.findFrameByTitle("XML Insert");
@@ -705,7 +778,7 @@
public String valueFrom(Component c) {
if(c instanceof XmlListCellRenderer){
return ((XmlListCellRenderer)c).getMainText();
- }else return null;
+ }else return "argh";
}
});
Modified: plugins/XML/trunk/test/xml/parser/TagParserTest.java
===================================================================
--- plugins/XML/trunk/test/xml/parser/TagParserTest.java 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/test/xml/parser/TagParserTest.java 2012-03-05 19:37:01 UTC (rev 21248)
@@ -451,11 +451,8 @@
public void testFindLastOpenTagHTML(){
final File in = new File(testData,"tagparser/test.html");
- Buffer b = openFile(in.getPath());
+ Buffer b = openParseAndWait(in.getPath());
- // wait for end of parsing
- parseAndWait();
-
XmlParsedData data = getXmlParsedData();
String text = b.getText(0, b.getLength());
Tag t;
Modified: plugins/XML/trunk/test/xml/parser/XmlTagTest.java
===================================================================
--- plugins/XML/trunk/test/xml/parser/XmlTagTest.java 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/test/xml/parser/XmlTagTest.java 2012-03-05 19:37:01 UTC (rev 21248)
@@ -79,8 +79,8 @@
JTreeFixture sourceTree = sidekick.tree();
// inspect the tree
- selectPath(sourceTree,"ACTIONS");
- selectPath(sourceTree,"ACTIONS/ACTION/CODE");
+ selectPath(sourceTree,"/ACTIONS");
+ selectPath(sourceTree,"/ACTIONS/ACTION/CODE");
// ensure some coherence in the assets
JEditTextArea area = TestUtils.view().getTextArea();
@@ -113,7 +113,7 @@
JTreeFixture sourceTree = sidekick.tree();
// inspect the tree
- selectPath(sourceTree,"chapter id=\"conventions\"");
+ selectPath(sourceTree,"/chapter id=\"conventions\"");
/*------ test Attributes = None ---------*/
@@ -134,7 +134,7 @@
Pause.pause(1000);
// inspect the tree
- selectPath(sourceTree,"chapter");
+ selectPath(sourceTree,"/chapter");
/*------ test Attributes = All ---------*/
@@ -153,7 +153,7 @@
Pause.pause(1000);
// inspect the tree
- selectPath(sourceTree,"chapter id=\"conventions\" xml:lang=\"en\"");
+ selectPath(sourceTree,"/chapter id=\"conventions\" xml:lang=\"en\"");
}
}
Modified: plugins/XML/trunk/test_data/abstract_substitution/abstract_element.xsd
===================================================================
--- plugins/XML/trunk/test_data/abstract_substitution/abstract_element.xsd 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/test_data/abstract_substitution/abstract_element.xsd 2012-03-05 19:37:01 UTC (rev 21248)
@@ -15,9 +15,12 @@
<element name="purchaseReport">
<complexType>
- <sequence maxOccurs="unbounded">
+ <choice minOccurs="0" maxOccurs="unbounded">
<element ref="xipo:comment"/>
- </sequence>
+ <!-- this one is in the Report namespace, to see how completion
+ handles elements in undeclared namespace vs declared namespace -->
+ <element name="reportTitle" type="string"/>
+ </choice>
</complexType>
</element>
Modified: plugins/XML/trunk/test_data/abstract_substitution/abstract_element_instance.xml
===================================================================
--- plugins/XML/trunk/test_data/abstract_substitution/abstract_element_instance.xml 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/test_data/abstract_substitution/abstract_element_instance.xml 2012-03-05 19:37:01 UTC (rev 21248)
@@ -4,14 +4,11 @@
<purchaseReport
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.example.com/Report"
- xmlns:ipo="http://www.example.com/IPO"
xsi:schemaLocation="http://www.example.com/Report
abstract_element.xsd
http://www.example.com/IPO
comments.xsd">
- <ipo:shipComment>Use gold wrap if possible</ipo:shipComment>
- <ipo:customerComment>Want this for the holidays!</ipo:customerComment>
- <!-- bah : no comment is allowed here -->
- <ipo:comment>I'm abstract, remember ?</ipo:comment>
+
+ <ipo:comment>I'm abstract, remember ?</ipo:comment>
</purchaseReport>
Modified: plugins/XML/trunk/test_data/relax_ng/schemas.xml
===================================================================
--- plugins/XML/trunk/test_data/relax_ng/schemas.xml 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/test_data/relax_ng/schemas.xml 2012-03-05 19:37:01 UTC (rev 21248)
@@ -4,5 +4,5 @@
<documentElement localName="ACTIONS" typeId="ACTIONS"/>
<uri pattern="*.rng" typeId="RNG"/>
<typeId id="ACTIONS" uri="actions.rng"/>
-<typeId id="RNG" uri="relaxng.rng"/>
+<typeId id="RNG" uri="jeditresource:XML.jar!/xml/dtds/relaxng.rng"/>
</locatingRules>
\ No newline at end of file
Modified: plugins/XML/trunk/test_data/xinclude/conventions.xml
===================================================================
--- plugins/XML/trunk/test_data/xinclude/conventions.xml 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/test_data/xinclude/conventions.xml 2012-03-05 19:37:01 UTC (rev 21248)
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<chapter id="conventions" >
+<chapter id="conventions" xml:lang="en">
<title>Conventions</title>
<para>Conventions are always useful.</para>
Modified: plugins/XML/trunk/xml/EditTagDialog.java
===================================================================
--- plugins/XML/trunk/xml/EditTagDialog.java 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/xml/EditTagDialog.java 2012-03-05 19:37:01 UTC (rev 21248)
@@ -220,13 +220,15 @@
}
ArrayList<Attribute> attributeModel = new ArrayList<Attribute>();
+ // keep original list of namespaces to insert, otherwise it gets polluted by namespaces of attributes not inserted
+ Map<String,String> localNamespacesToInsert = new HashMap<String,String>(namespacesToInsert);
for(int i = 0; i < declaredAttributes.size(); i++)
{
AttributeDecl attr =
(AttributeDecl)
declaredAttributes.get(i);
- String attrName = composeName(attr.name, attr.namespace, namespaces, namespacesToInsert);
+ String attrName = composeName(attr.name, attr.namespace, namespaces, localNamespacesToInsert);
boolean set;
String value = (String)attributeValues.get(attrName);
@@ -257,7 +259,7 @@
value = (String)values.get(0);
}
- attributeModel.add(new Attribute(set,attrName,
+ attributeModel.add(new Attribute(set,attrName,attr.namespace,
value,values,attr.type,attr.required));
}
@@ -270,7 +272,9 @@
private void updateTag()
{
int tagNameCase = TextUtilities.getStringCase(elementName);
-
+ // only append namespaces really used or in the original namespacesToInsert
+ Map<String,String> localNamespacesToInsert = new HashMap<String,String>(namespacesToInsert);
+
StringBuilder buf = new StringBuilder("<");
buf.append(elementName);
@@ -298,7 +302,16 @@
break;
}
}
-
+ else
+ {
+ String prefix = XmlParsedData.getElementNamePrefix(attrName);
+ if(!NamespaceSupport.XMLNS.equals(attr.namespace)
+ && !namespaces.containsKey(attr.namespace)
+ && !localNamespacesToInsert.containsKey(attr.namespace))
+ {
+ localNamespacesToInsert.put(attr.namespace,prefix);
+ }
+ }
buf.append(attrName);
if(html && attr.name.equals(attr.value.value))
@@ -315,7 +328,7 @@
buf.append("\"");
}
- appendNamespaces(namespacesToInsert,buf);
+ appendNamespaces(localNamespacesToInsert,buf);
if(empty.isSelected() && !html)
buf.append("/");
@@ -352,18 +365,20 @@
boolean set;
String name;
+ String namespace;
Value value;
String type;
boolean required;
//}}}
//{{{ Attribute constructor
- Attribute(boolean set, String name,
+ Attribute(boolean set, String name, String namespace,
String value, ArrayList values,
String type, boolean required)
{
this.set = set;
this.name = name;
+ this.namespace = namespace;
this.value = new Value(value,values);
this.type = type;
this.required = required;
@@ -684,7 +699,7 @@
/**
- * create open and close tags for an ElementDecl (with required attributes).
+ * create open and close tags for an ElementDecl (with required attributes but without starting < angle bracket).
* if elementDecl.isEmpty, close tag will be empty and open tag will be standalone (if not html)
* @param data
* @param elementDecl element to create tags for
@@ -730,13 +745,15 @@
* @return new prefix
*/
public static String generatePrefix(Map<String,String> ... namespaces) {
+ String pre;
for(int i=0;;i++){
- String pre = "ns"+i;
+ pre = "ns"+i;
+ boolean notSeen = true;
for(Map<String,String> namespace: namespaces){
- if(!namespace.containsKey(pre)){
- return pre;
- }
+ notSeen &= !namespace.containsKey(pre);
+ if(!notSeen)break;
}
+ if(notSeen)return pre;
}
}
}
Modified: plugins/XML/trunk/xml/XmlActions.java
===================================================================
--- plugins/XML/trunk/xml/XmlActions.java 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/xml/XmlActions.java 2012-03-05 19:37:01 UTC (rev 21248)
@@ -89,7 +89,7 @@
XmlParsedData data = XmlParsedData.getParsedData(view, true);
if(data == null)return;
- String text = buffer.getText(0,buffer.getLength());
+ CharSequence text = buffer.getSegment(0,buffer.getLength());
int caret = textArea.getCaretPosition();
@@ -110,8 +110,8 @@
* the escape character, so we have to work around it here. */
char backslashSub = 127;
StreamTokenizer st = new StreamTokenizer(new StringReader(
- text.substring(tag.start + tag.tag.length() + 1,
- tag.end - 1)
+ text.subSequence(tag.start + tag.tag.length() + 1,
+ tag.end - 1).toString()
.replace('\\',backslashSub)));
st.resetSyntax();
st.wordChars('!',255);
@@ -193,7 +193,7 @@
}
// tag.start+1 because don't want the locally declared namespaces
- Map<String,String> namespaces = data.getNamespaces(tag.start+1);
+ Map<String,String> namespaces = data.getNamespaceBindings(tag.start+1);
Map<String,String> namespacesToInsert = new HashMap<String,String>();
// grab namespaces declared in this tag
@@ -229,13 +229,14 @@
/**
* show EditTagDialog in order to insert open and close tags or edit current tag
* @param view current view
+ * @param elementName qualified element name to insert
* @param elementDecl element to insert (may not be null)
* @param insideTag Selection of the current start tag (or part of, for instance inf XmlCompletion, what has been already typed)
* @param namespaces namespace bindings in scope for current location (not those declared inside the start tag itself)
* @param namespacesToInsert namespace bindings that will have to be inserted at the end of the start tag
* @param reallyShowEditTagDialog false to disable showing the dialog at all, but insert the start and end tags nonetheless
*/
- public static void showEditTagDialog(View view, ElementDecl elementDecl, Selection insideTag, Map<String, String> namespaces, Map<String, String> namespacesToInsert, boolean reallyShowEditTagDialog)
+ public static void showEditTagDialog(View view, String elementName, ElementDecl elementDecl, Selection insideTag, Map<String, String> namespaces, Map<String, String> namespacesToInsert, boolean reallyShowEditTagDialog)
{
Buffer buffer = view.getBuffer();
@@ -249,32 +250,24 @@
if(!reallyShowEditTagDialog)
{
StringBuilder[] openclose = EditTagDialog.composeTag(data, elementDecl, namespaces, namespacesToInsert, true);
+ // composeTag doesn't insert the <
+ openclose[0].insert(0, '<');
newTag = openclose[0].toString();
closingTag = openclose[1].toString();
}
else
{
- EditTagDialog dialog = new EditTagDialog(view,elementDecl.name,elementDecl,
+ EditTagDialog dialog = new EditTagDialog(view,elementName,elementDecl,
new HashMap<String, Object>(),elementDecl.empty,
elementDecl.completionInfo.entityHash,
data.getSortedIds(),data.html, namespaces, namespacesToInsert);
- // painfully recover the qualified name of the element
newTag = dialog.getNewTag();
- String newName;
- if(newTag==null){
- newName = "";
- }else if(newTag.contains(" ")){
- newName = newTag.substring(1,newTag.indexOf(" "));
- }else{
- newName = newTag.substring(1, newTag.length()-1);
- }
-
if(dialog.isEmpty())
closingTag = "";
else
- closingTag = "</" + newName + ">";
+ closingTag = "</" + elementName + ">";
}
// really insert now
@@ -346,7 +339,7 @@
/**
* Splits tag at caret, so that attributes are on separate lines.
*/
- public static void splitTag(Tag tag, JEditTextArea textArea, String text) {
+ public static void splitTag(Tag tag, JEditTextArea textArea, CharSequence text) {
View view = textArea.getView();
textArea.setSelection(new Selection.Range(tag.start, tag.end));
XmlParsedData data = XmlParsedData.getParsedData(view,true);
@@ -423,7 +416,7 @@
JEditTextArea textArea = view.getTextArea();
Buffer buffer = view.getBuffer();
int pos = textArea.getCaretPosition();
- String text = buffer.getText(0,buffer.getLength());
+ CharSequence text = buffer.getSegment(0,buffer.getLength());
Tag tag = TagParser.getTagAtOffset(text, pos);
if (tag == null) return; // we're not in a tag;
@@ -502,7 +495,7 @@
JEditTextArea textArea = view.getTextArea();
Buffer buffer = view.getBuffer();
int pos = textArea.getCaretPosition();
- String text = buffer.getText(0,buffer.getLength());
+ CharSequence text = buffer.getSegment(0,buffer.getLength());
Tag t = TagParser.getTagAtOffset(text, pos);
if (t != null && t.end != pos) { // getTagAtOffset will return a tag if you are just after it
splitTag(t, textArea, text);
@@ -580,9 +573,9 @@
{
buffer.beginCompoundEdit();
- String text = buffer.getText(off,len);
- for (int i = text.indexOf('<');
- i != -1; i = text.indexOf('<', ++i))
+ CharSequence text = buffer.getSegment(off,len);
+ for (int i = TagParser.indexOf(text, '<',0);
+ i != -1; i = TagParser.indexOf(text,'<', ++i))
{
TagParser.Tag tag = TagParser.getTagAtOffset(text,i + 1);
if (tag == null)
@@ -625,7 +618,7 @@
//{{{ xmlMatchTag() method
public static void xmlMatchTag(JEditTextArea textArea)
{
- String text = textArea.getText();
+ CharSequence text = textArea.getBuffer().getSegment(0,textArea.getBufferLength());
int caret = textArea.getCaretPosition();
// De-Select previous selection
@@ -666,7 +659,7 @@
final int step = 2;
- String text = textArea.getText();
+ CharSequence text = textArea.getBuffer().getSegment(0, textArea.getBufferLength());
boolean isSel = textArea.getSelectionCount() == 1;
int caret, pos;
@@ -735,7 +728,7 @@
* Selects tag at caret. Also returns it. Returns null if there is no tag.
* */
public static Tag selectTag(JEditTextArea textArea) {
- String text = textArea.getText();
+ CharSequence text = textArea.getBuffer().getSegment(0, textArea.getBufferLength());
int pos = textArea.getCaretPosition();
Tag t = TagParser.getTagAtOffset(text, pos);
if (t == null) return null;
@@ -752,7 +745,7 @@
final int step = 2;
- String text = textArea.getText();
+ CharSequence text = textArea.getBuffer().getSegment(0,textArea.getBufferLength());
boolean isSel = textArea.getSelectionCount() == 1;
int caret, pos;
@@ -836,7 +829,7 @@
int caret = textArea.getCaretPosition();
- String text = buffer.getText(0,caret);
+ CharSequence text = buffer.getSegment(0,caret);
TagParser.Tag tag = TagParser.getTagAtOffset(text,caret - 1);
if(tag == null)
@@ -896,7 +889,7 @@
if(caret == 1)
return;
- String text = buffer.getText(0,buffer.getLength());
+ CharSequence text = buffer.getSegment(0,buffer.getLength());
if(text.charAt(caret - 2) != '<')
return;
Modified: plugins/XML/trunk/xml/XmlInsert.java
===================================================================
--- plugins/XML/trunk/xml/XmlInsert.java 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/xml/XmlInsert.java 2012-03-05 19:37:01 UTC (rev 21248)
@@ -24,6 +24,7 @@
import java.awt.Rectangle;
import java.util.HashMap;
import java.util.List;
+import java.util.ArrayList;
import java.util.Map;
import org.gjt.sp.jedit.msg.*;
@@ -32,6 +33,7 @@
import org.gjt.sp.jedit.io.VFSManager;
import org.gjt.sp.util.Log;
import sidekick.*;
+import xml.XmlListCellRenderer.WithLabel;
import xml.completion.*;
import xml.parser.TagParser;
//}}}
@@ -250,7 +252,7 @@
if(elements == null)
{
DefaultListModel model = new DefaultListModel();
- model.addElement(jEdit.getProperty("xml-insert.not-parsed"));
+ model.addElement(new WithLabel<String>("",jEdit.getProperty("xml-insert.not-parsed")));
elementList.setModel(model);
}
else
@@ -271,17 +273,22 @@
} //}}}
//{{{ setDeclaredEntities() method
- private void setDeclaredEntities(List entities)
+ private void setDeclaredEntities(List<EntityDecl> entities)
{
if(entities == null)
{
DefaultListModel model = new DefaultListModel();
- model.addElement(jEdit.getProperty("xml-insert.not-parsed"));
+ model.addElement(new WithLabel<String>(jEdit.getProperty("xml-insert.not-parsed")));
entityList.setModel(model);
}
else
{
- ArrayListModel model = new ArrayListModel(entities);
+ List<WithLabel<EntityDecl>> nentities = new ArrayList<WithLabel<EntityDecl>>(entities.size());
+ for(EntityDecl e:entities){
+ nentities.add(new WithLabel<EntityDecl>(e));
+ }
+
+ ArrayListModel model = new ArrayListModel(nentities);
entityList.setModel(model);
if(model.getSize() != 0)
@@ -298,17 +305,23 @@
} //}}}
//{{{ setDeclaredIDs() method
- private void setDeclaredIDs(List ids)
+ private void setDeclaredIDs(List<IDDecl> ids)
{
if(ids == null)
{
DefaultListModel model = new DefaultListModel();
- model.addElement(jEdit.getProperty("xml-insert.not-parsed"));
+ model.addElement(new WithLabel<String>(jEdit.getProperty("xml-insert.not-parsed")));
idList.setModel(model);
}
else
{
- ArrayListModel model = new ArrayListModel(ids);
+
+ List<WithLabel<IDDecl>> nids = new ArrayList<WithLabel<IDDecl>>(ids.size());
+ for(IDDecl id:ids){
+ nids.add(new WithLabel<IDDecl>(id));
+ }
+
+ ArrayListModel model = new ArrayListModel(nids);
idList.setModel(model);
if(model.getSize() != 0)
@@ -334,17 +347,60 @@
{
Selection[] selection = view.getTextArea().getSelection();
-
+ List<ElementDecl> l;
if(selection.length > 0) {
- setDeclaredElements(data.getAllowedElements(
- buffer,
- selection[0].getStart(),
- selection[0].getEnd()));
+ l = data.getAllowedElements(
+ buffer,
+ selection[0].getStart(),
+ selection[0].getEnd());
}
- else {
- setDeclaredElements(data.getAllowedElements(
+ else
+ {
+ l = (data.getAllowedElements(
buffer,view.getTextArea().getCaretPosition()));
}
+
+ List<WithLabel<ElementDecl>> nl = new ArrayList<WithLabel<ElementDecl>>(l.size());
+ Map<String, String> namespaces = data.getNamespaceBindings(view.getTextArea().getCaretPosition());
+ Map<String, String> localNamespacesToInsert = new HashMap<String, String>();
+ for(ElementDecl elementDecl: l){
+ String elementName;
+ String elementNamespace = elementDecl.completionInfo.namespace;
+ // elementDecl.name is the local name, now we must find a qualified name
+ if(elementNamespace == null || "".equals(elementNamespace))
+ {
+ elementName = elementDecl.name;
+ }
+ else
+ {
+ String pre = namespaces.get(elementNamespace);
+ if(pre == null)
+ {
+ pre = localNamespacesToInsert.get(elementNamespace);
+ }
+ if(pre == null)
+ {
+ // handle elements in undeclared namespace and no prefix.
+ // Generate a new prefix.
+ // Store it locally, so that the declaration is not inserted when this completion is not chosen.
+ // If it's chosen, a prefix (maybe different) will be generated
+ pre = EditTagDialog.generatePrefix(namespaces, localNamespacesToInsert);
+ localNamespacesToInsert.put(elementNamespace,pre);
+ elementName = pre + ":" + elementDecl.name;
+ }
+ else
+ {
+ if("".equals(pre)){
+ elementName = elementDecl.name;
+ }else{
+ elementName = pre + ":" + elementDecl.name;
+ }
+ }
+ }
+
+ nl.add(new WithLabel<ElementDecl>(elementName, elementDecl));
+ }
+ setDeclaredElements(nl);
}
else
{
@@ -422,27 +478,27 @@
if(data==null)return;
int pos = textArea.getCaretPosition();
- //FIXME: crude parsing and getting a big chunk of text here !
- String t = buffer.getText(0, pos);
/* Check if we are inside a tag, and if so, wipe it out before
inserting the one we just created */
- if (TagParser.isInsideTag(t, pos)) {
- int openAngle = t.lastIndexOf('<');
- insideTag = new Selection.Range(openAngle, pos);
+ CharSequence text = buffer.getSegment(0, buffer.getLength());
+ TagParser.Tag current = TagParser.getTagAtOffset(text,pos);
+ if (current!=null && current.start < pos && current.end >= pos) {
+ insideTag = new Selection.Range(current.start, current.end+1);
}
idList.setSelectedIndex(index);
- Object obj = elementList.getModel().getElementAt(index);
+ WithLabel<Object> wqn = (WithLabel<Object>)elementList.getModel().getElementAt(index);
+ Object obj = wqn.element;
if(!(obj instanceof ElementDecl))
return;
ElementDecl element = (ElementDecl)obj;
- Map<String,String> namespaces = data.getNamespaces(pos);
+ Map<String,String> namespaces = data.getNamespaceBindings(pos);
Map<String,String> namespacesToInsert = new HashMap<String,String>();
// all the work is done in XmlActions.showEditTagDialog
- XmlActions.showEditTagDialog(view,element,insideTag, namespaces, namespacesToInsert,GUIUtilities.isPopupTrigger(evt));
+ XmlActions.showEditTagDialog(view,wqn.label, element,insideTag, namespaces, namespacesToInsert,GUIUtilities.isPopupTrigger(evt));
} //}}}
//{{{ Handle clicks in entity list
else if(evt.getSource() == entityList)
@@ -452,7 +508,8 @@
if(index == -1)
return;
- Object obj = entityList.getModel().getElementAt(index);
+ WithLabel<Object> wl = (WithLabel<Object>) entityList.getModel().getElementAt(index);
+ Object obj = wl.element;
if(!(obj instanceof EntityDecl))
return;
@@ -472,7 +529,8 @@
return;
idList.setSelectedIndex(index);
- Object obj = idList.getModel().getElementAt(index);
+ WithLabel<Object> wl = (WithLabel<Object>) idList.getModel().getElementAt(index);
+ Object obj = wl.element;
if(!(obj instanceof IDDecl))
return;
Modified: plugins/XML/trunk/xml/XmlListCellRenderer.java
===================================================================
--- plugins/XML/trunk/xml/XmlListCellRenderer.java 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/xml/XmlListCellRenderer.java 2012-03-05 19:37:01 UTC (rev 21248)
@@ -62,7 +62,7 @@
//{{{ getListCellRendererComponent() method
public Component getListCellRendererComponent(
JList list,
- Object value,
+ Object obj,
int index,
boolean isSelected,
boolean cellHasFocus)
@@ -75,6 +75,11 @@
setBorder(left.getBorder());
left.setBorder(null);
right.setBorder(null);
+ // objects are stored in a WithLabel,
+ // to have a preview of the qualified element name
+ // without modifying the ElementDecl (resp. AttributeDecl)
+ WithLabel<Object> wqn = (WithLabel<Object>)obj;
+ Object value = wqn.element;
if(value instanceof Comment)
{
left.setIcon(COMMENT_ICON);
@@ -94,13 +99,12 @@
{
ElementDecl element = (ElementDecl)value;
left.setIcon(element.empty ? EMPTY_ELEMENT_ICON : ELEMENT_ICON);
- left.setText(element.name);
+ left.setText(wqn.label);
}
/* Add a case for AttribDecl */
else if(value instanceof AttributeDecl)
{
- AttributeDecl ad = (AttributeDecl)value;
- left.setText(ad.name);
+ left.setText(wqn.label);
}
else if(value instanceof EntityDecl)
{
@@ -208,4 +212,26 @@
public static class Comment {}
public static class CDATA {}
+
+ /**
+ * store a completion with its label for preview
+ */
+ public static class WithLabel<Q extends Object>
+ {
+ public String label;
+ public Q element;
+
+ /** label will be null */
+ public WithLabel(Q element)
+ {
+ this(null, element);
+ }
+
+ public WithLabel(String qname, Q element)
+ {
+ this.label = qname;
+ this.element = element;
+ }
+
+ }
}
Modified: plugins/XML/trunk/xml/XmlParsedData.java
===================================================================
--- plugins/XML/trunk/xml/XmlParsedData.java 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/xml/XmlParsedData.java 2012-03-05 19:37:01 UTC (rev 21248)
@@ -149,7 +149,6 @@
} //}}}
//{{{ getElementDecl(String,int) method
- // FIXME: pass buffer as parameter,
public ElementDecl getElementDecl(String name, int pos)
{
if(Debug.DEBUG_COMPLETION)Log.log(Log.DEBUG,XmlParsedData.class,
@@ -162,7 +161,7 @@
if(html)
{
- decl = getElementDeclInternal(name,pos);
+ decl = getElementDeclHTML(name,pos);
}
else
{
@@ -220,7 +219,7 @@
{
if(Debug.DEBUG_COMPLETION)Log.log(Log.DEBUG,XmlParsedData.class,
"SideKick tree is in sync");
- decl = getElementDecl(parentNode,parentXmlTag);
+ decl = getElementDeclFromSideKick(parentNode,parentXmlTag);
}
else
{
@@ -256,36 +255,15 @@
}
return decl;
}
- /**
- * @param ancestorDecl ElementDecl to inspect; never the one looked for
- * @param visitedDecls avoid lopping by storing visited decls
- */
- ElementDecl findElementDeclInDescendants(ElementDecl ancestorDecl,String namespace,String localName, List<ElementDecl> visitedDecls){
- if(visitedDecls.contains(ancestorDecl))return null;
- if(ancestorDecl.elementHash != null){
- for(ElementDecl child : ancestorDecl.elementHash.values()){
- ElementDecl res = null;
- if(child.name.equals(localName) && namespace.equals(child.completionInfo.namespace)){
- return child;
- }else{
- visitedDecls.add(ancestorDecl);
- res = findElementDeclInDescendants(child,namespace,localName,visitedDecls);
- if(res != null)return res;
- else visitedDecls.remove(visitedDecls.size()-1);
- }
- }
- }
- return null;
- }
//}}}
//{{{ getElementDeclInternal(name, pos) method
/**
- * finds a global declaration of an element, returns it with correct prefix
+ * finds a global declaration of an element, returns it without prefix
* @param name qualified name (with prefix) of an element
* @param pos used to get the namespace bindings
*/
- public ElementDecl getElementDeclInternal(String name,int pos)
+ private ElementDecl getElementDeclHTML(String name,int pos)
{
if(html)
name = name.toLowerCase();
@@ -313,23 +291,17 @@
return null;
else
{
- String lName;
- int prefixLen = prefix.length();
- if(prefixLen == 0)
- lName = name;
- else
- lName = name.substring(prefixLen + 1);
-
+ String lName = getElementLocalName(name);
ElementDecl decl = info.elementHash.get(lName);
if(decl == null)
return null;
else
- return decl.withPrefix(prefix);
+ return decl;
}
} //}}}
//{{{ getElementDecl() method
- public ElementDecl getElementDecl(DefaultMutableTreeNode node,XmlTag tag)
+ private ElementDecl getElementDeclFromSideKick(DefaultMutableTreeNode node,XmlTag tag)
{
if(Debug.DEBUG_COMPLETION)Log.log(Log.DEBUG,XmlParsedData.class,
"getElementDecl("+node+","+tag.getName()+")");
@@ -342,10 +314,8 @@
String prefix = tag.getPrefix();
String lName = tag.getLocalName();
- ElementDecl decl;
if(!info.nameConflict && info.elementHash != null) {
- decl = info.elementHash.get(lName);
- return decl.withPrefix(prefix);
+ return info.elementHash.get(lName);
}
else
{
@@ -353,17 +323,16 @@
if(parentNode.getUserObject() instanceof XmlTag)
{
XmlTag parentTag = (XmlTag)parentNode.getUserObject();
- ElementDecl parentDecl = getElementDecl(parentNode,parentTag);
+ ElementDecl parentDecl = getElementDeclFromSideKick(parentNode,parentTag);
if(parentDecl != null && parentDecl.elementHash!=null && parentDecl.elementHash.containsKey(lName))
{
- return parentDecl.elementHash.get(lName).withPrefix(prefix);
+ return parentDecl.elementHash.get(lName);
}
}
else if(info.elementHash != null)
{
// at root node : allowed to use a global ElementDecl
- decl = info.elementHash.get(lName);
- return decl.withPrefix(prefix);
+ return info.elementHash.get(lName);
}
return null;
}
@@ -497,9 +466,12 @@
/** @return a list containing Elements or Attributes */
public List<ElementDecl> getAllowedElements(Buffer buffer, int pos)
{
+ /*{{{ debug only */
IAsset asset = getAssetAtOffset(pos);
if(Debug.DEBUG_COMPLETION && asset != null)Log.log(Log.DEBUG, XmlParsedData.class,
("asset at "+pos+" is :"+asset+" ("+asset.getStart().getOffset()+","+asset.getEnd().getOffset()+")"));
+ /* }}} */
+
List<ElementDecl> returnValue = new LinkedList<ElementDecl>();
TagParser.Tag parentTag = null;
@@ -514,83 +486,58 @@
if(parentTag == null)
{
// add everything
- Iterator iter = mappings.keySet().iterator();
- while(iter.hasNext())
- {
- String ns = (String)iter.next();
- CompletionInfo info = (CompletionInfo)
- mappings.get(ns);
+ for(CompletionInfo info: mappings.values()) {
info.getAllElements(returnValue);
}
}
else
{
ElementDecl parentDecl = null;
- //String parentPrefix = getElementNamePrefix(parentTag.tag);
- //String parentLocalName = "".equals(parentPrefix) ? parentTag.tag : parentTag.tag.substring(parentPrefix.length()+1);
-
- if(html)
- {
- parentDecl = getElementDeclInternal(parentTag.tag,pos);
- returnValue.addAll(parentDecl.getChildElements(Collections.<String,String>emptyMap()));
+ parentDecl = getElementDecl(parentTag.tag,parentTag.start+1);
+ if(parentDecl != null){
+ returnValue.addAll(parentDecl.getChildElements());
}
- else
- {
- TreePath path = null;
- Map<String,String> bindings = null;
-
- if(allNamespacesBindingsAtTop){
- if(Debug.DEBUG_COMPLETION)Log.log(Log.DEBUG,XmlParsedData.class, "allNamespacesBindingsAtTop");
- bindings = getRootNamespaceBindings();
- }else {
- path = getTreePathForPosition(pos);
- bindings = getNamespaceBindings(path);
- }
-
- parentDecl = getElementDecl(parentTag.tag,parentTag.start+1);
- if(parentDecl != null){
- if(bindings == null)bindings = Collections.<String,String>emptyMap();
- returnValue.addAll(parentDecl.getChildElements(bindings));
- }
- }
}
Collections.sort(returnValue, new ElementDecl.Compare());
return returnValue;
} //}}}
//{{{ getAllowedElements() method
- /* called by updateTagList only */
- // FIXME: use new algorithms
- public List getAllowedElements(Buffer buffer, int startPos, int endPos)
+ /** get allowed elements at startPos.
+ * called by updateTagList only.
+ * ensures:
+ * - that startPos and endPos are not inside a tag (then returns all global elements),
+ * - that both startPos and endPos have a parent (may be different) or none has
+ * (then return startPos parent declaration's children).
+ * DO KEEP in sync with the other getAllowedElements() !!
+ * @see XmlParsedData#getAllowedElements(Buffer, int)
+ */
+ public List<ElementDecl> getAllowedElements(Buffer buffer, int startPos, int endPos)
{
- ArrayList returnValue = new ArrayList();
-
+ ArrayList<ElementDecl> returnValue = new ArrayList<ElementDecl>();
+ CharSequence bufferText = buffer.getSegment(0, buffer.getLength());
+
// make sure we are not inside a tag
- if(TagParser.isInsideTag(buffer.getText(0,startPos),startPos)) {
+ if(TagParser.isInsideTag(bufferText,startPos)) {
return returnValue;
}
// make sure we are not inside a tag
- if(TagParser.isInsideTag(buffer.getText(0,endPos),endPos)) {
+ if(TagParser.isInsideTag(bufferText,endPos)) {
return returnValue;
}
TagParser.Tag startParentTag = TagParser.findLastOpenTag(
- buffer.getText(0,startPos),startPos,this);
+ bufferText,startPos,this);
TagParser.Tag endParentTag = TagParser.findLastOpenTag(
- buffer.getText(0,endPos),endPos,this);
+ bufferText,endPos,this);
if(startParentTag == null) {
if(endParentTag == null) {
// add everything
- Iterator iter = mappings.keySet().iterator();
- while(iter.hasNext())
- {
- String prefix = (String)iter.next();
- CompletionInfo info = (CompletionInfo)
- mappings.get(prefix);
+ for(CompletionInfo info: mappings.values()) {
info.getAllElements(returnValue);
}
}
@@ -602,6 +549,9 @@
}
else
{
+ // it's not clear to me what situation this covers : if start and end parent tags
+ // are not the same, why do we require that they are in same prefix ?
+ // especially since only chilren of start parent are proposed
String startParentPrefix = getElementNamePrefix(startParentTag.tag);
ElementDecl startParentDecl = getElementDecl(startParentTag.tag,startParentTag.start+1);
@@ -616,22 +566,7 @@
return returnValue;
else
{
-
- if(startParentDecl != null)
- returnValue.addAll(startParentDecl.getChildElements());
-
- // add everything but the parent's prefix now
- Iterator iter = mappings.keySet().iterator();
- while(iter.hasNext())
- {
- String prefix = (String)iter.next();
- if(!prefix.equals(startParentPrefix))
- {
- CompletionInfo info = (CompletionInfo)
- mappings.get(prefix);
- info.getAllElements(returnValue);
- }
- }
+ returnValue.addAll(startParentDecl.getChildElements());
}
}
@@ -640,8 +575,10 @@
} //}}}
//{{{ getNamespaceBindings() method
- /** namespace to prefix */
- public Map<String,String> getNamespaces(int pos){
+ /** namespace to prefix
+ * (from sidekick)
+ **/
+ public Map<String,String> getNamespaceBindings(int pos){
if(html) return new HashMap<String,String>();
@@ -655,7 +592,7 @@
}
/** namespace to prefix */
- public Map<String,String> getNamespaceBindings(TreePath path){
+ private Map<String,String> getNamespaceBindings(TreePath path){
Map<String,String> bindings = new HashMap<String,String>();
if(path == null)return bindings;
@@ -673,7 +610,7 @@
//}}}
//{{{ getRootNamespaceBindings() method
- public Map<String,String> getRootNamespaceBindings(){
+ private Map<String,String> getRootNamespaceBindings(){
Map<String,String> bindings;
if(!html && root != null && root.getChildCount() > 0){
@@ -695,7 +632,7 @@
//}}}
//{{{ getNamespaceForPrefix() method
- public String getNamespaceForPrefix(String prefix, int pos){
+ private String getNamespaceForPrefix(String prefix, int pos){
if(html)return null;
@@ -726,7 +663,7 @@
//}}}
//{{{ getNS() method
- public String getNS(Map<String,String> nsToPrefix, String prefix){
+ private String getNS(Map<String,String> nsToPrefix, String prefix){
for(Map.Entry<String,String> en:nsToPrefix.entrySet()){
if(prefix.equals(en.getValue())){
return en.getKey();
Modified: plugins/XML/trunk/xml/completion/ElementDecl.java
===================================================================
--- plugins/XML/trunk/xml/completion/ElementDecl.java 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/xml/completion/ElementDecl.java 2012-03-05 19:37:01 UTC (rev 21248)
@@ -102,38 +102,6 @@
}
} //}}}
- //{{{ withPrefix()
- public ElementDecl withPrefix(String prefix)
- {
- if(prefix.equals(""))
- return this;
- else
- {
- ElementDecl d = new ElementDecl(completionInfo, prefix + ':' + name,
- empty, any, attributes, attributeHash, content);
- d.elementHash = elementHash;
- return d;
- }
- } //}}}
-
- //{{{ withContext()
- public ElementDecl withContext(Map<String,String> context)
- {
- String ns = completionInfo.namespace;
- String prefix = context.get(ns);
- if(prefix == null || "".equals(prefix))
- {
- return this;
- }
- else
- {
- ElementDecl d = new ElementDecl(completionInfo, prefix + ':' + name,
- empty, any, attributes, attributeHash, content);
- d.elementHash = elementHash;
- return d;
- }
- } //}}}
-
//{{{ getChildElements() method
public List<ElementDecl> getChildElements()
{
@@ -141,17 +109,11 @@
if(any)
{
- for(int i = 0; i < completionInfo.elements.size(); i++)
- {
- children.add(((ElementDecl)completionInfo.elements.get(i)));
- }
+ children.addAll(completionInfo.elements);
}
else
{
- for(int i = 0; i < completionInfo.elementsAllowedAnywhere.size(); i++)
- {
- children.add(((ElementDecl)completionInfo.elementsAllowedAnywhere.get(i)));
- }
+ children.addAll(completionInfo.elementsAllowedAnywhere);
if(content != null)
{
@@ -181,54 +143,6 @@
return children;
} //}}}
- //{{{ getChildElements() method
- public List<ElementDecl> getChildElements(Map<String,String> namespaceContext)
- {
- ArrayList<ElementDecl>children = new ArrayList<ElementDecl>(100);
-
- if(any)
- {
- for(int i = 0; i < completionInfo.elements.size(); i++)
- {
- children.add(((ElementDecl)completionInfo.elements.get(i)).withContext(namespaceContext));
- }
- }
- else
- {
- for(int i = 0; i < completionInfo.elementsAllowedAnywhere.size(); i++)
- {
- children.add(((ElementDecl)completionInfo.elementsAllowedAnywhere.get(i))
- .withContext(namespaceContext));
- }
-
- if(content != null)
- {
- Iterator iter = content.iterator();
- while(iter.hasNext())
- {
- ElementDecl decl = null;
- Object n = (String)iter.next();
- if(elementHash == null){
- //backward compatible
- decl = (ElementDecl)completionInfo
- .elementHash.get(n);
- }else{
- decl = elementHash.get(n);
- }
-
- if(decl != null) {
- if (decl.isAbstract())
- children.addAll(decl.findReplacements(namespaceContext));
- else
- children.add(decl.withContext(namespaceContext));
- }
- }
- }
- }
-
- return children;
- } //}}}
-
/**
* Finds all elements which can be replaced by this one.
*
@@ -240,17 +154,6 @@
return null;
}
- /**
- * Finds all elements which can be replaced by this one.
- *
- * @return a list of all elements with matching substitutionGroup, or null if there are
- * none.
- *
- */
- public List<ElementDecl> findReplacements(Map<String,String> prefix) {
- return null;
- }
-
//{{{ getAttribute() method
public AttributeDecl getAttribute(String attrname)
{
Modified: plugins/XML/trunk/xml/completion/XmlCompletion.java
===================================================================
--- plugins/XML/trunk/xml/completion/XmlCompletion.java 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/xml/completion/XmlCompletion.java 2012-03-05 19:37:01 UTC (rev 21248)
@@ -38,6 +38,7 @@
import sidekick.SideKickCompletion;
import xml.XmlActions;
import xml.XmlListCellRenderer;
+import xml.XmlListCellRenderer.WithLabel;
import xml.XmlParsedData;
import xml.completion.ElementDecl.AttributeDecl;
import xml.EditTagDialog;
@@ -75,7 +76,7 @@
//{{{ insert() method
public void insert(int index)
{
- insert(get(index),'\n');
+ insert((WithLabel<Object>)get(index),'\n');
} //}}}
//{{{ handleKeystroke() method
@@ -103,7 +104,7 @@
}
if(index != -1)
- insert(get(index),ch);
+ insert((WithLabel<Object>)get(index),ch);
else if(ch == '>')
XmlActions.insertClosingTagKeyTyped(view);
else
@@ -118,12 +119,14 @@
//{{{ insert() method
/**
- * @param obj - an object to insert
+ * @param wqn - an object to insert (label will be used for EditTagDialog)
* @param ch - an additional character to insert afterwards
*
*/
- private void insert(Object obj, char ch)
+ private void insert(final WithLabel<Object> wqn, char ch)
{
+ Object obj = wqn.element;
+
Macros.Recorder recorder = view.getMacroRecorder();
String insert;
@@ -196,7 +199,7 @@
Selection s = textArea.getSelectionAtOffset(caret);
int start = (s == null ? caret : s.getStart());
Selection textSel = new Selection.Range(start - text.length() - 1,start); // < is not part of text but must be removed also
- XmlActions.showEditTagDialog(view, elementDecl, textSel, namespaces, namespacesToInsert, !elementDecl.attributes.isEmpty());
+ XmlActions.showEditTagDialog(view, wqn.label, elementDecl, textSel, namespaces, namespacesToInsert, !elementDecl.attributes.isEmpty());
}
});
return;
Modified: plugins/XML/trunk/xml/completion/XsdElementDecl.java
===================================================================
--- plugins/XML/trunk/xml/completion/XsdElementDecl.java 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/xml/completion/XsdElementDecl.java 2012-03-05 19:37:01 UTC (rev 21248)
@@ -24,6 +24,7 @@
xsed = element;
}
+ @Override
public boolean isAbstract() {
return xsed.getAbstract();
}
@@ -32,6 +33,7 @@
* Returns a List of ElementDecl objects which are equivalent to this one, if it is indeed
* an abstract class.
*/
+ @Override
public List<ElementDecl> findReplacements()
{
Modified: plugins/XML/trunk/xml/parser/SchemaToCompletion.java
===================================================================
--- plugins/XML/trunk/xml/parser/SchemaToCompletion.java 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/xml/parser/SchemaToCompletion.java 2012-03-05 19:37:01 UTC (rev 21248)
@@ -106,11 +106,11 @@
// use a more intuitive '' key for the completion info
// of the no-namespace elements
if(infos.containsKey(INHERIT)){
- infos.put("",infos.get(INHERIT));
+ CompletionInfo nons = infos.get(INHERIT);
+ nons.namespace = "";
+ infos.put("",nons);
infos.remove(INHERIT);
}
-
-
//{{{ put everything in cache
List<CacheEntry> related = new ArrayList<CacheEntry>(schemas.getSchemaDocumentMap().size());
Modified: plugins/XML/trunk/xml/parser/TagParser.java
===================================================================
--- plugins/XML/trunk/xml/parser/TagParser.java 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/xml/parser/TagParser.java 2012-03-05 19:37:01 UTC (rev 21248)
@@ -32,13 +32,13 @@
public static final int T_END_TAG = 2;
//{{{ getTagAtOffset() method
- public static Tag getTagAtOffset(String text, int pos)
+ public static Tag getTagAtOffset(CharSequence text, int pos)
{
if(pos < 0 || pos > text.length())
return null;
// Get the last '<' before current position.
- int startTag = text.lastIndexOf('<', pos - 1); // -1 because don't want to return something when cursor is here: |<a>
+ int startTag = lastIndexOf(text, '<', pos - 1); // -1 because don't want to return something when cursor is here: |<a>
if(startTag == -1 || startTag + 2 >= text.length()) // at least 2 chars after '<'
return null;
@@ -52,7 +52,7 @@
endTag = i+1;
break;
}else if(ch == '\'' || ch == '"'){
- int nextQuote = text.indexOf(ch,i+1);
+ int nextQuote = indexOf(text, ch,i+1);
if(nextQuote == -1)
{
System.err.println("quote is not closed !");
@@ -103,14 +103,14 @@
}
Tag tag = new Tag(startTag,endTag);
- tag.tag = text.substring(startTagName, endTagName);
+ tag.tag = text.subSequence(startTagName, endTagName).toString();
tag.type = tagType;
return tag;
} //}}}
//{{{ getMatchingTag() method
- public static Tag getMatchingTag(String text, Tag tag)
+ public static Tag getMatchingTag(CharSequence text, Tag tag)
{
if (tag.type == T_START_TAG)
return findEndTag(text, tag);
@@ -120,7 +120,7 @@
} //}}}
//{{{ findLastOpenTag() method
- public static Tag findLastOpenTag(String text, int pos,
+ public static Tag findLastOpenTag(CharSequence text, int pos,
XmlParsedData data)
{
Stack<String> tagStack = new Stack<String>();
@@ -235,9 +235,9 @@
//{{{ isInsideTag() method
//it doesn't skip comments and such but it works ???
- public static boolean isInsideTag(String text, int pos)
+ public static boolean isInsideTag(CharSequence text, int pos)
{
- int start = text.lastIndexOf('<',pos);
+ int start = lastIndexOf(text, '<',pos);
if(start > -1 && start < pos)
{
@@ -250,7 +250,7 @@
end = i;
break;
}else if(ch == '\'' || ch == '"'){
- int nextQuote = text.indexOf(ch,i+1);
+ int nextQuote = indexOf(text,ch,i+1);
if(nextQuote == -1)
{
System.err.println("quote is not closed !");
@@ -277,7 +277,7 @@
//{{{ Private members
//{{{ findEndTag() method
- private static Tag findEndTag(String text, Tag startTag)
+ private static Tag findEndTag(CharSequence text, Tag startTag)
{
int tagCounter = 0;
@@ -343,7 +343,7 @@
} //}}}
//{{{ findStartTag() method
- private static Tag findStartTag(String text, Tag endTag)
+ private static Tag findStartTag(CharSequence text, Tag endTag)
{
int tagCounter = 0;
@@ -412,7 +412,7 @@
//{{{ getAttrs() method
// works only for XML : all attributes must be quote
- public static List<Attr> getAttrs(String text, Tag tag)
+ public static List<Attr> getAttrs(CharSequence text, Tag tag)
{
if (tag.type == T_START_TAG || tag.type == T_STANDALONE_TAG)
{
@@ -457,7 +457,7 @@
}
else if( ch == '\'' || ch == '"' )
{
- int nextQuote = text.indexOf(ch,i+1);
+ int nextQuote = indexOf(text,ch,i+1);
if(nextQuote == -1)
{
System.err.println("quote is not closed !");
@@ -466,8 +466,8 @@
else
{
Attr a = new Attr(startAttrName,nextQuote+1);
- a.name = text.substring(startAttrName,endAttrName);
- a.val = text.substring(i, nextQuote+1);
+ a.name = text.subSequence(startAttrName,endAttrName).toString();
+ a.val = text.subSequence(i, nextQuote+1).toString();
attrs.add(a);
startAttrName=-1;
@@ -489,6 +489,31 @@
}
} //}}}
+ /**
+ * replacement for String.lastIndexOf on CharSequence
+ * @param pos position from which to look (backward)
+ * */
+ public static int lastIndexOf(CharSequence text, int c, int pos){
+ int len = text.length();
+ if(pos>=len) pos = len -1;
+ for(int i=pos; i>= 0; i--){
+ if(text.charAt(i) == c)return i;
+ }
+ return -1;
+ }
+
+ /**
+ * replacement for String.indexOf on CharSequence
+ * @param pos position from which to look (forward)
+ * */
+ public static int indexOf(CharSequence text, int c, int pos){
+ int len = text.length();
+ if(pos>=len)return -1;
+ for(int i=pos; i<len ; i++){
+ if(text.charAt(i) == c)return i;
+ }
+ return -1;
+ }
//}}}
//{{{ Tag class
Modified: plugins/XML/trunk/xml/parser/XmlParser.java
===================================================================
--- plugins/XML/trunk/xml/parser/XmlParser.java 2012-03-05 19:23:48 UTC (rev 21247)
+++ plugins/XML/trunk/xml/parser/XmlParser.java 2012-03-05 19:37:01 UTC (rev 21248)
@@ -26,6 +26,7 @@
import xml.completion.*;
import xml.completion.ElementDecl.AttributeDecl;
import xml.*;
+import xml.XmlListCellRenderer.WithLabel;
/**
* This is the common base class for both HTML and XML Parsers.
@@ -207,10 +208,10 @@
insideQuote = !insideQuote;
}
// whitespace is not allowed in element tag names or entities;
- // in xml mode attributes can only occur in Token.MARKUP or Token.END
+ // in xml mode attributes can only occur in Token.MARKUP or Token.END (or Token.OPERATOR when just typing the colon)
// this solves the problem of attributes defined with ' for xml mode
// xsl mode parses the markup more finely so the logic gets more complex but probably could be done
- else if (Character.isWhitespace(ch) && !(token.id == Token.MARKUP || token.id == Token.END) && modename.equals("xml")) {
+ else if (Character.isWhitespace(ch) && !(token.id == Token.MARKUP || token.id == Token.END || (token.id == Token.OPERATOR && text.charAt(lastchar) == ':')) && modename.equals("xml")) {
return null;
}
// whitespace is not allowed in element tags or entities;
@@ -230,8 +231,9 @@
String word;
List allowedCompletions = new ArrayList(20);
- Map<String, String> namespaces = data.getNamespaceBindings(data.getTreePathForPosition(caret));
+ Map<String, String> namespaces = data.getNamespaceBindings(caret);
Map<String, String> namespacesToInsert = new HashMap<String, String>();
+ Map<String, String> localNamespacesToInsert = new HashMap<String, String>();
if(wordStart != -1 && mode != -1)
@@ -252,19 +254,20 @@
if(mode == ELEMENT_COMPLETE)
{
String wordWithoutPrefix = XmlParsedData.getElementLocalName(word);
+ String wordPrefix = XmlParsedData.getElementNamePrefix(word);
List<ElementDecl> completions = data.getAllowedElements(buffer, lastchar);
TagParser.Tag tag = TagParser.findLastOpenTag(text,lastchar - 1,data);
if(tag != null)
closingTag = tag.tag;
if("!--".startsWith(word))
- allowedCompletions.add(new XmlListCellRenderer.Comment());
+ allowedCompletions.add(new WithLabel(new XmlListCellRenderer.Comment()));
if(!data.html && "![CDATA[".startsWith(word))
- allowedCompletions.add(new XmlListCellRenderer.CDATA());
+ allowedCompletions.add(new WithLabel(new XmlListCellRenderer.CDATA()));
if(closingTag != null && ("/" + closingTag).startsWith(word))
{
if(word.length() == 0 || !jEdit.getBooleanProperty("xml.close-complete"))
- allowedCompletions.add(new XmlListCellRenderer.ClosingTag(closingTag));
+ allowedCompletions.add(new WithLabel(new XmlListCellRenderer.ClosingTag(closingTag)));
else
{
// just insert immediately
@@ -280,6 +283,7 @@
ElementDecl elementDecl = completions.get(i);
String elementName;
String elementNamespace = elementDecl.completionInfo.namespace;
+ // elementDecl.name is the local name, now we must find a qualified name
if(elementNamespace == null || "".equals(elementNamespace))
{
elementName = elementDecl.name;
@@ -289,9 +293,32 @@
String pre = namespaces.get(elementNamespace);
if(pre == null)
{
- elementName = elementDecl.name;
- namespacesToInsert.put(elementNamespace, pre);
+ pre = localNamespacesToInsert.get(elementNamespace);
}
+ if(pre == null)
+ {
+ // handle using unknown prefix
+ // if users types "<mathml:" and mathml ns is undeclared use mathml:... as prefix
+ if(!"".equals(wordPrefix)
+ && elementDecl.name.startsWith(wordWithoutPrefix))
+ {
+ pre = wordPrefix;
+ namespacesToInsert.put(elementNamespace, pre);
+ localNamespacesToInsert.put(elementNamespace, pre);
+ elementName = pre + ":" + elementDecl.name;
+
+ }
+ else
+ {
+ // handle elements in undeclared namespace and no prefix.
+ // Generate a new prefix.
+ // Store it locally, so that the declaration is not inserted when this completion is not chosen.
+ // If it's chosen, a prefix (maybe different) will be generated
+ pre = EditTagDialog.generatePrefix(namespaces, localNamespacesToInsert);
+ localNamespacesToInsert.put(elementNamespace,pre);
+ elementName = pre + ":" + elementDecl.name;
+ }
+ }
else
{
if("".equals(pre)){
@@ -301,14 +328,12 @@
}
}
}
- //TODO: handle using unknown prefix ?
- // ie. if users types "<mathml:" and mathml ns is undeclared use mathml:... as prefix
if(elementName.startsWith(word)
|| (data.html && elementName.toLowerCase()
.startsWith(word.toLowerCase())))
{
- allowedCompletions.add(elementDecl);
+ allowedCompletions.add(new XmlListCellRenderer.WithLabel<ElementDecl>(elementName,elementDecl));
}
}
}
@@ -320,13 +345,15 @@
EntityDecl entity = completions.get(i);
if(entity.name.startsWith(word))
{
- allowedCompletions.add(entity);
+ allowedCompletions.add(new WithLabel(entity));
}
}
}
else if (mode == ATTRIB_COMPLETE)
{
String prefix = text.substring(attribStart, caret);
+ String wordWithoutPrefix = XmlParsedData.getElementLocalName(prefix);
+ String wordPrefix = XmlParsedData.getElementNamePrefix(prefix);
ElementDecl decl = data.getElementDecl(word,caret);
List<AttributeDecl> completions;
if (decl != null)
@@ -352,6 +379,28 @@
else
{
attrName = attrDecl.name;
+ // handle using unknown prefix
+ // if users types "<mathml:" and mathml ns is undeclared use mathml:... as prefix
+ if(!"".equals(wordPrefix) && !"xml".equals(wordPrefix)
+ && attrName.startsWith(wordWithoutPrefix))
+ {
+ pre = wordPrefix;
+ namespacesToInsert.put(attrDecl.namespace, pre);
+ attrName = pre + ":" + attrDecl.name;
+ }
+ else
+ {
+ // handle attribute in undeclared namespace and no prefix.
+ // Generate a new prefix.
+ // Store it locally, so that the declaration is not inserted when this completion is not chosen.
+ // If it's chosen, a prefix (maybe different) will be generated again
+ pre = EditTagDialog.generatePrefix(namespaces, localNamespacesToInsert);
+ localNamespacesToInsert.put(attrDecl.namespace,pre);
+ attrName = pre + ":" + attrDecl.name;
+ // this can get cumbersome, if one types 'a' expecting to get 'someprefix:attribute' because
+ // attribute will not be proposed. On the other hand if we don't put the prefix, one cannot distinguish between
+ // ns1:attr and ns2:attr...
+ }
}
}
else
@@ -361,7 +410,7 @@
}
if (attrName.startsWith(prefix))
{
- allowedCompletions.add(attrDecl);
+ allowedCompletions.add(new XmlListCellRenderer.WithLabel<AttributeDecl>(attrName,attrDecl));
}
}
}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|