const tools::Long SC_NOTECAPTION_WIDTH = 2900; /// Default width of note caption textbox. const tools::Long SC_NOTECAPTION_MAXWIDTH_TEMP = 12000; /// Maximum width of temporary note caption textbox. const tools::Long SC_NOTECAPTION_HEIGHT = 1800; /// Default height of note caption textbox. const tools::Long SC_NOTECAPTION_CELLDIST = 600; /// Default distance of note captions to border of anchor cell. const tools::Long SC_NOTECAPTION_OFFSET_Y = -1500; /// Default Y offset of note captions to top border of anchor cell. const tools::Long SC_NOTECAPTION_OFFSET_X = 1500; /// Default X offset of note captions to left border of anchor cell. const tools::Long SC_NOTECAPTION_BORDERDIST_TEMP = 100; /// Distance of temporary note captions to visible sheet area.
/** Static helper functions for caption objects. */ class ScCaptionUtil
{ public: /** Moves the caption object to the correct layer according to passed visibility. */ staticvoid SetCaptionLayer( SdrCaptionObj& rCaption, bool bShown ); /** Sets basic caption settings required for note caption objects. */ staticvoid SetBasicCaptionSettings( SdrCaptionObj& rCaption, bool bShown ); /** Stores the cell position of the note in the user data area of the caption. */ staticvoid SetCaptionUserData( SdrCaptionObj& rCaption, const ScAddress& rPos ); /** Sets all hard formatting attributes to the caption object. */ staticvoid SetExtraItems( SdrCaptionObj& rCaption, const SfxItemSet& rExtraItemSet );
};
aItemSet.Put(rExtraItemSet); // reset shadow visibility (see also ScNoteUtil::CreateNoteFromCaption)
aItemSet.ClearItem(SDRATTR_SHADOW); // ... but not distance, as that will fallback to wrong values // if the comment is shown and then opened in older versions:
aItemSet.Put( makeSdrShadowXDistItem( 100 ) );
aItemSet.Put( makeSdrShadowYDistItem( 100 ) );
/** Helper for creation and manipulation of caption drawing objects independent
from cell annotations. */ class ScCaptionCreator
{ public: /** Create a new caption. The caption will not be inserted into the document. */ explicit ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, bool bTailFront ); /** Manipulate an existing caption. */ explicit ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, const rtl::Reference<SdrCaptionObj>& xCaption );
/** Returns the drawing layer page of the sheet contained in maPos. */
SdrPage* GetDrawPage(); /** Returns the caption drawing object. */
rtl::Reference<SdrCaptionObj> & GetCaption() { return mxCaption; }
/** Moves the caption inside the passed rectangle. Uses page area if 0 is passed. */ void FitCaptionToRect( const tools::Rectangle* pVisRect = nullptr ); /** Places the caption inside the passed rectangle, tries to keep the cell rectangle uncovered. Uses page area if 0 is passed. */ void AutoPlaceCaption( const tools::Rectangle* pVisRect = nullptr ); /** Updates caption tail and textbox according to current cell position. Uses page area if 0 is passed. */ void UpdateCaptionPos();
/** Calculates the caption tail position according to current cell position. */
Point CalcTailPos( bool bTailFront ); /** Implements creation of the caption object. The caption will not be inserted into the document. */ void CreateCaption( bool bShown, bool bTailFront );
// n***Space contains available space between border of visible area and cell
tools::Long nLeftSpace = maCellRect.Left() - rVisRect.Left() + 1;
tools::Long nRightSpace = rVisRect.Right() - maCellRect.Right() + 1;
tools::Long nTopSpace = maCellRect.Top() - rVisRect.Top() + 1;
tools::Long nBottomSpace = rVisRect.Bottom() - maCellRect.Bottom() + 1;
// nNeeded*** contains textbox dimensions plus needed distances to cell or border of visible area
tools::Long nNeededSpaceX = nWidth + SC_NOTECAPTION_CELLDIST;
tools::Long nNeededSpaceY = nHeight + SC_NOTECAPTION_CELLDIST;
// bFitsWidth*** == true means width of textbox fits into horizontal free space of visible area bool bFitsWidthLeft = nNeededSpaceX <= nLeftSpace; // text box width fits into the width left of cell bool bFitsWidthRight = nNeededSpaceX <= nRightSpace; // text box width fits into the width right of cell bool bFitsWidth = nWidth <= rVisRect.GetWidth(); // text box width fits into width of visible area
// bFitsHeight*** == true means height of textbox fits into vertical free space of visible area bool bFitsHeightTop = nNeededSpaceY <= nTopSpace; // text box height fits into the height above cell bool bFitsHeightBottom = nNeededSpaceY <= nBottomSpace; // text box height fits into the height below cell bool bFitsHeight = nHeight <= rVisRect.GetHeight(); // text box height fits into height of visible area
// bFits*** == true means the textbox fits completely into free space of visible area bool bFitsLeft = bFitsWidthLeft && bFitsHeight; bool bFitsRight = bFitsWidthRight && bFitsHeight; bool bFitsTop = bFitsWidth && bFitsHeightTop; bool bFitsBottom = bFitsWidth && bFitsHeightBottom;
Point aCaptPos; // use left/right placement if possible, or if top/bottom placement not possible if( bFitsLeft || bFitsRight || (!bFitsTop && !bFitsBottom) )
{ // prefer left in RTL sheet and right in LTR sheets bool bPreferLeft = bFitsLeft && (mbNegPage || !bFitsRight); bool bPreferRight = bFitsRight && (!mbNegPage || !bFitsLeft); // move to left, if left is preferred, or if neither left nor right fit and there is more space to the left if( bPreferLeft || (!bPreferRight && (nLeftSpace > nRightSpace)) )
aCaptPos.setX( maCellRect.Left() - SC_NOTECAPTION_CELLDIST - nWidth ); else// to right
aCaptPos.setX( maCellRect.Right() + SC_NOTECAPTION_CELLDIST ); // Y position according to top cell border
aCaptPos.setY( maCellRect.Top() + SC_NOTECAPTION_OFFSET_Y );
} else// top or bottom placement
{ // X position
aCaptPos.setX( maCellRect.Left() + SC_NOTECAPTION_OFFSET_X ); // top placement, if possible if( bFitsTop )
aCaptPos.setY( maCellRect.Top() - SC_NOTECAPTION_CELLDIST - nHeight ); else// bottom placement
aCaptPos.setY( maCellRect.Bottom() + SC_NOTECAPTION_CELLDIST );
}
// update textbox position in note caption object
aCaptRect.SetPos( aCaptPos );
mxCaption->SetLogicRect( aCaptRect );
FitCaptionToRect( pVisRect );
}
/** Helper for creation of permanent caption drawing objects for cell notes. */ class ScNoteCaptionCreator : public ScCaptionCreator
{ public: /** Create a new caption object and inserts it into the document. */ explicit ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScNoteData& rNoteData ); /** Manipulate an existing caption. */ explicit ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, const rtl::Reference<SdrCaptionObj>& xCaption, bool bShown );
};
ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, ScNoteData& rNoteData ) :
ScCaptionCreator( rDoc, rPos ) // use helper c'tor that does not create the caption yet
{
SdrPage* pDrawPage = GetDrawPage();
OSL_ENSURE( pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - no drawing page" ); if( !pDrawPage ) return;
// create the caption drawing object
CreateCaption( rNoteData.mbShown, false );
rNoteData.mxCaption = GetCaption();
OSL_ENSURE( rNoteData.mxCaption, "ScNoteCaptionCreator::ScNoteCaptionCreator - missing caption object" ); if( rNoteData.mxCaption )
{ // store note position in user data of caption object
ScCaptionUtil::SetCaptionUserData( *rNoteData.mxCaption, rPos ); // insert object into draw page
pDrawPage->InsertObject( rNoteData.mxCaption.get() );
}
}
ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, const rtl::Reference<SdrCaptionObj>& xCaption, bool bShown ) :
ScCaptionCreator( rDoc, rPos, xCaption )
{
SdrPage* pDrawPage = GetDrawPage();
OSL_ENSURE( pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - no drawing page" );
OSL_ENSURE( xCaption->getSdrPageFromSdrObject() == pDrawPage, "ScNoteCaptionCreator::ScNoteCaptionCreator - wrong drawing page in caption" ); if( pDrawPage && (xCaption->getSdrPageFromSdrObject() == pDrawPage) )
{ // store note position in user data of caption object
ScCaptionUtil::SetCaptionUserData( *xCaption, rPos ); // basic caption settings
ScCaptionUtil::SetBasicCaptionSettings( *xCaption, bShown ); // set correct tail position
xCaption->SetTailPos( CalcTailPos( false ) );
}
}
} // namespace
struct ScCaptionInitData
{
std::optional< SfxItemSet > moItemSet; /// Caption object formatting.
std::optional< OutlinerParaObject > mxOutlinerObj; /// Text object with all text portion formatting.
std::unique_ptr< GenerateNoteCaption > mxGenerator; /// Operator to generate Caption Object from import data
OUString maStyleName; /// Drawing style associated with the caption object.
OUString maSimpleText; /// Simple text without formatting.
Point maCaptionOffset; /// Caption position relative to cell corner.
Size maCaptionSize; /// Size of the caption object. bool mbDefaultPosSize; /// True = use default position and size for caption.
void ScPostIt::ForgetCaption( bool bPreserveData )
{ if (bPreserveData)
{ // Used in clipboard when the originating document is destructed to be // able to paste into another document. Caption size and relative // position are not preserved but default created when pasted. Also the // MergedItemSet can not be carried over or it had to be adapted to // defaults and pool. At least preserve the text and outline object if // possible.
ScCaptionInitData* pInitData = new ScCaptionInitData; const OutlinerParaObject* pOPO = GetOutlinerObject(); if (pOPO)
pInitData->mxOutlinerObj = *pOPO;
pInitData->maSimpleText = GetText();
maNoteData.mxInitData.reset(pInitData);
maNoteData.mxCaption.clear();
} else
{ /* This function is used in undo actions to give up the responsibility for
the caption object which is handled by separate drawing undo actions. */
maNoteData.mxCaption.clear();
maNoteData.mxInitData.reset();
}
}
void ScPostIt::CreateCaptionFromInitData( const ScAddress& rPos ) const
{ // Captions are not created in Undo documents and only rarely in Clipboard, // but otherwise we need caption or initial data.
assert((maNoteData.mxCaption || maNoteData.mxInitData) || mrDoc.IsUndo() || mrDoc.IsClipboard()); if( !maNoteData.mxInitData ) return;
/* This function is called from ScPostIt::Clone() when copying cells totheclipboard/undodocument,andwhencopyingcellsfromthe clipboard/undodocument.Theformershouldalwaysbecalledfirst, soifcalledinaclipboard/undodocument,thecaptionshouldhave beencreatedalready.However,forclipboardincasethe originatingdocumentwasdestructedanewcaptionhastobe
created. */
OSL_ENSURE( !mrDoc.IsUndo() && (!mrDoc.IsClipboard() || !maNoteData.mxCaption), "ScPostIt::CreateCaptionFromInitData - note caption should not be created in undo/clip documents" );
// going to forget the initial caption data struct when this method returns auto xInitData = std::move(maNoteData.mxInitData);
/* #i104915# Never try to create notes in Undo document, leads to
crash due to missing document members (e.g. row height array). */ if( maNoteData.mxCaption || mrDoc.IsUndo() ) return;
if (mrDoc.IsClipboard())
mrDoc.InitDrawLayer(); // ensure there is a drawing layer
// ScNoteCaptionCreator c'tor creates the caption and inserts it into the document and maNoteData
ScNoteCaptionCreator aCreator( mrDoc, rPos, maNoteData ); if( !maNoteData.mxCaption ) return;
// Prevent triple change broadcasts of the same object. bool bWasLocked = maNoteData.mxCaption->getSdrModelFromSdrObject().isLocked();
maNoteData.mxCaption->getSdrModelFromSdrObject().setLock(true);
if (xInitData->mxGenerator)
xInitData->mxGenerator->Generate(*maNoteData.mxCaption); else
{ // transfer ownership of outliner object to caption, or set simple text
OSL_ENSURE( xInitData->mxOutlinerObj || !xInitData->maSimpleText.isEmpty(), "ScPostIt::CreateCaptionFromInitData - need either outliner para object or simple text" ); if (xInitData->mxOutlinerObj)
maNoteData.mxCaption->NbcSetOutlinerParaObjectForText(
std::move(xInitData->mxOutlinerObj),
maNoteData.mxCaption->getActiveText(), /*bAdjustTextFrameWidthAndHeight*/false ); else
maNoteData.mxCaption->SetText( xInitData->maSimpleText );
}
if (!xInitData->maStyleName.isEmpty())
{ if (auto pStyleSheet = mrDoc.GetStyleSheetPool()->Find(xInitData->maStyleName, SfxStyleFamily::Frame))
maNoteData.mxCaption->NbcSetStyleSheet(static_cast<SfxStyleSheet*>(pStyleSheet), true, /*bAdjustTextFrameWidthAndHeight*/false);
if (xInitData->moItemSet)
maNoteData.mxCaption->SetMergedItemSet(*xInitData->moItemSet, /*bClearAllItems*/false, /*bAdjustTextFrameWidthAndHeight*/false);
} else
{ if (auto pStyleSheet = mrDoc.GetStyleSheetPool()->Find(ScResId(STR_STYLENAME_NOTE), SfxStyleFamily::Frame))
maNoteData.mxCaption->NbcSetStyleSheet(static_cast<SfxStyleSheet*>(pStyleSheet), true, /*bAdjustTextFrameWidthAndHeight*/false);
// copy all items and reset shadow items if (xInitData->moItemSet)
ScCaptionUtil::SetExtraItems(*maNoteData.mxCaption, *xInitData->moItemSet);
}
// set position and size of the caption object if( xInitData->mbDefaultPosSize )
{ // set other items and fit caption size to text
maNoteData.mxCaption->SetMergedItem( makeSdrTextMinFrameWidthItem( SC_NOTECAPTION_WIDTH ) );
maNoteData.mxCaption->SetMergedItem( makeSdrTextMaxFrameWidthItem( SC_NOTECAPTION_MAXWIDTH_TEMP ) );
maNoteData.mxCaption->AdjustTextFrameWidthAndHeight();
aCreator.AutoPlaceCaption();
} else
{
tools::Rectangle aCellRect = ScDrawLayer::GetCellRect( mrDoc, rPos, true ); bool bNegPage = mrDoc.IsNegativePage( rPos.Tab() );
tools::Long nPosX = bNegPage ? (aCellRect.Left() - xInitData->maCaptionOffset.X()) : (aCellRect.Right() + xInitData->maCaptionOffset.X());
tools::Long nPosY = aCellRect.Top() + xInitData->maCaptionOffset.Y();
tools::Rectangle aCaptRect( Point( nPosX, nPosY ), xInitData->maCaptionSize );
maNoteData.mxCaption->NbcSetLogicRect( aCaptRect, /*bAdaptTextMinSize*/false );
aCreator.FitCaptionToRect();
}
// End prevent triple change broadcasts of the same object.
maNoteData.mxCaption->getSdrModelFromSdrObject().setLock(bWasLocked);
maNoteData.mxCaption->BroadcastObjectChange();
}
/* #i104915# Never try to create notes in Undo document, leads to
crash due to missing document members (e.g. row height array). */
OSL_ENSURE( !mrDoc.IsUndo(), "ScPostIt::CreateCaption - note caption should not be created in undo documents" ); if( mrDoc.IsUndo() ) return;
// drawing layer may be missing, if a note is copied into a clipboard document if( mrDoc.IsClipboard() )
mrDoc.InitDrawLayer();
// ScNoteCaptionCreator c'tor creates the caption and inserts it into the document and maNoteData
ScNoteCaptionCreator aCreator( mrDoc, rPos, maNoteData ); if( !maNoteData.mxCaption ) return;
// clone settings of passed caption if( pCaption )
{ // copy edit text object (object must be inserted into page already) if( OutlinerParaObject* pOPO = pCaption->GetOutlinerParaObject() )
maNoteData.mxCaption->SetOutlinerParaObject( *pOPO ); // copy formatting items (after text has been copied to apply font formatting) if (auto pStyleSheet = pCaption->GetStyleSheet())
{ auto pPool = mrDoc.GetStyleSheetPool();
pPool->CopyStyleFrom(pStyleSheet->GetPool(), pStyleSheet->GetName(), pStyleSheet->GetFamily(), true);
if (auto pDestStyleSheet = pPool->Find(pStyleSheet->GetName(), pStyleSheet->GetFamily()))
maNoteData.mxCaption->SetStyleSheet(static_cast<SfxStyleSheet*>(pDestStyleSheet), true);
}
maNoteData.mxCaption->SetMergedItemSetAndBroadcast( pCaption->GetMergedItemSet() ); // move textbox position relative to new cell, copy textbox size
tools::Rectangle aCaptRect = pCaption->GetLogicRect();
Point aDist = maNoteData.mxCaption->GetTailPos() - pCaption->GetTailPos();
aCaptRect.Move( aDist.X(), aDist.Y() );
maNoteData.mxCaption->SetLogicRect( aCaptRect );
aCreator.FitCaptionToRect();
} else
{ if (auto pStyleSheet = mrDoc.GetStyleSheetPool()->Find(ScResId(STR_STYLENAME_NOTE), SfxStyleFamily::Frame))
maNoteData.mxCaption->SetStyleSheet(static_cast<SfxStyleSheet*>(pStyleSheet), true); // set default size, undoing sdr::TextProperties::SetStyleSheet's // adjustment that use a wrong min height.
tools::Rectangle aCaptRect = maNoteData.mxCaption->GetLogicRect();
aCaptRect.SetSize({ SC_NOTECAPTION_WIDTH, SC_NOTECAPTION_HEIGHT });
maNoteData.mxCaption->SetLogicRect(aCaptRect); // set default position
aCreator.AutoPlaceCaption();
}
void ScPostIt::RemoveCaption()
{ if (!maNoteData.mxCaption) return;
/* Remove caption object only, if this note is its owner (e.g. notes in undodocumentsrefertocaptionsinoriginaldocument,donotremove
them from drawing layer here). */ // TTTT maybe no longer needed - can that still happen?
ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer(); if (pDrawLayer == &maNoteData.mxCaption->getSdrModelFromSdrObject())
{
SdrPage* pDrawPage(maNoteData.mxCaption->getSdrPageFromSdrObject());
SAL_WARN_IF( !pDrawPage, "sc.core", "ScCaptionPtr::removeFromDrawPageAndFree - object without drawing page"); if (pDrawPage)
{
pDrawPage->RecalcObjOrdNums(); // create drawing undo action (before removing the object to have valid draw page in undo action) if (pDrawLayer->IsRecording())
pDrawLayer->AddCalcUndo( std::make_unique<SdrUndoDelObj>( *maNoteData.mxCaption )); // remove the object from the drawing page
rtl::Reference<SdrObject> pRemovedObj = pDrawPage->RemoveObject( maNoteData.mxCaption->GetOrdNum() );
assert(pRemovedObj.get() == maNoteData.mxCaption.get()); (void)pRemovedObj;
}
}
// Forget the caption object if removeFromDrawPageAndFree() did not free it. if (maNoteData.mxCaption)
{
SAL_INFO("sc.core","ScPostIt::RemoveCaption - forgetting one ref");
maNoteData.mxCaption.clear();
}
}
// insert caption into page (needed to set caption text)
rtl::Reference<SdrCaptionObj> pCaption = aCreator.GetCaption(); // just for ease of use
rDrawPage.InsertObject( pCaption.get() );
// clone the edit text object, then seta and format the Author and date text if (pNoteCaption)
{ if( OutlinerParaObject* pOPO = pNoteCaption->GetOutlinerParaObject() )
pCaption->SetOutlinerParaObject( *pOPO ); // Setting and formatting rUserText: Author name and date time if (officecfg::Office::Calc::Content::Display::NoteAuthor::get())
lcl_FormatAndInsertAuthorAndDatepara(pCaption.get(), aBuffer, bUserWithTrackText); // set formatting (must be done after setting text) and resize the box to fit the text if (auto pStyleSheet = pNoteCaption->GetStyleSheet())
pCaption->SetStyleSheet(pStyleSheet, true);
pCaption->SetMergedItemSetAndBroadcast(pNoteCaption->GetMergedItemSet());
} else
{
pCaption->SetText(aBuffer.makeStringAndClear()); if (auto pStyleSheet = rDoc.GetStyleSheetPool()->Find(ScResId(STR_STYLENAME_NOTE), SfxStyleFamily::Frame))
pCaption->SetStyleSheet(static_cast<SfxStyleSheet*>(pStyleSheet), true);
}
// ScNoteCaptionCreator c'tor updates the caption object to be part of a note
ScNoteCaptionCreator aCreator( rDoc, rPos, aNoteData.mxCaption, true/*bShown*/ );
if (!bHasStyle)
{ if (auto pStyleSheet = rDoc.GetStyleSheetPool()->Find(ScResId(STR_STYLENAME_NOTE), SfxStyleFamily::Frame))
aNoteData.mxCaption->SetStyleSheet(static_cast<SfxStyleSheet*>(pStyleSheet), true);
/* We used to show a shadow despite of the shadow item being set to false. Cleartheexistingitem,soitinheritsthetruesettingfromthestyle.
Setting explicitly to true would corrupt the shadow when opened in older versions. */
aNoteData.mxCaption->ClearMergedItem(SDRATTR_SHADOW);
}
ScPostIt* ScNoteUtil::CreateNoteFromGenerator(
ScDocument& rDoc, const ScAddress& rPos,
std::unique_ptr<GenerateNoteCaption> xGenerator, const tools::Rectangle& rCaptionRect, bool bShown )
{
ScNoteData aNoteData(CreateNoteData(rDoc, rPos, rCaptionRect, bShown));
ScCaptionInitData& rInitData = *aNoteData.mxInitData;
rInitData.mxGenerator = std::move(xGenerator); // because the Caption is generated on demand, we will need to create the // simple text now to supply any queries for that which don't require // creation of a full Caption
rInitData.maSimpleText = rInitData.mxGenerator->GetSimpleText();
aNoteData.maAuthor = rInitData.mxGenerator->GetAuthorName(); return InsertNote(rDoc, rPos, std::move(aNoteData), /*bAlwaysCreateCaption*/ false, 0/*nPostItId*/, false /*bShouldAutoStamp*/);
}
ScPostIt* ScNoteUtil::InsertNote(ScDocument& rDoc, const ScAddress& rPos, ScNoteData&& rNoteData, bool bAlwaysCreateCaption, sal_uInt32 nPostItId, bool bShouldAutoStamp)
{ /* Create the note and insert it into the document. If the note is
visible, the caption object will be created automatically. */
ScPostIt* pNote = new ScPostIt( rDoc, rPos, std::move(rNoteData), bAlwaysCreateCaption, nPostItId );
pNote->AutoStamp(bShouldAutoStamp); //insert takes ownership
rDoc.SetNote(rPos, std::unique_ptr<ScPostIt>(pNote)); return pNote;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.