/// <summary> /// Create a content control mapped to the selected XML node. /// </summary> /// <param name="CCType">A WdContentControlType value specifying the type of control to create.</param> public void CreateMappedControl(Word.WdContentControlType CCType, ControlTreeView.OpenDopeType odType, ControlTreeView controlTreeView, ControlMain controlMain, Word.Document CurrentDocument, Office.CustomXMLPart CurrentPart, //XmlDocument OwnerDocument, bool _PictureContentControlsReplace ) { OpenDoPEModel.DesignMode designMode = new OpenDoPEModel.DesignMode(CurrentDocument); designMode.Off(); try { object missing = Type.Missing; TreeNode tn = controlTreeView.treeView.SelectedNode; if (((XmlNode)tn.Tag).NodeType == XmlNodeType.Text) { tn = tn.Parent; } //get an nsmgr NameTable nt = new NameTable(); //generate the xpath and the ns manager XmlNamespaceManager xmlnsMgr = new XmlNamespaceManager(nt); string strXPath = Utilities.XpathFromXn(CurrentPart.NamespaceManager, (XmlNode)tn.Tag, true, xmlnsMgr); log.Info("Right click for XPath: " + strXPath); string prefixMappings = Utilities.GetPrefixMappings(xmlnsMgr); // Insert bind | condition | repeat // depending on which mode button is pressed. TagData td = new TagData(""); if ((controlMain.modeControlEnabled == false && odType == ControlTreeView.OpenDopeType.Unspecified) || // ie always mode bind (controlMain.modeControlEnabled == true && controlMain.controlMode1.isModeBind()) || odType == ControlTreeView.OpenDopeType.Bind) { log.Debug("In bind mode"); String val = ((XmlNode)tn.Tag).InnerText; //bool isXHTML = HasXHTMLContent(tn); bool isPicture = false; bool isXHTML = false; bool isFlatOPC = ContentDetection.IsFlatOPCContent(val); Word.ContentControl cc = null; if (isFlatOPC) { // <?mso-application progid="Word.Document"?> // <pkg:package xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage"> log.Debug(".. contains block content "); cc = CurrentDocument.Application.Selection.ContentControls.Add( Word.WdContentControlType.wdContentControlRichText, ref missing); // Ensure block level Inline2Block i2b = new Inline2Block(); cc = i2b.convertToBlockLevel(cc, false, true); if (cc == null) { MessageBox.Show("Problems inserting block level WordML at this location."); return; } } else { isXHTML = ContentDetection.IsXHTMLContent(val); } if (isXHTML) { cc = CurrentDocument.Application.Selection.ContentControls.Add( Word.WdContentControlType.wdContentControlRichText, ref missing); 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."); designMode.restoreState(); return; } } } else if (ContentDetection.IsBase64Encoded(val)) { isPicture = true; if (_PictureContentControlsReplace) { // Use a rich text control instead cc = CurrentDocument.ContentControls.Add( Word.WdContentControlType.wdContentControlRichText, ref missing); PictureUtils.pastePictureIntoCC(cc, Convert.FromBase64String(val)); } else { // Force picture content control log.Debug("Detected picture"); cc = CurrentDocument.Application.Selection.ContentControls.Add(Word.WdContentControlType.wdContentControlPicture, ref missing); } } else if (!isFlatOPC) { log.Debug("Not picture or XHTML; " + CCType.ToString()); // This formulation seems more susceptible to "locked for editing" //object rng = CurrentDocument.Application.Selection.Range; //cc = CurrentDocument.ContentControls.Add(Word.WdContentControlType.wdContentControlText, ref rng); // so prefer: cc = CurrentDocument.Application.Selection.ContentControls.Add(CCType, ref missing); } XPathsPartEntry xppe = new XPathsPartEntry(controlMain.model); xppe.setup(null, CurrentPart.Id, strXPath, prefixMappings, true); xppe.save(); td.set("od:xpath", xppe.xpathId); if (isFlatOPC) { td.set("od:progid", "Word.Document"); cc.Title = "Word: " + xppe.xpathId; //cc.Range.Text = val; // don't escape it cc.Range.InsertXML(val, ref missing); } else if (isXHTML) { td.set("od:ContentType", "application/xhtml+xml"); cc.Title = "XHTML: " + xppe.xpathId; cc.Range.Text = val; } else if (isPicture) { PictureUtils.setPictureHandler(td); cc.Title = "Image: " + xppe.xpathId; } else { cc.Title = "Data value: " + xppe.xpathId; } cc.Tag = td.asQueryString(); if (cc.Type == Word.WdContentControlType.wdContentControlText) { cc.MultiLine = true; } if (cc.Type != Word.WdContentControlType.wdContentControlRichText) { cc.XMLMapping.SetMappingByNode(Utilities.MxnFromTn(tn, CurrentPart, true)); } designMode.restoreState(); } else if ((controlMain.modeControlEnabled == true && controlMain.controlMode1.isModeCondition()) || odType == ControlTreeView.OpenDopeType.Condition) { log.Debug("In condition mode"); // User can make a condition whatever type they like, // but if they make it text, change it to RichText. if (CCType == Word.WdContentControlType.wdContentControlText) { CCType = Word.WdContentControlType.wdContentControlRichText; } Word.ContentControl cc = CurrentDocument.Application.Selection.ContentControls.Add(CCType, ref missing); ConditionsPartEntry cpe = new ConditionsPartEntry(controlMain.model); cpe.setup(CurrentPart.Id, strXPath, prefixMappings, true); cpe.save(); cc.Title = "Conditional: " + cpe.conditionId; // Write tag td.set("od:condition", cpe.conditionId); cc.Tag = td.asQueryString(); // We want to be in Design Mode, so user can see their gesture take effect designMode.On(); Ribbon.editXPath(cc); } else if ((controlMain.modeControlEnabled == true && controlMain.controlMode1.isModeRepeat()) || odType == ControlTreeView.OpenDopeType.Repeat) { log.Debug("In repeat mode"); // User can make a repeat whatever type they like // (though does it ever make sense for it to be other than RichText?), // but if they make it text, change it to RichText. if (CCType == Word.WdContentControlType.wdContentControlText) { CCType = Word.WdContentControlType.wdContentControlRichText; } Word.ContentControl cc = CurrentDocument.Application.Selection.ContentControls.Add(CCType, ref missing); // 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(controlMain.model); xppe.setup("rpt", CurrentPart.Id, strXPath, prefixMappings, false); xppe.save(); cc.Title = "Data value: " + xppe.xpathId; // Write tag td.set("od:repeat", xppe.xpathId); cc.Tag = td.asQueryString(); // We want to be in Design Mode, so user can see their gesture take effect designMode.On(); } } catch (COMException cex) { controlTreeView.ShowErrorMessage(cex.Message); designMode.restoreState(); } }
public void treeView_ItemDrag(object sender, ItemDragEventArgs e, ControlTreeView controlTreeView, ControlMain controlMain, Word.Document CurrentDocument, Office.CustomXMLPart CurrentPart, XmlDocument OwnerDocument, bool _PictureContentControlsReplace) { object missing = System.Type.Missing; TreeNode tn = (TreeNode)e.Item; if (tn == null) { Debug.Fail("no tn"); return; } //check if this is something we can drag if (((XmlNode)tn.Tag).NodeType == XmlNodeType.ProcessingInstruction || ((XmlNode)tn.Tag).NodeType == XmlNodeType.Comment) { return; } if (controlMain.modeControlEnabled == false || // ie always mode bind controlMain.controlMode1.isModeBind()) { if (!ControlTreeView.IsLeafNode(tn) || ((XmlNode)tn.Tag).NodeType == XmlNodeType.Text && !ControlTreeView.IsLeafNode(tn.Parent)) { return; } } // repeats and conditions; let them drag any node //get an nsmgr NameTable nt = new NameTable(); //generate the xpath and the ns manager XmlNamespaceManager xmlnsMgr = new XmlNamespaceManager(nt); string strXPath = Utilities.XpathFromXn(CurrentPart.NamespaceManager, (XmlNode)tn.Tag, true, xmlnsMgr); log.Info("Dragging XPath: " + strXPath); string prefixMappings = Utilities.GetPrefixMappings(xmlnsMgr); // OpenDoPE TagData td = new TagData(""); String val = ((XmlNode)tn.Tag).InnerText; DesignMode designMode = new OpenDoPEModel.DesignMode(CurrentDocument); // Special case for pictures, since drag/drop does not seem // to work properly (the XHTML pasted doesn't do what it should?) bool isPicture = ContentDetection.IsBase64Encoded(val); if (isPicture && !_PictureContentControlsReplace) { designMode.Off(); log.Debug("Special case handling for pictures.."); // Selection can't be textual content, so ensure it isn't. // It is allowed to be a picture, so in the future we could // leave the selection alone if it is just a picture. Globals.ThisAddIn.Application.Selection.Collapse(ref missing); // Are they dragging to an existing picture content control Word.ContentControl picCC = ContentControlMaker.getActiveContentControl(CurrentDocument, Globals.ThisAddIn.Application.Selection); try { if (picCC == null || (picCC.Type != Word.WdContentControlType.wdContentControlPicture)) { picCC = CurrentDocument.ContentControls.Add( Word.WdContentControlType.wdContentControlPicture, ref missing); designMode.restoreState(); } } catch (COMException ce) { // Will happen if you try to drag a text node onto an existing image content control log.Debug("Ignoring " + ce.Message); return; } XPathsPartEntry xppe = new XPathsPartEntry(controlMain.model); xppe.setup(null, CurrentPart.Id, strXPath, prefixMappings, false); xppe.save(); td.set("od:xpath", xppe.xpathId); picCC.Tag = td.asQueryString(); picCC.Title = "Data value: " + xppe.xpathId; picCC.XMLMapping.SetMappingByNode(Utilities.MxnFromTn(tn, CurrentPart, true)); return; } log.Debug("\n\ntreeView_ItemDrag for WdSelectionType " + Globals.ThisAddIn.Application.Selection.Type.ToString()); bool isXHTML = false; bool isFlatOPC = ContentDetection.IsFlatOPCContent(val); if (!isFlatOPC) { isXHTML = ContentDetection.IsXHTMLContent(val); } if (Globals.ThisAddIn.Application.Selection.Type != Microsoft.Office.Interop.Word.WdSelectionType.wdSelectionIP) { // ie something is selected, since "inline paragraph selection" // just means the cursor is somewhere inside // a paragraph, but with nothing selected. designMode.Off(); // Selection types: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.wdselectiontype(v=office.11).aspx log.Debug("treeView_ItemDrag fired, but interpreted as gesture for WdSelectionType " + Globals.ThisAddIn.Application.Selection.Type.ToString()); Word.ContentControl parentCC = ContentControlMaker.getActiveContentControl(CurrentDocument, Globals.ThisAddIn.Application.Selection); // Insert bind | condition | repeat // depending on which mode button is pressed. if (controlMain.modeControlEnabled == false || // ie always mode bind controlMain.controlMode1.isModeBind()) { log.Debug("In bind mode"); Word.ContentControl cc = null; try { if (isFlatOPC || isXHTML || (isPicture && _PictureContentControlsReplace)) { // Rich text if (parentCC != null && ContentControlOpenDoPEType.isBound(parentCC)) { // Reuse existing cc cc = ContentControlMaker.MakeOrReuse(true, Word.WdContentControlType.wdContentControlRichText, CurrentDocument, Globals.ThisAddIn.Application.Selection); } else { // Make new cc cc = ContentControlMaker.MakeOrReuse(true, Word.WdContentControlType.wdContentControlRichText, CurrentDocument, Globals.ThisAddIn.Application.Selection); } if (isFlatOPC) { log.Debug(".. contains block content "); // Ensure block level Inline2Block i2b = new Inline2Block(); cc = i2b.convertToBlockLevel(cc, false, true); if (cc == null) { MessageBox.Show("Problems inserting block level WordML at this location."); return; } } else if (isXHTML && // and thus not picture Inline2Block.containsBlockLevelContent(val)) { log.Debug(".. contains block content "); // Ensure block level Inline2Block i2b = new Inline2Block(); cc = i2b.convertToBlockLevel(cc, false, true); if (cc == null) { MessageBox.Show("Problems inserting block level XHTML at this location."); return; } } } else { // Plain text if (parentCC != null && ContentControlOpenDoPEType.isBound(parentCC)) { // Reuse existing cc cc = ContentControlMaker.MakeOrReuse(true, Word.WdContentControlType.wdContentControlText, CurrentDocument, Globals.ThisAddIn.Application.Selection); } else { // Make new cc cc = ContentControlMaker.MakeOrReuse(false, Word.WdContentControlType.wdContentControlText, CurrentDocument, Globals.ThisAddIn.Application.Selection); } cc.MultiLine = true; // Is a text content control always run-level? // No, not if you have a single para selected and you do drag gesture // (or if you remap a rich text control) } } catch (Exception ex) { log.Error("Couldn't add content control: " + ex.Message); return; } XPathsPartEntry xppe = new XPathsPartEntry(controlMain.model); xppe.setup(null, CurrentPart.Id, strXPath, prefixMappings, true); xppe.save(); td.set("od:xpath", xppe.xpathId); if (isFlatOPC) { // <?mso-application progid="Word.Document"?> // <pkg:package xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage"> td.set("od:progid", "Word.Document"); cc.Title = "Word: " + xppe.xpathId; //cc.Range.Text = val; // don't escape it cc.Range.InsertXML(val, ref missing); } else if (isXHTML) { td.set("od:ContentType", "application/xhtml+xml"); cc.Title = "XHTML: " + xppe.xpathId; cc.Range.Text = val; // don't escape it } else if (isPicture) { PictureUtils.setPictureHandler(td); cc.Title = "Image: " + xppe.xpathId; string picContent = CurrentPart.SelectSingleNode(strXPath).Text; PictureUtils.pastePictureIntoCC(cc, Convert.FromBase64String(picContent)); } else { cc.XMLMapping.SetMappingByNode(Utilities.MxnFromTn(tn, CurrentPart, true)); string nodeXML = cc.XMLMapping.CustomXMLNode.XML; log.Info(nodeXML); cc.Title = "Data value: " + xppe.xpathId; } cc.Tag = td.asQueryString(); designMode.restoreState(); } else if (controlMain.controlMode1.isModeCondition()) { log.Debug("In condition mode"); Word.ContentControl cc = null; try { // always make new cc = ContentControlMaker.MakeOrReuse(false, Word.WdContentControlType.wdContentControlRichText, CurrentDocument, Globals.ThisAddIn.Application.Selection); } catch (Exception ex) { log.Error("Couldn't add content control: " + ex.Message); return; } ConditionsPartEntry cpe = new ConditionsPartEntry(controlMain.model); cpe.setup(CurrentPart.Id, strXPath, prefixMappings, true); cpe.save(); cc.Title = "Conditional: " + cpe.conditionId; // Write tag td.set("od:condition", cpe.conditionId); cc.Tag = td.asQueryString(); designMode.On(); } else if (controlMain.controlMode1.isModeRepeat()) { log.Debug("In repeat mode"); Word.ContentControl cc = null; try { // always make new cc = ContentControlMaker.MakeOrReuse(false, Word.WdContentControlType.wdContentControlRichText, CurrentDocument, Globals.ThisAddIn.Application.Selection); } catch (Exception ex) { log.Error("Couldn't add content control: " + ex.Message); return; } // 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(controlMain.model); xppe.setup("rpt", CurrentPart.Id, strXPath, prefixMappings, false); // no Q for repeat xppe.save(); cc.Title = "Repeat: " + xppe.xpathId; // Write tag td.set("od:repeat", xppe.xpathId); cc.Tag = td.asQueryString(); designMode.On(); } return; } // end if (Globals.ThisAddIn.Application.Selection.Type != Microsoft.Office.Interop.Word.WdSelectionType.wdSelectionIP) // Selection.Type: Microsoft.Office.Interop.Word.WdSelectionType.wdSelectionIP // ie cursor is somewhere inside a paragraph, but with nothing selected. log.Info("In wdSelectionIP specific code."); // leave designMode alone here // Following processing uses clipboard HTML to implement drag/drop processing // Could avoid dealing with that (what's the problem anyway?) if they are dragging onto an existing content control, with: //Word.ContentControl existingCC = ContentControlMaker.getActiveContentControl(CurrentDocument, Globals.ThisAddIn.Application.Selection); //if (existingCC != null) return; // But that stops them from dragging any more content into a repeat. string title = ""; string tag = ""; bool needBind = false; log.Debug(strXPath); Office.CustomXMLNode targetNode = CurrentPart.SelectSingleNode(strXPath); string nodeContent = targetNode.Text; // or ((XmlNode)tn.Tag).InnerXml // Insert bind | condition | repeat // depending on which mode button is pressed. if (controlMain.modeControlEnabled == false || // ie always mode bind controlMain.controlMode1.isModeBind()) { log.Debug("In bind mode"); // OpenDoPE: create w:tag=od:xpath=x1 // and add XPath to xpaths part XPathsPartEntry xppe = new XPathsPartEntry(controlMain.model); xppe.setup(null, CurrentPart.Id, strXPath, prefixMappings, false); // Don't setup Q until after drop xppe.save(); // Write tag td.set("od:xpath", xppe.xpathId); // Does this node contain XHTML? // TODO: error handling log.Info(nodeContent); if (isFlatOPC) { // <?mso-application progid="Word.Document"?> // <pkg:package xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage"> td.set("od:progid", "Word.Document"); title = "Word: " + xppe.xpathId; needBind = false; // make it a rich text control } else if (isXHTML) { td.set("od:ContentType", "application/xhtml+xml"); // TODO since this is a run-level sdt, // the XHTML content will need to be run-level. // Help the user with this? // Or in a run-level context, docx4j could convert // p to soft-enter? But what to do about tables? title = "XHTML: " + xppe.xpathId; needBind = false; // make it a rich text control // Word will only replace our HTML-imported-to-docx with the raw HTML // if we have the bind. // Without this, giving the user visual feedback in Word is a TODO } else if (isPicture) { designMode.Off(); log.Debug("NEW Special case handling for pictures.."); //object missing = System.Type.Missing; Globals.ThisAddIn.Application.Selection.Collapse(ref missing); // Are they dragging to an existing picture content control Word.ContentControl picCC = ContentControlMaker.getActiveContentControl(CurrentDocument, Globals.ThisAddIn.Application.Selection); try { if (picCC == null || (picCC.Type != Word.WdContentControlType.wdContentControlPicture)) { picCC = CurrentDocument.ContentControls.Add( Word.WdContentControlType.wdContentControlRichText, ref missing); designMode.restoreState(); } } catch (COMException ce) { // Will happen if you try to drag a text node onto an existing image content control log.Debug("Ignoring " + ce.Message); return; } PictureUtils.setPictureHandler(td); picCC.Title = "Image: " + xppe.xpathId; picCC.Tag = td.asQueryString(); PictureUtils.pastePictureIntoCC(picCC, Convert.FromBase64String(nodeContent)); return; } else { title = "Data value: " + xppe.xpathId; needBind = true; } tag = td.asQueryString(); } else if (controlMain.controlMode1.isModeCondition()) { log.Debug("In condition mode"); ConditionsPartEntry cpe = new ConditionsPartEntry(controlMain.model); cpe.setup(CurrentPart.Id, strXPath, prefixMappings, false); cpe.save(); title = "Conditional: " + cpe.conditionId; // Write tag td.set("od:condition", cpe.conditionId); tag = td.asQueryString(); } else if (controlMain.controlMode1.isModeRepeat()) { log.Debug("In repeat mode"); // 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(controlMain.model); xppe.setup("rpt", CurrentPart.Id, strXPath, prefixMappings, false); xppe.save(); title = "Data value: " + xppe.xpathId; // Write tag td.set("od:repeat", xppe.xpathId); tag = td.asQueryString(); } //create the HTML string strHTML = string.Empty; if (isFlatOPC) { // <?mso-application progid="Word.Document"?> // <pkg:package xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage"> nodeContent = ControlTreeView.EscapeXHTML(nodeContent); strHTML = ClipboardUtilities.GenerateClipboardHTML(needBind, strXPath, Utilities.GetPrefixMappings(xmlnsMgr), CurrentPart.Id, Utilities.MappingType.RichText, title, tag, nodeContent); } else if (isXHTML) { // need to escape eg <span> for it to get through the Clipboard nodeContent = ControlTreeView.EscapeXHTML(nodeContent); // use a RichText control, and set nodeContent strHTML = ClipboardUtilities.GenerateClipboardHTML(needBind, strXPath, Utilities.GetPrefixMappings(xmlnsMgr), CurrentPart.Id, Utilities.MappingType.RichText, title, tag, nodeContent); // alternatively, this could be done in DocumentEvents.doc_ContentControlAfterAdd // but to do it there, we'd need to manually resolve the XPath to // find the value of the CustomXMLNode it pointed to. } else if (!needBind) { // For conditions & repeats, we use a RichText control strHTML = ClipboardUtilities.GenerateClipboardHTML(needBind, strXPath, Utilities.GetPrefixMappings(xmlnsMgr), CurrentPart.Id, Utilities.MappingType.RichText, title, tag); } else { // Normal bind if (OwnerDocument.Schemas.Count > 0) { switch (Utilities.CheckNodeType((XmlNode)tn.Tag)) { case Utilities.MappingType.Date: strHTML = ClipboardUtilities.GenerateClipboardHTML(needBind, strXPath, prefixMappings, CurrentPart.Id, Utilities.MappingType.Date, title, tag); break; case Utilities.MappingType.DropDown: strHTML = ClipboardUtilities.GenerateClipboardHTML(needBind, strXPath, prefixMappings, CurrentPart.Id, Utilities.MappingType.DropDown, title, tag); break; case Utilities.MappingType.Picture: strHTML = ClipboardUtilities.GenerateClipboardHTML(needBind, strXPath, prefixMappings, CurrentPart.Id, Utilities.MappingType.Picture, title, tag); break; default: strHTML = ClipboardUtilities.GenerateClipboardHTML(needBind, strXPath, prefixMappings, CurrentPart.Id, Utilities.MappingType.Text, title, tag); break; } } else { //String val = ((XmlNode)tn.Tag).InnerText; if (ContentDetection.IsBase64Encoded(val)) { // Force picture content control strHTML = ClipboardUtilities.GenerateClipboardHTML(needBind, strXPath, Utilities.GetPrefixMappings(xmlnsMgr), CurrentPart.Id, Utilities.MappingType.Picture, title, tag); } else { strHTML = ClipboardUtilities.GenerateClipboardHTML(needBind, strXPath, Utilities.GetPrefixMappings(xmlnsMgr), CurrentPart.Id, Utilities.MappingType.Text, title, tag); } } } // All cases:- //notify ourselves of a pending drag/drop controlMain.NotifyDragDrop(true); //throw it on the clipboard to drag DataObject dobj = new DataObject(); dobj.SetData(DataFormats.Html, strHTML); dobj.SetData(DataFormats.Text, tn.Text); controlTreeView.DoDragDrop(dobj, DragDropEffects.Move); //notify ourselves of a completed drag/drop controlMain.NotifyDragDrop(false); Clipboard.SetData(DataFormats.Text, ((XmlNode)tn.Tag).InnerXml); }
/// <summary> /// used when they right click then select "map to" /// </summary> /// <param name="odType"></param> public void mapToSelectedControl(ControlTreeView.OpenDopeType odType, ControlTreeView controlTreeView, ControlMain controlMain, Word.Document CurrentDocument, Office.CustomXMLPart CurrentPart, //XmlDocument OwnerDocument, bool _PictureContentControlsReplace ) { object missing = System.Type.Missing; DesignMode designMode = new OpenDoPEModel.DesignMode(CurrentDocument); // In this method, we're usually not creating a control, // so we don't need to turn off try { //create a binding Word.ContentControl cc = null; if (CurrentDocument.Application.Selection.ContentControls.Count == 1) { log.Debug("CurrentDocument.Application.Selection.ContentControls.Count == 1"); object objOne = 1; cc = CurrentDocument.Application.Selection.ContentControls.get_Item(ref objOne); log.Info("Mapped content control to tree view node " + controlTreeView.treeView.SelectedNode.Name); } else if (CurrentDocument.Application.Selection.ParentContentControl != null) { log.Debug("ParentContentControl != null"); cc = CurrentDocument.Application.Selection.ParentContentControl; } if (cc != null) { TreeNode tn = controlTreeView.treeView.SelectedNode; //get an nsmgr NameTable nt = new NameTable(); //generate the xpath and the ns manager XmlNamespaceManager xmlnsMgr = new XmlNamespaceManager(nt); string strXPath = Utilities.XpathFromXn(CurrentPart.NamespaceManager, (XmlNode)tn.Tag, true, xmlnsMgr); log.Info("Right clicked with XPath: " + strXPath); string prefixMappings = Utilities.GetPrefixMappings(xmlnsMgr); // Insert bind | condition | repeat // depending on which mode button is pressed. TagData td = new TagData(""); if ((controlMain.modeControlEnabled == false && odType == ControlTreeView.OpenDopeType.Unspecified) || // ie always mode bind (controlMain.modeControlEnabled == true && controlMain.controlMode1.isModeBind()) || odType == ControlTreeView.OpenDopeType.Bind) { log.Debug("In bind mode"); XPathsPartEntry xppe = new XPathsPartEntry(controlMain.model); xppe.setup(null, CurrentPart.Id, strXPath, prefixMappings, true); xppe.save(); td.set("od:xpath", xppe.xpathId); String val = ((XmlNode)tn.Tag).InnerText; bool isXHTML = false; bool isFlatOPC = ContentDetection.IsFlatOPCContent(val); if (isFlatOPC) { // <?mso-application progid="Word.Document"?> // <pkg:package xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage"> log.Debug(".. contains Flat OPC content "); cc.Type = Word.WdContentControlType.wdContentControlRichText; // Ensure block level Inline2Block i2b = new Inline2Block(); cc = i2b.convertToBlockLevel(cc, false, true); if (cc == null) { MessageBox.Show("Problems inserting block level WordML at this location."); return; } td.set("od:progid", "Word.Document"); cc.Title = "Word: " + xppe.xpathId; //cc.Range.Text = val; // don't escape it cc.Range.InsertXML(val, ref missing); } else 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"). // They've said map, so delete existing, and replace it. designMode.Off(); cc.Delete(true); // Now add a new cc Globals.ThisAddIn.Application.Selection.Collapse(ref missing); if (_PictureContentControlsReplace) { // Use a rich text control instead cc = CurrentDocument.ContentControls.Add( Word.WdContentControlType.wdContentControlRichText, ref missing); PictureUtils.setPictureHandler(td); cc.Title = "Image: " + xppe.xpathId; PictureUtils.pastePictureIntoCC(cc, Convert.FromBase64String(val)); } else { cc = CurrentDocument.ContentControls.Add( Word.WdContentControlType.wdContentControlPicture, ref missing); } designMode.restoreState(); } else { isXHTML = ContentDetection.IsXHTMLContent(val); } if (cc.Type == Word.WdContentControlType.wdContentControlText) { // cc.Type = Word.WdContentControlType.wdContentControlText; // ??? cc.MultiLine = true; } //if (HasXHTMLContent(tn)) if (isXHTML) { log.Info("detected XHTML.. "); td.set("od:ContentType", "application/xhtml+xml"); cc.Title = "XHTML: " + xppe.xpathId; cc.Type = Word.WdContentControlType.wdContentControlRichText; cc.Range.Text = val; // don't escape it 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; } } } else if (!isFlatOPC) { cc.Title = "Data value: " + xppe.xpathId; } cc.Tag = td.asQueryString(); if (cc.Type != Word.WdContentControlType.wdContentControlRichText) { cc.XMLMapping.SetMappingByNode( Utilities.MxnFromTn(controlTreeView.treeView.SelectedNode, CurrentPart, true)); } } else if ((controlMain.modeControlEnabled == true && controlMain.controlMode1.isModeCondition()) || odType == ControlTreeView.OpenDopeType.Condition) { log.Debug("In condition mode"); // We want to be in Design Mode, so user can see their gesture take effect designMode.On(); ConditionsPartEntry cpe = new ConditionsPartEntry(controlMain.model); cpe.setup(CurrentPart.Id, strXPath, prefixMappings, true); cpe.save(); cc.Title = "Conditional: " + cpe.conditionId; // Write tag td.set("od:condition", cpe.conditionId); cc.Tag = td.asQueryString(); // Make it RichText; remove any pre-existing bind if (cc.XMLMapping.IsMapped) { cc.XMLMapping.Delete(); } if (cc.Type == Word.WdContentControlType.wdContentControlText) { cc.Type = Word.WdContentControlType.wdContentControlRichText; } } else if ((controlMain.modeControlEnabled == true && controlMain.controlMode1.isModeRepeat()) || odType == ControlTreeView.OpenDopeType.Repeat) { log.Debug("In repeat mode"); // We want to be in Design Mode, so user can see their gesture take effect designMode.On(); // 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(controlMain.model); xppe.setup("rpt", CurrentPart.Id, strXPath, prefixMappings, false); xppe.save(); cc.Title = "Data value: " + xppe.xpathId; // Write tag td.set("od:repeat", xppe.xpathId); cc.Tag = td.asQueryString(); // Make it RichText; remove any pre-existing bind if (cc.XMLMapping.IsMapped) { cc.XMLMapping.Delete(); } if (cc.Type == Word.WdContentControlType.wdContentControlText) { cc.Type = Word.WdContentControlType.wdContentControlRichText; } } //ensure it's checked controlTreeView.mapToSelectedControlToolStripMenuItem.Checked = true; } } catch (COMException cex) { controlTreeView.ShowErrorMessage(cex.Message); designMode.restoreState(); } }
private void buttonCondition_Click(object sender, RibbonControlEventArgs e) { 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); }
// 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> private void buttonRepeat_Click(object sender, RibbonControlEventArgs e) { 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(); }
/// <summary> /// used when they right click then select "map to" /// </summary> /// <param name="odType"></param> public void mapToSelectedControl(ControlTreeView.OpenDopeType odType, ControlTreeView controlTreeView, ControlMain controlMain, Word.Document CurrentDocument, Office.CustomXMLPart CurrentPart, //XmlDocument OwnerDocument, bool _PictureContentControlsReplace ) { object missing = System.Type.Missing; DesignMode designMode = new OpenDoPEModel.DesignMode(CurrentDocument); // In this method, we're usually not creating a control, // so we don't need to turn off try { //create a binding Word.ContentControl cc = null; if (CurrentDocument.Application.Selection.ContentControls.Count == 1) { log.Debug("CurrentDocument.Application.Selection.ContentControls.Count == 1"); object objOne = 1; cc = CurrentDocument.Application.Selection.ContentControls.get_Item(ref objOne); log.Info("Mapped content control to tree view node " + controlTreeView.treeView.SelectedNode.Name); } else if (CurrentDocument.Application.Selection.ParentContentControl != null) { log.Debug("ParentContentControl != null"); cc = CurrentDocument.Application.Selection.ParentContentControl; } if (cc != null) { TreeNode tn = controlTreeView.treeView.SelectedNode; //get an nsmgr NameTable nt = new NameTable(); //generate the xpath and the ns manager XmlNamespaceManager xmlnsMgr = new XmlNamespaceManager(nt); string strXPath = Utilities.XpathFromXn(CurrentPart.NamespaceManager, (XmlNode)tn.Tag, true, xmlnsMgr); log.Info("Right clicked with XPath: " + strXPath); string prefixMappings = Utilities.GetPrefixMappings(xmlnsMgr); // Insert bind | condition | repeat // depending on which mode button is pressed. TagData td = new TagData(""); if ((controlMain.modeControlEnabled == false && odType == ControlTreeView.OpenDopeType.Unspecified) // ie always mode bind || (controlMain.modeControlEnabled == true && controlMain.controlMode1.isModeBind()) || odType == ControlTreeView.OpenDopeType.Bind) { log.Debug("In bind mode"); XPathsPartEntry xppe = new XPathsPartEntry(controlMain.model); xppe.setup(null, CurrentPart.Id, strXPath, prefixMappings, true); xppe.save(); td.set("od:xpath", xppe.xpathId); String val = ((XmlNode)tn.Tag).InnerText; bool isXHTML = false; bool isFlatOPC = ContentDetection.IsFlatOPCContent(val); if (isFlatOPC) { // <?mso-application progid="Word.Document"?> // <pkg:package xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage"> log.Debug(".. contains Flat OPC content "); cc.Type = Word.WdContentControlType.wdContentControlRichText; // Ensure block level Inline2Block i2b = new Inline2Block(); cc = i2b.convertToBlockLevel(cc, false, true); if (cc == null) { MessageBox.Show("Problems inserting block level WordML at this location."); return; } td.set("od:progid", "Word.Document"); cc.Title = "Word: " + xppe.xpathId; //cc.Range.Text = val; // don't escape it cc.Range.InsertXML(val, ref missing); } else 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"). // They've said map, so delete existing, and replace it. designMode.Off(); cc.Delete(true); // Now add a new cc Globals.ThisAddIn.Application.Selection.Collapse(ref missing); if (_PictureContentControlsReplace) { // Use a rich text control instead cc = CurrentDocument.ContentControls.Add( Word.WdContentControlType.wdContentControlRichText, ref missing); PictureUtils.setPictureHandler(td); cc.Title = "Image: " + xppe.xpathId; PictureUtils.pastePictureIntoCC(cc, Convert.FromBase64String(val)); } else { cc = CurrentDocument.ContentControls.Add( Word.WdContentControlType.wdContentControlPicture, ref missing); } designMode.restoreState(); } else { isXHTML = ContentDetection.IsXHTMLContent(val); } if (cc.Type == Word.WdContentControlType.wdContentControlText) { // cc.Type = Word.WdContentControlType.wdContentControlText; // ??? cc.MultiLine = true; } //if (HasXHTMLContent(tn)) if (isXHTML) { log.Info("detected XHTML.. "); td.set("od:ContentType", "application/xhtml+xml"); cc.Title = "XHTML: " + xppe.xpathId; cc.Type = Word.WdContentControlType.wdContentControlRichText; cc.Range.Text = val; // don't escape it 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; } } } else if (!isFlatOPC) { cc.Title = "Data value: " + xppe.xpathId; } cc.Tag = td.asQueryString(); if (cc.Type != Word.WdContentControlType.wdContentControlRichText) { cc.XMLMapping.SetMappingByNode( Utilities.MxnFromTn(controlTreeView.treeView.SelectedNode, CurrentPart, true)); } } else if ((controlMain.modeControlEnabled == true && controlMain.controlMode1.isModeCondition()) || odType == ControlTreeView.OpenDopeType.Condition) { log.Debug("In condition mode"); // We want to be in Design Mode, so user can see their gesture take effect designMode.On(); ConditionsPartEntry cpe = new ConditionsPartEntry(controlMain.model); cpe.setup(CurrentPart.Id, strXPath, prefixMappings, true); cpe.save(); cc.Title = "Conditional: " + cpe.conditionId; // Write tag td.set("od:condition", cpe.conditionId); cc.Tag = td.asQueryString(); // Make it RichText; remove any pre-existing bind if (cc.XMLMapping.IsMapped) { cc.XMLMapping.Delete(); } if (cc.Type == Word.WdContentControlType.wdContentControlText) { cc.Type = Word.WdContentControlType.wdContentControlRichText; } } else if ((controlMain.modeControlEnabled == true && controlMain.controlMode1.isModeRepeat()) || odType == ControlTreeView.OpenDopeType.Repeat) { log.Debug("In repeat mode"); // We want to be in Design Mode, so user can see their gesture take effect designMode.On(); // 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(controlMain.model); xppe.setup("rpt", CurrentPart.Id, strXPath, prefixMappings, false); xppe.save(); cc.Title = "Data value: " + xppe.xpathId; // Write tag td.set("od:repeat", xppe.xpathId); cc.Tag = td.asQueryString(); // Make it RichText; remove any pre-existing bind if (cc.XMLMapping.IsMapped) { cc.XMLMapping.Delete(); } if (cc.Type == Word.WdContentControlType.wdContentControlText) { cc.Type = Word.WdContentControlType.wdContentControlRichText; } } //ensure it's checked controlTreeView.mapToSelectedControlToolStripMenuItem.Checked = true; } } catch (COMException cex) { controlTreeView.ShowErrorMessage(cex.Message); designMode.restoreState(); } }
/// <summary> /// Create a content control mapped to the selected XML node. /// </summary> /// <param name="CCType">A WdContentControlType value specifying the type of control to create.</param> public void CreateMappedControl(Word.WdContentControlType CCType, ControlTreeView.OpenDopeType odType, ControlTreeView controlTreeView, ControlMain controlMain, Word.Document CurrentDocument, Office.CustomXMLPart CurrentPart, //XmlDocument OwnerDocument, bool _PictureContentControlsReplace ) { OpenDoPEModel.DesignMode designMode = new OpenDoPEModel.DesignMode(CurrentDocument); designMode.Off(); try { object missing = Type.Missing; TreeNode tn = controlTreeView.treeView.SelectedNode; if (((XmlNode)tn.Tag).NodeType == XmlNodeType.Text) { tn = tn.Parent; } //get an nsmgr NameTable nt = new NameTable(); //generate the xpath and the ns manager XmlNamespaceManager xmlnsMgr = new XmlNamespaceManager(nt); string strXPath = Utilities.XpathFromXn(CurrentPart.NamespaceManager, (XmlNode)tn.Tag, true, xmlnsMgr); log.Info("Right click for XPath: " + strXPath); string prefixMappings = Utilities.GetPrefixMappings(xmlnsMgr); // Insert bind | condition | repeat // depending on which mode button is pressed. TagData td = new TagData(""); if ((controlMain.modeControlEnabled == false && odType == ControlTreeView.OpenDopeType.Unspecified) // ie always mode bind || (controlMain.modeControlEnabled == true && controlMain.controlMode1.isModeBind()) || odType == ControlTreeView.OpenDopeType.Bind) { log.Debug("In bind mode"); String val = ((XmlNode)tn.Tag).InnerText; //bool isXHTML = HasXHTMLContent(tn); bool isPicture = false; bool isXHTML = false; bool isFlatOPC = ContentDetection.IsFlatOPCContent(val); Word.ContentControl cc = null; if (isFlatOPC) { // <?mso-application progid="Word.Document"?> // <pkg:package xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage"> log.Debug(".. contains block content "); cc = CurrentDocument.Application.Selection.ContentControls.Add( Word.WdContentControlType.wdContentControlRichText, ref missing); // Ensure block level Inline2Block i2b = new Inline2Block(); cc = i2b.convertToBlockLevel(cc, false, true); if (cc == null) { MessageBox.Show("Problems inserting block level WordML at this location."); return; } } else { isXHTML = ContentDetection.IsXHTMLContent(val); } if (isXHTML) { cc = CurrentDocument.Application.Selection.ContentControls.Add( Word.WdContentControlType.wdContentControlRichText, ref missing); 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."); designMode.restoreState(); return; } } } else if (ContentDetection.IsBase64Encoded(val)) { isPicture = true; if (_PictureContentControlsReplace) { // Use a rich text control instead cc = CurrentDocument.ContentControls.Add( Word.WdContentControlType.wdContentControlRichText, ref missing); PictureUtils.pastePictureIntoCC(cc, Convert.FromBase64String(val)); } else { // Force picture content control log.Debug("Detected picture"); cc = CurrentDocument.Application.Selection.ContentControls.Add(Word.WdContentControlType.wdContentControlPicture, ref missing); } } else if (!isFlatOPC) { log.Debug("Not picture or XHTML; " + CCType.ToString()); // This formulation seems more susceptible to "locked for editing" //object rng = CurrentDocument.Application.Selection.Range; //cc = CurrentDocument.ContentControls.Add(Word.WdContentControlType.wdContentControlText, ref rng); // so prefer: cc = CurrentDocument.Application.Selection.ContentControls.Add(CCType, ref missing); } XPathsPartEntry xppe = new XPathsPartEntry(controlMain.model); xppe.setup(null, CurrentPart.Id, strXPath, prefixMappings, true); xppe.save(); td.set("od:xpath", xppe.xpathId); if (isFlatOPC) { td.set("od:progid", "Word.Document"); cc.Title = "Word: " + xppe.xpathId; //cc.Range.Text = val; // don't escape it cc.Range.InsertXML(val, ref missing); } else if (isXHTML) { td.set("od:ContentType", "application/xhtml+xml"); cc.Title = "XHTML: " + xppe.xpathId; cc.Range.Text = val; } else if (isPicture) { PictureUtils.setPictureHandler(td); cc.Title = "Image: " + xppe.xpathId; } else { cc.Title = "Data value: " + xppe.xpathId; } cc.Tag = td.asQueryString(); if (cc.Type == Word.WdContentControlType.wdContentControlText) { cc.MultiLine = true; } if (cc.Type != Word.WdContentControlType.wdContentControlRichText) { cc.XMLMapping.SetMappingByNode(Utilities.MxnFromTn(tn, CurrentPart, true)); } designMode.restoreState(); } else if ((controlMain.modeControlEnabled == true && controlMain.controlMode1.isModeCondition()) || odType == ControlTreeView.OpenDopeType.Condition) { log.Debug("In condition mode"); // User can make a condition whatever type they like, // but if they make it text, change it to RichText. if (CCType == Word.WdContentControlType.wdContentControlText) { CCType = Word.WdContentControlType.wdContentControlRichText; } Word.ContentControl cc = CurrentDocument.Application.Selection.ContentControls.Add(CCType, ref missing); ConditionsPartEntry cpe = new ConditionsPartEntry(controlMain.model); cpe.setup(CurrentPart.Id, strXPath, prefixMappings, true); cpe.save(); cc.Title = "Conditional: " + cpe.conditionId; // Write tag td.set("od:condition", cpe.conditionId); cc.Tag = td.asQueryString(); // We want to be in Design Mode, so user can see their gesture take effect designMode.On(); Ribbon.editXPath(cc); } else if ((controlMain.modeControlEnabled == true && controlMain.controlMode1.isModeRepeat()) || odType == ControlTreeView.OpenDopeType.Repeat) { log.Debug("In repeat mode"); // User can make a repeat whatever type they like // (though does it ever make sense for it to be other than RichText?), // but if they make it text, change it to RichText. if (CCType == Word.WdContentControlType.wdContentControlText) { CCType = Word.WdContentControlType.wdContentControlRichText; } Word.ContentControl cc = CurrentDocument.Application.Selection.ContentControls.Add(CCType, ref missing); // 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(controlMain.model); xppe.setup("rpt", CurrentPart.Id, strXPath, prefixMappings, false); xppe.save(); cc.Title = "Data value: " + xppe.xpathId; // Write tag td.set("od:repeat", xppe.xpathId); cc.Tag = td.asQueryString(); // We want to be in Design Mode, so user can see their gesture take effect designMode.On(); } } catch (COMException cex) { controlTreeView.ShowErrorMessage(cex.Message); designMode.restoreState(); } }
// 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); }
public void treeView_ItemDrag(object sender, ItemDragEventArgs e, ControlTreeView controlTreeView, ControlMain controlMain, Word.Document CurrentDocument, Office.CustomXMLPart CurrentPart, XmlDocument OwnerDocument, bool _PictureContentControlsReplace) { object missing = System.Type.Missing; TreeNode tn = (TreeNode)e.Item; if (tn == null) { Debug.Fail("no tn"); return; } //check if this is something we can drag if (((XmlNode)tn.Tag).NodeType == XmlNodeType.ProcessingInstruction || ((XmlNode)tn.Tag).NodeType == XmlNodeType.Comment) return; if (controlMain.modeControlEnabled == false // ie always mode bind || controlMain.controlMode1.isModeBind()) { if (!ControlTreeView.IsLeafNode(tn) || ((XmlNode)tn.Tag).NodeType == XmlNodeType.Text && !ControlTreeView.IsLeafNode(tn.Parent)) return; } // repeats and conditions; let them drag any node //get an nsmgr NameTable nt = new NameTable(); //generate the xpath and the ns manager XmlNamespaceManager xmlnsMgr = new XmlNamespaceManager(nt); string strXPath = Utilities.XpathFromXn(CurrentPart.NamespaceManager, (XmlNode)tn.Tag, true, xmlnsMgr); log.Info("Dragging XPath: " + strXPath); string prefixMappings = Utilities.GetPrefixMappings(xmlnsMgr); // OpenDoPE TagData td = new TagData(""); String val = ((XmlNode)tn.Tag).InnerText; DesignMode designMode = new OpenDoPEModel.DesignMode(CurrentDocument); // Special case for pictures, since drag/drop does not seem // to work properly (the XHTML pasted doesn't do what it should?) bool isPicture = ContentDetection.IsBase64Encoded(val); if (isPicture && !_PictureContentControlsReplace) { designMode.Off(); log.Debug("Special case handling for pictures.."); // Selection can't be textual content, so ensure it isn't. // It is allowed to be a picture, so in the future we could // leave the selection alone if it is just a picture. Globals.ThisAddIn.Application.Selection.Collapse(ref missing); // Are they dragging to an existing picture content control Word.ContentControl picCC = ContentControlMaker.getActiveContentControl(CurrentDocument, Globals.ThisAddIn.Application.Selection); try { if (picCC == null || (picCC.Type != Word.WdContentControlType.wdContentControlPicture)) { picCC = CurrentDocument.ContentControls.Add( Word.WdContentControlType.wdContentControlPicture, ref missing); designMode.restoreState(); } } catch (COMException ce) { // Will happen if you try to drag a text node onto an existing image content control log.Debug("Ignoring " + ce.Message); return; } XPathsPartEntry xppe = new XPathsPartEntry(controlMain.model); xppe.setup(null, CurrentPart.Id, strXPath, prefixMappings, false); xppe.save(); td.set("od:xpath", xppe.xpathId); picCC.Tag = td.asQueryString(); picCC.Title = "Data value: " + xppe.xpathId; picCC.XMLMapping.SetMappingByNode(Utilities.MxnFromTn(tn, CurrentPart, true)); return; } log.Debug("\n\ntreeView_ItemDrag for WdSelectionType " + Globals.ThisAddIn.Application.Selection.Type.ToString()); bool isXHTML = false; bool isFlatOPC = ContentDetection.IsFlatOPCContent(val); if (!isFlatOPC) isXHTML = ContentDetection.IsXHTMLContent(val); if (Globals.ThisAddIn.Application.Selection.Type != Microsoft.Office.Interop.Word.WdSelectionType.wdSelectionIP) { // ie something is selected, since "inline paragraph selection" // just means the cursor is somewhere inside // a paragraph, but with nothing selected. designMode.Off(); // Selection types: http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.wdselectiontype(v=office.11).aspx log.Debug("treeView_ItemDrag fired, but interpreted as gesture for WdSelectionType " + Globals.ThisAddIn.Application.Selection.Type.ToString()); Word.ContentControl parentCC = ContentControlMaker.getActiveContentControl(CurrentDocument, Globals.ThisAddIn.Application.Selection); // Insert bind | condition | repeat // depending on which mode button is pressed. if (controlMain.modeControlEnabled == false // ie always mode bind || controlMain.controlMode1.isModeBind()) { log.Debug("In bind mode"); Word.ContentControl cc = null; try { if (isFlatOPC || isXHTML || (isPicture && _PictureContentControlsReplace)) { // Rich text if (parentCC != null && ContentControlOpenDoPEType.isBound(parentCC)) { // Reuse existing cc cc = ContentControlMaker.MakeOrReuse(true, Word.WdContentControlType.wdContentControlRichText, CurrentDocument, Globals.ThisAddIn.Application.Selection); } else { // Make new cc cc = ContentControlMaker.MakeOrReuse(true, Word.WdContentControlType.wdContentControlRichText, CurrentDocument, Globals.ThisAddIn.Application.Selection); } if (isFlatOPC) { log.Debug(".. contains block content "); // Ensure block level Inline2Block i2b = new Inline2Block(); cc = i2b.convertToBlockLevel(cc, false, true); if (cc == null) { MessageBox.Show("Problems inserting block level WordML at this location."); return; } } else if (isXHTML // and thus not picture && Inline2Block.containsBlockLevelContent(val)) { log.Debug(".. contains block content "); // Ensure block level Inline2Block i2b = new Inline2Block(); cc = i2b.convertToBlockLevel(cc, false, true); if (cc == null) { MessageBox.Show("Problems inserting block level XHTML at this location."); return; } } } else { // Plain text if (parentCC != null && ContentControlOpenDoPEType.isBound(parentCC)) { // Reuse existing cc cc = ContentControlMaker.MakeOrReuse(true, Word.WdContentControlType.wdContentControlText, CurrentDocument, Globals.ThisAddIn.Application.Selection); } else { // Make new cc cc = ContentControlMaker.MakeOrReuse(false, Word.WdContentControlType.wdContentControlText, CurrentDocument, Globals.ThisAddIn.Application.Selection); } cc.MultiLine = true; // Is a text content control always run-level? // No, not if you have a single para selected and you do drag gesture // (or if you remap a rich text control) } } catch (Exception ex) { log.Error("Couldn't add content control: " + ex.Message); return; } XPathsPartEntry xppe = new XPathsPartEntry(controlMain.model); xppe.setup(null, CurrentPart.Id, strXPath, prefixMappings, true); xppe.save(); td.set("od:xpath", xppe.xpathId); if (isFlatOPC) { // <?mso-application progid="Word.Document"?> // <pkg:package xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage"> td.set("od:progid", "Word.Document"); cc.Title = "Word: " + xppe.xpathId; //cc.Range.Text = val; // don't escape it cc.Range.InsertXML(val, ref missing); } else if (isXHTML) { td.set("od:ContentType", "application/xhtml+xml"); cc.Title = "XHTML: " + xppe.xpathId; cc.Range.Text = val; // don't escape it } else if (isPicture) { PictureUtils.setPictureHandler(td); cc.Title = "Image: " + xppe.xpathId; string picContent = CurrentPart.SelectSingleNode(strXPath).Text; PictureUtils.pastePictureIntoCC(cc, Convert.FromBase64String(picContent)); } else { cc.XMLMapping.SetMappingByNode(Utilities.MxnFromTn(tn, CurrentPart, true)); string nodeXML = cc.XMLMapping.CustomXMLNode.XML; log.Info(nodeXML); cc.Title = "Data value: " + xppe.xpathId; } cc.Tag = td.asQueryString(); designMode.restoreState(); } else if (controlMain.controlMode1.isModeCondition()) { log.Debug("In condition mode"); Word.ContentControl cc = null; try { // always make new cc = ContentControlMaker.MakeOrReuse(false, Word.WdContentControlType.wdContentControlRichText, CurrentDocument, Globals.ThisAddIn.Application.Selection); } catch (Exception ex) { log.Error("Couldn't add content control: " + ex.Message); return; } ConditionsPartEntry cpe = new ConditionsPartEntry(controlMain.model); cpe.setup(CurrentPart.Id, strXPath, prefixMappings, true); cpe.save(); cc.Title = "Conditional: " + cpe.conditionId; // Write tag td.set("od:condition", cpe.conditionId); cc.Tag = td.asQueryString(); designMode.On(); } else if (controlMain.controlMode1.isModeRepeat()) { log.Debug("In repeat mode"); Word.ContentControl cc = null; try { // always make new cc = ContentControlMaker.MakeOrReuse(false, Word.WdContentControlType.wdContentControlRichText, CurrentDocument, Globals.ThisAddIn.Application.Selection); } catch (Exception ex) { log.Error("Couldn't add content control: " + ex.Message); return; } // 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(controlMain.model); xppe.setup("rpt", CurrentPart.Id, strXPath, prefixMappings, false); // no Q for repeat xppe.save(); cc.Title = "Repeat: " + xppe.xpathId; // Write tag td.set("od:repeat", xppe.xpathId); cc.Tag = td.asQueryString(); designMode.On(); } return; } // end if (Globals.ThisAddIn.Application.Selection.Type != Microsoft.Office.Interop.Word.WdSelectionType.wdSelectionIP) // Selection.Type: Microsoft.Office.Interop.Word.WdSelectionType.wdSelectionIP // ie cursor is somewhere inside a paragraph, but with nothing selected. log.Info("In wdSelectionIP specific code."); // leave designMode alone here // Following processing uses clipboard HTML to implement drag/drop processing // Could avoid dealing with that (what's the problem anyway?) if they are dragging onto an existing content control, with: //Word.ContentControl existingCC = ContentControlMaker.getActiveContentControl(CurrentDocument, Globals.ThisAddIn.Application.Selection); //if (existingCC != null) return; // But that stops them from dragging any more content into a repeat. string title = ""; string tag = ""; bool needBind = false; log.Debug(strXPath); Office.CustomXMLNode targetNode = CurrentPart.SelectSingleNode(strXPath); string nodeContent = targetNode.Text; // or ((XmlNode)tn.Tag).InnerXml // Insert bind | condition | repeat // depending on which mode button is pressed. if (controlMain.modeControlEnabled == false // ie always mode bind || controlMain.controlMode1.isModeBind()) { log.Debug("In bind mode"); // OpenDoPE: create w:tag=od:xpath=x1 // and add XPath to xpaths part XPathsPartEntry xppe = new XPathsPartEntry(controlMain.model); xppe.setup(null, CurrentPart.Id, strXPath, prefixMappings, false); // Don't setup Q until after drop xppe.save(); // Write tag td.set("od:xpath", xppe.xpathId); // Does this node contain XHTML? // TODO: error handling log.Info(nodeContent); if (isFlatOPC) { // <?mso-application progid="Word.Document"?> // <pkg:package xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage"> td.set("od:progid", "Word.Document"); title = "Word: " + xppe.xpathId; needBind = false; // make it a rich text control } else if (isXHTML) { td.set("od:ContentType", "application/xhtml+xml"); // TODO since this is a run-level sdt, // the XHTML content will need to be run-level. // Help the user with this? // Or in a run-level context, docx4j could convert // p to soft-enter? But what to do about tables? title = "XHTML: " + xppe.xpathId; needBind = false; // make it a rich text control // Word will only replace our HTML-imported-to-docx with the raw HTML // if we have the bind. // Without this, giving the user visual feedback in Word is a TODO } else if (isPicture) { designMode.Off(); log.Debug("NEW Special case handling for pictures.."); //object missing = System.Type.Missing; Globals.ThisAddIn.Application.Selection.Collapse(ref missing); // Are they dragging to an existing picture content control Word.ContentControl picCC = ContentControlMaker.getActiveContentControl(CurrentDocument, Globals.ThisAddIn.Application.Selection); try { if (picCC == null || (picCC.Type != Word.WdContentControlType.wdContentControlPicture)) { picCC = CurrentDocument.ContentControls.Add( Word.WdContentControlType.wdContentControlRichText, ref missing); designMode.restoreState(); } } catch (COMException ce) { // Will happen if you try to drag a text node onto an existing image content control log.Debug("Ignoring " + ce.Message); return; } PictureUtils.setPictureHandler(td); picCC.Title = "Image: " + xppe.xpathId; picCC.Tag = td.asQueryString(); PictureUtils.pastePictureIntoCC(picCC, Convert.FromBase64String(nodeContent)); return; } else { title = "Data value: " + xppe.xpathId; needBind = true; } tag = td.asQueryString(); } else if (controlMain.controlMode1.isModeCondition()) { log.Debug("In condition mode"); ConditionsPartEntry cpe = new ConditionsPartEntry(controlMain.model); cpe.setup(CurrentPart.Id, strXPath, prefixMappings, false); cpe.save(); title = "Conditional: " + cpe.conditionId; // Write tag td.set("od:condition", cpe.conditionId); tag = td.asQueryString(); } else if (controlMain.controlMode1.isModeRepeat()) { log.Debug("In repeat mode"); // 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(controlMain.model); xppe.setup("rpt", CurrentPart.Id, strXPath, prefixMappings, false); xppe.save(); title = "Data value: " + xppe.xpathId; // Write tag td.set("od:repeat", xppe.xpathId); tag = td.asQueryString(); } //create the HTML string strHTML = string.Empty; if (isFlatOPC) { // <?mso-application progid="Word.Document"?> // <pkg:package xmlns:pkg="http://schemas.microsoft.com/office/2006/xmlPackage"> nodeContent = ControlTreeView.EscapeXHTML(nodeContent); strHTML = ClipboardUtilities.GenerateClipboardHTML(needBind, strXPath, Utilities.GetPrefixMappings(xmlnsMgr), CurrentPart.Id, Utilities.MappingType.RichText, title, tag, nodeContent); } else if (isXHTML) { // need to escape eg <span> for it to get through the Clipboard nodeContent = ControlTreeView.EscapeXHTML(nodeContent); // use a RichText control, and set nodeContent strHTML = ClipboardUtilities.GenerateClipboardHTML(needBind, strXPath, Utilities.GetPrefixMappings(xmlnsMgr), CurrentPart.Id, Utilities.MappingType.RichText, title, tag, nodeContent); // alternatively, this could be done in DocumentEvents.doc_ContentControlAfterAdd // but to do it there, we'd need to manually resolve the XPath to // find the value of the CustomXMLNode it pointed to. } else if (!needBind) { // For conditions & repeats, we use a RichText control strHTML = ClipboardUtilities.GenerateClipboardHTML(needBind, strXPath, Utilities.GetPrefixMappings(xmlnsMgr), CurrentPart.Id, Utilities.MappingType.RichText, title, tag); } else { // Normal bind if (OwnerDocument.Schemas.Count > 0) { switch (Utilities.CheckNodeType((XmlNode)tn.Tag)) { case Utilities.MappingType.Date: strHTML = ClipboardUtilities.GenerateClipboardHTML(needBind, strXPath, prefixMappings, CurrentPart.Id, Utilities.MappingType.Date, title, tag); break; case Utilities.MappingType.DropDown: strHTML = ClipboardUtilities.GenerateClipboardHTML(needBind, strXPath, prefixMappings, CurrentPart.Id, Utilities.MappingType.DropDown, title, tag); break; case Utilities.MappingType.Picture: strHTML = ClipboardUtilities.GenerateClipboardHTML(needBind, strXPath, prefixMappings, CurrentPart.Id, Utilities.MappingType.Picture, title, tag); break; default: strHTML = ClipboardUtilities.GenerateClipboardHTML(needBind, strXPath, prefixMappings, CurrentPart.Id, Utilities.MappingType.Text, title, tag); break; } } else { //String val = ((XmlNode)tn.Tag).InnerText; if (ContentDetection.IsBase64Encoded(val)) { // Force picture content control strHTML = ClipboardUtilities.GenerateClipboardHTML(needBind, strXPath, Utilities.GetPrefixMappings(xmlnsMgr), CurrentPart.Id, Utilities.MappingType.Picture, title, tag); } else { strHTML = ClipboardUtilities.GenerateClipboardHTML(needBind, strXPath, Utilities.GetPrefixMappings(xmlnsMgr), CurrentPart.Id, Utilities.MappingType.Text, title, tag); } } } // All cases:- //notify ourselves of a pending drag/drop controlMain.NotifyDragDrop(true); //throw it on the clipboard to drag DataObject dobj = new DataObject(); dobj.SetData(DataFormats.Html, strHTML); dobj.SetData(DataFormats.Text, tn.Text); controlTreeView.DoDragDrop(dobj, DragDropEffects.Move); //notify ourselves of a completed drag/drop controlMain.NotifyDragDrop(false); Clipboard.SetData(DataFormats.Text, ((XmlNode)tn.Tag).InnerXml); }