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);
        }
        /// <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 buildCondition()
        {
            ConditionsPartEntry cpe = new ConditionsPartEntry(model);
            TagData td;

            if (this.dataGridView.Rows.Count == 2 // auto last row
                &&  !this.listBoxGovernor.SelectedItem.ToString().Equals("none") ) // none handled separately
            {
                // a simple condition

                if (this.dataGridView.Rows[0].Cells["Questions"].Value is condition)
                {
                    // this is just condition re-use!
                    condition cReused = (condition)this.dataGridView.Rows[0].Cells["Questions"].Value;
                    setTag(cc, cReused);
                    cc.Title = cReused.description; // that'll do for now
                    return;
                }

                // Usual case
                Pairing pair = buildXPathRef(this.dataGridView.Rows[0]);
                cc.Title = restrict64chars(pair.titleText);

                if (pair.xpathEntry.dataBinding.xpath.Contains("position()"))
                {
                    // special case.  TODO: make this a normal condition!
                    // since this approach won't work if it is in complex condition
                    td = new TagData("");
                    td.set("od:RptPosCon", pair.xpathEntry.id);
                    cc.Tag = td.asQueryString();

                    cc.SetPlaceholderText(null, null, "Type the text that'll appear between repeated items.");
                    // that'll only be displayed if the cc is not being wrapped around existing content :-)
                    return;
                }

                condition result = cpe.setup(pair.xpathEntry);
                result.name = this.textBoxName.Text;
                if (string.IsNullOrWhiteSpace(this.textBoxDescription.Text))
                {
                    result.description = pair.titleText;
                }
                else
                {
                    result.description = this.textBoxDescription.Text;
                }
                cpe.save();

                setTag(cc, result);

                return;
            }

            // multi-row
            int last = this.dataGridView.Rows.Count - 1;
            condition outer = new condition();
            cc.Title = null;
            if (this.listBoxGovernor.SelectedItem.ToString().Equals("all"))
            {
                // = and
                and and = new and();
                outer.Item = and;

                foreach (DataGridViewRow row in this.dataGridView.Rows)
                {
                    // Last row is added automatically
                    if (row == this.dataGridView.Rows[last]) continue;

                    if (row.Cells["Questions"].Value is condition)
                    {
                        // this is just condition re-use!
                        condition cReused = (condition)row.Cells["Questions"].Value;

                        if (cc.Title == null)
                        {
                            cc.Title = this.restrict64chars(cReused.description); // that'll do for now
                        }
                        else
                        {
                            cc.Title = this.restrict64chars(cc.Title + " and " + cReused.description); // that'll do for now
                        }

                        conditionref conditionref = new conditionref();
                        conditionref.id = cReused.id;
                        and.Items.Add(conditionref);

                    }
                    else
                    {
                        // xpathref
                        Pairing pair = buildXPathRef(row);

                        if (cc.Title == null)
                        {
                            cc.Title = this.restrict64chars(pair.titleText);
                        }
                        else
                        {
                            cc.Title = this.restrict64chars(cc.Title + " and " + pair.titleText);
                        }

                        xpathref xpathref = new xpathref();
                        xpathref.id = pair.xpathEntry.id;

                        and.Items.Add(xpathref);
                    }
                }

                outer.name = this.textBoxName.Text;
                if (string.IsNullOrWhiteSpace(this.textBoxDescription.Text))
                {
                    outer.description = cc.Title;
                }
                else
                {
                    outer.description = this.textBoxDescription.Text;
                }

                cpe.add(outer, null);
                cpe.save();

                setTag(cc, outer);

                return;
            }

            if (this.listBoxGovernor.SelectedItem.ToString().Equals("any") ) {
                // = or
                or or = new or();
                outer.Item = or;

                foreach (DataGridViewRow row in this.dataGridView.Rows)
                {
                    // Last row is added automatically
                    if (row == this.dataGridView.Rows[last]) continue;

                    if (row.Cells["Questions"].Value is condition)
                    {
                        // this is just condition re-use!
                        condition cReused = (condition)row.Cells["Questions"].Value;

                        if (cc.Title == null)
                        {
                            cc.Title = this.restrict64chars(cReused.description); // that'll do for now
                        }
                        else
                        {
                            cc.Title = this.restrict64chars(cc.Title + " and " + cReused.description); // that'll do for now
                        }

                        conditionref conditionref = new conditionref();
                        conditionref.id = cReused.id;
                        or.Items.Add(conditionref);

                    }
                    else
                    {

                        Pairing pair = buildXPathRef(row);

                        if (cc.Title == null)
                        {
                            cc.Title = this.restrict64chars(pair.titleText);
                        }
                        else
                        {
                            cc.Title = this.restrict64chars(cc.Title + " or " + pair.titleText);
                        }

                        xpathref xpathref = new xpathref();
                        xpathref.id = pair.xpathEntry.id;

                        or.Items.Add(xpathref);
                    }
                }

                outer.name = this.textBoxName.Text;
                if (string.IsNullOrWhiteSpace(this.textBoxDescription.Text))
                {
                    outer.description = cc.Title;
                }
                else
                {
                    outer.description = this.textBoxDescription.Text;
                }

                cpe.add(outer, null);
                cpe.save();

                setTag(cc, outer);

                return;
            }

            if (this.listBoxGovernor.SelectedItem.ToString().Equals("none"))
            {
                // none:  not(A || B) = !A && !B
                not not = new not();
                outer.Item = not;

                or or = new or();
                not.Item = or;

                cc.Title = "NONE OF ";
                foreach (DataGridViewRow row in this.dataGridView.Rows)
                {
                    // Last row is added automatically
                    if (row == this.dataGridView.Rows[last]) continue;
                    if (row.Cells["Questions"].Value is condition)
                    {
                        // this is just condition re-use!
                        condition cReused = (condition)row.Cells["Questions"].Value;

                        if (cc.Title == null)
                        {
                            cc.Title = this.restrict64chars(cReused.description); // that'll do for now
                        }
                        else
                        {
                            cc.Title = this.restrict64chars(cc.Title + " and " + cReused.description); // that'll do for now
                        }

                        conditionref conditionref = new conditionref();
                        conditionref.id = cReused.id;
                        or.Items.Add(conditionref);

                    }
                    else
                    {

                        Pairing pair = buildXPathRef(row);

                        if (cc.Title.Equals("NONE OF "))
                        {
                            cc.Title = this.restrict64chars(cc.Title + pair.titleText);
                        }
                        else
                        {
                            cc.Title = this.restrict64chars(cc.Title + " or " + pair.titleText);
                        }

                        xpathref xpathref = new xpathref();
                        xpathref.id = pair.xpathEntry.id;

                        or.Items.Add(xpathref);
                    }
                }

                outer.name = this.textBoxName.Text;
                if (string.IsNullOrWhiteSpace(this.textBoxDescription.Text))
                {
                    outer.description = cc.Title;
                }
                else
                {
                    outer.description = this.textBoxDescription.Text;
                }

                cpe.add(outer, null);
                cpe.save();

                setTag(cc, outer);

                return;
            }

            //// Make sure this question is allowed here
            //// ie the it is top level or in a common repeat ancestor.
            //// We do this last, so this cc has od:condition on it,
            //// in which case we can re-use existing code to do the check
            //// TODO: when we support and/or, will need to do this
            //// for each variable.
            //ContentControlNewConditionCheck variableRelocator = new ContentControlNewConditionCheck();
            //variableRelocator.checkAnswerAncestry(xpathExisting.id);
        }
        /// <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);
        }