/// <summary> /// Replace the contents of the existing XML part. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> public void buttonReplaceXML_Click(Office.IRibbonControl control) { CustomTaskPane ctpPaneForThisWindow = Utilities.FindTaskPaneForCurrentWindow(); Controls.ControlMain ccm = (Controls.ControlMain)ctpPaneForThisWindow.Control; Office.CustomXMLPart userPart = null; bool cancelled = false; while (userPart == null && !cancelled) { using (Forms.FormAddPart fap = new Forms.FormAddPart()) { if (fap.ShowDialog() == DialogResult.OK) { string requiredRoot = System.Configuration.ConfigurationManager.AppSettings["RootElement"]; if (string.IsNullOrWhiteSpace(requiredRoot)) { ccm.EventHandlerAndOnChildren.NodeAfterReplaceDisconnect(); Office.CustomXMLPart existingPart = ccm.model.getUserPart(requiredRoot); CustomXmlUtilities.replaceXmlDoc(existingPart, fap.XmlString); userPart = existingPart; } else { Office.CustomXMLPart existingPart = ccm.model.getUserPart(requiredRoot); if (existingPart.DocumentElement.BaseName.Equals(requiredRoot)) { ccm.EventHandlerAndOnChildren.NodeAfterReplaceDisconnect(); CustomXmlUtilities.replaceXmlDoc(existingPart, fap.XmlString); userPart = existingPart; } else { MessageBox.Show("You need to use root element: " + requiredRoot); } } } else { cancelled = true; } } } if (!cancelled) { ccm.EventHandlerAndOnChildren.NodeAfterReplaceReconnect(); } ccm.RefreshTreeControl(null); }
/// <summary> /// Create OpenDoPE parts, including optionally, question part. /// </summary> public void process() { Microsoft.Office.Interop.Word.Document document = null; try { document = Globals.ThisAddIn.Application.ActiveDocument; } catch (Exception ex) { Mbox.ShowSimpleMsgBoxError("No document is open/active. Create or open a docx first."); return; } Model model = Model.ModelFactory(document); // Button shouldn't be available if this exists, // but .. if (model.conditionsPart == null) { conditions conditions = new conditions(); string conditionsXml = conditions.Serialize(); model.conditionsPart = addCustomXmlPart(document, conditionsXml); } if (model.componentsPart == null) { components components = new components(); string componentsXml = components.Serialize(); model.componentsPart = addCustomXmlPart(document, componentsXml); } // Add XPath xpaths xpaths = new xpaths(); // Button shouldn't be available if this exists, // but .. if (model.xpathsPart != null) { xpaths.Deserialize(model.xpathsPart.XML, out xpaths); } int idInt = 1; foreach (Word.ContentControl cc in Globals.ThisAddIn.Application.ActiveDocument.ContentControls) { if (cc.XMLMapping.IsMapped) { log.Debug("Adding xpath for " + cc.ID); // then we need to add an XPath string xmXpath = cc.XMLMapping.XPath; xpathsXpath item = new xpathsXpath(); // I make no effort here to check whether the xpath // already exists, since the part shouldn't already exist! item.id = "x" + idInt; xpathsXpathDataBinding db = new xpathsXpathDataBinding(); db.xpath = xmXpath; db.storeItemID = cc.XMLMapping.CustomXMLPart.Id; if (!string.IsNullOrWhiteSpace(cc.XMLMapping.PrefixMappings)) { db.prefixMappings = cc.XMLMapping.PrefixMappings; } item.dataBinding = db; xpaths.xpath.Add(item); // Write tag TagData td = new TagData(cc.Tag); td.set("od:xpath", item.id); cc.Tag = td.asQueryString(); log.Debug(".. added for " + cc.ID); idInt++; } } string xpathsXml = xpaths.Serialize(); if (model.xpathsPart == null) { model.xpathsPart = addCustomXmlPart(document, xpathsXml); } else { CustomXmlUtilities.replaceXmlDoc(model.xpathsPart, xpathsXml); } Microsoft.Office.Tools.Word.Document extendedDocument = Globals.ThisAddIn.Application.ActiveDocument.GetVstoObject(Globals.Factory); //Microsoft.Office.Tools.CustomTaskPane ctp // = Globals.ThisAddIn.createCTP(document, cxp, xpathsPart, conditionsPart, questionsPart, componentsPart); //extendedDocument.Tag = ctp; //// Want a 2 way association //WedTaskPane wedTaskPane = (WedTaskPane)ctp.Control; //wedTaskPane.associatedDocument = document; //extendedDocument.Shutdown += new EventHandler( // Globals.ThisAddIn.extendedDocument_Shutdown); //taskPane.setupCcEvents(document); log.Debug("Done. Task pane now also open."); }
public static void editXPath(Word.ContentControl cc) { Word.Document document = Globals.ThisAddIn.Application.ActiveDocument; object missing = System.Type.Missing; // First, work out whether this is a condition or a repeat or a plain bind bool isCondition = false; bool isRepeat = false; bool isBind = false; if ((cc.Title != null && cc.Title.StartsWith("Condition")) || (cc.Tag != null && cc.Tag.Contains("od:condition"))) { isCondition = true; } else if ((cc.Title != null && cc.Title.StartsWith("Repeat")) || (cc.Tag != null && cc.Tag.Contains("od:repeat"))) { isRepeat = true; } else if ((cc.Title != null && cc.Title.StartsWith("Data")) || (cc.Tag != null && cc.Tag.Contains("od:xpath")) || cc.XMLMapping.IsMapped ) { isBind = true; } else { // Ask user using (Forms.ConditionOrRepeat cor = new Forms.ConditionOrRepeat()) { if (cor.ShowDialog() == DialogResult.OK) { isCondition = cor.radioButtonCondition.Checked; isRepeat = cor.radioButtonRepeat.Checked; isBind = cor.radioButtonBind.Checked; } else { // They cancelled return; } } } // OK, now we know whether its a condition or a repeat or a bind // Is it already mapped to something? TagData td = new TagData(cc.Tag); Model model = Model.ModelFactory(document); string strXPath = ""; // In order to get Id and prefix mappings for current part CustomTaskPane ctpPaneForThisWindow = Utilities.FindTaskPaneForCurrentWindow(); Controls.ControlMain ccm = (Controls.ControlMain)ctpPaneForThisWindow.Control; string cxpId = ccm.CurrentPart.Id; string prefixMappings = ""; // TODO GetPrefixMappings(ccm.CurrentPart.NamespaceManager); log.Debug("default prefixMappings: " + prefixMappings); XPathsPartEntry xppe = null; ConditionsPartEntry cpe = null; if (isCondition && td.get("od:condition") != null) { string conditionId = td.get("od:condition"); cpe = new ConditionsPartEntry(model); condition c = cpe.getConditionByID(conditionId); string xpathid = null; if (c != null && c.Item is xpathref) { xpathref ex = (xpathref)c.Item; xpathid = ex.id; // Now fetch the XPath xppe = new XPathsPartEntry(model); xpathsXpath xx = xppe.getXPathByID(xpathid); if (xx != null) { strXPath = xx.dataBinding.xpath; cxpId = xx.dataBinding.storeItemID; prefixMappings = xx.dataBinding.prefixMappings; } } } else if (isRepeat && td.get("od:repeat") != null) { string repeatId = td.get("od:repeat"); // Now fetch the XPath xppe = new XPathsPartEntry(model); xpathsXpath xx = xppe.getXPathByID(repeatId); if (xx != null) { strXPath = xx.dataBinding.xpath; cxpId = xx.dataBinding.storeItemID; prefixMappings = xx.dataBinding.prefixMappings; } } else if (isBind) { if (cc.XMLMapping.IsMapped) { // Prefer this, if for some reason it contradicts od:xpath strXPath = cc.XMLMapping.XPath; cxpId = cc.XMLMapping.CustomXMLPart.Id; prefixMappings = cc.XMLMapping.PrefixMappings; } else if (td.get("od:xpath") != null) { string xpathId = td.get("od:xpath"); // Now fetch the XPath xppe = new XPathsPartEntry(model); xpathsXpath xx = xppe.getXPathByID(xpathId); if (xx != null) { strXPath = xx.dataBinding.xpath; cxpId = xx.dataBinding.storeItemID; prefixMappings = xx.dataBinding.prefixMappings; } } } // Now we can present the form using (Forms.XPathEditor xpe = new Forms.XPathEditor()) { xpe.textBox1.Text = strXPath; if (xpe.ShowDialog() == DialogResult.OK) { strXPath = xpe.textBox1.Text; } else { // They cancelled return; } } // Now give effect to it td = new TagData(""); if (isCondition) { // Create the new condition. Doesn't attempt to delete // the old one (if any) if (cpe == null) { cpe = new ConditionsPartEntry(model); } cpe.setup(cxpId, strXPath, prefixMappings, true); cpe.save(); cc.Title = "Conditional: " + cpe.conditionId; // Write tag td.set("od:condition", cpe.conditionId); cc.Tag = td.asQueryString(); } else if (isRepeat) { // Create the new repeat. Doesn't attempt to delete // the old one (if any) if (xppe == null) { xppe = new XPathsPartEntry(model); } xppe.setup("rpt", cxpId, strXPath, prefixMappings, false); xppe.save(); cc.Title = "Repeat: " + xppe.xpathId; // Write tag td.set("od:repeat", xppe.xpathId); cc.Tag = td.asQueryString(); } else if (isBind) { // Create the new bind. Doesn't attempt to delete // the old one (if any) if (xppe == null) { xppe = new XPathsPartEntry(model); } Word.XMLMapping bind = cc.XMLMapping; bool mappable = false; try { mappable = bind.SetMapping(strXPath, prefixMappings, CustomXmlUtilities.getPartById(document, cxpId)); } catch (COMException ce) { if (ce.Message.Contains("Data bindings cannot be created for rich text content controls")) { // TODO: editing a rich text control // TODO manually check whether it is mappable // So for now, cc.Delete(true); cc = document.ContentControls.Add( Word.WdContentControlType.wdContentControlText, ref missing); mappable = cc.XMLMapping.SetMapping(strXPath, prefixMappings, CustomXmlUtilities.getPartById(document, cxpId)); } else { log.Error(ce); //What to do?? } } if (mappable) { // What does the XPath point to? string val = cc.XMLMapping.CustomXMLNode.Text; cc.Title = "Data value: " + xppe.xpathId; if (ContentDetection.IsBase64Encoded(val)) { // Force picture content control ... // cc.Type = Word.WdContentControlType.wdContentControlPicture; // from wdContentControlText (or wdContentControlRichText for that matter) // doesn't work (you get "inappropriate range for applying this // content control type"). cc.Delete(true); // Now add a new cc Globals.ThisAddIn.Application.Selection.Collapse(ref missing); bool _PictureContentControlsReplace = true; String picSetting = System.Configuration.ConfigurationManager.AppSettings["ContentControl.Picture.RichText.Override"]; if (picSetting != null) { Boolean.TryParse(picSetting, out _PictureContentControlsReplace); } if (_PictureContentControlsReplace) { // Use a rich text control instead cc = document.ContentControls.Add( Word.WdContentControlType.wdContentControlRichText, ref missing); PictureUtils.setPictureHandler(td); cc.Title = "Image: " + xppe.xpathId; PictureUtils.pastePictureIntoCC(cc, Convert.FromBase64String(val)); } else { cc = document.ContentControls.Add( Word.WdContentControlType.wdContentControlPicture, ref missing); cc.XMLMapping.SetMapping(strXPath, prefixMappings, CustomXmlUtilities.getPartById(document, cxpId)); } } else if (ContentDetection.IsFlatOPCContent(val)) { // <?mso-application progid="Word.Document"?> // <pkg:package xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage"> td.set("od:progid", "Word.Document"); cc.Tag = td.asQueryString(); cc.XMLMapping.Delete(); cc.Type = Word.WdContentControlType.wdContentControlRichText; cc.Title = "Word: " + xppe.xpathId; //cc.Range.Text = val; // don't escape it Inline2Block i2b = new Inline2Block(); cc = i2b.convertToBlockLevel(cc, false, true); if (cc == null) { MessageBox.Show("Problems inserting block level WordML at this location."); return; } cc.Range.InsertXML(val, ref missing); } else if (ContentDetection.IsXHTMLContent(val)) { td.set("od:ContentType", "application/xhtml+xml"); cc.Tag = td.asQueryString(); cc.XMLMapping.Delete(); cc.Type = Word.WdContentControlType.wdContentControlRichText; cc.Title = "XHTML: " + xppe.xpathId; if (Inline2Block.containsBlockLevelContent(val)) { Inline2Block i2b = new Inline2Block(); cc = i2b.convertToBlockLevel(cc, true, true); if (cc == null) { MessageBox.Show("Problems inserting block level XHTML at this location."); return; } } } xppe.setup(null, cxpId, strXPath, prefixMappings, true); xppe.save(); td.set("od:xpath", xppe.xpathId); cc.Tag = td.asQueryString(); } else { xppe.setup(null, cxpId, strXPath, prefixMappings, true); xppe.save(); td.set("od:xpath", xppe.xpathId); cc.Title = "Data value: " + xppe.xpathId; cc.Tag = td.asQueryString(); // FIXME TODO handle pictures/FlatOPC/XHTML in this case log.Warn(" XPath \n\r " + strXPath + "\n\r does not return an element. The OpenDoPE pre-processor will attempt to evaluate it, but Word will never update the result. "); bind.Delete(); MessageBox.Show(" XPath \n\r " + strXPath + "\n\r does not return an element. Check this is what you want? "); } } }
public void toggleButtonMapping_Click(Office.IRibbonControl control, bool pressed)//, ref bool cancelDefault) { Word.Document document = Globals.ThisAddIn.Application.ActiveDocument; //get the ctp for this window (or null if there's not one) CustomTaskPane ctpPaneForThisWindow = Utilities.FindTaskPaneForCurrentWindow(); if (pressed) { toggleButtonMappingChecked = true; } if (toggleButtonMappingChecked == false) { //Debug.Assert(ctpPaneForThisWindow != null, // "how was the ribbon button pressed if there was a control?"); //it's being unclicked if (ctpPaneForThisWindow != null) { ctpPaneForThisWindow.Visible = false; } } else if (ctpPaneForThisWindow == null) { if (CustomXmlUtilities.areOpenDoPEPartsPresent(Globals.ThisAddIn.Application.ActiveDocument)) { log.Debug("OpenDoPE parts detected as present"); } else { log.Info("OpenDoPE parts not detected; adding now."); Model model = Model.ModelFactory(document); string requiredRoot = System.Configuration.ConfigurationManager.AppSettings["RootElement"]; Office.CustomXMLPart userPart = model.getUserPart(requiredRoot); bool cancelled = false; while (userPart == null && !cancelled) { using (Forms.FormAddPart fap = new Forms.FormAddPart()) { //add a new stream from the XML retrieved from the Add New dialog //otherwise, select the last selected item and populate with its xml if (fap.ShowDialog() == DialogResult.OK) { object missing = System.Reflection.Missing.Value; Office.CustomXMLPart newCxp = document.CustomXMLParts.Add(fap.XmlString, missing); model = Model.ModelFactory(document); userPart = model.getUserPart(requiredRoot); if (userPart == null) { newCxp.Delete(); MessageBox.Show("You need to use root element: " + requiredRoot); } } else { cancelled = true; } } } if (cancelled) { MessageBox.Show("For template authoring, you need to add your XML."); toggleButtonMappingChecked = false; return; } InitialSetup init = new InitialSetup(); init.process(); } launchTaskPane(); } else { //it's built and being clicked, show it ctpPaneForThisWindow.Visible = true; } }