1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <controller/SlsFocusManager.hxx>
21 
22 #include <SlideSorter.hxx>
23 #include <controller/SlideSorterController.hxx>
24 #include <controller/SlsCurrentSlideManager.hxx>
25 #include <controller/SlsVisibleAreaManager.hxx>
26 #include <model/SlideSorterModel.hxx>
27 #include <model/SlsPageDescriptor.hxx>
28 #include <view/SlideSorterView.hxx>
29 #include <view/SlsLayouter.hxx>
30 #include <osl/diagnose.h>
31 
32 #include <Window.hxx>
33 #include <sdpage.hxx>
34 
35 namespace sd::slidesorter::controller {
36 
FocusManager(SlideSorter & rSlideSorter)37 FocusManager::FocusManager (SlideSorter& rSlideSorter)
38     : mrSlideSorter(rSlideSorter),
39       mnPageIndex(0),
40       mbPageIsFocused(false)
41 {
42     if (mrSlideSorter.GetModel().GetPageCount() > 0)
43         mnPageIndex = 0;
44 }
45 
~FocusManager()46 FocusManager::~FocusManager()
47 {
48 }
49 
MoveFocus(FocusMoveDirection eDirection)50 void FocusManager::MoveFocus (FocusMoveDirection eDirection)
51 {
52     if (!(mnPageIndex >= 0 && mbPageIsFocused))
53         return;
54 
55     HideFocusIndicator (GetFocusedPageDescriptor());
56 
57     const sal_Int32 nColumnCount (mrSlideSorter.GetView().GetLayouter().GetColumnCount());
58     const sal_Int32 nPageCount (mrSlideSorter.GetModel().GetPageCount());
59     switch (eDirection)
60     {
61         case FocusMoveDirection::Left:
62             if (mnPageIndex > 0)
63                 mnPageIndex -= 1;
64             break;
65 
66         case FocusMoveDirection::Right:
67             if (mnPageIndex < nPageCount-1)
68                 mnPageIndex += 1;
69             break;
70 
71         case FocusMoveDirection::Up:
72         {
73             const sal_Int32 nCandidate (mnPageIndex - nColumnCount);
74             if (nCandidate >= 0)
75             {
76                 // Move the focus the previous row.
77                 mnPageIndex = nCandidate;
78             }
79         }
80         break;
81 
82         case FocusMoveDirection::Down:
83         {
84             const sal_Int32 nCandidate (mnPageIndex + nColumnCount);
85             if (nCandidate < nPageCount)
86             {
87                 // Move the focus to the next row.
88                 mnPageIndex = nCandidate;
89             }
90         }
91         break;
92     }
93 
94     if (mnPageIndex < 0)
95     {
96         OSL_ASSERT(mnPageIndex>=0);
97         mnPageIndex = 0;
98     }
99     else if (mnPageIndex >= nPageCount)
100     {
101         OSL_ASSERT(mnPageIndex<nPageCount);
102         mnPageIndex = nPageCount - 1;
103     }
104 
105     if (mbPageIsFocused)
106     {
107         ShowFocusIndicator(GetFocusedPageDescriptor(), true);
108     }
109 }
110 
ShowFocus(const bool bScrollToFocus)111 void FocusManager::ShowFocus (const bool bScrollToFocus)
112 {
113     mbPageIsFocused = true;
114     ShowFocusIndicator(GetFocusedPageDescriptor(), bScrollToFocus);
115 }
116 
HideFocus()117 void FocusManager::HideFocus()
118 {
119     mbPageIsFocused = false;
120     HideFocusIndicator(GetFocusedPageDescriptor());
121 }
122 
ToggleFocus()123 bool FocusManager::ToggleFocus()
124 {
125     if (mnPageIndex >= 0)
126     {
127         if (mbPageIsFocused)
128             HideFocus ();
129         else
130             ShowFocus ();
131     }
132     return mbPageIsFocused;
133 }
134 
HasFocus() const135 bool FocusManager::HasFocus() const
136 {
137     return mrSlideSorter.GetContentWindow()->HasFocus();
138 }
139 
GetFocusedPageDescriptor() const140 model::SharedPageDescriptor FocusManager::GetFocusedPageDescriptor() const
141 {
142     return mrSlideSorter.GetModel().GetPageDescriptor(mnPageIndex);
143 }
144 
SetFocusedPage(const model::SharedPageDescriptor & rpDescriptor)145 bool FocusManager::SetFocusedPage (const model::SharedPageDescriptor& rpDescriptor)
146 {
147     if (rpDescriptor)
148     {
149         FocusHider aFocusHider (*this);
150         mnPageIndex = (rpDescriptor->GetPage()->GetPageNum()-1)/2;
151         return true;
152     }
153     return false;
154 }
155 
SetFocusedPage(sal_Int32 nPageIndex)156 void FocusManager::SetFocusedPage (sal_Int32 nPageIndex)
157 {
158     FocusHider aFocusHider (*this);
159     mnPageIndex = nPageIndex;
160 }
161 
SetFocusedPageToCurrentPage()162 bool FocusManager::SetFocusedPageToCurrentPage()
163 {
164     return SetFocusedPage(mrSlideSorter.GetController().GetCurrentSlideManager()->GetCurrentSlide());
165 }
166 
IsFocusShowing() const167 bool FocusManager::IsFocusShowing() const
168 {
169     return HasFocus() && mbPageIsFocused;
170 }
171 
HideFocusIndicator(const model::SharedPageDescriptor & rpDescriptor)172 void FocusManager::HideFocusIndicator (const model::SharedPageDescriptor& rpDescriptor)
173 {
174     if (rpDescriptor)
175     {
176         mrSlideSorter.GetView().SetState(rpDescriptor, model::PageDescriptor::ST_Focused, false);
177 
178         // Hide focus should also fire the focus event, Currently, only accessibility add the focus listener
179         NotifyFocusChangeListeners();
180     }
181 }
182 
ShowFocusIndicator(const model::SharedPageDescriptor & rpDescriptor,const bool bScrollToFocus)183 void FocusManager::ShowFocusIndicator (
184     const model::SharedPageDescriptor& rpDescriptor,
185     const bool bScrollToFocus)
186 {
187     if (!rpDescriptor)
188         return;
189 
190     mrSlideSorter.GetView().SetState(rpDescriptor, model::PageDescriptor::ST_Focused, true);
191 
192     if (bScrollToFocus)
193     {
194         // Scroll the focused page object into the visible area and repaint
195         // it, so that the focus indicator becomes visible.
196         mrSlideSorter.GetController().GetVisibleAreaManager().RequestVisible(rpDescriptor,true);
197     }
198     mrSlideSorter.GetView().RequestRepaint(rpDescriptor);
199 
200     NotifyFocusChangeListeners();
201 }
202 
AddFocusChangeListener(const Link<LinkParamNone *,void> & rListener)203 void FocusManager::AddFocusChangeListener (const Link<LinkParamNone*,void>& rListener)
204 {
205     if (::std::find (maFocusChangeListeners.begin(), maFocusChangeListeners.end(), rListener)
206         == maFocusChangeListeners.end())
207     {
208         maFocusChangeListeners.push_back (rListener);
209     }
210 }
211 
RemoveFocusChangeListener(const Link<LinkParamNone *,void> & rListener)212 void FocusManager::RemoveFocusChangeListener (const Link<LinkParamNone*,void>& rListener)
213 {
214     maFocusChangeListeners.erase (
215         ::std::find (maFocusChangeListeners.begin(), maFocusChangeListeners.end(), rListener));
216 }
217 
NotifyFocusChangeListeners() const218 void FocusManager::NotifyFocusChangeListeners() const
219 {
220     // Create a copy of the listener list to be safe when that is modified.
221     ::std::vector<Link<LinkParamNone*,void>> aListeners (maFocusChangeListeners);
222 
223     // Tell the selection change listeners that the selection has changed.
224     for (const auto& rListener : aListeners)
225     {
226         rListener.Call(nullptr);
227     }
228 }
229 
FocusHider(FocusManager & rManager)230 FocusManager::FocusHider::FocusHider (FocusManager& rManager)
231 : mbFocusVisible(rManager.IsFocusShowing())
232 , mrManager(rManager)
233 {
234     mrManager.HideFocus();
235 }
236 
~FocusHider()237 FocusManager::FocusHider::~FocusHider() COVERITY_NOEXCEPT_FALSE
238 {
239     if (mbFocusVisible)
240         mrManager.ShowFocus();
241 }
242 
243 } // end of namespace ::sd::slidesorter::controller
244 
245 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
246