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 <editeng/flditem.hxx>
21 
22 #include <svx/fmpage.hxx>
23 #include <svx/svdobj.hxx>
24 #include <svx/svdpagv.hxx>
25 #include <svx/ImageMapInfo.hxx>
26 #include <vcl/imapobj.hxx>
27 #include <vcl/help.hxx>
28 #include <tools/urlobj.hxx>
29 #include <sfx2/sfxhelp.hxx>
30 
31 #include <AccessibleDocument.hxx>
32 #include <com/sun/star/accessibility/XAccessible.hpp>
33 
34 #include <gridwin.hxx>
35 #include <viewdata.hxx>
36 #include <drawview.hxx>
37 #include <drwlayer.hxx>
38 #include <document.hxx>
39 #include <notemark.hxx>
40 #include <chgtrack.hxx>
41 #include <chgviset.hxx>
42 #include <dbfunc.hxx>
43 #include <userdat.hxx>
44 #include <postit.hxx>
45 #include <global.hxx>
46 
ShowNoteMarker(SCCOL nPosX,SCROW nPosY,bool bKeyboard)47 bool ScGridWindow::ShowNoteMarker( SCCOL nPosX, SCROW nPosY, bool bKeyboard )
48 {
49     bool bDone = false;
50 
51     ScDocument& rDoc = mrViewData.GetDocument();
52     SCTAB       nTab = mrViewData.GetTabNo();
53     ScAddress   aCellPos( nPosX, nPosY, nTab );
54 
55     OUString aTrackText;
56     bool bLeftEdge = false;
57 
58     // change tracking
59 
60     ScChangeTrack* pTrack = rDoc.GetChangeTrack();
61     ScChangeViewSettings* pSettings = rDoc.GetChangeViewSettings();
62     if ( pTrack && pTrack->GetFirst() && pSettings && pSettings->ShowChanges())
63     {
64         const ScChangeAction* pFound = nullptr;
65         const ScChangeAction* pFoundContent = nullptr;
66         const ScChangeAction* pFoundMove = nullptr;
67         const ScChangeAction* pAction = pTrack->GetFirst();
68         while (pAction)
69         {
70             if ( pAction->IsVisible() &&
71                  ScViewUtil::IsActionShown( *pAction, *pSettings, rDoc ) )
72             {
73                 ScChangeActionType eType = pAction->GetType();
74                 const ScBigRange& rBig = pAction->GetBigRange();
75                 if ( rBig.aStart.Tab() == nTab )
76                 {
77                     ScRange aRange = rBig.MakeRange();
78 
79                     if ( eType == SC_CAT_DELETE_ROWS )
80                         aRange.aEnd.SetRow( aRange.aStart.Row() );
81                     else if ( eType == SC_CAT_DELETE_COLS )
82                         aRange.aEnd.SetCol( aRange.aStart.Col() );
83 
84                     if ( aRange.In( aCellPos ) )
85                     {
86                         pFound = pAction;       // the last one wins
87                         switch ( eType )
88                         {
89                             case SC_CAT_CONTENT :
90                                 pFoundContent = pAction;
91                             break;
92                             case SC_CAT_MOVE :
93                                 pFoundMove = pAction;
94                             break;
95                             default:
96                             {
97                                 // added to avoid warnings
98                             }
99                         }
100                     }
101                 }
102                 if ( eType == SC_CAT_MOVE )
103                 {
104                     ScRange aRange =
105                         static_cast<const ScChangeActionMove*>(pAction)->
106                         GetFromRange().MakeRange();
107                     if ( aRange.In( aCellPos ) )
108                     {
109                         pFound = pAction;
110                     }
111                 }
112             }
113             pAction = pAction->GetNext();
114         }
115 
116         if ( pFound )
117         {
118             if ( pFoundContent && pFound->GetType() != SC_CAT_CONTENT )
119                 pFound = pFoundContent;     // content wins
120             if ( pFoundMove && pFound->GetType() != SC_CAT_MOVE &&
121                     pFoundMove->GetActionNumber() >
122                     pFound->GetActionNumber() )
123                 pFound = pFoundMove;        // move wins
124 
125             // for deleted columns: Arrow on the left side of the cell
126             if ( pFound->GetType() == SC_CAT_DELETE_COLS )
127                 bLeftEdge = true;
128 
129             DateTime aDT = pFound->GetDateTime();
130             aTrackText  = pFound->GetUser()
131                         + ", "
132                         + ScGlobal::getLocaleDataPtr()->getDate(aDT)
133                         + " "
134                         + ScGlobal::getLocaleDataPtr()->getTime(aDT)
135                         + ":\n";
136             OUString aComStr=pFound->GetComment();
137             if(!aComStr.isEmpty())
138             {
139                 aTrackText += aComStr + "\n( ";
140             }
141             OUString aTmp;
142             pFound->GetDescription(aTmp, rDoc);
143             aTrackText += aTmp;
144             if(!aComStr.isEmpty())
145             {
146                 aTrackText += ")";
147             }
148         }
149     }
150 
151     // Note, only if it is not already displayed on the Drawing Layer:
152     const ScPostIt* pNote = rDoc.GetNote( aCellPos );
153     if ( (!aTrackText.isEmpty()) || (pNote && !pNote->IsCaptionShown()) )
154     {
155         bool bNew = true;
156         bool bFast = false;
157         if (mpNoteMarker) // A note already shown
158         {
159             if (mpNoteMarker->GetDocPos() == aCellPos)
160                 bNew = false; // then stop
161             else
162                 bFast = true; // otherwise, at once
163 
164             //  marker which was shown for ctrl-F1 isn't removed by mouse events
165             if (mpNoteMarker->IsByKeyboard() && !bKeyboard)
166                 bNew = false;
167         }
168         if (bNew)
169         {
170             if (bKeyboard)
171                 bFast = true; // keyboard also shows the marker immediately
172 
173             mpNoteMarker.reset();
174 
175             bool bHSplit = mrViewData.GetHSplitMode() != SC_SPLIT_NONE;
176             bool bVSplit = mrViewData.GetVSplitMode() != SC_SPLIT_NONE;
177 
178             vcl::Window* pLeft = mrViewData.GetView()->GetWindowByPos( bVSplit ? SC_SPLIT_TOPLEFT : SC_SPLIT_BOTTOMLEFT );
179             vcl::Window* pRight = bHSplit ? mrViewData.GetView()->GetWindowByPos( bVSplit ? SC_SPLIT_TOPRIGHT : SC_SPLIT_BOTTOMRIGHT ) : nullptr;
180             vcl::Window* pBottom = bVSplit ? mrViewData.GetView()->GetWindowByPos( SC_SPLIT_BOTTOMLEFT ) : nullptr;
181             vcl::Window* pDiagonal = (bHSplit && bVSplit) ? mrViewData.GetView()->GetWindowByPos( SC_SPLIT_BOTTOMRIGHT ) : nullptr;
182             OSL_ENSURE( pLeft, "ScGridWindow::ShowNoteMarker - missing top-left grid window" );
183 
184             /*  If caption is shown from right or bottom windows, adjust
185                 mapmode to include size of top-left window. */
186             MapMode aMapMode = GetDrawMapMode( true );
187             Size aLeftSize = pLeft->PixelToLogic( pLeft->GetOutputSizePixel(), aMapMode );
188             Point aOrigin = aMapMode.GetOrigin();
189             if( (this == pRight) || (this == pDiagonal) )
190                 aOrigin.AdjustX(aLeftSize.Width() );
191             if( (this == pBottom) || (this == pDiagonal) )
192                 aOrigin.AdjustY(aLeftSize.Height() );
193             aMapMode.SetOrigin( aOrigin );
194 
195             mpNoteMarker.reset(new ScNoteMarker(pLeft, pRight, pBottom, pDiagonal,
196                                                 &rDoc, aCellPos, aTrackText,
197                                                 aMapMode, bLeftEdge, bFast, bKeyboard));
198         }
199 
200         bDone = true;       // something is shown (old or new)
201     }
202 
203     return bDone;
204 }
205 
RequestHelp(const HelpEvent & rHEvt)206 void ScGridWindow::RequestHelp(const HelpEvent& rHEvt)
207 {
208     bool bDone = false;
209     bool bHelpEnabled = bool(rHEvt.GetMode() & ( HelpEventMode::BALLOON | HelpEventMode::QUICK ));
210     SdrView* pDrView = mrViewData.GetScDrawView();
211     bool bDrawTextEdit = false;
212     if (pDrView)
213         bDrawTextEdit = pDrView->IsTextEdit();
214     //  notes or change tracking
215     if ( bHelpEnabled && !bDrawTextEdit )
216     {
217         Point       aPosPixel = ScreenToOutputPixel( rHEvt.GetMousePosPixel() );
218         SCCOL nPosX;
219         SCROW nPosY;
220         mrViewData.GetPosFromPixel( aPosPixel.X(), aPosPixel.Y(), eWhich, nPosX, nPosY );
221 
222         if ( ShowNoteMarker( nPosX, nPosY, false ) )
223         {
224             Window::RequestHelp( rHEvt );   // turn off old Tip/Balloon
225             bDone = true;
226         }
227     }
228 
229     if (!bDone && mpNoteMarker)
230     {
231         if (mpNoteMarker->IsByKeyboard())
232         {
233             //  marker which was shown for ctrl-F1 isn't removed by mouse events
234         }
235         else
236         {
237             mpNoteMarker.reset();
238         }
239     }
240 
241     //  Image-Map / Text-URL
242 
243     if ( bHelpEnabled && !bDone && !nButtonDown )       // only without pressed button
244     {
245         OUString aHelpText;
246         tools::Rectangle aPixRect;
247         Point aPosPixel = ScreenToOutputPixel( rHEvt.GetMousePosPixel() );
248 
249         if ( pDrView )                                      // URL / Image-Map
250         {
251             SdrViewEvent aVEvt;
252             MouseEvent aMEvt( aPosPixel, 1, MouseEventModifiers::NONE, MOUSE_LEFT );
253             SdrHitKind eHit = pDrView->PickAnything( aMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt );
254 
255             if ( eHit != SdrHitKind::NONE && aVEvt.pObj != nullptr )
256             {
257                 // URL for IMapObject below Pointer is help text
258                 if ( SvxIMapInfo::GetIMapInfo( aVEvt.pObj ) )
259                 {
260                     Point aLogicPos = PixelToLogic( aPosPixel );
261                     IMapObject* pIMapObj = SvxIMapInfo::GetHitIMapObject(
262                                                     aVEvt.pObj, aLogicPos, GetOutDev() );
263 
264                     if ( pIMapObj )
265                     {
266                         // For image maps show the description, if available
267                         aHelpText = pIMapObj->GetAltText();
268                         if (aHelpText.isEmpty())
269                             aHelpText = SfxHelp::GetURLHelpText(pIMapObj->GetURL());
270                         aPixRect = LogicToPixel(aVEvt.pObj->GetLogicRect());
271                     }
272                 }
273                 // URL in shape text or at shape itself (URL in text overrides object URL)
274                 if ( aHelpText.isEmpty() )
275                 {
276                     if( aVEvt.eEvent == SdrEventKind::ExecuteUrl )
277                     {
278                         aHelpText = SfxHelp::GetURLHelpText(aVEvt.pURLField->GetURL());
279                         aPixRect = LogicToPixel(aVEvt.pObj->GetLogicRect());
280                     }
281                     else
282                     {
283                         SdrPageView* pPV = nullptr;
284                         Point aMDPos = PixelToLogic( aPosPixel );
285                         SdrObject* pObj = pDrView->PickObj(aMDPos, pDrView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER);
286                         if (pObj)
287                         {
288                             if ( pObj->IsGroupObject() )
289                             {
290                                     SdrObject* pHit = pDrView->PickObj(aMDPos, pDrView->getHitTolLog(), pPV, SdrSearchOptions::DEEP);
291                                     if (pHit)
292                                         pObj = pHit;
293                             }
294                             ScMacroInfo* pInfo = ScDrawLayer::GetMacroInfo( pObj );
295                             if ( pInfo && (pInfo->GetHlink().getLength() > 0) )
296                             {
297                                 aPixRect = LogicToPixel(aVEvt.pObj->GetLogicRect());
298                                 aHelpText = SfxHelp::GetURLHelpText(pInfo->GetHlink());
299                             }
300                         }
301                     }
302                 }
303             }
304         }
305 
306         if ( aHelpText.isEmpty() )                                 // Text-URL
307         {
308             OUString aUrl;
309             if ( GetEditUrl( aPosPixel, nullptr, &aUrl ) )
310             {
311                 aHelpText = SfxHelp::GetURLHelpText(
312                     INetURLObject::decode(aUrl, INetURLObject::DecodeMechanism::Unambiguous));
313 
314                 ScDocument& rDoc = mrViewData.GetDocument();
315                 SCCOL nPosX;
316                 SCROW nPosY;
317                 SCTAB       nTab = mrViewData.GetTabNo();
318                 mrViewData.GetPosFromPixel( aPosPixel.X(), aPosPixel.Y(), eWhich, nPosX, nPosY );
319                 const ScPatternAttr* pPattern = rDoc.GetPattern( nPosX, nPosY, nTab );
320 
321                 // bForceToTop = sal_False, use the cell's real position
322                 aPixRect = mrViewData.GetEditArea( eWhich, nPosX, nPosY, this, pPattern, false );
323             }
324         }
325 
326         if ( !aHelpText.isEmpty() )
327         {
328             tools::Rectangle aScreenRect(OutputToScreenPixel(aPixRect.TopLeft()),
329                                          OutputToScreenPixel(aPixRect.BottomRight()));
330 
331             if ( rHEvt.GetMode() & HelpEventMode::BALLOON )
332                 Help::ShowBalloon(this,rHEvt.GetMousePosPixel(), aScreenRect, aHelpText);
333             else if ( rHEvt.GetMode() & HelpEventMode::QUICK )
334                 Help::ShowQuickHelp(this,aScreenRect, aHelpText);
335 
336             bDone = true;
337         }
338     }
339 
340     // basic controls
341 
342     if ( pDrView && bHelpEnabled && !bDone )
343     {
344         SdrPageView* pPV = pDrView->GetSdrPageView();
345         OSL_ENSURE( pPV, "SdrPageView* is NULL" );
346         if (pPV)
347             bDone = FmFormPage::RequestHelp( this, pDrView, rHEvt );
348     }
349 
350     // If QuickHelp for AutoFill is shown, do not allow it to be removed
351 
352     if ( nMouseStatus == SC_GM_TABDOWN && mrViewData.GetRefType() == SC_REFTYPE_FILL &&
353             Help::IsQuickHelpEnabled() )
354         bDone = true;
355 
356     if (!bDone)
357         Window::RequestHelp( rHEvt );
358 }
359 
IsMyModel(const SdrEditView * pSdrView)360 bool ScGridWindow::IsMyModel(const SdrEditView* pSdrView)
361 {
362     return pSdrView &&
363             pSdrView->GetModel() == mrViewData.GetDocument().GetDrawLayer();
364 }
365 
HideNoteMarker()366 void ScGridWindow::HideNoteMarker()
367 {
368     mpNoteMarker.reset();
369 }
370 
371 css::uno::Reference< css::accessibility::XAccessible >
CreateAccessible()372     ScGridWindow::CreateAccessible()
373 {
374     css::uno::Reference< css::accessibility::XAccessible > xAcc= GetAccessible(false);
375     if (xAcc.is())
376     {
377         return xAcc;
378     }
379 
380     rtl::Reference<ScAccessibleDocument> pAccessibleDocument =
381         new ScAccessibleDocument(GetAccessibleParentWindow()->GetAccessible(),
382             mrViewData.GetViewShell(), eWhich);
383     pAccessibleDocument->PreInit();
384 
385     xAcc = pAccessibleDocument;
386     SetAccessible(xAcc);
387 
388     pAccessibleDocument->Init();
389 
390     return xAcc;
391 }
392 
393 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
394