sd/source/console/PresenterAccessibility.cxx |    1 
 sd/source/console/PresenterSlideSorter.cxx   |   16 +++++
 sd/source/console/PresenterSlideSorter.hxx   |    1 
 sd/source/console/PresenterToolBar.cxx       |   78 +++++++++++----------------
 sd/source/console/PresenterToolBar.hxx       |    3 -
 5 files changed, 53 insertions(+), 46 deletions(-)

New commits:
commit 7b37a38960afe0d990c508d6a3fa51a0bec04776
Author:     Michael Weghorn <m.wegh...@posteo.de>
AuthorDate: Thu May 15 14:23:06 2025 +0200
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Thu May 15 22:23:30 2025 +0200

    sd presenter a11y: Set preview's parent
    
    The `mpAccessibleConsole` is the XAccessibleContext
    for the PresenterAccessible, i.e. the PresenterAccessible
    object is the XAccessible object for its `mpAccessibleConsole`.
    
    PresenterAccessible::UpdateAccessibilityHierarchy sets
    the `mpAccessiblePreview` as a child of `mpAccessibleConsole`.
    Therefore, the PresenterAccessible is the parent XAccessible
    for the preview. Set it accordingly.
    
    This fixes an inconsistency in the a11y hierarchy that
    could be seen as follows with the qt6 VCL plugin:
    
    * start an Impress presentation with Presenter Console activated
    * start Accerciser
    * navigate to the "Presenter Console" object in Accerciser's
      tree view of LO a11y.
    * in Accerciser's IPython console:
    
        In [30]: acc.get_child_at_index(0).get_parent() == acc
        Out[30]: False
    
    This means the Presenter Console's a11y child at index 0 (which
    is the current slide preview) doesn't report it's actual
    parent as its parent.
    
    With this commit in place, this behaves as expected now:
    
        In [1]: acc.get_child_at_index(0).get_parent() == acc
        Out[1]: True
    
    Change-Id: Id41da5139214437de44d6b1cf29ad8de1d9d13be
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185364
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>
    Tested-by: Jenkins

diff --git a/sd/source/console/PresenterAccessibility.cxx 
b/sd/source/console/PresenterAccessibility.cxx
index 39af66d3324f..4adc3be02560 100644
--- a/sd/source/console/PresenterAccessibility.cxx
+++ b/sd/source/console/PresenterAccessibility.cxx
@@ -190,6 +190,7 @@ void PresenterAccessible::UpdateAccessibilityHierarchy (
                 mxPreviewBorderWindow);
             mpAccessibleConsole->AddChild(mpAccessiblePreview);
             mpAccessiblePreview->SetAccessibleName(rsTitle);
+            mpAccessiblePreview->SetAccessibleParent(this);
         }
     }
 
commit 03dfd09f7e3d009b6f5a0dc32f403352935ccd48
Author:     Michael Weghorn <m.wegh...@posteo.de>
AuthorDate: Thu May 15 11:27:05 2025 +0200
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Thu May 15 22:23:24 2025 +0200

    tdf#76029 sd console: Scroll to new slide as needed
    
    When switching to a new slide in Impress, make sure that
    this new slide is fully visible in the Presenter Console
    "Slides" mode automatically, by scrolling to adjust the
    visible area as needed.
    (Make the slide's row the topmost one that's visible.)
    
    This removes the need for the user to manually scroll
    using the scroll bar after switching slides.
    
    Change-Id: I7d2a245e6f4b705a8a2492ccb02bbef490adbe88
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185358
    Tested-by: Jenkins
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>

