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