diff options
-rw-r--r-- | sw/inc/crsrsh.hxx | 3 | ||||
-rw-r--r-- | sw/inc/docsh.hxx | 3 | ||||
-rw-r--r-- | sw/qa/extras/uiwriter/uiwriter3.cxx | 44 | ||||
-rw-r--r-- | sw/source/core/crsr/crsrsh.cxx | 39 | ||||
-rw-r--r-- | sw/source/uibase/app/docst.cxx | 78 |
5 files changed, 166 insertions, 1 deletions
diff --git a/sw/inc/crsrsh.hxx b/sw/inc/crsrsh.hxx index 02a08289a889..806b1b7d2472 100644 --- a/sw/inc/crsrsh.hxx +++ b/sw/inc/crsrsh.hxx @@ -552,6 +552,9 @@ public: // Check if selection is within one paragraph. bool IsSelOnePara() const; + // Check if selection starts a paragraph. + bool IsSelStartPara() const; + /* * Returns SRectangle, at which the cursor is located. */ diff --git a/sw/inc/docsh.hxx b/sw/inc/docsh.hxx index f29c4ed78134..858c778ac784 100644 --- a/sw/inc/docsh.hxx +++ b/sw/inc/docsh.hxx @@ -54,6 +54,7 @@ class SwDrawModel; class SwViewShell; class SwDocStyleSheetPool; class SwXTextDocument; +class SwTextFormatColl; namespace svt { class EmbeddedObjectRef; @@ -143,6 +144,8 @@ class SW_DLLPUBLIC SwDocShell SAL_DLLPRIVATE void Delete(const OUString &rName, SfxStyleFamily nFamily); SAL_DLLPRIVATE void Hide(const OUString &rName, SfxStyleFamily nFamily, bool bHidden); + SAL_DLLPRIVATE bool MakeInlineHeading(SwWrtShell *pSh, SwTextFormatColl* pColl, + const sal_uInt16 nMode); SAL_DLLPRIVATE SfxStyleFamily ApplyStyles(const OUString &rName, const SfxStyleFamily nFamily, SwWrtShell* pShell, diff --git a/sw/qa/extras/uiwriter/uiwriter3.cxx b/sw/qa/extras/uiwriter/uiwriter3.cxx index f7c31f4e76d8..cbd860f0aabf 100644 --- a/sw/qa/extras/uiwriter/uiwriter3.cxx +++ b/sw/qa/extras/uiwriter/uiwriter3.cxx @@ -1315,6 +1315,50 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, testTdf147206) u"HyperLinkURL"_ustr)); } +CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, testTdf48459) +{ + createSwDoc(); + SwDoc* pDoc = getSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + + // insert paragraph text + pWrtShell->Insert(u"Heading and normal text"_ustr); + + // select the first word (proposed for inline heading) + pWrtShell->SttEndDoc(/*bStart=*/true); + pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, 7, /*bBasicCall=*/false); + + // apply styles only on the selected word -> create inline heading + uno::Sequence<beans::PropertyValue> aPropertyValues = comphelper::InitPropertySequence({ + { "Style", uno::Any(u"Heading 1"_ustr) }, + { "FamilyName", uno::Any(u"ParagraphStyles"_ustr) }, + }); + dispatchCommand(mxComponent, u".uno:StyleApply"_ustr, aPropertyValues); + + uno::Reference<frame::XFrames> xFrames = mxDesktop->getFrames(); + + // inline heading frame + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xFrames->getCount()); + + pWrtShell->EndOfSection(false); + + // insert table of contents to check ToC content (containing only the inline heading) + SwTOXMgr mgr(pWrtShell); + SwTOXDescription desc{ TOX_CONTENT }; + mgr.UpdateOrInsertTOX(desc, nullptr, nullptr); + + CPPUNIT_ASSERT_EQUAL(int(3), getParagraphs()); + + // first paragraph: selected text moved to the inline heading frame + CPPUNIT_ASSERT_EQUAL(u" and normal text"_ustr, getParagraph(1)->getString()); + + // ToC title + CPPUNIT_ASSERT_EQUAL(u"Table of Contents"_ustr, getParagraph(2)->getString()); + + // ToC contains only the inline heading + CPPUNIT_ASSERT_EQUAL(u"Heading\t1"_ustr, getParagraph(3)->getString()); +} + CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, testTdf144840) { createSwDoc("tdf144840.odt"); diff --git a/sw/source/core/crsr/crsrsh.cxx b/sw/source/core/crsr/crsrsh.cxx index fce43323b19b..6386b8673856 100644 --- a/sw/source/core/crsr/crsrsh.cxx +++ b/sw/source/core/crsr/crsrsh.cxx @@ -1394,6 +1394,45 @@ bool SwCursorShell::IsSelOnePara() const return false; } +bool SwCursorShell::IsSelStartPara() const +{ + if (m_pCurrentCursor->IsMultiSelection()) + { + return false; + } + if (m_pCurrentCursor->GetPoint()->GetContentIndex() == 0 || + m_pCurrentCursor->GetMark()->GetContentIndex() == 0) + { + return true; + } + if (GetLayout()->HasMergedParas()) + { + SwTextNode const*const pNode(m_pCurrentCursor->GetPoint()->GetNode().GetTextNode()); + if (pNode) + { + SwTextFrame const*const pFrame(static_cast<SwTextFrame*>( + pNode->getLayoutFrame(GetLayout()))); + if (pFrame) + { + return pFrame->MapModelToViewPos(*m_pCurrentCursor->GetPoint()) + == TextFrameIndex(0); + } + } + SwTextNode const*const pNode2(m_pCurrentCursor->GetMark()->GetNode().GetTextNode()); + if (pNode2) + { + SwTextFrame const*const pFrame(static_cast<SwTextFrame*>( + pNode2->getLayoutFrame(GetLayout()))); + if (pFrame) + { + return pFrame->MapModelToViewPos(*m_pCurrentCursor->GetMark()) + == TextFrameIndex(0); + } + } + } + return false; +} + bool SwCursorShell::IsSttPara() const { if (GetLayout()->HasMergedParas()) diff --git a/sw/source/uibase/app/docst.cxx b/sw/source/uibase/app/docst.cxx index d6be439d4259..e81ccb9aff8d 100644 --- a/sw/source/uibase/app/docst.cxx +++ b/sw/source/uibase/app/docst.cxx @@ -85,6 +85,10 @@ #include <docmodel/theme/Theme.hxx> #include <svx/svdpage.hxx> #include <officecfg/Office/Common.hxx> +#include <fmtfsize.hxx> +#include <svl/ptitem.hxx> +#include <editeng/sizeitem.hxx> +#include <editeng/ulspitem.hxx> using namespace ::com::sun::star; @@ -1170,6 +1174,71 @@ void SwDocShell::Hide(const OUString &rName, SfxStyleFamily nFamily, bool bHidde } } +#define MAX_CHAR_IN_INLINE_HEADING 75 +bool SwDocShell::MakeInlineHeading(SwWrtShell *pSh, SwTextFormatColl* pColl, const sal_uInt16 nMode) +{ + // insert an inline heading frame, if only MAX_CHAR_IN_INLINE_HEADING or less + // characters are selected beginning of a single paragraph, but not the full paragraph + // TODO extend it for multiple selections + if ( pSh->IsSelOnePara() && !pSh->IsSelFullPara() && pSh->IsSelStartPara() && + GetView()->GetSelectionText().getLength() < MAX_CHAR_IN_INLINE_HEADING && + 0 < GetView()->GetSelectionText().getLength() ) + { + SwTextFormatColl *pLocal = pColl? pColl: (*GetDoc()->GetTextFormatColls())[0]; + + // put inside a single Undo + SwRewriter aRewriter; + aRewriter.AddRule(UndoArg1, pLocal->GetName()); + GetWrtShell()->StartUndo(SwUndoId::SETFMTCOLL, &aRewriter); + + // anchor as character + SfxUInt16Item aAnchor(FN_INSERT_FRAME, static_cast<sal_uInt16>(1)); + SvxSizeItem aSizeItem(FN_PARAM_2, Size(1, 1)); + GetView()->GetViewFrame().GetDispatcher()->ExecuteList(FN_INSERT_FRAME, + SfxCallMode::SYNCHRON|SfxCallMode::RECORD, { &aAnchor, &aSizeItem }); + if ( pSh->IsFrameSelected() ) + { + // use the borderless frame style "Formula" + // TODO add a new frame style "Inline Heading" + SwDocStyleSheet* pStyle2 = static_cast<SwDocStyleSheet*>( + m_xBasePool->Find( "Formula", SfxStyleFamily::Frame)); + pSh->SetFrameFormat( pStyle2->GetFrameFormat() ); + + // set variable width frame to extend for the width of the text content + SfxItemSetFixed<RES_FRMATR_BEGIN, RES_FRMATR_END - 1> aSet(pSh->GetAttrPool()); + pSh->GetFlyFrameAttr( aSet ); + SwTwips nMinWidth = 100; + SwFormatFrameSize aSize(SwFrameSize::Variable, nMinWidth, nMinWidth); + aSize.SetWidthSizeType(SwFrameSize::Variable); + aSet.Put(aSize); + pSh->SetFlyFrameAttr( aSet ); + + // select the text content of the frame, and apply the paragraph style + pSh->UnSelectFrame(); + pSh->LeaveSelFrameMode(); + pSh->MoveSection( GoCurrSection, fnSectionEnd ); + pSh->SelAll(); + + pSh->SetTextFormatColl( pColl, true, (nMode & KEY_MOD1) ? SetAttrMode::REMOVE_ALL_ATTR : SetAttrMode::DEFAULT); + + // zero the upper and lower margins of the paragraph (also an interoperability issue) + SfxItemSetFixed<RES_UL_SPACE, RES_UL_SPACE> aSet2(pSh->GetAttrPool()); + pSh->GetCurAttr( aSet2 ); + SvxULSpaceItem aUL( 0, 0, RES_UL_SPACE ); + pSh->SetAttrItem( aUL ); + + // leave the inline heading frame + GetView()->GetViewFrame().GetDispatcher()->Execute(FN_ESCAPE, SfxCallMode::ASYNCHRON); + GetView()->GetViewFrame().GetDispatcher()->Execute(FN_ESCAPE, SfxCallMode::ASYNCHRON); + GetView()->GetViewFrame().GetDispatcher()->Execute(FN_ESCAPE, SfxCallMode::SYNCHRON); + + GetWrtShell()->EndUndo(); + return true; + } + } + return false; +} + // apply template SfxStyleFamily SwDocShell::ApplyStyles(const OUString &rName, SfxStyleFamily nFamily, SwWrtShell* pShell, const sal_uInt16 nMode ) @@ -1211,10 +1280,17 @@ SfxStyleFamily SwDocShell::ApplyStyles(const OUString &rName, SfxStyleFamily nFa // outline node become folded content of the previous outline node if the previous // outline node's content is folded. MakeAllOutlineContentTemporarilyVisible a(GetDoc()); + + // if the first 75 or less characters are selected, but not the full paragraph, + // create an inline heading from the selected text + SwTextFormatColl* pColl = pStyle->GetCollection(); + if ( MakeInlineHeading( pSh, pColl, nMode ) ) + break; + // #i62675# // clear also list attributes at affected text nodes, if paragraph // style has the list style attribute set. - pSh->SetTextFormatColl( pStyle->GetCollection(), true, (nMode & KEY_MOD1) ? SetAttrMode::REMOVE_ALL_ATTR : SetAttrMode::DEFAULT); + pSh->SetTextFormatColl( pColl, true, (nMode & KEY_MOD1) ? SetAttrMode::REMOVE_ALL_ATTR : SetAttrMode::DEFAULT); } break; } |