1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <svx/svdundo.hxx>
21 #include <svx/svdocapt.hxx>
22 #include <sfx2/bindings.hxx>
23 #include <sfx2/dispatch.hxx>
24 #include <vcl/msgbox.hxx>
25 #include <svl/zforlist.hxx>
26 #include <svl/zformat.hxx>
27 #include <editeng/editview.hxx>
29 #include "viewfunc.hxx"
30 #include "detfunc.hxx"
31 #include "detdata.hxx"
32 #include "viewdata.hxx"
33 #include "drwlayer.hxx"
35 #include "undocell.hxx"
37 #include "docfunc.hxx"
38 #include "globstr.hrc"
41 #include "reftokenhelper.hxx"
42 #include "externalrefmgr.hxx"
43 #include "formulacell.hxx"
44 #include "markdata.hxx"
45 #include "drawview.hxx"
46 #include "globalnames.hxx"
47 #include "inputhdl.hxx"
53 void ScViewFunc::DetectiveAddPred()
55 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
56 pDocSh
->GetDocFunc().DetectiveAddPred( GetViewData().GetCurPos() );
57 RecalcPPT(); //! use broadcast in DocFunc instead?
60 void ScViewFunc::DetectiveDelPred()
62 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
63 pDocSh
->GetDocFunc().DetectiveDelPred( GetViewData().GetCurPos() );
67 void ScViewFunc::DetectiveAddSucc()
69 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
70 pDocSh
->GetDocFunc().DetectiveAddSucc( GetViewData().GetCurPos() );
74 void ScViewFunc::DetectiveDelSucc()
76 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
77 pDocSh
->GetDocFunc().DetectiveDelSucc( GetViewData().GetCurPos() );
81 void ScViewFunc::DetectiveAddError()
83 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
84 pDocSh
->GetDocFunc().DetectiveAddError( GetViewData().GetCurPos() );
88 void ScViewFunc::DetectiveDelAll()
90 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
91 pDocSh
->GetDocFunc().DetectiveDelAll( GetViewData().GetTabNo() );
95 void ScViewFunc::DetectiveMarkInvalid()
97 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
98 pDocSh
->GetDocFunc().DetectiveMarkInvalid( GetViewData().GetTabNo() );
102 void ScViewFunc::DetectiveRefresh()
104 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
105 pDocSh
->GetDocFunc().DetectiveRefresh();
109 static void lcl_jumpToRange(const ScRange
& rRange
, ScViewData
* pView
, ScDocument
* pDoc
)
111 OUString
aAddrText(rRange
.Format(SCR_ABS_3D
, pDoc
));
112 SfxStringItem
aPosItem(SID_CURRENTCELL
, aAddrText
);
113 SfxBoolItem
aUnmarkItem(FN_PARAM_1
, true); // remove existing selection
114 pView
->GetDispatcher().Execute(
115 SID_CURRENTCELL
, SfxCallMode::SYNCHRON
| SfxCallMode::RECORD
,
116 &aPosItem
, &aUnmarkItem
, 0L);
119 void ScViewFunc::MarkAndJumpToRanges(const ScRangeList
& rRanges
)
121 ScViewData
& rView
= GetViewData();
122 ScDocShell
* pDocSh
= rView
.GetDocShell();
124 ScRangeList
aRanges(rRanges
);
125 ScRangeList aRangesToMark
;
126 ScAddress aCurPos
= rView
.GetCurPos();
127 size_t ListSize
= aRanges
.size();
128 for ( size_t i
= 0; i
< ListSize
; ++i
)
130 const ScRange
* p
= aRanges
[i
];
131 // Collect only those ranges that are on the same sheet as the current
133 if (p
->aStart
.Tab() == aCurPos
.Tab())
134 aRangesToMark
.Append(*p
);
137 if (aRangesToMark
.empty())
140 // Jump to the first range of all precedent ranges.
141 const ScRange
* p
= aRangesToMark
.front();
142 lcl_jumpToRange(*p
, &rView
, &pDocSh
->GetDocument());
144 ListSize
= aRangesToMark
.size();
145 for ( size_t i
= 0; i
< ListSize
; ++i
)
147 p
= aRangesToMark
[i
];
148 MarkRange(*p
, false, true);
152 void ScViewFunc::DetectiveMarkPred()
154 ScViewData
& rView
= GetViewData();
155 ScDocShell
* pDocSh
= rView
.GetDocShell();
156 ScDocument
& rDoc
= pDocSh
->GetDocument();
157 ScMarkData
& rMarkData
= rView
.GetMarkData();
158 ScAddress aCurPos
= rView
.GetCurPos();
160 if (rMarkData
.IsMarked() || rMarkData
.IsMultiMarked())
161 rMarkData
.FillRangeListWithMarks(&aRanges
, false);
163 aRanges
.Append(aCurPos
);
165 vector
<ScTokenRef
> aRefTokens
;
166 pDocSh
->GetDocFunc().DetectiveCollectAllPreds(aRanges
, aRefTokens
);
168 if (aRefTokens
.empty())
169 // No precedents found. Nothing to do.
172 ScTokenRef p
= aRefTokens
.front();
173 if (ScRefTokenHelper::isExternalRef(p
))
175 // This is external. Open the external document if available, and
176 // jump to the destination.
178 sal_uInt16 nFileId
= p
->GetIndex();
179 ScExternalRefManager
* pRefMgr
= rDoc
.GetExternalRefManager();
180 const OUString
* pPath
= pRefMgr
->getExternalFileName(nFileId
);
183 if (pPath
&& ScRefTokenHelper::getRangeFromToken(aRange
, p
, aCurPos
, true))
185 OUString aTabName
= p
->GetString().getString();
189 aBuf
.append(aTabName
);
192 OUString
aRangeStr(aRange
.Format(SCA_VALID
));
193 aBuf
.append(aRangeStr
);
195 ScGlobal::OpenURL(aBuf
.makeStringAndClear(), OUString());
202 ScRefTokenHelper::getRangeFromToken(aRange
, p
, aCurPos
, false);
203 if (aRange
.aStart
.Tab() != aCurPos
.Tab())
205 // The first precedent range is on a different sheet. Jump to it
206 // immediately and forget the rest.
207 lcl_jumpToRange(aRange
, &rView
, &rDoc
);
212 ScRangeList aDestRanges
;
213 ScRefTokenHelper::getRangeListFromTokens(aDestRanges
, aRefTokens
, aCurPos
);
214 MarkAndJumpToRanges(aDestRanges
);
217 void ScViewFunc::DetectiveMarkSucc()
219 ScViewData
& rView
= GetViewData();
220 ScDocShell
* pDocSh
= rView
.GetDocShell();
221 ScMarkData
& rMarkData
= rView
.GetMarkData();
222 ScAddress aCurPos
= rView
.GetCurPos();
224 if (rMarkData
.IsMarked() || rMarkData
.IsMultiMarked())
225 rMarkData
.FillRangeListWithMarks(&aRanges
, false);
227 aRanges
.Append(aCurPos
);
229 vector
<ScTokenRef
> aRefTokens
;
230 pDocSh
->GetDocFunc().DetectiveCollectAllSuccs(aRanges
, aRefTokens
);
232 if (aRefTokens
.empty())
233 // No dependents found. Nothing to do.
236 ScRangeList aDestRanges
;
237 ScRefTokenHelper::getRangeListFromTokens(aDestRanges
, aRefTokens
, aCurPos
);
238 MarkAndJumpToRanges(aDestRanges
);
241 /** Insert date or time into current cell.
243 If cell is in input or edit mode, insert date/time at cursor position, else
244 create a date or time or date+time cell as follows:
246 - key date on time cell => current date + time of cell => date+time formatted cell
247 - unless time cell was empty or 00:00 time => current date => date formatted cell
248 - key date on date+time cell => current date + 00:00 time => date+time formatted cell
249 - unless date was current date => current date => date formatted cell
250 - key date on other cell => current date => date formatted cell
251 - key time on date cell => date of cell + current time => date+time formatted cell
252 - unless date cell was empty => current time => time formatted cell
253 - key time on date+time cell => current time => time formatted cell
254 - unless cell was empty => current date+time => date+time formatted cell
255 - key time on other cell => current time => time formatted cell
257 void ScViewFunc::InsertCurrentTime(short nReqFmt
, const OUString
& rUndoStr
)
259 ScViewData
& rViewData
= GetViewData();
261 ScInputHandler
* pInputHdl
= SC_MOD()->GetInputHdl( rViewData
.GetViewShell());
262 bool bInputMode
= (pInputHdl
&& pInputHdl
->IsInputMode());
264 ScDocShell
* pDocSh
= rViewData
.GetDocShell();
265 ScDocument
& rDoc
= pDocSh
->GetDocument();
266 ScAddress aCurPos
= rViewData
.GetCurPos();
267 const sal_uInt32 nCurNumFormat
= rDoc
.GetNumberFormat(aCurPos
);
268 SvNumberFormatter
* pFormatter
= rDoc
.GetFormatTable();
269 const SvNumberformat
* pCurNumFormatEntry
= pFormatter
->GetEntry(nCurNumFormat
);
270 const short nCurNumFormatType
= (pCurNumFormatEntry
?
271 (pCurNumFormatEntry
->GetType() & ~css::util::NumberFormat::DEFINED
) : css::util::NumberFormat::UNDEFINED
);
276 sal_uInt32 nFormat
= 0;
279 case css::util::NumberFormat::DATE
:
281 Date
aActDate( Date::SYSTEM
);
282 fVal
= aActDate
- *pFormatter
->GetNullDate();
283 if (nCurNumFormatType
== css::util::NumberFormat::DATE
)
284 nFormat
= nCurNumFormat
;
287 case css::util::NumberFormat::TIME
:
289 tools::Time
aActTime( tools::Time::SYSTEM
);
290 fVal
= aActTime
.GetTimeInDays();
291 if (nCurNumFormatType
== css::util::NumberFormat::TIME
)
292 nFormat
= nCurNumFormat
;
296 assert(!"unhandled current date/time request");
297 nReqFmt
= css::util::NumberFormat::DATETIME
;
299 case css::util::NumberFormat::DATETIME
:
301 DateTime
aActDateTime( DateTime::SYSTEM
);
302 fVal
= aActDateTime
- DateTime( *pFormatter
->GetNullDate());
303 if (nCurNumFormatType
== css::util::NumberFormat::DATETIME
)
304 nFormat
= nCurNumFormat
;
311 const LanguageType nLang
= (pCurNumFormatEntry
? pCurNumFormatEntry
->GetLanguage() : ScGlobal::eLnge
);
312 nFormat
= pFormatter
->GetStandardFormat( nReqFmt
, nLang
);
313 // This would return a more precise format with seconds and 100th
314 // seconds for a time request.
315 //nFormat = pFormatter->GetStandardFormat( fVal, nFormat, nReqFmt, nLang);
319 pFormatter
->GetOutputString( fVal
, nFormat
, aString
, &pColor
);
321 pInputHdl
->DataChanging();
322 EditView
* pTopView
= pInputHdl
->GetTopView();
324 pTopView
->InsertText( aString
);
325 EditView
* pTableView
= pInputHdl
->GetTableView();
327 pTableView
->InsertText( aString
);
328 pInputHdl
->DataChanged( false, true);
332 bool bForceReqFmt
= false;
333 const double fCell
= rDoc
.GetValue( aCurPos
);
334 // Combine requested date/time stamp with existing cell time/date, if any.
337 case css::util::NumberFormat::DATE
:
338 switch (nCurNumFormatType
)
340 case css::util::NumberFormat::TIME
:
341 // An empty cell formatted as time (or 00:00 time) shall
342 // not result in the current date with 00:00 time, but only
345 nReqFmt
= css::util::NumberFormat::DATETIME
;
347 case css::util::NumberFormat::DATETIME
:
349 // Force to only date if the existing date+time is the
350 // current date. This way inserting current date twice
351 // on an existing date+time cell can be used to force
352 // date, which otherwise would only be possible by
353 // applying a date format.
354 double fDate
= rtl::math::approxFloor( fCell
);
355 if (fDate
== (Date( Date::SYSTEM
) - *pFormatter
->GetNullDate()))
361 case css::util::NumberFormat::TIME
:
362 switch (nCurNumFormatType
)
364 case css::util::NumberFormat::DATE
:
365 // An empty cell formatted as date shall not result in the
366 // null date and current time, but only in current time.
368 nReqFmt
= css::util::NumberFormat::DATETIME
;
370 case css::util::NumberFormat::DATETIME
:
371 // Requesting current time on an empty date+time cell
372 // inserts both current date+time.
374 nReqFmt
= css::util::NumberFormat::DATETIME
;
377 // Add current time to an existing date+time where time is
378 // zero and date is current date, else force time only.
379 double fDate
= rtl::math::approxFloor( fCell
);
380 double fTime
= fCell
- fDate
;
381 if (fTime
== 0.0 && fDate
== (Date( Date::SYSTEM
) - *pFormatter
->GetNullDate()))
382 nReqFmt
= css::util::NumberFormat::DATETIME
;
390 assert(!"unhandled current date/time request");
391 nReqFmt
= css::util::NumberFormat::DATETIME
;
393 case css::util::NumberFormat::DATETIME
:
399 case css::util::NumberFormat::DATE
:
401 Date
aActDate( Date::SYSTEM
);
402 fVal
= aActDate
- *pFormatter
->GetNullDate();
405 case css::util::NumberFormat::TIME
:
407 tools::Time
aActTime( tools::Time::SYSTEM
);
408 fVal
= aActTime
.GetTimeInDays();
411 case css::util::NumberFormat::DATETIME
:
412 switch (nCurNumFormatType
)
414 case css::util::NumberFormat::DATE
:
416 double fDate
= rtl::math::approxFloor( fCell
);
417 tools::Time
aActTime( tools::Time::SYSTEM
);
418 fVal
= fDate
+ aActTime
.GetTimeInDays();
421 case css::util::NumberFormat::TIME
:
423 double fTime
= fCell
- rtl::math::approxFloor( fCell
);
424 Date
aActDate( Date::SYSTEM
);
425 fVal
= (aActDate
- *pFormatter
->GetNullDate()) + fTime
;
430 DateTime
aActDateTime( DateTime::SYSTEM
);
431 // Converting the null date to DateTime forces the
432 // correct operator-() to be used, resulting in a
433 // fractional date+time instead of only date value.
434 fVal
= aActDateTime
- DateTime( *pFormatter
->GetNullDate());
440 ::svl::IUndoManager
* pUndoMgr
= pDocSh
->GetUndoManager();
441 pUndoMgr
->EnterListAction(rUndoStr
, rUndoStr
);
443 pDocSh
->GetDocFunc().SetValueCell(aCurPos
, fVal
, true);
445 // Set the new cell format only when it differs from the current cell
446 // format type. Preserve a date+time format unless we force a format
448 if (bForceReqFmt
|| (nReqFmt
!= nCurNumFormatType
&& nCurNumFormatType
!= css::util::NumberFormat::DATETIME
))
449 SetNumberFormat(nReqFmt
);
451 rViewData
.UpdateInputHandler(); // update input bar with new value
453 pUndoMgr
->LeaveListAction();
457 void ScViewFunc::ShowNote( bool bShow
)
461 const ScViewData
& rViewData
= GetViewData();
462 ScAddress
aPos( rViewData
.GetCurX(), rViewData
.GetCurY(), rViewData
.GetTabNo() );
463 // show note moved to ScDocFunc, to be able to use it in notesuno.cxx
464 rViewData
.GetDocShell()->GetDocFunc().ShowNote( aPos
, bShow
);
467 void ScViewFunc::EditNote()
469 // for editing display and activate
471 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
472 ScDocument
& rDoc
= pDocSh
->GetDocument();
473 SCCOL nCol
= GetViewData().GetCurX();
474 SCROW nRow
= GetViewData().GetCurY();
475 SCTAB nTab
= GetViewData().GetTabNo();
476 ScAddress
aPos( nCol
, nRow
, nTab
);
478 // start drawing undo to catch undo action for insertion of the caption object
479 pDocSh
->MakeDrawLayer();
480 ScDrawLayer
* pDrawLayer
= rDoc
.GetDrawLayer();
481 pDrawLayer
->BeginCalcUndo(true);
482 // generated undo action is processed in FuText::StopEditMode
484 // get existing note or create a new note (including caption drawing object)
485 if( ScPostIt
* pNote
= rDoc
.GetOrCreateNote( aPos
) )
487 // hide temporary note caption
489 // show caption object without changing internal visibility state
490 pNote
->ShowCaptionTemp( aPos
);
492 /* Drawing object has been created in ScDocument::GetOrCreateNote() or
493 in ScPostIt::ShowCaptionTemp(), so ScPostIt::GetCaption() should
494 return a caption object. */
495 if( SdrCaptionObj
* pCaption
= pNote
->GetCaption() )
497 if ( ScDrawView
* pScDrawView
= GetScDrawView() )
498 pScDrawView
->SyncForGrid( pCaption
);
499 // #i33764# enable the resize handles before starting edit mode
500 if( FuPoor
* pDraw
= GetDrawFuncPtr() )
501 static_cast< FuSelection
* >( pDraw
)->ActivateNoteHandles( pCaption
);
503 // activate object (as in FuSelection::TestComment)
504 GetViewData().GetDispatcher().Execute( SID_DRAW_NOTEEDIT
, SfxCallMode::SYNCHRON
| SfxCallMode::RECORD
);
505 // now get the created FuText and set into EditMode
506 FuPoor
* pPoor
= GetDrawFuncPtr();
507 if ( pPoor
&& (pPoor
->GetSlotID() == SID_DRAW_NOTEEDIT
) ) // has no RTTI
509 ScrollToObject( pCaption
); // make object fully visible
510 static_cast< FuText
* >( pPoor
)->SetInEditMode( pCaption
);
516 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */