/// <summary>
        // RULE: A variable cc can copied wherever.
        // If its repeat ancestors change, its "vary in repeat"
        // will need to change (to lowest common denominator).
        // If this cc is not in any repeat,
        // make the answer top level and we're done
        // Otherwise, could assume its position is OK wrt
        // existing repeats.
        // So if anything, we just need to move it
        // up the tree until
        // we reach a node which contains this additional repeat.
        // But we'd like this code to
        // be used for both moves and copy. (Move case
        // needs this constraint relaxed)
        // So our algorithm finds viable positions
        // (ie ancestors common to all
        // repeats).
        // That node and higher are candidates for new position
        // Ask user to choose.
        /// </summary>
        protected void handleXPath(string xpathID, bool dontAskIfOkAsis)
        {
            xpathsXpath xp = xppe.getXPathByID(xpathID);

            string questionID = xp.questionID;

            // If this cc is not in any repeat,
            // make the answer top level and we're done

            // Otherwise, we can assume its position is OK wrt
            // existing repeats.

            // So if anything, we just need to move it
            // up the tree until
            // we reach a node which contains this additional repeat.

            // But for the variable move case (handled in MoveHandler)
            // an existing repeat will no longer be a constraint.
            // So better to just have a single algorithm which
            // finds viable positions (ie ancestors common to all
            // repeats).

            // 2 algorithms for doing this.
            // The first:  Make a list of the ancestors of the
            // first repeat.  Then cross off that list anything
            // which isn't an ancestor of the other repeats.

            // The second: Get XPath for each repeat.
            // Find the shortest XPath.
            // Then find the shortest substring common to each
            // repeat. Then make a list out of that.

            // I like the first better.

            // Find all cc's in which this question is used.
            QuestionHelper qh = new QuestionHelper(xppe, cpe);
            List<Word.ContentControl> thisQuestionControls = qh.getControlsUsingQuestion(questionID, xpathID);

            // For each such cc, find closest repeat ancestor cc (if any).
            // With each such repeat, do the above algorithm.

            // Find all cc's in which this question is used.
            List<Word.ContentControl> relevantRepeats = new List<Word.ContentControl>();
            foreach (Word.ContentControl ccx in thisQuestionControls)
            {
                Word.ContentControl rpt = RepeatHelper.getYoungestRepeatAncestor(ccx);
                if (rpt == null)
                {
                    // make the answer top level and we're done.
                    // That means moving it in AF, and XPaths part.
                    log.Info("question " + questionID + " used at top level, so moving it there.");
                    NodeMover nm = new NodeMover();
                    nm.Move(xp.dataBinding.xpath, "/oda:answers");
                    nm.adjustBinding(thisQuestionControls, "/oda:answers", questionID);
                    return;

                }
                else
                {
                    relevantRepeats.Add(rpt);
                }
            }

            Office.CustomXMLPart answersPart = model.answersPart; // userParts[0]; // TODO: make this better

            // That node and higher are candidates for new position
            // Ask user to choose, or cancel (and remove this cc,
            // but what about any impending child add events??  Maybe
            // need a cancel state)

            this.questionsPart = model.questionsPart;
            questionnaire = new questionnaire();
            questionnaire.Deserialize(questionsPart.XML, out questionnaire);

            FormMoveQuestion formMoveQuestion = new FormMoveQuestion(answersPart, relevantRepeats, questionnaire, questionID, xppe);
            if (dontAskIfOkAsis
                && formMoveQuestion.OkAsis() )
            {
                // Do nothing
            }
            else
            {
                formMoveQuestion.ShowDialog();
                formMoveQuestion.moveIfNecessary(questionID, xp, answersPart);

                //string varyInRepeat = formMoveQuestion.getVaryingRepeat();
                //if (varyInRepeat == null)
                //{
                //    // make the answer top level and we're done.
                //    NodeMover nm = new NodeMover();
                //    nm.Move(xp.dataBinding.xpath, "/oda:answers");
                //    nm.adjustBinding(thisQuestionControls, "/oda:answers", questionID);
                //}
                //else
                //{
                //    // Move it to the selected repeat
                //    // get the node corresponding to the repeat's row
                //    Office.CustomXMLNode node = answersPart.SelectSingleNode("//oda:repeat[@qref='" + varyInRepeat + "']/oda:row[1]");
                //    if (node == null)
                //    {
                //        log.Error("no node for nested repeat " + varyInRepeat);
                //    }
                //    string toRepeat = NodeToXPath.getXPath(node);
                //    NodeMover nm = new NodeMover();
                //    nm.Move(xp.dataBinding.xpath, toRepeat);
                //    nm.adjustBinding(thisQuestionControls, toRepeat, questionID);

                //}
            }
            formMoveQuestion.Dispose();
        }
        public void init(
            Office.CustomXMLPart answersPart,
            questionnaire questionnaire,
            question q,
            XPathsPartEntry xppe,
            ConditionsPartEntry cpe)
        {
            QuestionHelper qh = new QuestionHelper(xppe, cpe);
            thisQuestionControls = qh.getControlsUsingQuestion(q);

            List<Word.ContentControl> relevantRepeats = new List<Word.ContentControl>();
            foreach (Word.ContentControl ccx in thisQuestionControls)
            {
                Word.ContentControl rpt = RepeatHelper.getYoungestRepeatAncestor(ccx);
                if (rpt == null)
                {
                    // will have to make the answer top level and we're done.
                    break;
                }
                else
                {
                    relevantRepeats.Add(rpt);
                }
            }

            init(
                answersPart,
                relevantRepeats,
                 questionnaire,
                 q.id,
                 xppe);
        }