// We can't add a tag for a repeat or a condition, // unless we know the XPath. And we can't know that // if there is no suitable child to deduce it from. // But if they later press the edit button, we // would prefer not to have to ask them whether it // is a repeat or a condition. We could track the // content controls by their ID, but it seems // better to just use the Title. /// <summary> /// Wrap the selection in a Repeat. /// The XPath is deduced from plain binds in the contents. /// If there are none of these, just insert an empty content control. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> public void buttonRepeat_Click(Office.IRibbonControl control) { Word.Document document = Globals.ThisAddIn.Application.ActiveDocument; // Workaround for reported Word crash. // Can't reproduce with Word 2010 sp1: 14.0.6129.500 Word.ContentControl currentCC = ContentControlMaker.getActiveContentControl(document, Globals.ThisAddIn.Application.Selection); if (currentCC != null && currentCC.Type != Word.WdContentControlType.wdContentControlRichText) { MessageBox.Show("You can't add a repeat here."); return; } OpenDoPEModel.DesignMode designMode = new OpenDoPEModel.DesignMode(document); designMode.Off(); // Find a content control within the selection List <Word.ContentControl> shallowChildren = ContentControlUtilities.getShallowestSelectedContentControls(document, Globals.ThisAddIn.Application.Selection); log.Debug(shallowChildren.Count + " shallowChildren found."); Word.ContentControl repeatCC = null; object missing = System.Type.Missing; try { repeatCC = document.ContentControls.Add(Word.WdContentControlType.wdContentControlRichText, ref missing); // Limitation here: you can't make your content control of eg type picture log.Debug("New content control added, with id: " + repeatCC.ID); designMode.On(); } catch (System.Exception) { MessageBox.Show("Selection must be either part of a single paragraph, or one or more whole paragraphs"); designMode.restoreState(); return; } repeatCC.Title = "Repeat [unbound]"; // This used if they later click edit if (shallowChildren.Count == 0) { log.Debug("No child control found. So Repeat not set on our new CC"); //MessageBox.Show("Unbound content control only added. Click the edit button to setup the repeat."); editXPath(repeatCC); return; } // For now, just use the tag on the first simple bind we find. // Later, we could try parsing a condition or repeat Word.ContentControl usableChild = null; foreach (Word.ContentControl child in shallowChildren) { //if (child.Tag.Contains("od:xpath")) if (child.XMLMapping.IsMapped) { usableChild = child; break; } } if (usableChild == null) { log.Debug("No usable child found. So Repeat not set on our new CC"); //MessageBox.Show("Naked content control only added. Click the edit button to setup the repeat."); editXPath(repeatCC); return; } string strXPath = null; // Need to work out what repeats. Could be this child, // the parent, etc. If its obvious from this exemplar xml doc, // we can do it automatically. Otherwise, we'll ask user. // Currently the logic supports repeating ., .., or grandparent. // See whether this child repeats in this exemplar. Office.CustomXMLNode thisNode = usableChild.XMLMapping.CustomXMLNode; Office.CustomXMLNode thisNodeSibling = usableChild.XMLMapping.CustomXMLNode.NextSibling; Office.CustomXMLNode parent = usableChild.XMLMapping.CustomXMLNode.ParentNode; Office.CustomXMLNode parentSibling = usableChild.XMLMapping.CustomXMLNode.ParentNode.NextSibling; if (thisNodeSibling != null && thisNodeSibling.BaseName.Equals(thisNode.BaseName)) { // Looks like this node repeats :-) strXPath = usableChild.XMLMapping.XPath; // Get XPath. Could use the od xpaths part, but // easier here to work with the binding log.Debug("Using . as repeat: " + strXPath); } // If it doesn't, test parent. else if (parentSibling != null && parentSibling.BaseName.Equals(parent.BaseName)) { strXPath = usableChild.XMLMapping.XPath; log.Debug("Using parent for repeat "); strXPath = strXPath.Substring(0, strXPath.LastIndexOf("/")); log.Debug("Using: " + strXPath); } else // If that doesn't either, ask user. { Office.CustomXMLNode grandparent = null; if (parent != null) { grandparent = parent.ParentNode; } using (Forms.FormSelectRepeatedElement sr = new Forms.FormSelectRepeatedElement()) { sr.labelXPath.Text = usableChild.XMLMapping.XPath; sr.listElementNames.Items.Add(thisNode.BaseName); sr.listElementNames.Items.Add(parent.BaseName); if (grandparent != null) { sr.listElementNames.Items.Add(grandparent.BaseName); } sr.listElementNames.SelectedIndex = 0; sr.ShowDialog(); if (sr.listElementNames.SelectedIndex == 0) { strXPath = usableChild.XMLMapping.XPath; } else if (sr.listElementNames.SelectedIndex == 1) { strXPath = parent.XPath; log.Debug("Using parent for repeat: " + strXPath); } else { // Grandparent strXPath = grandparent.XPath; log.Debug("Using grandparent for repeat: " + strXPath); } } } // Need to drop eg [1] (if any), so BetterForm-based interactive processing works if (strXPath.EndsWith("]")) { strXPath = strXPath.Substring(0, strXPath.LastIndexOf("[")); log.Debug("Having dropped '[]': " + strXPath); } XPathsPartEntry xppe = new XPathsPartEntry(Model.ModelFactory(document)); // TODO fix usableChild.XMLMapping.PrefixMappings xppe.setup("rpt", usableChild.XMLMapping.CustomXMLPart.Id, strXPath, "", false); // No Q for repeat xppe.save(); repeatCC.Title = "Repeat: " + xppe.xpathId; // Write tag TagData td = new TagData(""); td.set("od:repeat", xppe.xpathId); repeatCC.Tag = td.asQueryString(); }
public void buttonCondition_Click(Office.IRibbonControl control) { Word.Document document = Globals.ThisAddIn.Application.ActiveDocument; // Workaround for reported Word crash. // Can't reproduce with Word 2010 sp1: 14.0.6129.500 Word.ContentControl currentCC = ContentControlMaker.getActiveContentControl(document, Globals.ThisAddIn.Application.Selection); if (currentCC != null && currentCC.Type != Word.WdContentControlType.wdContentControlRichText) { MessageBox.Show("You can't add a condition here."); return; } OpenDoPEModel.DesignMode designMode = new OpenDoPEModel.DesignMode(document); designMode.Off(); // Find a content control within the selection List <Word.ContentControl> shallowChildren = ContentControlUtilities.getShallowestSelectedContentControls(document, Globals.ThisAddIn.Application.Selection); log.Debug(shallowChildren.Count + " shallowChildren found."); Word.ContentControl conditionCC = null; object missing = System.Type.Missing; try { if (Globals.ThisAddIn.Application.Selection.Type == Microsoft.Office.Interop.Word.WdSelectionType.wdSelectionIP) { // Nothing is selected, so type "condition" document.Windows[1].Selection.Text = "condition"; } object range = Globals.ThisAddIn.Application.Selection.Range; conditionCC = document.ContentControls.Add(Word.WdContentControlType.wdContentControlRichText, ref range); // Limitation here: you can't make your content control of eg type picture designMode.On(); } catch (System.Exception) { MessageBox.Show("Selection must be either part of a single paragraph, or one or more whole paragraphs"); designMode.restoreState(); return; } conditionCC.Title = "Condition [unbound]"; // // This used if they later click edit if (shallowChildren.Count == 0) { log.Debug("No child control found. So Condition not set on our new CC"); //MessageBox.Show("Unbound content control only added. Click the edit button to setup the condition."); editXPath(conditionCC); return; } // For now, just use the tag on the first simple bind we find. // Later, we could try parsing a condition or repeat Word.ContentControl usableChild = null; foreach (Word.ContentControl child in shallowChildren) { //if (child.Tag.Contains("od:xpath")) if (child.XMLMapping.IsMapped) { usableChild = child; break; } } if (usableChild == null) { log.Debug("No usable child found. So Condition not set on our new CC"); //MessageBox.Show("Naked content control only added. Click the edit button to setup the condition."); editXPath(conditionCC); return; } // Get XPath. Could use the od xpaths part, but // easier here to get it from the binding string strXPath = usableChild.XMLMapping.XPath; log.Debug("Getting count condition from " + strXPath); strXPath = "count(" + strXPath + ")>0"; log.Debug(strXPath); ConditionsPartEntry cpe = new ConditionsPartEntry(Model.ModelFactory(document)); // TODO fix usableChild.XMLMapping.PrefixMappings cpe.setup(usableChild.XMLMapping.CustomXMLPart.Id, strXPath, "", true); cpe.save(); conditionCC.Title = "Conditional: " + cpe.conditionId; // Write tag TagData td = new TagData(""); td.set("od:condition", cpe.conditionId); conditionCC.Tag = td.asQueryString(); editXPath(conditionCC); }