diff --git a/sd/source/console/PresenterSlideSorter.cxx 
b/sd/source/console/PresenterSlideSorter.cxx
index 77c5d3cf2786..077a2d3f3b52 100644
--- a/sd/source/console/PresenterSlideSorter.cxx
+++ b/sd/source/console/PresenterSlideSorter.cxx
@@ -599,6 +599,8 @@ void SAL_CALL PresenterSlideSorter::setCurrentPage (const 
Reference<drawing::XDr
     mpPresenterController->GetPaintManager()->Invalidate(
         mxWindow,
         maCurrentSlideFrameBoundingBox);
+
+    ScrollSlideIntoView(mnCurrentSlideIndex);
 }
 
 Reference<drawing::XDrawPage> SAL_CALL PresenterSlideSorter::getCurrentPage()
@@ -1014,6 +1016,20 @@ void PresenterSlideSorter::GotoSlide (const sal_Int32 
nSlideIndex)
     mxSlideShowController->gotoSlideIndex(nSlideIndex);
 }
 
+void PresenterSlideSorter::ScrollSlideIntoView(sal_Int32 nSlideIndex)
+{
+    const double fThumbPos = mpVerticalScrollBar->GetThumbPosition();
+    const double fThumbSize = mpVerticalScrollBar->GetThumbSize();
+    const double fSlidePos = mpLayout->GetPoint(nSlideIndex, -1, -1).Y;
+
+    const bool bFullyVisible
+        = (fSlidePos - mpLayout->mnVerticalBorder >= fThumbPos)
+          && (fSlidePos + mpLayout->maPreviewSize.Height + 
mpLayout->mnVerticalBorder
+              <= fThumbPos + fThumbSize);
+    if (!bFullyVisible)
+        mpVerticalScrollBar->SetThumbPosition(fSlidePos - 
mpLayout->mnVerticalBorder, false);
+}
+
 bool PresenterSlideSorter::ProvideCanvas()
 {
     if ( ! mxCanvas.is())
diff --git a/sd/source/console/PresenterSlideSorter.hxx 
b/sd/source/console/PresenterSlideSorter.hxx
index f1056fbeba6b..ef047a41bdc8 100644
--- a/sd/source/console/PresenterSlideSorter.hxx
+++ b/sd/source/console/PresenterSlideSorter.hxx
@@ -174,6 +174,7 @@ private:
     void SetHorizontalOffset (const double nXOffset);
     void SetVerticalOffset (const double nYOffset);
     void GotoSlide (const sal_Int32 nSlideIndex);
+    void ScrollSlideIntoView(sal_Int32 nSlideIndex);
     bool ProvideCanvas();
 
     /** @throws css::lang::DisposedException when the object has already been
commit f63690411df62f373d04d6b78bb93956f5532abf
Author:     Michael Weghorn <m.wegh...@posteo.de>
AuthorDate: Thu May 15 09:27:22 2025 +0200
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Thu May 15 22:23:16 2025 +0200

    sd console: Don't subclass std::vector
    
    ... without adding any additional functionality.
    Instead, make PresenterToolBar::ElementContainerPart
    an alias for std::vector<rtl::Reference<Element>>.
    
    Forward-declare Element and make it an inner class
    of PresenterToolBar, which also fits with the existing
    
        //===== PresenterToolBar::Element 
=============================================
    
    comments.
    
    Change-Id: I49c2ef88fb4e4280c4cc21b02ce8a20253947933
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185357
    Tested-by: Jenkins
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>

diff --git a/sd/source/console/PresenterToolBar.cxx 
b/sd/source/console/PresenterToolBar.cxx
index 10291eead413..77030d2254dc 100644
--- a/sd/source/console/PresenterToolBar.cxx
+++ b/sd/source/console/PresenterToolBar.cxx
@@ -109,14 +109,12 @@ public:
 
 //===== PresenterToolBar::Element =============================================
 
-namespace {
-
 typedef cppu::WeakComponentImplHelper<
     css::document::XEventListener,
     css::frame::XStatusListener
     > ElementInterfaceBase;
 
-class Element
+class PresenterToolBar::Element
     : private ::cppu::BaseMutex,
       public ElementInterfaceBase
 {
@@ -182,18 +180,11 @@ private:
     bool mbIsEnabled;
 };
 
-} // end of anonymous namespace
-
-class PresenterToolBar::ElementContainerPart
-    : public ::std::vector<rtl::Reference<Element> >
-{
-};
-
 //===== Button ================================================================
 
 namespace {
 
-class Button : public Element
+class Button : public PresenterToolBar::Element
 {
 public:
     static ::rtl::Reference<Element> Create (
@@ -227,7 +218,7 @@ private:
 
 //===== Label =================================================================
 
-class Label : public Element
+class Label : public PresenterToolBar::Element
 {
 public:
     explicit Label (const ::rtl::Reference<PresenterToolBar>& rpToolBar);
@@ -258,7 +249,7 @@ public:
     virtual void TimeHasChanged (const oslDateTime& rCurrentTime) = 0;
 protected:
     explicit TimeLabel(const ::rtl::Reference<PresenterToolBar>& rpToolBar);
-    using Element::disposing;
+    using PresenterToolBar::Element::disposing;
     virtual void SAL_CALL disposing() override;
 private:
     class Listener : public PresenterClockTimer::Listener
@@ -317,7 +308,7 @@ private:
     virtual void TimeHasChanged (const oslDateTime& rCurrentTime) override;
 };
 
-class VerticalSeparator : public Element
+class VerticalSeparator : public PresenterToolBar::Element
 {
 public:
     explicit VerticalSeparator (const ::rtl::Reference<PresenterToolBar>& 
rpToolBar);
@@ -331,7 +322,7 @@ protected:
         const Reference<rendering::XCanvas>& rxCanvas) override;
 };
 
-class HorizontalSeparator : public Element
+class HorizontalSeparator : public PresenterToolBar::Element
 {
 public:
     explicit HorizontalSeparator (const ::rtl::Reference<PresenterToolBar>& 
rpToolBar);
@@ -412,7 +403,7 @@ void SAL_CALL PresenterToolBar::disposing()
         mxWindow = nullptr;
     }
 
-    // Dispose tool bar elements.
+    // Dispose tool bar PresenterToolBar::Elements.
     for (const auto& rxPart : maElementContainer)
     {
         OSL_ASSERT(rxPart != nullptr);
@@ -1115,9 +1106,7 @@ Reference<drawing::XDrawPage> SAL_CALL 
PresenterToolBarView::getCurrentPage()
 
 //===== PresenterToolBar::Element =============================================
 
-namespace {
-
-Element::Element (
+PresenterToolBar::Element::Element (
     ::rtl::Reference<PresenterToolBar> pToolBar)
     : ElementInterfaceBase(m_aMutex),
       mpToolBar(std::move(pToolBar)),
@@ -1133,7 +1122,7 @@ Element::Element (
     }
 }
 
-void Element::SetModes (
+void PresenterToolBar::Element::SetModes (
     const SharedElementMode& rpNormalMode,
     const SharedElementMode& rpMouseOverMode,
     const SharedElementMode& rpSelectedMode,
@@ -1148,38 +1137,38 @@ void Element::SetModes (
     mpMode = rpNormalMode;
 }
 
-void Element::disposing()
+void PresenterToolBar::Element::disposing()
 {
 }
 
-awt::Size const & Element::GetBoundingSize (
+awt::Size const & PresenterToolBar::Element::GetBoundingSize (
     const Reference<rendering::XCanvas>& rxCanvas)
 {
     maSize = CreateBoundingSize(rxCanvas);
     return maSize;
 }
 
-awt::Rectangle Element::GetBoundingBox() const
+awt::Rectangle PresenterToolBar::Element::GetBoundingBox() const
 {
     return awt::Rectangle(maLocation.X,maLocation.Y, maSize.Width, 
maSize.Height);
 }
 
-void Element::CurrentSlideHasChanged()
+void PresenterToolBar::Element::CurrentSlideHasChanged()
 {
     UpdateState();
 }
 
-void Element::SetLocation (const awt::Point& rLocation)
+void PresenterToolBar::Element::SetLocation (const awt::Point& rLocation)
 {
     maLocation = rLocation;
 }
 
-void Element::SetSize (const geometry::RealSize2D& rSize)
+void PresenterToolBar::Element::SetSize (const geometry::RealSize2D& rSize)
 {
     maSize = awt::Size(sal_Int32(0.5+rSize.Width), 
sal_Int32(0.5+rSize.Height));
 }
 
-bool Element::SetState (
+bool PresenterToolBar::Element::SetState (
     const bool bIsOver,
     const bool bIsPressed)
 {
@@ -1232,13 +1221,13 @@ bool Element::SetState (
     return bModified;
 }
 
-void Element::Invalidate (const bool bSynchronous)
+void PresenterToolBar::Element::Invalidate (const bool bSynchronous)
 {
     OSL_ASSERT(mpToolBar.is());
     mpToolBar->InvalidateArea(GetBoundingBox(), bSynchronous);
 }
 
-bool Element::IsOutside (const awt::Rectangle& rBox)
+bool PresenterToolBar::Element::IsOutside (const awt::Rectangle& rBox)
 {
     if (rBox.X >= maLocation.X+maSize.Width)
         return true;
@@ -1253,12 +1242,12 @@ bool Element::IsOutside (const awt::Rectangle& rBox)
 }
 
 
-bool Element::IsFilling() const
+bool PresenterToolBar::Element::IsFilling() const
 {
     return false;
 }
 
-void Element::UpdateState()
+void PresenterToolBar::Element::UpdateState()
 {
     OSL_ASSERT(mpToolBar);
     OSL_ASSERT(mpToolBar->GetPresenterController());
@@ -1277,18 +1266,18 @@ void Element::UpdateState()
 
 //----- lang::XEventListener --------------------------------------------------
 
-void SAL_CALL Element::disposing (const css::lang::EventObject&) {}
+void SAL_CALL PresenterToolBar::Element::disposing (const 
css::lang::EventObject&) {}
 
 //----- document::XEventListener ----------------------------------------------
 
-void SAL_CALL Element::notifyEvent (const css::document::EventObject&)
+void SAL_CALL PresenterToolBar::Element::notifyEvent (const 
css::document::EventObject&)
 {
     UpdateState();
 }
 
 //----- frame::XStatusListener ------------------------------------------------
 
-void SAL_CALL Element::statusChanged (const css::frame::FeatureStateEvent& 
rEvent)
+void SAL_CALL PresenterToolBar::Element::statusChanged (const 
css::frame::FeatureStateEvent& rEvent)
 {
     bool bIsSelected (mbIsSelected);
     bool bIsEnabled (rEvent.IsEnabled);
@@ -1303,7 +1292,6 @@ void SAL_CALL Element::statusChanged (const 
css::frame::FeatureStateEvent& rEven
     }
 }
 
-} // end of anonymous namespace
 
 //===== ElementMode ===========================================================
 
@@ -1371,7 +1359,7 @@ void ElementMode::ReadElementMode (
 
 namespace {
 
-::rtl::Reference<Element> Button::Create (
+::rtl::Reference<PresenterToolBar::Element> Button::Create (
     const ::rtl::Reference<PresenterToolBar>& rpToolBar)
 {
     ::rtl::Reference<Button> pElement (new Button(rpToolBar));
@@ -1381,7 +1369,7 @@ namespace {
 
 Button::Button (
     const ::rtl::Reference<PresenterToolBar>& rpToolBar)
-    : Element(rpToolBar),
+    : PresenterToolBar::Element(rpToolBar),
       mbIsListenerRegistered(false)
 {
     OSL_ASSERT(mpToolBar);
@@ -1406,7 +1394,7 @@ void Button::disposing()
         mbIsListenerRegistered = false;
         
mpToolBar->GetPresenterController()->GetWindowManager()->RemoveLayoutListener(this);
     }
-    Element::disposing();
+    PresenterToolBar::Element::disposing();
 }
 
 void Button::Paint (
@@ -1527,7 +1515,7 @@ PresenterBitmapDescriptor::Mode Button::GetMode() const
 void SAL_CALL Button::disposing (const css::lang::EventObject& rEvent)
 {
     mbIsListenerRegistered = false;
-    Element::disposing(rEvent);
+    PresenterToolBar::Element::disposing(rEvent);
 }
 
 } // end of anonymous namespace
@@ -1537,7 +1525,7 @@ void SAL_CALL Button::disposing (const 
css::lang::EventObject& rEvent)
 namespace {
 
 Label::Label (const ::rtl::Reference<PresenterToolBar>& rpToolBar)
-    : Element(rpToolBar)
+    : PresenterToolBar::Element(rpToolBar)
 {
 }
 
@@ -1585,7 +1573,7 @@ void Label::Paint (
 bool Label::SetState (const bool, const bool)
 {
     // For labels there is no mouse over effect.
-    return Element::SetState(false, false);
+    return PresenterToolBar::Element::SetState(false, false);
 }
 
 } // end of anonymous namespace
@@ -1730,7 +1718,7 @@ void TimeLabel::ConnectToTimer()
 
 //===== CurrentTimeLabel ======================================================
 
-::rtl::Reference<Element> CurrentTimeLabel::Create (
+::rtl::Reference<PresenterToolBar::Element> CurrentTimeLabel::Create (
     const ::rtl::Reference<PresenterToolBar>& rpToolBar)
 {
     ::rtl::Reference<TimeLabel> pElement(new CurrentTimeLabel(rpToolBar));
@@ -1767,7 +1755,7 @@ void CurrentTimeLabel::SetModes (
 
 //===== PresentationTimeLabel =================================================
 
-::rtl::Reference<Element> PresentationTimeLabel::Create (
+::rtl::Reference<PresenterToolBar::Element> PresentationTimeLabel::Create (
     const ::rtl::Reference<PresenterToolBar>& rpToolBar)
 {
     ::rtl::Reference<TimeLabel> pElement(new PresentationTimeLabel(rpToolBar));
@@ -1910,7 +1898,7 @@ void PresentationTimeLabel::SetModes (
 
 VerticalSeparator::VerticalSeparator (
     const ::rtl::Reference<PresenterToolBar>& rpToolBar)
-    : Element(rpToolBar)
+    : PresenterToolBar::Element(rpToolBar)
 {
 }
 
@@ -1959,7 +1947,7 @@ bool VerticalSeparator::IsFilling() const
 
 HorizontalSeparator::HorizontalSeparator (
     const ::rtl::Reference<PresenterToolBar>& rpToolBar)
-    : Element(rpToolBar)
+    : PresenterToolBar::Element(rpToolBar)
 {
 }
 
diff --git a/sd/source/console/PresenterToolBar.hxx 
b/sd/source/console/PresenterToolBar.hxx
index f95884ee9adc..9cf00e589f63 100644
--- a/sd/source/console/PresenterToolBar.hxx
+++ b/sd/source/console/PresenterToolBar.hxx
@@ -135,11 +135,12 @@ public:
     virtual css::uno::Reference<css::drawing::XDrawPage> SAL_CALL 
getCurrentPage() override;
 
     class Context;
+    class Element;
 
 private:
     css::uno::Reference<css::uno::XComponentContext> mxComponentContext;
 
-    class ElementContainerPart;
+    using ElementContainerPart = std::vector<rtl::Reference<Element>>;
     typedef std::shared_ptr<ElementContainerPart> SharedElementContainerPart;
     typedef ::std::vector<SharedElementContainerPart> ElementContainer;
     ElementContainer maElementContainer;

Reply via email to