Skip to content

Instantly share code, notes, and snippets.

@mcecchetti
Last active August 29, 2015 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mcecchetti/15b3ebc505d6582ea0db to your computer and use it in GitHub Desktop.
Save mcecchetti/15b3ebc505d6582ea0db to your computer and use it in GitHub Desktop.
LibreOffice - Collabora Log Book
## Fixing Bug [83773](https://bugs.freedesktop.org/show_bug.cgi?id=83773)
### 07/10/2014 (Day 1 - 5 hours)
- Set a breakpoint in the `SelectionManager::SelectionHasChanged` method.
*Reason*: in order to find out some different behavior between selecting a slide (in the left pane), in `Normal` mode and selecting it in `Outline` mode.
*Result*: the method creates a `selected slide in sorter slide view` event, which is handled through a EventMultiplexer. In `Normal` mode there is one listener that has registered a call back for such kind of events, whilst in `Outline` mode there is no listener at all. After a bit of investigation I found out that the listener in `Normal` mode is not the `DrawViewShell` object but the `LayoutMenu` which is usually present in `Normal` mode, placed in the right pane, but not in `Outline` mode. The `LayoutMenu` object utilizes such an event for showing the correct MasterPage.
- Set a breakpoint in the `SelectionFunction::MouseButtonDown` method.
*Reason*: in order to find out some different behavior between selecting a slide in `Normal` mode and selecting it in `Outline` mode.
*Result*: Even if I repeated the tracing several times, I was not able to see any difference (well, except for the `SelectionHasChanged` method, as it was explained earlier). Essentially the `PageSelector::SelectPage` and `CurrentSlideManager::SwitchCurrentSlide` methods are invoked in both modes. The `SelectionHasChanged` method is called on invocation of the `BroadcastLock` destructor.
### 08/10/2014 (Day 2 - 3 hours)
- Set a breakpoint in the `SelectionFunction::MouseButtonUp` method.
*Reason*: in order to find out more differences.
*Result*: nothing interesting to be reported.
- In order to find out which part of code is involved when the slide title in Outline mode is selected, I set a breakpoint in the `SelectionFunction::MouseButtonDown` method, one more time, and I performed a tracing by selecting the slide title.
I followed the the call chain untill the invocation of the `EditView::Selection` method. `EditView` is the class that manages edit fields. Soon after I performed a new tracing. I set a breakpoint in the `EditView::Selection` method, and I selected a slide in the left pane (in Outline mode). As I expected the breakpoint is triggered by the slide selection event.
- After reading the interface for the `EditView` class I set a breakpoint in the `EditView::Copy` method. Then, in Outline mode, I performed a right-click on a slide in the left pane and I started a copy event, as I expected the breakpoint is triggered. In Normal mode the breakpoint is not triggered.
### 09/10/2014 (Day 3 - 5 hours)
- Compared the two call chains I got by triggering the breakpoint in the `SelectionFunction::MouseButtonDown` method and the breakpoint in the `EditView::Selection` method: they are equal only up to the call of the `ViewShell::MouseButtonDown` method, then they diverge: in the first case there is the call to the `SelectionFunction::MouseButtonDown` method, in the second case there is a call to the `sd::Window::GrabFocus` method.
- By analizing several methods which are present in the call chain from `ViewShell::MouseButtonDown` to `EditView::Selection` I noticed that the method responsible for selecting the slide title is `OutlineView::SetActualPage`: indeed this method selects the first paragraph of a slide. By resuming the program after the breakpoint was triggered I was able to see that the breakpoint is triggered many times. I performed a test: commented `SetActualPage` implementation. With this modification the slide title is no more selected but the related text field still grabs focus, in Outline mode.
- A new test: set a breakpoint on one method belonging to the call chain from `ViewShell::MouseButtonDown` to `EditView::Selection` that we get in Outline mode, following a bisect rule. Then I select a slide (in the left pane) in Normal mode. I am interested in comparing the two call chains , especially to find out when they start diverging.
- Going on with the test. After some tries I got that the last call common to both chains is the `SfxShell::DoActivate_Impl` method. Interesting facts are that while `DrawViewShell::Activate` simply invokes the superclass method, `OutlineViewShell::Activate` does more things. I modified `OutlineViewShell::Activate` implementation, doing it equal to `DrawViewShell::Activate` implementation. The result is a bit odd: in two cases in Outline mode, the copy/paste actions worked exactly as in Normal mode, then Impress crashed. In all other cases the copy/paste actions in Outline mode worked exactly as no modification had been performed.
- Set a breakpoint in the `SfxShell::DoActivate_Impl` method. This breakpoint is triggered several times both in Normal mode and in Outline mode. So there is a sequence of calls to the `Activate` method for different views.
Tracing result:
- *slide selection in outline mode*
```
void FmFormShell::Activate
void OutlineViewShell::Activate
void SlideSorterViewShell::Activate
void FmFormShell::Activate
void OutlineViewShell::Activate
void SfxShell::Activate
```
- *switch from outline to normal*
```
void DrawViewShell::Activate
void FmFormShell::Activate
void DrawViewShell::Activate
```
- *slide selection in normal mode*
```
void FmFormShell::Activate
void DrawViewShell::Activate
void SlideSorterViewShell::Activate
```
- *switch from normal to outline*
```
void SlideSorterViewShell::Activate (true)
void OutlineViewShell::Activate( true )
void SfxShell::Activate()
void FmFormShell::Activate(true)
void OutlineViewShell::Activate( true )
void SfxShell::Activate()
```
### 10/10/2014 (Day 4 - 5,5 hours)
- Set a breakpoint in the `SfxShell::DoDeactivate_Impl` method, too. In this way we are able to trace both activations and deactivations.
Tracing result:
- *slide selection in outline mode*
```
void SfxShell::Deactivate
void OutlineViewShell::Deactivate
void FmFormShell::Deactivate
void SlideSorterViewShell::Deactivate
void FmFormShell::Activate
void OutlineViewShell::Activate
void OutlineViewShell::Deactivate
void FmFormShell::Deactivate
void SlideSorterViewShell::Activate
void FmFormShell::Activate
void OutlineViewShell::Activate
void SfxShell::Activate
```
- *switch from outline to normal*
```
void SfxShell::Deactivate
void OutlineViewShell::Deactivate
void FmFormShell::Deactivate
void DrawViewShell::Activate
void DrawViewShell::Deactivate
void FmFormShell::Activate
void DrawViewShell::Activate
```
- slide selection in normal mode
```
void SfxShell::Deactivate
void DrawViewShell::Deactivate
void FmFormShell::Deactivate
void SlideSorterViewShell::Deactivate
void FmFormShell::Activate
void DrawViewShell::Activate
void SlideSorterViewShell::Activate
```
- Analyzing the tracing we can see that on slide selection all views are deactivated and then activated again, it worths noting that in outline mode the `OutlineViewShell` is activated and immediately deactivated. It would be nice to know the rationale for such a behavior.
- The call to the `Activate` method for `SlideSorterViewShell` and the call to the `Activate` method for the main view are ordered differently in the two calls sequences: in normal mode, `SlideSorterViewShell::Activate` is invoked after `DrawViewShell::Activate`, on the contrary in outline mode `SlideSorterViewShell::Activate` is invoked before `OutlineViewShell::Activate`.
Could be this behavior the reason for which the `OutlineViewShell` grabs the focus after selecting a Slide in the Slide Sorter Left Pane ?
- Started analyzing the call chain segment from `sd::Window::GrabFocus` to `SfxShell::DoActivate_Impl`. The ViewShellManager class seems to be widely involved with the view shells activation/deactivation tasks.
Started the reading of the ShellViewManager implementation. Fortunately the class is well documented: "The ViewShellManager has the responsibility to manage the view shells and sub shells on the SFX shell stack. ....". Why are view shells organized in a stack data structure ? Is it something related to focus ? The shell stack is owned by a SfxViewShell object (indeed it is some kind of ViewShellBase such as ImpressShellBase). On the stack are put view shells like DrawViewShell, OutlineVieShell, SlideSorterViewShell and subshells such as toolbars. These two types of shells are all placed on the stack where subshells are above (in the stack) the view shell they belong to. The ViewShallManager handles them in two separated data members: an internal stack for all active view shells named `maActiveViewShells` and a map (`maActiveSubShells`) where at each view shell is associated a list of subshells.
The ViewShellManager implementation exploits an `UpdateLock` class in order to prevent multiple rebuilds of the shell stack. It works in the following way: on construction an internal counter is increased by one, on destruction the counter is decreased by one; if the counter value is zero the `UpdateShellStack` is invoked. This method is responsible for performing the actual rebuild of the stack.
### 13/10/2014 (Day 5 - 1,5 hours)
- Completed the reading of ViewShellManager implementation: `MoveToTop`, `TakeShellsFromStack`, `UpdateShellStack`, `CreateShells`, `CreateSubShell`, `CreateTargetStack`.
- A side note: the `mbKeepMainViewShellOnTop` data member should be used when the view shell of the center pane is to be kept top most and the new view shell is not displayed in the center pane and should be inserted at the position one below the top. This feature makes the implementation of some method more complex, however the `mbKeepMainViewShellOnTop` data member is modified only in the (default) constructor, where it is initialized to false.
- For what I can see the `Activate` methods are always invoked to the end of a call chain which starts with the `ViewShellManager::Implementation::LinkStubWindowEventHandler`. This event handler is set up on the call to `ViewShellManager::ActivateViewShell`. So the ordering of the view shells in the stack is due to the sequence of invocation to `LinkStubWindowEventHandler` which, in turn, should depend on the calls order of the `ActivateViewShell` method.
### 21/10/2014 (Day 6 - 2,5 hours)
- Unexpectedly, the breakpoint set in the `ViewShellManager::ActivateViewShell` method is not triggered when a slide is selected (in the left pane) but only when the user switches from normal mode to outline mode or when the user switches from outline mode to normal mode. In the former case the activated view shell is an instance of `OutlineViewShell`, in the latter case an instance of `DrawViewShell`. For the other types of views the breakpoint is not triggered.
- However the `Activate` methods are always invoked to the end of a call chain which starts with the `ViewShellManager::Implementation::LinkStubWindowEventHandler` method. Hence somewhere, outside the `ViewShellManager::ActivateViewShell` method, there must be some invocation of `vcl::Window::AddEventListener` with argument a `Link` object wrapping a `ViewShellManager::Implementation::LinkStubWindowEventHandler` method.
- Set a breakpoint in `vcl::Window::AddEventListener`, however it is triggered by too many events. Tried to set a conditional breakpoint but I do not succeed in getting it to work correctly.
### 22/10/2014 (Day 7 - 3 hours)
- Well, I was wrong: the `ViewShellManager::ActivateViewShell` method is the only place where `LinkStubWindowEventHandler` is appended to the list of window event listeners. It is the `ViewShellManager::Implementation::LinkStubWindowEventHandler` method itself that causes the invocation of the `Activate` method for more view shells such as `SlideSorterViewShell`. The actual call to the `Activate` method is performed by the `ViewShellManager::Implementation::MoveToTop` method.
- In order to study how the `maActiveViewShells` data member changes, when some user event occurs, I set breakpoints in `ActivateView`, `MoveToTop`, and `WindowEventHandler` (all belonging to `ViewShellManager::Implementation` class).
- Trace of `maActiveViewShells` changes:
- switch from outline to normal
- on BP 497 (ActivateShell)
* SlideSorterViewShell
* LeftImpressPaneShell
- on exit from method ActivateShell
* DrawViewShell
* SlideSorterViewShell
* LeftImpressPaneShell
- on resume control go back to user.
- switch from normal to outline
- on BP 497 (ActivateShell)
* SlideSorterViewShell
* LeftImpressPaneShell
- on exit from method ActivateShell
* OutlineViewShell
* SlideSorterViewShell
* LeftImpressPaneShell
- on BP 980 (WindowEventHandler)
- pEventWindow: shell type: "OutlineViewShell"
* OutlineViewShell
* SlideSorterViewShell
* LeftImpressPaneShell
- on exit from method WindowEventHandler
* OutlineViewShell
* SlideSorterViewShell
* LeftImpressPaneShell
- on resume control go back to user.
- Note 1: Even if the `LinkStubWindowEventHandler` is set as a callback for a window event in both modes, `WindowEventHandler` is invoked only when the user switches from normal to outline mode.
- Note 2: In both cases after switching to the new mode the top view shell on the stack is the main view (`DrawViewShell` or `OutlineViewShell`) and the `SlideSorterViewShell` is one below the top position.
### 23/10/2014 (Day 8 - 4,5 hours)
- For the first fact I decided to set a breakpoint in `Window::ImplGrabFocus`, too. I set also a further breakpoint in `DeactivateViewShell`.
- New tracing:
- switch from outline to normal
- BP 452 (DeactivateViewShell)
- BP 201 (ImplGrabFocus)
- BP 423 (ActivateViewShell) *- not invoked by ImplGrabFocus*
- BP 497 (ActivateShell)
- on resume control go back to user.
- switch from normal to outline
- BP 452 (DeactivateViewShell)
- BP 423 (ActivateViewShell)
- BP 497 (ActivateShell)
- BP (mouse.cxx, 201) (ImplGrabFocus)
- BP 980 (WindowEventHandler)
- BP (mouse.cxx, 201) (ImplGrabFocus)
- on resume control go back to user.
- Note: In normal mode `ImplGrabFocus` is invoked earlier than `ActivateViewShell` and its invocation does not cause a call to `WindowEventHandler`.
- After the resume action, control is back to user. When focus is grabbed from the Impress window, we can see that:
- when Impress window gets focus in outline mode:
- BP 201 (ImplGrabFocus)
- BP 980 (WindowEventHandler)
- when Impress window gets focus in normal mode:
- BP 201 (ImplGrabFocus)
- That is, in normal mode `ImplGrabFocus` invocation does not cause a call to `WindowEventHandler`.
- Unfortunately it is not possible to have a breakpoint in `ImplGrabFocus` and `WindowEventHandler` enabled soon after resuming, because the window grab focus event is triggered immediately, before user can perform a mode switch or selecting a slide in the left pane.
- For this reason I take the decision to add simple print instruction to the two methods. Indeed, I exploited a new feature available in latest version of gdb: a *dynamic printf*. This tool let you insert a printf before a given line of code at debugging time and behaves exactly like a real printf. The main advantage is that it removes the need to rebuild the source code.
- New trace:
- on change selected slide in normal mode
- BP (mouse.cxx, 201) (ImplGrabFocus)
- BP 980 (WindowEventHandler)
- pEventWindow: shell type: SlideSorterViewShell
- BP 665 (MoveToTop)
- on enter method MoveToTop:
* DrawViewShell
* SlideSorterViewShell
* LeftImpressPaneShell
- on exit from method MoveToTop:
* SlideSorterViewShell
* DrawViewShell
* LeftImpressPaneShell
- on resume control go back to user.
- Note 1: When a slide is selected, in the left pane, the `mpViewShell` data member of the `sd::Window` instance (`pEventWindow`) is of type `SlideSorterViewShell`.
So it is the `SlideSorterViewShell` to be moved to the top of the stack (`maActiveViewShells`).
- Note 2: However in some cases selecting a new slide does not trigger any breakpoint.
- Note 3: Since `ImplGrabFocus`/`WindowEventHandler` are triggered by window focus grab, it is not clear how many invocation to `ImplGrabFocus`/`WindowEventHandler` are performed before/after the mouse click event.
### 24/10/2014 (Day 9 - 2,5 hours)
- In order to clarify the issue in note 3 I set a dynamic printf in `ImplHandleSalMouseButtonDown` (winproc.cxx).
- After some tries, I got a better understanding of how window focus grab works:
- when Impress window gets focus in outline mode:
- BP 201 (ImplGrabFocus)
- BP 980 (WindowEventHandler)
- when Impress window gets focus in normal mode:
- BP 201 (ImplGrabFocus)
- BP 980 (WindowEventHandler) (only if user selects a slide at least once after Impress started or after mode has switched back to normal)
- I performed one more time tracing for some interesting events.
- switch from outline to normal
- BP (winproc.cxx, 1972) (ImplHandleSalMouseButtonDown)
- BP 452 (DeactivateViewShell)
- BP 201 (ImplGrabFocus)
- BP 423 (ActivateViewShell) *- not invoked by ImplGrabFocus*
- BP 497 (ActivateShell)
- on resume control go back to user.
- switch from normal to outline
- BP (winproc.cxx, 1972) (ImplHandleSalMouseButtonDown)
- BP 452 (DeactivateViewShell)
- BP 423 (ActivateViewShell)
- BP 497 (ActivateShell)
- BP (mouse.cxx, 201) (ImplGrabFocus)
- BP 980 (WindowEventHandler)
- BP (mouse.cxx, 201) (ImplGrabFocus)
- on resume control go back to user.
- on change selected slide in normal mode (on first time after mode has switched back to normal)
- BP (winproc.cxx, 1972) (ImplHandleSalMouseButtonDown)
- BP (mouse.cxx, 201) (ImplGrabFocus)
- BP 980 (WindowEventHandler)
- pEventWindow: shell type: SlideSorterViewShell
- BP 665 (MoveToTop)
- on enter method MoveToTop:
* DrawViewShell
* SlideSorterViewShell
* LeftImpressPaneShell
- on exit from method MoveToTop:
* SlideSorterViewShell
* DrawViewShell
* LeftImpressPaneShell
- on resume control go back to user.
- on change selected slide in normal mode (after first time)
- BP (winproc.cxx, 1972) (ImplHandleSalMouseButtonDown)
- on resume control go back to user.
- Note: In the last trace we can see that `ImplGrabFocus` is not invoked at all.
- Finally, I performed tracing for slide selection in outline mode:
- on change selected slide in outline mode
- BP (winproc.cxx, 1972) (ImplHandleSalMouseButtonDown)
- BP (mouse.cxx, 201) (ImplGrabFocus)
- BP 980 (WindowEventHandler)
- pEventWindow: shell type: SlideSorterViewShell
- BP 665 (MoveToTop)
- on enter method MoveToTop:
* OutlineViewShell
* SlideSorterViewShell
* LeftImpressPaneShell
- on exit from method MoveToTop:
* SlideSorterViewShell
* OutlineViewShell
* LeftImpressPaneShell
- BP (mouse.cxx, 201) (ImplGrabFocus)
- BP 980 (WindowEventHandler)
- pEventWindow: shell type: OutlineViewShell
- BP 665 (MoveToTop)
- on enter method MoveToTop:
* SlideSorterViewShell
* OutlineViewShell
* LeftImpressPaneShell
- on exit from method MoveToTop:
* OutlineViewShell
* SlideSorterViewShell
* LeftImpressPaneShell
- BP (mouse.cxx, 201) (ImplGrabFocus)
- on resume control go back to user.
- Note: At first the `SlideSorterViewShell` is moved to the top of the stack but then `OutlineViewShell` is moved back to top.
### 26/10/2014 (Day 10 - 3 hours)
- Traced again slide selection in outline mode: by comparing the two call chains related to the breakpoint set in `MoveToTop`, we can see that while the first call to `MoveToTop` is due to the mouse click event `ImplHandleSalMouseButtonDown`, the second call is due to the implementation of the `OutlineViewShell::Activate` method. Note that `Activate` is the final call of the chain which starts with the destruction of the `UpdateLock` object defined in `MoveToTop`. Hence is the view shell stack change which occurs on the first call to `MoveToTop` that causes the invocation of `OutlineViewShell::Activate`.
- Here we can see the call stack for the second invocation to `MoveToTop`:
```cpp
sd::ViewShellManager::Implementation::MoveToTop() at ViewShellManager.cxx:665 0x7ff01cf20dfb
sd::ViewShellManager::Implementation::WindowEventHandler() at ViewShellManager.cxx:982 0x7ff01cf22a3c
sd::ViewShellManager::Implementation::LinkStubWindowEventHandler() at ViewShellManager.cxx:965 0x7ff01cf22967
Link::Call() at link.hxx:139 0x7ff03632f594
VclEventListeners::Call() at vclevent.cxx:62 0x7ff0368b0258
vcl::Window::CallEventListeners() at event.cxx:223 0x7ff0363d3c38
vcl::Window::ImplCallEventListeners() at event.cxx:208 0x7ff0363d3b9d
vcl::Window::PreNotify() at event.cxx:70 0x7ff0363d33c1
ImplCallPreNotify() at winproc.cxx:60 0x7ff0364c74d3
vcl::Window::ImplGrabFocus() at mouse.cxx:384 0x7ff036428b3c
vcl::Window::GrabFocus() at window.cxx:3,098 0x7ff0364b8ce7
sd::Window::GrabFocus() at sdwindow.cxx:711 0x7ff01cfcf9af
sd::OutlineView::ConnectToApplication() at outlview.cxx:206 0x7ff01cfa577b
sd::OutlineViewShell::Activate() at outlnvsh.cxx:351 0x7ff01cf9df65
```
- This is the simple implementation of `ConnectToApplication`:
```
void OutlineView::ConnectToApplication (void)
{
mrOutlineViewShell.GetActiveWindow()->GrabFocus();
Application::AddEventListener(LINK(this, OutlineView, AppEventListenerHdl));
}
```
- The method performs two tasks:
- let the Outline view shell grab focus
- set a callback `AppEventListenerHdl` for an application event.
The only action performed by the callback is to invoke the `onUpdateStyleSettings` method which is responsible for updating the background color of the outline view.
- Question: is the focus grabbing needed for the correct work of the callback ?
- Traced slide selection in outline mode for a non-first selection after switching to outline mode. On the contrary to what happens in normal mode, the behavior is the same that for the first selection action performed after switching to outline mode.
- Some more detailed notes on what happens when the focus has got back to the Impress window:
- when Impress window gets focus in outline mode we have the following call chain:
- ImplGrabFocus
- WindowEventHandler
- MoveToTop
- However the call to `MoveToTop` does nothing because the outline view is already on the top of the view shell stack.
- Some notes on call chains we get when we change mode:
- switch from outline to normal
- BP (winproc.cxx, 1972) (ImplHandleSalMouseButtonDown)
- BP 452 (DeactivateViewShell)
- BP 201 (ImplGrabFocus)
- BP 423 (ActivateViewShell) *- not invoked by ImplGrabFocus*
- BP 497 (ActivateShell)
- on resume control go back to user.
1- `ImplGrabFocus` does not invoke the `WindowEventHandler` because `DeactivateViewShell` removes it from the window event listener list.
2- `ImplGrabFocus` is invoked by the `OutlineViewShell` destructor (the shell is destroyed on switching). To be exact it is invoked by the `vcl::Window` destructor.
- switch from normal to outline
- BP (winproc.cxx, 1972) (ImplHandleSalMouseButtonDown)
- BP 452 (DeactivateViewShell)
- BP 423 (ActivateViewShell)
- BP 497 (ActivateShell)
- BP (mouse.cxx, 201) (ImplGrabFocus)
- BP 980 (WindowEventHandler)
- BP (mouse.cxx, 201) (ImplGrabFocus)
- on resume control go back to user.
3- `ImplGrabFocus` is invoked by `vcl::~Window` only when the window object related to the current main view is the current focused window:
```cpp
// check if the focus window is our child
bool bHasFocussedChild = false;
if( pSVData->maWinData.mpFocusWin && ImplIsRealParentPath( pSVData->maWinData.mpFocusWin ) )
{
bHasFocussedChild = true;
}
if ( pSVData->maWinData.mpFocusWin == this
|| bHasFocussedChild )
{
...
}
```
So in normal mode if the view does not own focus when the switch mode event occurs, the `ImplGrabFocus` is not invoked. On the contrary when you leave outline mode the window related to the outline view shell has always focus since, as we have seen, `OutlineViewShell::Activate` causes the outline view shell to grab focus and hence `ImplGrabFocus` is always invoked by `vcl::~Window`.
4- When switching to outline mode `ImplGrabFocus` is invoked after the outline view shell has been set on the top of the stack. The invocation occurs on toolbars updating. The call to `WindowEventHandler` causes the invocation of `MoveToTop` which does nothing since the view shell is already at the top.
### 27/10/2014 (Day 11 - 1 hour)
- SUSE: bug 83773
- Commented the call to `GrabFocus` in the `ConnectToApplication` method which, in turn, is invoked by `OutlineViewShell::Activate`. Build and tested Impress with this modification. Unexpectedly, the copy/paste action do not yet work in the correct way it looks like nothing is changed.
- Now, when I change selected slide in normal or outline mode only the breakpoint for `ImplHandleSalMouseButtonDown` is triggered, and on resume control go back to user. That is a bit odd.
### 28/10/2014 (day 12 - 1 hour)
- SUSE: bug 83773
- Performed some tracing task in order to understand which view shell grabs focus when Impress window get focus back.
- Created a new slide, attached the debugger, resumed, clicked on the Impress item in the task bar.
- dynamic printf trace:
* `vcl::Window::ImplGrabFocus()`
* `sd::ViewShellManager::Implementation::WindowEventHandler()`
- BP in `WindowEventHandler` method before invoking `MoveToTop`
- `maActiveViewShells`:
[0] SlideSorterViewShell
[1] DrawViewShell
[2] LeftImpressPaneShell
- `pEventWindow->mpViewShell`: `SlideSorterViewShell`
- call stack:
```cpp
sd::ViewShellManager::Implementation::WindowEventHandler() at ViewShellManager.cxx:980 0x7f65f44b403e
sd::ViewShellManager::Implementation::LinkStubWindowEventHandler() at ViewShellManager.cxx:965 0x7f65f44b3faf
Link::Call() at link.hxx:139 0x7f660d8bc474
VclEventListeners::Call() at vclevent.cxx:62 0x7f660de3c4d8
vcl::Window::CallEventListeners() at event.cxx:223 0x7f660d961038
vcl::Window::ImplCallEventListeners() at event.cxx:208 0x7f660d960f9d
vcl::Window::PreNotify() at event.cxx:70 0x7f660d9607c1
ImplCallPreNotify() at winproc.cxx:60 0x7f660da5431b
vcl::Window::ImplGrabFocus() at mouse.cxx:384 0x7f660d9b60a8
vcl::Window::GrabFocus() at window.cxx:3,098 0x7f660da468eb (this: SlideSorterViewShell)
vcl::Window::ImplAsyncFocusHdl() at winproc.cxx:1,683 0x7f660da5949f
vcl::Window::LinkStubImplAsyncFocusHdl() at winproc.cxx:1,660 0x7f660da59327 (this : ImplBorderWindow)
Link::Call() at link.hxx:139 0x7f660d8bc474
ImplHandleUserEvent() at winproc.cxx:1,914 0x7f660da59f26
ImplWindowFrameProc() at winproc.cxx:2,485 0x7f660da5b380
SalFrame::CallCallback() at salframe.hxx:242 0x7f660dee97b5
SalGenericDisplay::DispatchInternalEvent() at gendisp.cxx:90 0x7f660dee92ea
GtkData::userEventFn() at gtkdata.cxx:935 0x7f6602d359c9
```
- note:
```cpp
vcl::Window::ImplAsyncFocusHdl()
{
...
ImplGetWindowImpl()->mpFrameData->mpFocusWin->GrabFocus();
...
}
```
- note: `mpFocusWin` is the current view having focus. It is set in `ImplGrabFocus`. When Impress gets focus back the last view, which owned focus, grabs it again.
### 29/10/2014 (Day 13 - 2 hours)
- SUSE: bug 83773
- I performed tracing for mode switching.
- switch from outline to normal
- BP (winproc.cxx, 1972) (ImplHandleSalMouseButtonDown)
- BP 452 (DeactivateViewShell)
- BP 423 (ActivateViewShell)
- BP 497 (ActivateShell)
- on resume control go back to user.
- switch from normal to outline
- BP (winproc.cxx, 1972) (ImplHandleSalMouseButtonDown)
- BP 452 (DeactivateViewShell)
- BP 423 (ActivateViewShell)
- BP 497 (ActivateShell)
- on resume control go back to user.
- note: the mode switch behaves in the same way for both modes. When we switch from outline to normal there is no more the focus grabbing by the parent view shell (Impress) when the `OutlineViewShell` object is destroyed. This means that the `OutlineViewShell` object has no more the focus on switching. When we switch from normal to outline there is no more a call to `ImplGrabFocus`. Both changes are surely due to the fact that the focus grabbing action is no more performed when `OutlineViewShell::Activate` is invoked.
- In order to understand the reason `GrabFocus` is not invoked I performed a trace when a slide is selected in outline mode: starting from the breakpoint in `ImplHandleSalMouseButtonDown` I debugged the program step by step, after a few steps I got into the ViewShell::MouseButtonDown method where there is this enlightening fragment of code:
```
if ( pWin && !pWin->HasFocus() )
{
pWin->GrabFocus();
SetActiveWindow(pWin);
}
```
where `pWin` is a pointer to the window related to the view shell where the mouse button down event occurs.
So the picture we get is that when the `SlideSorterViewShell` grabs focus then it keeps focus even after mode switch occurred. The `SlideSorterViewShell` loses focus only when the main view shell gets a mouse button down event.
### 30/10/2014 (Day 14 - 2,5 hours)
- SUSE: bug 83773
- Performed a trace for copy/paste action: the copied slide is correctly pasted in the slide sorter view. Since this was an unexpected result I repeated the test two times. This is the call stack I got for the `copy action`:
```cpp
EditView::SetSelection() at editview.cxx:204 0x7faf3a9005f6
OutlinerView::Select() at outlvw.cxx:391 0x7faf3aa4255e
sd::OutlineView::FillOutliner() at outlview.cxx:1,181 0x7faf3d057943
sd::OutlineView::EventMultiplexerListener() at outlview.cxx:1,484 0x7faf3d058e2a
sd::OutlineView::LinkStubEventMultiplexerListener() at outlview.cxx:1,467 0x7faf3d058d1f
Link::Call() at link.hxx:139 0x7faf3cbb002c
sd::tools::EventMultiplexer::Implementation::CallListeners() at EventMultiplexer.cxx:709 0x7faf3cf095ef
sd::tools::EventMultiplexer::Implementation::CallListeners() at EventMultiplexer.cxx:698 0x7faf3cf0950a
sd::tools::EventMultiplexer::Implementation::Notify() at EventMultiplexer.cxx:660 0x7faf3cf093df
SfxBroadcaster::Broadcast() at SfxBroadcaster.cxx:41 0x7faf58eb5962
ImpPageChange() at svdpage.cxx:1,144 0x7faf38ac9aa7
SdrPageProperties::SetStyleSheet() at svdpage.cxx:1,228 0x7faf38ac9f7a
SdrPage::operator=() at svdpage.cxx:1,418 0x7faf38acaf02
SdrPage::SdrPage() at svdpage.cxx:1,286 0x7faf38aca58d
FmFormPage::FmFormPage() at fmpage.cxx:67 0x7faf38d42b86
SdPage::SdPage() at sdpage2.cxx:375 0x7faf3cbca4cf
SdPage::Clone() at sdpage2.cxx:435 0x7faf3cbcabdf
SdPage::Clone() at sdpage2.cxx:427 0x7faf3cbcab74
SdrModel::Merge() at svdmodel.cxx:1,665 0x7faf389fd26f
SdDrawDocument::Merge() at drawdoc3.cxx:1,916 0x7faf3cb94a4c
SdDrawDocument::InsertBookmarkAsPage() at drawdoc3.cxx:676 0x7faf3cb8eba5
SdTransferable::SetPageBookmarks() at sdxfer.cxx:700 0x7faf3cccf8d5
sd::slidesorter::controller::Clipboard::CreateSlideTransferable() at SlsClipboard.cxx:459 0x7faf3ce98625
sd::slidesorter::controller::Clipboard::DoCopy() at SlsClipboard.cxx:239 0x7faf3ce978ce
sd::slidesorter::controller::SelectionFunction::DoCopy() at SlsSelectionFunction.cxx:613 0x7faf3cea9bfe
sd::slidesorter::controller::Clipboard::HandleSlotCall() at SlsClipboard.cxx:190 0x7faf3ce97647
sd::slidesorter::controller::SlotManager::FuSupport() at SlsSlotManager.cxx:388 0x7faf3ceb48c0
sd::slidesorter::controller::SlideSorterController::FuSupport() at SlideSorterController.cxx:301 0x7faf3ce89257
sd::slidesorter::SlideSorterViewShell::FuSupport() at SlideSorterViewShell.cxx:406 0x7faf3ced04f4
SfxStubSlideSorterViewShellFuSupport() at sdslots.hxx:17,736 0x7faf3cecee44
SfxShell::CallExec() at shell.hxx:209 0x7faf594f4c1a
SfxDispatcher::Call_Impl() at dispatch.cxx:260 0x7faf594ec367
SfxDispatcher::_Execute() at dispatch.cxx:862 0x7faf594ef205
```
We can see the call to `sd::slidesorter::controller::SelectionFunction::DoCopy()` and no call at all to `EditView::Copy`.
I got a similar call stack when I traced the paste action.
- Tested, again, the copy/paste action (no debugging). After having performed several tests, I got the following picture: the copy/paste action stops to work correctly when we switch mode. In order to have the correct behavior back we need to select the current main view once or to select another window and then go back to the Impress window. Note that now this issue affects the copy/paste action in normal mode, too: the behavior has become symmetric.
### 31/10/2014 (Day 15 - 3 hours)
- SUSE: bug 83773
- Performed a new debug session for tracing the cases when the copy/paste action does not work in the correct way. In order to be able to perform the test I utilized a breakpoint provided with a counter for the `ImplHandleSalMouseButtonDown` method. I got the following call stack:
```cpp
EditView::Copy() at editview.cxx:514 0x7f46ac34b7ab
OutlinerView::Copy() at outlvw.cxx:1,338 0x7f46ac48f454
sd::FuOutlineText::DoCopy() at fuoltext.cxx:262 0x7f46ae7fc056
sd::OutlineViewShell::FuSupport() at outlnvsh.cxx:483 0x7f46aea96fd4
SfxStubOutlineViewShellFuSupport() at sdslots.hxx:15,748 0x7f46aea953f3
SfxShell::CallExec() at shell.hxx:209 0x7f46caf3ec1a
SfxDispatcher::Call_Impl() at dispatch.cxx:260 0x7f46caf36367
SfxDispatcher::_Execute() at dispatch.cxx:862 0x7f46caf39205
SfxBindings::Execute_Impl() at bindings.cxx:1,204 0x7f46caf26142
SfxDispatchController_Impl::dispatch() at unoctitm.cxx:851 0x7f46cafa385f
SfxOfficeDispatch::dispatch() at unoctitm.cxx:365 0x7f46cafa15b1
```
By comparing the two call stacks we can see that they diverge after the call to `SfxShell::CallExec()`, in fact in the correct case the next call is to the `SfxStubSlideSorterViewShellFuSupport()` routine whilst in the wrong case the next call is to the `SfxStubOutlineViewShellFuSupport()`.
- Read the interface and some method implementation for the `SfxDispatcher` class. The class is used for dispatching command to view shell both synchronously than asynchronously. It handles a shell stack which is updated whenever it is updated the sfx shell stack owned by the `ImpressViewShellBase` class.
- The most important finding is that the cut/copy/paste commands that are placed in the context menu (accessible through right click) do not refer to the focused view shell but to the top-most active view shell on the shell stack handled by the `SfxDispatcher` object. Hence what matters is to get the `SlideSorterViewShell` instance always to become the top-most active view shell when a slide in the left pane is clicked. The problem here is that when we switch mode and the focused view is the `SlideSorterViewShell` instance, it keeps the focus after mode change occurred but it is no more the top-most view shell. So we need to have `DrawViewShell` and `OutlineViewShell` grabbing focus when we switch mode. In this way the next time a mouse button down event occurs, for a slide on the left pane, the `GrabFocus` method is invoked which in turn causes the new focused view shell (`SlideSorterViewShell`) to be moved to the top-most position on the stack.
### 01/11/2014 (Day 16 - 3 hours)
- SUSE: bug 83773
- Evaluated several solutions for the bug:
1. When a shell is destroyed we could move always focus to the parent window even if the destroyed view has not the focus.
This solution would make the `SlideSorterViewShell` instance to lose focus whenever a mode change occurs. However we do not know how many events can cause a shell destruction, so it could result in s very odd behavior if the focus was moved to the Impress view shell whenever any shell is destroyed. This issue could be mitigated by adding the needed code only to the destructor for the `OutlineViewShell` and the `DrawViewShell`.
2. Make the new top-most active view shell always grabs focus.
The focus grabbing action could occur in the `UpdateShellStack` method. However it is not clear if there are reasons for not having the top-most active view shell and the focused view to be always the same view. I wonder what is the role of sub-shells, such as tool bars, for what it concerns the focus property.
3. Make the `OutlineViewShell` grabs focus only if it is the top-most active view shell.
When `OutlineViewShell::Activate` is invoked, instead of removing the focus grabbing action completely, we could check if the `OutlineViewShell` instance is the the top-most view shell and perform the focus grabbing action only in such a case. In order to implement this solution we need a way for getting the top-most active view shell.
- note: the third solution looks like to be the one having less side-effects.
- I analyzed, again, the way the sfx shell stack is modified by the `UpdateShellStack` and `ActivateSubShell` methods.
- Note: In the sub-set of `ViewShellManager` methods that modify the internal shell stack or the related sub-shells, `ViewShellManager::ActivateShell` is the only one that does not use the `UpdateLock` class. So when a new shell is placed on the top of the internal stack, the sfx shell stack is updated only after the first sub-shell of the new view shell is placed on the sfx shell stack. New sub-shells are placed on the stack as soon as they are activated through `ActivateSubShell` which utilizes the `UpdateLock` class.
- Note: `GetTopShell` returns the top-most shell placed on the sfx shell stack, so it is not suitable for implementing the 3rd solution, since both shells and sub-shells are pushed on the sfx call stack, and sub-shells are pushed after the view shell they belong to. Moreover we need to know the new top-most active view shell while the sfx call stack is being updated.
- Note: `GetShell (ShellId nId)` returns a shell by id (an integral value). After looking for these ids in `ActivateViewShell` and `ActivateSubShell` implementations, I was able to see that the id for a view shell is always 0, so it is not possible to discriminate between them. Ids for sub-shells are passed directly to the `ActivateSubShell` method: `ActivateSubShell (const SfxShell& rParentShell, ShellId nId)`. After performing a tracing task, for seeing who invokes `ActivateSubShell`, I found out that it is invoked by a method belonging to the `ToolBarManager` class. Going back in the call stack, finally I have seen that these shell ids for sub-shells are set up through several define directives and their value starts from 23000 (probably in order to avoid collision with other ids). So, in the end, the call `GetShell(0)` should return the top-most active view shell, however it can't be regarded as a safe way for getting the top-most active view shell because it is based on an implementation detail.
- In order to implement the 3rd solution I needed to add a new method (and data member) to the `ViewShellManager` class. I named it `GetTopViewShell`. This method returns a pointer to the top-most active view shell of the internal stack. The returned pointer is updated in the `UpdateShellStack` method, before the sfx shell stack is updated.
- Tested the 3rd solution: it works fine except when we perform a copy/paste action soon after having switching from outline to normal mode and in outline mode the top-most view shell was the `SlideSorterViewShell` instance: in fact, exactly as it happened when switching to the outline mode, the focus is not lost from the `SlideSorterViewShell` instance but the `DrawViewShell` is the new top-most active shell, so the `SlideSorterViewShell` instance never succeed in becoming the top-most one. In order to solve this problem I added the code for grabbing focus used by `OutlineViewShell::Activate` to the `DrawViewShell::Activate` method.
- Tested the 3rd solution with the new introduced modifications: all work fine. One thing to point out is that in outline mode now, when you select a slide in the left pane in the right pane the property settings for text disappear and in the pane is showed a message saying that no suitable properties for the current selection has been found.
## Fixing Bug [N830738](https://bugzilla.novell.com/show_bug.cgi?id=830738)
### 08/11/2014 (Day 1 - 1 hour)
- SUSE: L3: Bug N830738:
- Opened test document. By enlarging bar chart group with 45 deg labels on page 14 all labels are shown correctly. This behavior is triggered only by horizontal resizing.
- Question: Are non-showed labels really overlapping ? That is, the issue is due to misplacing/wrong sizing or to an incorrect overlapping test ?
- Test: modified the following code fragment of method `VCartesianAxis::createTextShapes`:
```cpp
if (bOverlapsAfterAutoStagger)
{
// Staggering didn't solve the overlap.
if( !rAxisLabelProperties.bOverlapAllowed && ::rtl::math::approxEqual( rAxisLabelProperties.fRotationAngleDegree, 0.0 ) )
{
// Try auto-rotating the labels at 45 degrees and
// start over. This rotation angle will be stored for
// all future text shape creation runs.
rAxisLabelProperties.autoRotate45();
m_aAxisLabelProperties.fRotationAngleDegree = rAxisLabelProperties.fRotationAngleDegree; // Store it for future runs.
removeTextShapesFromTicks();
return false;
}
if( rAxisLabelProperties.bRhythmIsFix )
{
// Tick interval is fixed. We have no choice but to
// remove this label.
xTarget->remove(pTickInfo->xTextShape);
pTickInfo->xTextShape = NULL;
continue;
}
// Try incrementing the tick interval and start over.
rAxisLabelProperties.nRhythm++;
removeShapesAtWrongRhythm( rTickIter, rAxisLabelProperties.nRhythm, nTick, xTarget );
return false;
}
}
```
to:
```cpp
if (bOverlapsAfterAutoStagger)
{
// Staggering didn't solve the overlap.
if( !rAxisLabelProperties.bOverlapAllowed && ::rtl::math::approxEqual( rAxisLabelProperties.fRotationAngleDegree, 0.0 ) )
{
// Try auto-rotating the labels at 45 degrees and
// start over. This rotation angle will be stored for
// all future text shape creation runs.
rAxisLabelProperties.autoRotate45();
m_aAxisLabelProperties.fRotationAngleDegree = rAxisLabelProperties.fRotationAngleDegree; // Store it for future runs.
--> //removeTextShapesFromTicks();
return false;
}
--> if( false && rAxisLabelProperties.bRhythmIsFix )
{
// Tick interval is fixed. We have no choice but to
// remove this label.
xTarget->remove(pTickInfo->xTextShape);
pTickInfo->xTextShape = NULL;
continue;
}
// Try incrementing the tick interval and start over.
rAxisLabelProperties.nRhythm++;
--> //removeShapesAtWrongRhythm( rTickIter, rAxisLabelProperties.nRhythm, nTick, xTarget );
return false;
}
}
```
- Reason: The test is performed in order to get the labels drawn even if they are overlapping.
- Result: Impress still shows only 2 labels.
### 09/11/2014 (Day 2 - 4 hours)
- SUSE: L3: Bug N830738:
- Test: Set a method bp for `VCartesianAxis::createTextShapes`, and a bp at line 814:
```cpp
//if NO OVERLAP -> remove overlapping shapes
if( pLastVisibleNeighbourTickInfo && !rAxisLabelProperties.bOverlapAllowed )
```
- Reason: The test is performed in order to see if/when 45 deg labels rotation is performed.
- Result: The bp at line 814 is never triggered.
- call stack:
```cpp
chart::VCartesianAxis::createMaximumLabels() at VCartesianAxis.cxx:1,650 0x7f0f0f5b29cc
chart::VCoordinateSystem::createMaximumAxesLabels() at VCoordinateSystem.cxx:463 0x7f0f0f5cb36e
chart::ChartView::impl_createDiagramAndContent() at ChartView.cxx:1,593 0x7f0f0f678f1c
chart::ChartView::createShapes2D() at ChartView.cxx:3,163 0x7f0f0f68178c
chart::ChartView::createShapes() at ChartView.cxx:2,592 0x7f0f0f67e795
chart::ChartView::impl_updateView() at ChartView.cxx:2,663 0x7f0f0f67ecb2
chart::ChartView::updateHard() at ChartView.cxx:2,843 0x7f0f0f67f6f3
ChartHelper::updateChart() at charthelper.cxx:84 0x7f0f1e876e70
```
- Test: Set a method bp for `VCartesianAxis::createTextShapes`, and a bp at line x with x always nearer to the method begin.
- Reason: Try to understand where and why the method returns.
- Result: The method always returns at the very top, soon after invoking `VCartesianAxis::createTextShapesSimple`:
```cpp
bool VCartesianAxis::createTextShapes(
const Reference<drawing::XShapes>& xTarget, TickIter& rTickIter,
AxisLabelProperties& rAxisLabelProperties, TickFactory2D* pTickFactory,
sal_Int32 nScreenDistanceBetweenTicks )
{
const bool bIsHorizontalAxis = pTickFactory->isHorizontalAxis();
const bool bIsVerticalAxis = pTickFactory->isVerticalAxis();
if (!isBreakOfLabelsAllowed(rAxisLabelProperties, bIsHorizontalAxis) &&
!isAutoStaggeringOfLabelsAllowed(rAxisLabelProperties, bIsHorizontalAxis, bIsVerticalAxis) &&
!rAxisLabelProperties.isStaggered())
--> return createTextShapesSimple(xTarget, rTickIter, rAxisLabelProperties, pTickFactory);
.
.
.
```
- Test: Set a method bp for `VCartesianAxis::createTextShapesSimple`, and a bp at line 978:
```cpp
// It overlaps.
if( !rAxisLabelProperties.bOverlapAllowed && ::rtl::math::approxEqual( rAxisLabelProperties.fRotationAngleDegree, 0.0 ) )
```
- Reason: The test is performed in order to see if/when 45 deg labels rotation is performed.
- Result: The above `if` command is executed 4 times and it is true 2 times (but for 2 different method invocations).
- Test: Set several dynamic printf in `VCartesianAxis::createTextShapes` and in `VCartesianAxis::createTextShapesSimple`:
```cpp
VCartesianAxis.cxx [line: 657] [">> createTextShape: begin\n"]
VCartesianAxis.cxx [line: 665] [">> createTextShape: after `createTextShapeSimple` invocation.\n"]
VCartesianAxis.cxx [line: 875] [">> createTextShapesSimple: begin\n"]
VCartesianAxis.cxx [line: 973] [">> createTextShapesSimple: if no overlap allowed (973); tick: %d\n", nTick]
VCartesianAxis.cxx [line: 976] [">> createTextShapesSimple: if still overlapping (976); tick: %d\n", nTick]
VCartesianAxis.cxx [line: 983] [">> createTextShapesSimple: Try auto-rotating the labels at 45 degrees (983); Tick: %d\n",nTick]
VCartesianAxis.cxx [line: 990] [">> createTextShapesSimple: if Tick interval is fixed. We have no choice but to remove labels. (990); tick: %d\n", nTick ]
```
- Reason: Get a better understanding of `VCartesianAxis::createTextShapesSimple`.
- Result: Got the following trace:
>> createTextShape: begin
>> createTextShapesSimple: begin
warn:chart2:10832:1:chart2/source/view/main/PropertyMapper.cxx:117: Exception caught. Type: N3com3sun4star3uno9ExceptionE, Message:
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: if no overlap allowed (973); tick: 3
>> createTextShapesSimple: if still overlapping (976); tick: 3
>> createTextShapesSimple: Try auto-rotating the labels at 45 degrees (983); Tick: 3
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: if no overlap allowed (973); tick: 3
>> createTextShapesSimple: if still overlapping (976); tick: 3
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: if no overlap allowed (973); tick: 4
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: if no overlap allowed (973); tick: 1
>> createTextShapesSimple: if no overlap allowed (973); tick: 2
>> createTextShapesSimple: if no overlap allowed (973); tick: 3
>> createTextShapesSimple: if no overlap allowed (973); tick: 4
>> createTextShapesSimple: if no overlap allowed (973); tick: 5
>> createTextShapesSimple: if no overlap allowed (973); tick: 6
>> createTextShapesSimple: if no overlap allowed (973); tick: 7
>> createTextShapesSimple: if no overlap allowed (973); tick: 8
>> createTextShapesSimple: if no overlap allowed (973); tick: 9
>> createTextShapesSimple: if no overlap allowed (973); tick: 10
warn:legacy.tools:10832:1:editeng/source/editeng/impedit3.cxx:1831: ImpBreakLine: Start >= End?
warn:chart2:10832:1:chart2/source/view/main/ShapeFactory.cxx:2134: Exception caught. Type: N3com3sun4star3uno9ExceptionE, Message:
warn:legacy.tools:10832:1:editeng/source/editeng/impedit3.cxx:1831: ImpBreakLine: Start >= End?
warn:chart2:10832:1:chart2/source/view/main/ShapeFactory.cxx:2134: Exception caught. Type: N3com3sun4star3uno9ExceptionE, Message:
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: if no overlap allowed (973); tick: 3
>> createTextShapesSimple: if still overlapping (976); tick: 3
>> createTextShapesSimple: Try auto-rotating the labels at 45 degrees (983); Tick: 3
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: if no overlap allowed (973); tick: 3
>> createTextShapesSimple: if still overlapping (976); tick: 3
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: if no overlap allowed (973); tick: 4
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: if no overlap allowed (973); tick: 1
>> createTextShapesSimple: if no overlap allowed (973); tick: 2
>> createTextShapesSimple: if no overlap allowed (973); tick: 3
>> createTextShapesSimple: if no overlap allowed (973); tick: 4
>> createTextShapesSimple: if no overlap allowed (973); tick: 5
>> createTextShapesSimple: if no overlap allowed (973); tick: 6
>> createTextShapesSimple: if no overlap allowed (973); tick: 7
>> createTextShapesSimple: if no overlap allowed (973); tick: 8
>> createTextShapesSimple: if no overlap allowed (973); tick: 9
>> createTextShapesSimple: if no overlap allowed (973); tick: 10
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: if no overlap allowed (973); tick: 1
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: if no overlap allowed (973); tick: 1
>> createTextShapesSimple: if no overlap allowed (973); tick: 2
>> createTextShapesSimple: if no overlap allowed (973); tick: 3
>> createTextShapesSimple: if no overlap allowed (973); tick: 4
>> createTextShapesSimple: if no overlap allowed (973); tick: 5
>> createTextShapesSimple: if no overlap allowed (973); tick: 6
>> createTextShapesSimple: if no overlap allowed (973); tick: 7
>> createTextShapesSimple: if no overlap allowed (973); tick: 8
>> createTextShapesSimple: if no overlap allowed (973); tick: 9
>> createTextShapesSimple: if no overlap allowed (973); tick: 10
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: if no overlap allowed (973); tick: 1
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: if no overlap allowed (973); tick: 1
>> createTextShapesSimple: if no overlap allowed (973); tick: 2
>> createTextShapesSimple: if no overlap allowed (973); tick: 3
>> createTextShapesSimple: if no overlap allowed (973); tick: 4
>> createTextShapesSimple: if no overlap allowed (973); tick: 5
>> createTextShapesSimple: if no overlap allowed (973); tick: 6
>> createTextShapesSimple: if no overlap allowed (973); tick: 7
>> createTextShapesSimple: if no overlap allowed (973); tick: 8
>> createTextShapesSimple: if no overlap allowed (973); tick: 9
>> createTextShapesSimple: if no overlap allowed (973); tick: 10
- Test: Set even more dynamic printf in `VCartesianAxis::createTextShapes` and in `VCartesianAxis::createTextShapesSimple`:
```cpp
VCartesianAxis.cxx [line: 657] [">> createTextShape: begin\n"]
VCartesianAxis.cxx [line: 665] [">> createTextShape: after `createTextShapeSimple` invocation."]
VCartesianAxis.cxx [line: 875] [">> createTextShapesSimple: begin\n"]
VCartesianAxis.cxx [line: 910] [">> createTextShapesSimple: for loop begin (910); tick: %d\n", nTick]
VCartesianAxis.cxx [line: 914] [">> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: %d\n", nTick]
VCartesianAxis.cxx [line: 918] [">> createTextShapesSimple: don't create labels for invisible ticks (continue) (918); tick: %d\n", nTick]
VCartesianAxis.cxx [line: 921] [">> createTextShapesSimple: no overlapping allowed (1) (921); tick: %d\n", nTick]
VCartesianAxis.cxx [line: 930] [">> createTextShapesSimple: This tick overlaps with its neighbor (930); tick: %d\n", nTick]
VCartesianAxis.cxx [line: 936] [">> createTextShapesSimple: tick interval is not fixed: interval is incremented and return false (936); tick: %d\n", nTick]
VCartesianAxis.cxx [line: 967] [">> createTextShapesSimple: single label created (!pTickInfo->xTextShape.is()) (continue) (967); tick: %d\n", nTick]
VCartesianAxis.cxx [line: 973] [">> createTextShapesSimple: no overlapping allowed (2) (973); tick: %d\n", nTick]
VCartesianAxis.cxx [line: 976] [">> createTextShapesSimple: if still overlapping (976); tick: %d\n", nTick]
VCartesianAxis.cxx [line: 983] [">> createTextShapesSimple: Try auto-rotating the labels at 45 degrees and return false (983); Tick: %d\n",nTick]
VCartesianAxis.cxx [line: 990] [">> createTextShapesSimple: if Tick interval is fixed. We have no choice but to remove labels. (continue) (990); tick: %d\n", nTick ]
VCartesianAxis.cxx [line: 1007] [">> createTextShapesSimple: end: return true (1007); tick: %d\n", nTick]
```
- Reason: Get a better understanding of `VCartesianAxis::createTextShapesSimple`.
- Result: Got the following trace:
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: for loop begin (910); tick: 0
>> createTextShapesSimple: for loop begin (910); tick: 1
>> createTextShapesSimple: for loop begin (910); tick: 2
>> createTextShapesSimple: end: return true (1007); tick: 3
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: for loop begin (910); tick: 0
>> createTextShapesSimple: for loop begin (910); tick: 1
>> createTextShapesSimple: for loop begin (910); tick: 2
>> createTextShapesSimple: end: return true (1007); tick: 3
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: for loop begin (910); tick: 0
>> createTextShapesSimple: for loop begin (910); tick: 1
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 1
>> createTextShapesSimple: This tick overlaps with its neighbor (930); tick: 1
>> createTextShapesSimple: tick interval is not fixed: interval is incremented and return false (936); tick: 1
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: for loop begin (910); tick: 0
>> createTextShapesSimple: for loop begin (910); tick: 1
>> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: 1
>> createTextShapesSimple: for loop begin (910); tick: 2
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 2
>> createTextShapesSimple: This tick overlaps with its neighbor (930); tick: 2
>> createTextShapesSimple: tick interval is not fixed: interval is incremented and return false (936); tick: 2
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: for loop begin (910); tick: 0
>> createTextShapesSimple: for loop begin (910); tick: 1
>> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: 1
>> createTextShapesSimple: for loop begin (910); tick: 2
>> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: 2
>> createTextShapesSimple: for loop begin (910); tick: 3
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 3
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 3
>> createTextShapesSimple: if still overlapping (976); tick: 3
>> createTextShapesSimple: Try auto-rotating the labels at 45 degrees and return false (983); Tick: 3
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: for loop begin (910); tick: 0
>> createTextShapesSimple: for loop begin (910); tick: 1
>> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: 1
>> createTextShapesSimple: for loop begin (910); tick: 2
>> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: 2
>> createTextShapesSimple: for loop begin (910); tick: 3
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 3
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 3
>> createTextShapesSimple: if still overlapping (976); tick: 3
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: for loop begin (910); tick: 0
>> createTextShapesSimple: for loop begin (910); tick: 1
>> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: 1
>> createTextShapesSimple: for loop begin (910); tick: 2
>> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: 2
>> createTextShapesSimple: for loop begin (910); tick: 3
>> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: 3
>> createTextShapesSimple: for loop begin (910); tick: 4
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 4
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 4
>> createTextShapesSimple: for loop begin (910); tick: 5
>> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: 5
>> createTextShapesSimple: for loop begin (910); tick: 6
>> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: 6
>> createTextShapesSimple: end: return true (1007); tick: 7
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: for loop begin (910); tick: 0
>> createTextShapesSimple: for loop begin (910); tick: 1
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 1
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 1
>> createTextShapesSimple: for loop begin (910); tick: 2
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 2
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 2
>> createTextShapesSimple: for loop begin (910); tick: 3
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 3
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 3
>> createTextShapesSimple: for loop begin (910); tick: 4
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 4
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 4
>> createTextShapesSimple: for loop begin (910); tick: 5
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 5
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 5
>> createTextShapesSimple: for loop begin (910); tick: 6
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 6
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 6
>> createTextShapesSimple: for loop begin (910); tick: 7
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 7
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 7
>> createTextShapesSimple: for loop begin (910); tick: 8
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 8
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 8
>> createTextShapesSimple: for loop begin (910); tick: 9
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 9
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 9
>> createTextShapesSimple: for loop begin (910); tick: 10
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 10
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 10
>> createTextShapesSimple: end: return true (1007); tick: 11
The part related to the labels for the horizontal axes is:
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: for loop begin (910); tick: 0
>> createTextShapesSimple: for loop begin (910); tick: 1
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 1
>> createTextShapesSimple: This tick overlaps with its neighbor (930); tick: 1
>> createTextShapesSimple: tick interval is not fixed: interval is incremented and return false (936); tick: 1
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: for loop begin (910); tick: 0
>> createTextShapesSimple: for loop begin (910); tick: 1
>> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: 1
>> createTextShapesSimple: for loop begin (910); tick: 2
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 2
>> createTextShapesSimple: This tick overlaps with its neighbor (930); tick: 2
>> createTextShapesSimple: tick interval is not fixed: interval is incremented and return false (936); tick: 2
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: for loop begin (910); tick: 0
>> createTextShapesSimple: for loop begin (910); tick: 1
>> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: 1
>> createTextShapesSimple: for loop begin (910); tick: 2
>> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: 2
>> createTextShapesSimple: for loop begin (910); tick: 3
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 3
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 3
>> createTextShapesSimple: if still overlapping (976); tick: 3
>> createTextShapesSimple: Try auto-rotating the labels at 45 degrees and return false (983); Tick: 3
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: for loop begin (910); tick: 0
>> createTextShapesSimple: for loop begin (910); tick: 1
>> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: 1
>> createTextShapesSimple: for loop begin (910); tick: 2
>> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: 2
>> createTextShapesSimple: for loop begin (910); tick: 3
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 3
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 3
>> createTextShapesSimple: if still overlapping (976); tick: 3
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: for loop begin (910); tick: 0
>> createTextShapesSimple: for loop begin (910); tick: 1
>> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: 1
>> createTextShapesSimple: for loop begin (910); tick: 2
>> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: 2
>> createTextShapesSimple: for loop begin (910); tick: 3
>> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: 3
>> createTextShapesSimple: for loop begin (910); tick: 4
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 4
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 4
>> createTextShapesSimple: for loop begin (910); tick: 5
>> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: 5
>> createTextShapesSimple: for loop begin (910); tick: 6
>> createTextShapesSimple: don't create labels which does not fit into the rhythm (continue) (914); tick: 6
>> createTextShapesSimple: end: return true (1007); tick: 7
- Note: each set of label shapes is created twice (or at least we got a duplicate tracing for each set of labels).
- Test: Using the same set of dynamic printf set in the previous test I enlarged horizontally the bar graph enough to get all labels for the horizontal axes displayed correctly:
- Result: Got the following trace (reported only the part related to the labels for the horizontal axes (the only difference)):
>> createTextShapesSimple: for loop begin (910); tick: 0
>> createTextShapesSimple: for loop begin (910); tick: 1
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 1
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 1
>> createTextShapesSimple: if still overlapping (976); tick: 1
>> createTextShapesSimple: Try auto-rotating the labels at 45 degrees and return false (983); Tick: 1
>> createTextShape: begin
>> createTextShapesSimple: begin
>> createTextShapesSimple: for loop begin (910); tick: 0
>> createTextShapesSimple: for loop begin (910); tick: 1
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 1
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 1
>> createTextShapesSimple: for loop begin (910); tick: 2
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 2
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 2
>> createTextShapesSimple: for loop begin (910); tick: 3
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 3
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 3
>> createTextShapesSimple: for loop begin (910); tick: 4
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 4
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 4
>> createTextShapesSimple: for loop begin (910); tick: 5
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 5
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 5
>> createTextShapesSimple: for loop begin (910); tick: 6
>> createTextShapesSimple: no overlapping allowed (1) (921); tick: 6
>> createTextShapesSimple: no overlapping allowed (2) (973); tick: 6
>> createTextShapesSimple: end: return true (1007); tick: 7
- Note: The auto-rotation is triggered from tick 1 instead of tick 3, the "tick overlaps with its neighborhood" test is false, then no tentative to increase the tick interval is performed.
- Test: modified the following code fragment of method `VCartesianAxis::createTextShapesSimple`:
```cpp
if( pLastVisibleNeighbourTickInfo && !rAxisLabelProperties.bOverlapAllowed )
{
// Overlapping is not allowed. If the label overlaps with its
// neighbering label, try increasing the tick interval (or rhythm
// as it's called) and start over.
--> if( false && lcl_doesShapeOverlapWithTickmark( pLastVisibleNeighbourTickInfo->xTextShape
, rAxisLabelProperties.fRotationAngleDegree
, pTickInfo->aTickScreenPosition
, bIsHorizontalAxis, bIsVerticalAxis ) )
{
// This tick overlaps with its neighbor. Increment the visible
// tick intervals (if that's allowed) and start over.
if( rAxisLabelProperties.bRhythmIsFix )
continue;
rAxisLabelProperties.nRhythm++;
removeShapesAtWrongRhythm( rTickIter, rAxisLabelProperties.nRhythm, nTick, xTarget );
return false;
}
}
```
- Reason: The test is performed in order to get the labels drawn even if they are overlapping.
- Result: Impress shows only labels for tick 0, 2, 4, 6. They are non-overlapping.
- Note: Increasing horizontal size of a small amount is enough for getting all labels displayed.
- Note: In order to make space for labels the bar graph is enough smaller. In PowerPoint this does not happen because the second label (the label with the greatest length) is truncated ("Apps requiring a mobile connection to ...").
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment