private static OoAccComponent moveToPrevComponent(OoAccComponent comp)
        {
            if (comp != null && comp.IsValid())
            {
                //--------------------------
                // try to get the parent
                OoAccComponent parent = comp.GetParent();
                if (parent != null)
                {
                    int pIndex  = comp.IndexInParent;
                    int pcCount = parent.ChildCount;
                    int npIndex = mod(pIndex - 1, pcCount);

                    if (pIndex != npIndex)
                    {
                        // get prev sibling
                        var prevSibling = parent.GetChild(npIndex);
                        if (prevSibling != null)
                        {
                            System.Diagnostics.Debug.WriteLine("[MOVE PREV] ---> return prev sibling: " + prevSibling);
                            return(prevSibling);
                        }
                    }
                }
            }

            return(null);
        }
        /// <summary>
        /// Gets the OoShapeObserver for an accessible if already registered.
        /// </summary>
        /// <param name="accComp">The acc comp to get the observer for.</param>
        /// <param name="page">The page observer to search the observer in.</param>
        /// <returns>The related OoShapeObserver if already registered</returns>
        private static OoShapeObserver getObserverForAccessible(OoAccComponent accComp, OoDrawPageObserver page)
        {
            if (accComp != null && accComp.IsValid() && page != null)
            {
                var pObs = page.PagesObserver;
                if (pObs != null)
                {
                    OoShapeObserver sObs = pObs.GetRegisteredShapeObserver(accComp);

                    if (sObs == null)  // shape is not registered
                    {
                        page.Update(); // try to do it better for the next term
                        AudioRenderer.Instance.PlayWaveImmediately(StandardSounds.Error);

                        ////TODO: try to get the parent
                        return(null);
                    }

                    return(sObs);
                }
                else
                {
                    Logger.Instance.Log(LogPriority.DEBUG, "OpenOfficeDrawShapeManipulator", "[ERROR] can't get the pages observer to get a ShapeObserver for the next item");
                }
            }
            return(null);
        }
        /// <summary>
        /// Moves to a child element.
        /// </summary>
        /// <param name="shape">The parent shape to get the child of.</param>
        /// <param name="index">The index of the child to get (infinite loop by modulo child count).</param>
        /// <returns>
        /// The child shape on the screen if possible otherwise the child in the DOM if possible otherwise <c>null</c>
        /// </returns>
        public static OoShapeObserver MoveToChild(OoShapeObserver shape, ref int index)
        {
            if (shape != null && shape.IsValid())
            {
                // move thought the Accessible tree because this elements should be visible on the screen and the tree navigation is faster
                // TODO remove false to use search in accessibility tree again. Currently accessing the page AccessibleShape element during search crashes openoffice!
                if (false && shape.AccComponent != null && shape.AccComponent.IsValid())
                {
                    OoAccComponent comp = shape.AccComponent;

                    while (true)
                    {
                        OoAccComponent child = moveToChildComponent(comp, ref index);

                        if (child != null && child != comp)
                        {
                            if (acceptAsUsableShape(child))
                            {
                                return(getObserverForAccessible(child, shape.Page));
                            }
                            else
                            {
                                child = moveToChildComponent(child, ref index);
                            }
                        }
                        break;
                    }
                }
                else // go through the dom tree
                {
                    return(moveToChildShape(shape, ref index));
                }
            }
            return(null);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="OoDrawPagesObserver"/> class.
        /// </summary>
        /// <param name="dp">The Draw document.</param>
        /// <param name="doc">The document related accessibility component.</param>
        /// <param name="docWnd">The related document accessible window component.</param>
        public OoDrawPagesObserver(XDrawPagesSupplier dp, OoAccComponent doc, OoAccessibleDocWnd docWnd = null)
        {
            this.PagesSupplier = dp;
            Document           = doc;
            DocWnd             = docWnd;

            // get Zoom and ViewOffset first time
            if (Controller != null)
            {
                if (Controller is XPropertySet)
                {
                    refreshDrawViewProperties((XPropertySet)(Controller));
                }
                // try to get dpi settings from openoffice
                XWindow componentWindow = Controller.ComponentWindow;
                if (componentWindow != null && componentWindow is XDevice)
                {
                    DeviceInfo deviceInfo = (DeviceInfo)((XDevice)componentWindow).getInfo();
                    if (deviceInfo != null)
                    {
                        PixelPerMeterX = deviceInfo.PixelPerMeterX;
                        PixelPerMeterY = deviceInfo.PixelPerMeterY;
                    }
                }
            }
            // register for Zoom and ViewOffset updates
            addVisibleAreaPropertyChangeListener();

            if (this.PagesSupplier != null)
            {
                List <XDrawPage> dpL = OoDrawUtils.DrawDocGetXDrawPageList(dp);

                if (PagesSupplier is unoidl.com.sun.star.frame.XTitle)
                {
                    Title = ((unoidl.com.sun.star.frame.XTitle)PagesSupplier).getTitle();
                }

                Logger.Instance.Log(LogPriority.DEBUG, this, "create DrawPagesObserver for supplier " + dp.GetHashCode() + " width title '" + Title + "' - having " + dpL.Count + " pages");

                //FIXME: Do this if the api enable parallel access
                //Parallel.ForEach(dpL, (drawPage) =>
                //{
                //    OoDrawPageObserver dpobs = new OoDrawPageObserver(drawPage, this);
                //    DrawPageobservers[drawPage] = dpobs;
                //    DrawPages.Add(dpobs);
                //});

                foreach (var drawPage in dpL)
                {
                    OoDrawPageObserver dpobs = new OoDrawPageObserver(drawPage, this);
                    RegisterDrawPage(dpobs);
                }

                XModifyBroadcaster mdfBc = PagesSupplier as XModifyBroadcaster;
                if (mdfBc != null)
                {
                    mdfBc.addModifyListener(eventForwarder);
                }
            }
        }
        /// <summary>
        /// Gets the audio text for the given element and send it immediately to the audio renderer.
        /// </summary>
        /// <param name="element">The element to get the text of.</param>
        /// <param name="additionalText">An additional text, that is put behind the element properties and befor the label (if available).</param>
        /// <returns>The describing string of the element in the following form: [ROLE] [NAME] (addintionalText)</returns>
        public static string PlayElementImmediately(OoAccComponent element, string additionalText = "")
        {
            String text = GetElementAudioText(element, additionalText);

            if (!String.IsNullOrWhiteSpace(text))
            {
                audio.PlaySoundImmediately(text);
            }
            return(text);
        }
        /// <summary>
        /// Moves to prev component.
        /// </summary>
        /// <param name="comp">The comp.</param>
        /// <param name="handleChildren">if set to <c>true</c> [handle children].</param>
        /// <returns></returns>
        private static OoAccComponent moveDeterministicToPrevComponent(OoAccComponent comp, bool handleChildren = true)
        {
            if (comp != null)
            {
                //walk through the children and back to the parent
                //check if has children
                if (handleChildren && comp.HasChildren) // should have children --> go deeper
                {
                    //TODO: check if we accept this children - e.g. Text ???

                    // try get the first child
                    OoAccComponent child = comp.GetChild(comp.ChildCount - 1);
                    if (child != null)
                    {
                        System.Diagnostics.Debug.WriteLine("[MOVE PREV] ---> return child: " + child);
                        return(child);
                    }
                }

                // if has no children --> go to prev sibling
                //--------------------------
                // try to get the parent
                OoAccComponent parent = comp.GetParent();
                if (parent != null)
                {
                    int pIndex = comp.IndexInParent;
                    if (pIndex >= 0)
                    {
                        int pcCount = parent.ChildCount;
                        if (pIndex > 0) // is not the first child
                        {
                            // get prev sibling
                            var prevSibling = parent.GetChild(pIndex - 1);
                            if (prevSibling != null)
                            {
                                System.Diagnostics.Debug.WriteLine("[MOVE PREV] ---> return prev sibling: " + prevSibling);
                                return(prevSibling);
                            }
                        }
                        else // is first element --> go higher
                        {
                            return(moveDeterministicToPrevComponent(parent, false));
                        }
                    }
                    else
                    {
                        // ERROR - this happens e.g. when the parent object is invalid
                        AudioRenderer.Instance.PlayWaveImmediately(StandardSounds.Error);
                        Logger.Instance.Log(LogPriority.OFTEN, "AccDomWalker", "[ERROR] Index in parent is negative");
                    }
                }
            }
            return(null);
        }
        private static OoAccComponent moveToChildComponent(OoAccComponent comp, ref int index)
        {
            if (comp != null && comp.IsValid() && comp.HasChildren)
            {
                try
                {
                    int childNumber = comp.ChildCount;
                    index = index % childNumber;

                    return(comp.GetChild(index));
                }
                catch { }
            }

            return(null);
        }
        /// <summary>
        /// Moves to the next element.
        /// </summary>
        /// <param name="shape">The shape to get the next sibling.</param>
        /// <returns>
        /// The next shape on the screen if possible otherwise the next in the DOM if possible otherwise <c>null</c>
        /// </returns>
        public static OoShapeObserver MoveToNext(OoShapeObserver shape)
        {
            if (shape != null && shape.IsValid())
            {
                // move thought the Accessible tree because this elements should be visible on the screen and the tree navigation is faster
                // TODO remove false to use search in accessibility tree again. Currently accessing the page AccessibleShape element during search crashes openoffice!
                if (false && shape.AccComponent != null && shape.AccComponent.IsValid())
                {
                    OoAccComponent comp = shape.AccComponent;

                    while (true)
                    {
                        OoAccComponent next = moveToNextComponent(comp);

                        if (next != null && next != comp && next.IsValid())
                        {
                            if (acceptAsUsableShape(next))
                            {
                                OoShapeObserver obs = getObserverForAccessible(next, shape.Page);
                                if (obs != null)
                                {
                                    return(obs);
                                }
                                else
                                {
                                    break;
                                }
                            }
                            else
                            {
                                comp = next;
                                continue;
                            }
                        }
                        break;
                    }
                }

                // go through the dom tree
                {
                    return(moveToNextShape(shape));
                }
            }

            return(null);
        }
        private static OoAccComponent moveToParentComponent(OoAccComponent comp)
        {
            if (comp != null && comp.IsValid())
            {
                try
                {
                    OoAccComponent parent = comp.GetParent();
                    if (parent != null && acceptAsUsableShape(parent))
                    {
                        return(parent);
                    }
                }
                catch { }
            }

            return(null);
        }
        /// <summary>
        /// Gets the audio text for the given element.
        /// </summary>
        /// <param name="element">The element to get the text of.</param>
        /// <param name="additionalText">An additional text, that is put behind the element properties</param>
        /// <returns>A string that should describe the element in the following form: [ROLE] [NAME] (addintionalText)</returns>
        public static String GetElementAudioText(OoAccComponent element, string additionalText = "")
        {
            String result = String.Empty;

            try
            {
                if (element != null)
                {
                    result += LL.GetTrans("tangram.oomanipulation.element_speaker.audio.element", element.Role.ToString(), element.Name.ToString(), additionalText.ToString());
                }
            }
            catch (System.Exception ex)
            {
                Logger.Instance.Log(LogPriority.DEBUG, "OoElementSpeaker", "[ERROR] Can't play element: " + ex);
            }

            return(result);
        }
        /// <summary>
        /// Try to figure out if the accessible element is usable as interactive Shape
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        private static bool acceptAsUsableShape(OoAccComponent element)
        {
            if (element != null && element != null)
            {
                // check if the child is the paragraph
                if (element.ServiceNames.Contains(tud.mci.tangram.util.OO.Services.TEXT_ACCESSIBLE_PARAGRAPH))
                {
                    return(false);
                }
                else
                {
                    if (element.Name.StartsWith("PageShape: "))
                    {
                        //TODO: decide if is a proper result
                        return(false);
                    }
                }
            }

            return(element != null);
        }
        /// <summary>
        /// Gets the shape observer for modification.
        /// </summary>
        /// <param name="c">The component to get the corresponding observer to.</param>
        /// <param name="observed">The observed window / draw document.</param>
        /// <param name="silent">if set to <c>true</c> no audio feedback about the selection is given.</param>
        /// <param name="immediatly">if set to <c>true</c> the audio feedback is immediately given and all other audio feedback is aborted.</param>
        /// <returns>The corresponding observer to the shape in the given Draw document.</returns>
        public OoShapeObserver GetShapeForModification(OoAccComponent c, OoAccessibleDocWnd observed, bool silent = true, bool immediately = true)
        {
            if (observed != null && c.Role != AccessibleRole.INVALID)
            {
                //TODO: prepare name:

                OoShapeObserver shape = observed.GetRegisteredShapeObserver(c);
                if (shape != null)
                {
                    return(GetShapeForModification(shape, observed, silent, immediately));

                    //if (shapeManipulatorFunctionProxy != null && !ImageData.Instance.Active)
                    //{
                    //    OoElementSpeaker.PlayElementImmediately(shape, LL.GetTrans("tangram.lector.oo_observer.selected", String.Empty));
                    //    //audioRenderer.PlaySound("Form kann manipuliert werden");
                    //    shapeManipulatorFunctionProxy.LastSelectedShape = shape;
                    //    return shape;
                    //}
                    //else // title+desc dialog handling
                    //{
                    //    ImageData.Instance.NewSelectionHandling(shape);
                    //}
                }
                else
                {
                    // disable the pageShapes
                    if (c.Name.StartsWith("PageShape:"))
                    {
                        return(null);
                    }

                    OoElementSpeaker.PlayElementImmediately(c, LL.GetTrans("tangram.lector.oo_observer.selected"));
                    audioRenderer.PlaySound(LL.GetTrans("tangram.lector.oo_observer.selected_element.locked"));
                }
            }
            return(null);
        }
 /// <summary>
 /// Gets the registered shape observer.
 /// </summary>
 /// <param name="comp">The comp.</param>
 /// <returns></returns>
 public OoShapeObserver GetRegisteredShapeObserver(OoAccComponent comp)
 {
     return(GetRegisteredShapeObserver(comp.AccCont));
 }