officecfg/registry/schema/org/openoffice/Office/Writer.xcs | 13 ++ sw/inc/cmdid.h | 2 sw/inc/viewopt.hxx | 79 +++++++----- sw/qa/extras/uiwriter/uiwriter9.cxx | 83 +++++++++++++ sw/source/ui/config/optpage.cxx | 43 ++++++ sw/source/uibase/app/appopt.cxx | 9 + sw/source/uibase/config/cfgitems.cxx | 30 ++++ sw/source/uibase/config/usrpref.cxx | 71 +++++++++++ sw/source/uibase/config/viewopt.cxx | 3 sw/source/uibase/docvw/edtwin.cxx | 41 ++++++ sw/source/uibase/inc/cfgitems.hxx | 21 +++ sw/source/uibase/inc/optpage.hxx | 4 sw/source/uibase/inc/usrpref.hxx | 30 ++++ sw/source/uibase/inc/wrtsh.hxx | 1 sw/source/uibase/wrtsh/wrtsh1.cxx | 11 + sw/uiconfig/swriter/ui/optformataidspage.ui | 75 +++++++++++ 16 files changed, 478 insertions(+), 38 deletions(-)
New commits: commit a7dd2e5a4712083cc5934e1d677e7dff86ceb7e6 Author: Yiğit Akçay <yigit.ak...@icloud.com> AuthorDate: Thu Jan 25 23:05:59 2024 +0300 Commit: Andreas Heinisch <andreas.heini...@yahoo.de> CommitDate: Wed Feb 28 10:37:50 2024 +0100 tdf#151710 Enable enclosing of selected text with characters This patch implements a new setting in Tools -> Options -> Writer -> Formatting Aids -> Autocomplete -> Enclose with characters. When this option is enabled (default), selected text is enclosed with parentheses, square brackets, curly braces or quotation marks, depending on which character is pressed. For example, if the selected text is "abcd", the option is enabled and the button for the character '(' is hit, the text is replaced with "(abcd)". Change-Id: Ibc5b7be3cc96f00217dd068971e7c07e68439700 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162583 Reviewed-by: Andreas Heinisch <andreas.heini...@yahoo.de> Tested-by: Jenkins diff --git a/officecfg/registry/schema/org/openoffice/Office/Writer.xcs b/officecfg/registry/schema/org/openoffice/Office/Writer.xcs index 22f1481286b9..8497cc87bb67 100644 --- a/officecfg/registry/schema/org/openoffice/Office/Writer.xcs +++ b/officecfg/registry/schema/org/openoffice/Office/Writer.xcs @@ -2061,6 +2061,19 @@ </prop> </group> </group> + <group oor:name="FmtAidsAutocomplete"> + <info> + <desc>Contains formatting aids auto complete options.</desc> + </info> + <prop oor:name="EncloseWithCharacters" oor:type="xs:boolean" oor:nillable="false"> + <!-- UIHints: Tools - Options - Formatting Aids - Enclose with characters --> + <info> + <desc>Specifies whether selected text will be enclosed with parentheses, square brackets, curly braces or quotation marks, depending on which button is pressed.</desc> + <label>Enclose with characters</label> + </info> + <value>true</value> + </prop> + </group> <group oor:name="Revision"> <info> <desc>Contains settings for change recording.</desc> diff --git a/sw/inc/cmdid.h b/sw/inc/cmdid.h index e8521380c62c..3e611005c15e 100644 --- a/sw/inc/cmdid.h +++ b/sw/inc/cmdid.h @@ -850,7 +850,7 @@ class SwUINumRuleItem; #define FN_PARAM_CRSR_IN_PROTECTED TypedWhichId<SfxBoolItem>(FN_PARAM2+13) /* Cursor in protected areas */ #define FN_PARAM_TOX_TYPE TypedWhichId<SfxUInt16Item>(FN_PARAM2+14) /* TOX type in tox dialog*/ #define FN_PARAM_LINK_DISPLAY_NAME (FN_PARAM2+15) /* LinkDisplayName property*/ -// free +#define FN_PARAM_FMT_AIDS_AUTOCOMPL TypedWhichId<SwFmtAidsAutoComplItem>(FN_PARAM2+16) /* Formatting aids autocomplete options */ #define FN_PARAM_CONTOUR_PP (FN_PARAM2+17) /* contour PolyPolygon*/ #define FN_ANCHOR_POSITION (FN_PARAM2+18) /* AnchorPosition property */ diff --git a/sw/inc/viewopt.hxx b/sw/inc/viewopt.hxx index 8aac21e745b3..d58c361e24c9 100644 --- a/sw/inc/viewopt.hxx +++ b/sw/inc/viewopt.hxx @@ -252,39 +252,40 @@ class SW_DLLPUBLIC SwViewOption static sal_uInt16 s_nPixelTwips;// 1 Pixel == ? Twips - OUString m_sSymbolFont; // Symbolfont. - ViewOptFlags1 m_nCoreOptions; // Bits for SwViewShell. - ViewOptCoreFlags2 m_nCore2Options; // Bits for SwViewShell. - ViewOptFlags2 m_nUIOptions; // UI-Bits - Color m_aRetouchColor; // DefaultBackground for BrowseView - Size m_aSnapSize; // Describes horizontal and vertical snap. - sal_uInt16 mnViewLayoutColumns; // # columns for edit view - short m_nDivisionX; // Grid division. - short m_nDivisionY; - sal_uInt8 m_nPagePreviewRow; // Page Preview Row/Columns. - sal_uInt8 m_nPagePreviewCol; // Page Preview Row/Columns. - SwFillMode m_nShadowCursorFillMode; // FillMode for ShadowCursor. - bool m_bReadonly : 1; // Readonly-Doc. - bool m_bStarOneSetting : 1;// Prevent from UI automatics (no scrollbars in readonly documents). - bool m_bIsPagePreview : 1; // The preview mustn't print field/footnote/... shadings. - bool m_bSelectionInReadonly : 1; // Determines whether selection is switched on in readonly documents. - bool mbFormView : 1; - bool mbBrowseMode : 1; - bool mbBookView : 1; // View mode for page preview. - bool mbViewLayoutBookMode : 1; // Book view mode for edit view. - bool mbHideWhitespaceMode : 1; // Hide header, footer, and pagebreak. - bool m_bShowPlaceHolderFields : 1; // Only used in printing! - mutable bool m_bIdle; - sal_Int32 m_nDefaultAnchor; // GetDefaultAnchorType() to convert int to RndStdIds + OUString m_sSymbolFont; // Symbolfont. + ViewOptFlags1 m_nCoreOptions; // Bits for SwViewShell. + ViewOptCoreFlags2 m_nCore2Options; // Bits for SwViewShell. + ViewOptFlags2 m_nUIOptions; // UI-Bits + Color m_aRetouchColor; // DefaultBackground for BrowseView + Size m_aSnapSize; // Describes horizontal and vertical snap. + sal_uInt16 mnViewLayoutColumns; // # columns for edit view + short m_nDivisionX; // Grid division. + short m_nDivisionY; + sal_uInt8 m_nPagePreviewRow; // Page Preview Row/Columns. + sal_uInt8 m_nPagePreviewCol; // Page Preview Row/Columns. + SwFillMode m_nShadowCursorFillMode; // FillMode for ShadowCursor. + bool m_bReadonly : 1; // Readonly-Doc. + bool m_bStarOneSetting : 1; // Prevent from UI automatics (no scrollbars in readonly documents). + bool m_bIsPagePreview : 1; // The preview mustn't print field/footnote/... shadings. + bool m_bSelectionInReadonly : 1; // Determines whether selection is switched on in readonly documents. + bool mbFormView : 1; + bool mbBrowseMode : 1; + bool mbBookView : 1; // View mode for page preview. + bool mbViewLayoutBookMode : 1; // Book view mode for edit view. + bool mbHideWhitespaceMode : 1; // Hide header, footer, and pagebreak. + bool m_bShowPlaceHolderFields : 1; // Only used in printing! + bool m_bEncloseWithCharactersOn : 1; + mutable bool m_bIdle; + sal_Int32 m_nDefaultAnchor; // GetDefaultAnchorType() to convert int to RndStdIds // tdf#135266 - tox dialog: remember last used entry level depending on the index type - sal_uInt8 m_nTocEntryLvl; - sal_uInt8 m_nIdxEntryLvl; + sal_uInt8 m_nTocEntryLvl; + sal_uInt8 m_nIdxEntryLvl; // Scale - sal_uInt16 m_nZoom; // In percent. - SvxZoomType m_eZoom; // 'enum' for zoom. + sal_uInt16 m_nZoom; // In percent. + SvxZoomType m_eZoom; // 'enum' for zoom. - sal_uInt8 m_nTableDestination; // Destination for table background. + sal_uInt8 m_nTableDestination; // Destination for table background. #ifdef DBG_UTIL // Corresponds to statements in ui/config/cfgvw.src. @@ -792,6 +793,25 @@ public: void SetShadowCursor(bool b) { SetUIOption(b, ViewOptFlags2::ShadowCursor); } + // Enclose with characters autocomplete, switch on/off + bool IsEncloseWithCharactersOn() const { return m_bEncloseWithCharactersOn; } + void SetEncloseWithCharactersOn(bool b) { m_bEncloseWithCharactersOn = b; } + + static bool IsEncloseWithCharactersTrigger(sal_Unicode cChar) + { + switch (cChar) + { + case '(': [[fallthrough]]; + case '{': [[fallthrough]]; + case '[': [[fallthrough]]; + case '\'': [[fallthrough]]; + case '\"': + return true; + default: + return false; + } + } + //move vertical ruler to the right bool IsVRulerRight() const { return bool(m_nUIOptions & ViewOptFlags2::VRulerRight); } @@ -877,6 +897,7 @@ inline void SwViewOption::SetUIOptions( const SwViewOption& rVOpt ) m_nUIOptions = rVOpt.m_nUIOptions; m_nTableDestination = rVOpt.m_nTableDestination; m_nShadowCursorFillMode = rVOpt.m_nShadowCursorFillMode; + m_bEncloseWithCharactersOn = rVOpt.m_bEncloseWithCharactersOn; } // Helper function for checking HTML-capabilities. diff --git a/sw/qa/extras/uiwriter/uiwriter9.cxx b/sw/qa/extras/uiwriter/uiwriter9.cxx index b3d5d04a7f85..879c7cc15f08 100644 --- a/sw/qa/extras/uiwriter/uiwriter9.cxx +++ b/sw/qa/extras/uiwriter/uiwriter9.cxx @@ -21,6 +21,8 @@ #include <comphelper/propertysequence.hxx> #include <swdtflvr.hxx> #include <o3tl/string_view.hxx> +#include <editeng/acorrcfg.hxx> +#include <swacorr.hxx> #include <view.hxx> #include <wrtsh.hxx> @@ -313,6 +315,87 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf159816) xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true); } +CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf151710) +{ + createSwDoc(); + SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get()); + CPPUNIT_ASSERT(pTextDoc); + + // Check that the particular setting is turned on by default + const SwViewOption* pVwOpt = pTextDoc->GetDocShell()->GetWrtShell()->GetViewOptions(); + CPPUNIT_ASSERT(pVwOpt); + CPPUNIT_ASSERT(pVwOpt->IsEncloseWithCharactersOn()); + + // Localized quotation marks + SvxAutoCorrect* pACorr = SvxAutoCorrCfg::Get().GetAutoCorrect(); + CPPUNIT_ASSERT(pACorr); + LanguageType eLang = Application::GetSettings().GetLanguageTag().getLanguageType(); + OUString sStartSingleQuote{ pACorr->GetQuote('\'', true, eLang) }; + OUString sEndSingleQuote{ pACorr->GetQuote('\'', false, eLang) }; + OUString sStartDoubleQuote{ pACorr->GetQuote('\"', true, eLang) }; + OUString sEndDoubleQuote{ pACorr->GetQuote('\"', false, eLang) }; + + // Insert some text to work with + uno::Sequence<beans::PropertyValue> aArgsInsert( + comphelper::InitPropertySequence({ { "Text", uno::Any(OUString("abcd")) } })); + dispatchCommand(mxComponent, ".uno:InsertText", aArgsInsert); + CPPUNIT_ASSERT_EQUAL(OUString("abcd"), pTextDoc->getText()->getString()); + + // Successfully enclose the text; afterwards the selection should exist with the new + // enclosed text + dispatchCommand(mxComponent, ".uno:SelectAll", {}); + pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '(', 0); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL(OUString("(abcd)"), pTextDoc->getText()->getString()); + + pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '[', 0); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL(OUString("[(abcd)]"), pTextDoc->getText()->getString()); + + pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '{', 0); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL(OUString("{[(abcd)]}"), pTextDoc->getText()->getString()); + + pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '\'', 0); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL(OUString(sStartSingleQuote + "{[(abcd)]}" + sEndSingleQuote), + pTextDoc->getText()->getString()); + + pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '\"', 0); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL(OUString(sStartDoubleQuote + sStartSingleQuote + "{[(abcd)]}" + + sEndSingleQuote + sEndDoubleQuote), + pTextDoc->getText()->getString()); + + // Disable the setting and check that enclosing doesn't happen anymore + const_cast<SwViewOption*>(pVwOpt)->SetEncloseWithCharactersOn(false); + CPPUNIT_ASSERT(!pVwOpt->IsEncloseWithCharactersOn()); + + pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '(', 0); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL(OUString("("), pTextDoc->getText()->getString()); + + dispatchCommand(mxComponent, ".uno:SelectAll", {}); + pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '[', 0); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL(OUString("["), pTextDoc->getText()->getString()); + + dispatchCommand(mxComponent, ".uno:SelectAll", {}); + pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '{', 0); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL(OUString("{"), pTextDoc->getText()->getString()); + + dispatchCommand(mxComponent, ".uno:SelectAll", {}); + pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '\'', 0); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL(sStartSingleQuote, pTextDoc->getText()->getString()); + + dispatchCommand(mxComponent, ".uno:SelectAll", {}); + pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '\"', 0); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT_EQUAL(sStartDoubleQuote, pTextDoc->getText()->getString()); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/ui/config/optpage.cxx b/sw/source/ui/config/optpage.cxx index 6051a53b75f2..6ca432acc34e 100644 --- a/sw/source/ui/config/optpage.cxx +++ b/sw/source/ui/config/optpage.cxx @@ -1642,6 +1642,9 @@ SwShdwCursorOptionsTabPage::SwShdwCursorOptionsTabPage(weld::Container* pPage, w , m_xDefaultAnchorTypeImg(m_xBuilder->weld_widget("lockAnchor")) , m_xMathBaselineAlignmentCB(m_xBuilder->weld_check_button("mathbaseline")) , m_xMathBaselineAlignmentImg(m_xBuilder->weld_widget("lockmathbaseline")) + , m_xFmtAidsAutoComplFrame(m_xBuilder->weld_frame("fmtaidsautocompleteframe")) + , m_xEncloseWithCharactersCB(m_xBuilder->weld_check_button("enclosewithcharacters")) + , m_xEncloseWithCharactersImg(m_xBuilder->weld_widget("lockenclosewithcharacters")) { SwFillMode eMode = SwFillMode::Tab; bool bIsOn = false; @@ -1653,6 +1656,13 @@ SwShdwCursorOptionsTabPage::SwShdwCursorOptionsTabPage(weld::Container* pPage, w } m_xOnOffCB->set_active( bIsOn ); + bool bIsEncloseWithCharactersOn = false; + if (const SwFmtAidsAutoComplItem* pItem = rSet.GetItemIfSet(FN_PARAM_FMT_AIDS_AUTOCOMPL, false)) + { + bIsEncloseWithCharactersOn = pItem->IsEncloseWithCharactersOn(); + } + m_xEncloseWithCharactersCB->set_active(bIsEncloseWithCharactersOn); + m_xDirectCursorFillMode->set_active( static_cast<int>(eMode) ); const SfxUInt16Item* pHtmlModeItem = rSet.GetItemIfSet(SID_HTML_MODE, false); if(!pHtmlModeItem || !(pHtmlModeItem->GetValue() & HTMLMODE_ON)) @@ -1672,6 +1682,9 @@ SwShdwCursorOptionsTabPage::SwShdwCursorOptionsTabPage(weld::Container* pPage, w m_xCursorProtFrame->hide(); m_xCursorInProtCB->hide(); m_xImageFrame->hide(); + + m_xFmtAidsAutoComplFrame->hide(); + m_xEncloseWithCharactersCB->hide(); } SwShdwCursorOptionsTabPage::~SwShdwCursorOptionsTabPage() @@ -1693,8 +1706,8 @@ void SwShdwCursorOptionsTabPage::PageCreated( const SfxAllItemSet& aSet ) OUString SwShdwCursorOptionsTabPage::GetAllStrings() { OUString sAllStrings; - OUString labels[] = { "layoutopt", "displayfl", "cursoropt", "cursorlabel", - "fillmode", "lbImage", "lbDefaultAnchor" }; + OUString labels[] = { "layoutopt", "displayfl", "cursoropt", "cursorlabel", + "fillmode", "lbImage", "lbDefaultAnchor", "autocomplete" }; for (const auto& label : labels) { @@ -1703,8 +1716,9 @@ OUString SwShdwCursorOptionsTabPage::GetAllStrings() } OUString checkButton[] - = { "mathbaseline", "paragraph", "hyphens", "spaces", "nonbreak", "tabs", - "break", "hiddentext", "bookmarks", "cursorinprot", "cursoronoff" }; + = { "mathbaseline", "paragraph", "hyphens", "spaces", + "nonbreak", "tabs", "break", "hiddentext", + "bookmarks", "cursorinprot", "cursoronoff", "enclosewithcharacters" }; for (const auto& check : checkButton) { @@ -1743,6 +1757,16 @@ bool SwShdwCursorOptionsTabPage::FillItemSet( SfxItemSet* rSet ) bRet = true; } + SwFmtAidsAutoComplItem aFmtAidsAutoComplOpt; + aFmtAidsAutoComplOpt.SetEncloseWithCharactersOn(m_xEncloseWithCharactersCB->get_active()); + if (const SwFmtAidsAutoComplItem* pFmtAidsAutoComplItem + = rSet->GetItemIfSet(FN_PARAM_FMT_AIDS_AUTOCOMPL, false); + !pFmtAidsAutoComplItem || *pFmtAidsAutoComplItem != aFmtAidsAutoComplOpt) + { + rSet->Put(aFmtAidsAutoComplOpt); + bRet = true; + } + const SwDocDisplayItem* pOldAttr = GetOldItem(GetItemSet(), FN_PARAM_DOCDISP); SwDocDisplayItem aDisp; @@ -1796,6 +1820,17 @@ void SwShdwCursorOptionsTabPage::Reset( const SfxItemSet* rSet ) m_xMathBaselineAlignmentCB->hide(); } + bool bIsEncloseWithCharactersOn = false; + if (const SwFmtAidsAutoComplItem* pItem + = rSet->GetItemIfSet(FN_PARAM_FMT_AIDS_AUTOCOMPL, false)) + { + bIsEncloseWithCharactersOn = pItem->IsEncloseWithCharactersOn(); + } + bReadOnly = officecfg::Office::Writer::FmtAidsAutocomplete::EncloseWithCharacters::isReadOnly(); + m_xEncloseWithCharactersCB->set_active(bIsEncloseWithCharactersOn); + m_xEncloseWithCharactersCB->set_sensitive(!bReadOnly); + m_xEncloseWithCharactersImg->set_visible(bReadOnly); + if( const SfxBoolItem* pItem = rSet->GetItemIfSet( FN_PARAM_CRSR_IN_PROTECTED, false ) ) m_xCursorInProtCB->set_active(pItem->GetValue()); bReadOnly = officecfg::Office::Writer::Cursor::Option::ProtectedArea::isReadOnly(); diff --git a/sw/source/uibase/app/appopt.cxx b/sw/source/uibase/app/appopt.cxx index 7be59a1dab9a..f21fc733c92a 100644 --- a/sw/source/uibase/app/appopt.cxx +++ b/sw/source/uibase/app/appopt.cxx @@ -102,7 +102,8 @@ std::optional<SfxItemSet> SwModule::CreateItemSet( sal_uInt16 nId ) FN_PARAM_PRINTER, FN_PARAM_STDFONTS, FN_PARAM_WRTSHELL, FN_PARAM_WRTSHELL, FN_PARAM_SHADOWCURSOR, FN_PARAM_SHADOWCURSOR, - FN_PARAM_CRSR_IN_PROTECTED, FN_PARAM_CRSR_IN_PROTECTED> + FN_PARAM_CRSR_IN_PROTECTED, FN_PARAM_CRSR_IN_PROTECTED, + FN_PARAM_FMT_AIDS_AUTOCOMPL, FN_PARAM_FMT_AIDS_AUTOCOMPL> aRet(GetPool()); aRet.Put( SwDocDisplayItem( aViewOpt ) ); @@ -111,6 +112,7 @@ std::optional<SfxItemSet> SwModule::CreateItemSet( sal_uInt16 nId ) { aRet.Put( SwShadowCursorItem( aViewOpt )); aRet.Put( SfxBoolItem(FN_PARAM_CRSR_IN_PROTECTED, aViewOpt.IsCursorInProtectedArea())); + aRet.Put(SwFmtAidsAutoComplItem(aViewOpt)); } if( pAppView ) @@ -393,6 +395,11 @@ void SwModule::ApplyItemSet( sal_uInt16 nId, const SfxItemSet& rSet ) aViewOpt.SetCursorInProtectedArea(pItem->GetValue()); } + if (const SwFmtAidsAutoComplItem* pItem = rSet.GetItemIfSet(FN_PARAM_FMT_AIDS_AUTOCOMPL, false)) + { + aViewOpt.SetEncloseWithCharactersOn(pItem->IsEncloseWithCharactersOn()); + } + // set elements for the current view and shell ApplyUsrPref( aViewOpt, pAppView, bTextDialog? SvViewOpt::DestText : SvViewOpt::DestWeb); diff --git a/sw/source/uibase/config/cfgitems.cxx b/sw/source/uibase/config/cfgitems.cxx index e32c86e14c52..fc8c0e1c4ddc 100644 --- a/sw/source/uibase/config/cfgitems.cxx +++ b/sw/source/uibase/config/cfgitems.cxx @@ -232,6 +232,36 @@ void SwShadowCursorItem::FillViewOptions( SwViewOption& rVOpt ) const rVOpt.SetShdwCursorFillMode( m_eMode ); } +SwFmtAidsAutoComplItem::SwFmtAidsAutoComplItem() + : SfxPoolItem(FN_PARAM_FMT_AIDS_AUTOCOMPL) + , m_bEncloseWithCharactersOn(true) +{ +} + +SwFmtAidsAutoComplItem::SwFmtAidsAutoComplItem(const SwViewOption& rVOpt) + : SfxPoolItem(FN_PARAM_FMT_AIDS_AUTOCOMPL) + , m_bEncloseWithCharactersOn(rVOpt.IsEncloseWithCharactersOn()) +{ +} + +SwFmtAidsAutoComplItem* SwFmtAidsAutoComplItem::Clone(SfxItemPool*) const +{ + return new SwFmtAidsAutoComplItem(*this); +} + +bool SwFmtAidsAutoComplItem::operator==(const SfxPoolItem& rCmp) const +{ + assert(SfxPoolItem::operator==(rCmp)); + const SwFmtAidsAutoComplItem& rItem = static_cast<const SwFmtAidsAutoComplItem&>(rCmp); + + return m_bEncloseWithCharactersOn == rItem.m_bEncloseWithCharactersOn; +} + +void SwFmtAidsAutoComplItem::FillViewOptions(SwViewOption& rVOpt) const +{ + rVOpt.SetEncloseWithCharactersOn(m_bEncloseWithCharactersOn); +} + #ifdef DBG_UTIL SwTestItem* SwTestItem::Clone( SfxItemPool* ) const { diff --git a/sw/source/uibase/config/usrpref.cxx b/sw/source/uibase/config/usrpref.cxx index 8928e8e5470f..0d1ee2859a5d 100644 --- a/sw/source/uibase/config/usrpref.cxx +++ b/sw/source/uibase/config/usrpref.cxx @@ -52,6 +52,7 @@ SwMasterUsrPref::SwMasterUsrPref(bool bWeb) : m_aGridConfig(bWeb, *this), m_aCursorConfig(*this), m_pWebColorConfig(bWeb ? new SwWebColorConfig(*this) : nullptr), + m_aFmtAidsAutoComplConfig(*this), m_bApplyCharUnit(false) { if (comphelper::IsFuzzing()) @@ -73,6 +74,7 @@ SwMasterUsrPref::SwMasterUsrPref(bool bWeb) : m_aCursorConfig.Load(); if(m_pWebColorConfig) m_pWebColorConfig->Load(); + m_aFmtAidsAutoComplConfig.Load(); } SwMasterUsrPref::~SwMasterUsrPref() @@ -568,6 +570,75 @@ void SwCursorConfig::Load() void SwCursorConfig::Notify( const css::uno::Sequence< OUString >& ) {} +Sequence<OUString> SwFmtAidsAutoComplConfig::GetPropertyNames() +{ + static const char* aPropNames[] = { + "EncloseWithCharacters", // 0 + }; + const int nCount = SAL_N_ELEMENTS(aPropNames); + Sequence<OUString> aNames(nCount); + OUString* pNames = aNames.getArray(); + for (int i = 0; i < nCount; i++) + pNames[i] = OUString::createFromAscii(aPropNames[i]); + return aNames; +} + +SwFmtAidsAutoComplConfig::SwFmtAidsAutoComplConfig(SwMasterUsrPref& rPar) + : ConfigItem("Office.Writer/FmtAidsAutocomplete", ConfigItemMode::ReleaseTree) + , m_rParent(rPar) +{ +} + +SwFmtAidsAutoComplConfig::~SwFmtAidsAutoComplConfig() {} + +void SwFmtAidsAutoComplConfig::ImplCommit() +{ + Sequence<OUString> aNames = GetPropertyNames(); + + Sequence<Any> aValues(aNames.getLength()); + Any* pValues = aValues.getArray(); + + for (int nProp = 0; nProp < aNames.getLength(); nProp++) + { + switch (nProp) + { + case 0: + pValues[nProp] <<= m_rParent.IsEncloseWithCharactersOn(); + break; // "FmtAidsAutocomplete/EncloseWithCharacters" + } + } + PutProperties(aNames, aValues); +} + +void SwFmtAidsAutoComplConfig::Load() +{ + Sequence<OUString> aNames = GetPropertyNames(); + Sequence<Any> aValues = GetProperties(aNames); + const Any* pValues = aValues.getConstArray(); + OSL_ENSURE(aValues.getLength() == aNames.getLength(), "GetProperties failed"); + if (aValues.getLength() != aNames.getLength()) + return; + + for (int nProp = 0; nProp < aNames.getLength(); nProp++) + { + if (pValues[nProp].hasValue()) + { + switch (nProp) + { + case 0: + { + bool bSet = false; + pValues[nProp] >>= bSet; + m_rParent.SetEncloseWithCharactersOn(bSet); + break; // "FmtAidsAutocomplete/EncloseWithCharacters" + } + } + } + } +} + +void SwFmtAidsAutoComplConfig::Notify(const css::uno::Sequence<OUString>&) {} + SwWebColorConfig::SwWebColorConfig(SwMasterUsrPref& rPar) : ConfigItem("Office.WriterWeb/Background", ConfigItemMode::ReleaseTree), m_rParent(rPar), diff --git a/sw/source/uibase/config/viewopt.cxx b/sw/source/uibase/config/viewopt.cxx index 96ac6531e14d..d37f3bfecc32 100644 --- a/sw/source/uibase/config/viewopt.cxx +++ b/sw/source/uibase/config/viewopt.cxx @@ -251,6 +251,7 @@ SwViewOption::SwViewOption() : mbViewLayoutBookMode(false), mbHideWhitespaceMode(false), m_bShowPlaceHolderFields( true ), + m_bEncloseWithCharactersOn( true ), m_nZoom( 100 ), m_eZoom( SvxZoomType::PERCENT ), m_nTableDestination(TBL_DEST_CELL) @@ -327,6 +328,7 @@ SwViewOption::SwViewOption(const SwViewOption& rVOpt) mbViewLayoutBookMode = rVOpt.mbViewLayoutBookMode; mbHideWhitespaceMode = rVOpt.mbHideWhitespaceMode; m_bShowPlaceHolderFields = rVOpt.m_bShowPlaceHolderFields; + m_bEncloseWithCharactersOn = rVOpt.m_bEncloseWithCharactersOn; m_bIdle = rVOpt.m_bIdle; m_nDefaultAnchor = rVOpt.m_nDefaultAnchor; m_nTocEntryLvl = rVOpt.m_nTocEntryLvl; @@ -373,6 +375,7 @@ SwViewOption& SwViewOption::operator=( const SwViewOption &rVOpt ) mbViewLayoutBookMode = rVOpt.mbViewLayoutBookMode; mbHideWhitespaceMode = rVOpt.mbHideWhitespaceMode; m_bShowPlaceHolderFields = rVOpt.m_bShowPlaceHolderFields; + m_bEncloseWithCharactersOn = rVOpt.m_bEncloseWithCharactersOn; m_bIdle = rVOpt.m_bIdle; m_nDefaultAnchor = rVOpt.m_nDefaultAnchor; m_aColorConfig = rVOpt.m_aColorConfig; diff --git a/sw/source/uibase/docvw/edtwin.cxx b/sw/source/uibase/docvw/edtwin.cxx index 9c4a3e6c69ee..b3f8c6855e43 100644 --- a/sw/source/uibase/docvw/edtwin.cxx +++ b/sw/source/uibase/docvw/edtwin.cxx @@ -2578,8 +2578,45 @@ KEYINPUT_CHECKTABLE_INSDEL: m_aInBuffer += " "; } - const bool bIsAutoCorrectChar = SvxAutoCorrect::IsAutoCorrectChar( aCh ); - if( !aKeyEvent.GetRepeat() && pACorr && ( bIsAutoCorrectChar || rSh.IsNbspRunNext() ) && + const SwViewOption& rVwOpt = SwViewOption::GetCurrentViewOptions(); + const bool bIsAutoCorrectChar = SvxAutoCorrect::IsAutoCorrectChar(aCh); + if (!aKeyEvent.GetRepeat() && rSh.HasSelection() + && rVwOpt.IsEncloseWithCharactersOn() + && SwViewOption::IsEncloseWithCharactersTrigger(aCh)) + { + FlushInBuffer(); + switch (aCh) + { + case '(': + rSh.InsertEnclosingChars(u"(", u")"); + break; + case '[': + rSh.InsertEnclosingChars(u"[", u"]"); + break; + case '{': + rSh.InsertEnclosingChars(u"{", u"}"); + break; + case '\"': + { + LanguageType eLang + = Application::GetSettings().GetLanguageTag().getLanguageType(); + OUString sStartQuote{ pACorr->GetQuote('\"', true, eLang) }; + OUString sEndQuote{ pACorr->GetQuote('\"', false, eLang) }; + rSh.InsertEnclosingChars(sStartQuote, sEndQuote); + break; + } + case '\'': + { + LanguageType eLang + = Application::GetSettings().GetLanguageTag().getLanguageType(); + OUString sStartQuote{ pACorr->GetQuote('\'', true, eLang) }; + OUString sEndQuote{ pACorr->GetQuote('\'', false, eLang) }; + rSh.InsertEnclosingChars(sStartQuote, sEndQuote); + break; + } + } + } + else if( !aKeyEvent.GetRepeat() && pACorr && ( bIsAutoCorrectChar || rSh.IsNbspRunNext() ) && pACfg->IsAutoFormatByInput() && (( pACorr->IsAutoCorrFlag( ACFlags::ChgWeightUnderl ) && ( '*' == aCh || '_' == aCh ) ) || diff --git a/sw/source/uibase/inc/cfgitems.hxx b/sw/source/uibase/inc/cfgitems.hxx index 34ffa2d24e12..6ee5ea620cda 100644 --- a/sw/source/uibase/inc/cfgitems.hxx +++ b/sw/source/uibase/inc/cfgitems.hxx @@ -133,6 +133,27 @@ public: void SetOn( bool bFlag ) { m_bOn = bFlag; } }; +class SW_DLLPUBLIC SwFmtAidsAutoComplItem final : public SfxPoolItem +{ + friend class SwShdwCursorOptionsTabPage; + friend class SwModule; + + bool m_bEncloseWithCharactersOn; + +public: + SwFmtAidsAutoComplItem(); + SwFmtAidsAutoComplItem(const SwViewOption& rVOpt); + + virtual SwFmtAidsAutoComplItem* Clone(SfxItemPool* pPool = nullptr) const override; + virtual bool operator==(const SfxPoolItem&) const override; + + void FillViewOptions(SwViewOption& rVOpt) const; + + bool IsEncloseWithCharactersOn() const { return m_bEncloseWithCharactersOn; } + + void SetEncloseWithCharactersOn(bool bFlag) { m_bEncloseWithCharactersOn = bFlag; } +}; + #ifdef DBG_UTIL // Item for settings dialog - test settings diff --git a/sw/source/uibase/inc/optpage.hxx b/sw/source/uibase/inc/optpage.hxx index e2641fd7fc2b..68192a64f1d4 100644 --- a/sw/source/uibase/inc/optpage.hxx +++ b/sw/source/uibase/inc/optpage.hxx @@ -318,6 +318,10 @@ class SwShdwCursorOptionsTabPage final : public SfxTabPage std::unique_ptr<weld::CheckButton> m_xMathBaselineAlignmentCB; std::unique_ptr<weld::Widget> m_xMathBaselineAlignmentImg; + std::unique_ptr<weld::Frame> m_xFmtAidsAutoComplFrame; + std::unique_ptr<weld::CheckButton> m_xEncloseWithCharactersCB; + std::unique_ptr<weld::Widget> m_xEncloseWithCharactersImg; + public: SwShdwCursorOptionsTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); virtual ~SwShdwCursorOptionsTabPage() override; diff --git a/sw/source/uibase/inc/usrpref.hxx b/sw/source/uibase/inc/usrpref.hxx index 1464c90bce3c..24d9c6a7a34b 100644 --- a/sw/source/uibase/inc/usrpref.hxx +++ b/sw/source/uibase/inc/usrpref.hxx @@ -103,6 +103,24 @@ public: using ConfigItem::SetModified; }; +class SwFmtAidsAutoComplConfig final : public utl::ConfigItem +{ +private: + SwMasterUsrPref& m_rParent; + + static css::uno::Sequence<OUString> GetPropertyNames(); + + virtual void ImplCommit() override; + +public: + SwFmtAidsAutoComplConfig(SwMasterUsrPref& rParent); + virtual ~SwFmtAidsAutoComplConfig() override; + + virtual void Notify(const css::uno::Sequence<OUString>& aPropertyNames) override; + void Load(); + using ConfigItem::SetModified; +}; + class SwWebColorConfig final : public utl::ConfigItem { private: @@ -127,6 +145,7 @@ class SwMasterUsrPref : public SwViewOption friend class SwGridConfig; friend class SwCursorConfig; friend class SwWebColorConfig; + friend class SwFmtAidsAutoComplConfig; SwFieldUpdateFlags m_eFieldUpdateFlags; //update of fields and charts sal_Int32 m_nLinkUpdateMode; @@ -146,6 +165,7 @@ class SwMasterUsrPref : public SwViewOption SwGridConfig m_aGridConfig; SwCursorConfig m_aCursorConfig; std::unique_ptr<SwWebColorConfig> m_pWebColorConfig; + SwFmtAidsAutoComplConfig m_aFmtAidsAutoComplConfig; bool m_bApplyCharUnit; // apply_char_unit public: @@ -162,6 +182,7 @@ public: m_aCursorConfig.SetModified(); if(m_pWebColorConfig) m_pWebColorConfig->SetModified(); + m_aFmtAidsAutoComplConfig.SetModified(); } void SetUpdateLinkMode(sal_Int32 nSet, bool bNoModify = false) @@ -266,6 +287,15 @@ public: m_aLayoutConfig.SetModified(); } } + + void SetEncloseWithCharactersOn(bool bVal, bool noModify = false) + { + this->SwViewOption::SetEncloseWithCharactersOn(bVal); + if (!noModify) + { + m_aFmtAidsAutoComplConfig.SetModified(); + } + } }; #endif diff --git a/sw/source/uibase/inc/wrtsh.hxx b/sw/source/uibase/inc/wrtsh.hxx index dd97160b140b..8b8c85753e96 100644 --- a/sw/source/uibase/inc/wrtsh.hxx +++ b/sw/source/uibase/inc/wrtsh.hxx @@ -318,6 +318,7 @@ typedef bool (SwWrtShell::*FNSimpleMove)(); void InsertByWord( const OUString & ); SW_DLLPUBLIC void InsertPageBreak(const OUString *pPageDesc = nullptr, const ::std::optional<sal_uInt16>& rPgNum = std::nullopt); + void InsertEnclosingChars(std::u16string_view sStartStr, std::u16string_view sEndStr); SW_DLLPUBLIC void InsertLineBreak(std::optional<SwLineBreakClear> oClear = std::nullopt); void InsertColumnBreak(); SW_DLLPUBLIC void InsertContentControl(SwContentControlType eType); diff --git a/sw/source/uibase/wrtsh/wrtsh1.cxx b/sw/source/uibase/wrtsh/wrtsh1.cxx index 0054eca4cb34..2063029680df 100644 --- a/sw/source/uibase/wrtsh/wrtsh1.cxx +++ b/sw/source/uibase/wrtsh/wrtsh1.cxx @@ -986,6 +986,17 @@ void SwWrtShell::InsertPageBreak(const OUString *pPageDesc, const ::std::optiona collectUIInformation("BREAK_PAGE", "parameter"); } +// Insert enclosing characters +// Selections will be overwritten +void SwWrtShell::InsertEnclosingChars(std::u16string_view sStartStr, std::u16string_view sEndStr) +{ + for (SwPaM& rPaM : SwWrtShell::GetCursor()->GetRingContainer()) + { + const OUString aStr = sStartStr + rPaM.GetText() + sEndStr; + SwViewShell::getIDocumentContentOperations().ReplaceRange(rPaM, aStr, false); + } +} + // Insert hard page break; // Selections will be overwritten diff --git a/sw/uiconfig/swriter/ui/optformataidspage.ui b/sw/uiconfig/swriter/ui/optformataidspage.ui index 4825b51a356e..a454c39b872e 100644 --- a/sw/uiconfig/swriter/ui/optformataidspage.ui +++ b/sw/uiconfig/swriter/ui/optformataidspage.ui @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.38.2 --> +<!-- Generated with glade 3.40.0 --> <interface domain="sw"> <requires lib="gtk+" version="3.20"/> <object class="GtkBox" id="OptFormatAidsPage"> @@ -551,6 +551,7 @@ <property name="visible">True</property> <property name="can-focus">False</property> <property name="orientation">vertical</property> + <property name="spacing">12</property> <child> <object class="GtkFrame" id="directcrsrframe"> <property name="visible">True</property> @@ -758,6 +759,78 @@ <property name="position">1</property> </packing> </child> + <child> + <object class="GtkFrame" id="fmtaidsautocompleteframe"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="valign">start</property> + <property name="label-xalign">0</property> + <property name="shadow-type">none</property> + <child> + <!-- n-columns=2 n-rows=1 --> + <object class="GtkGrid" id="grid7"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="margin-start">12</property> + <property name="margin-top">6</property> + <property name="row-spacing">6</property> + <child> + <object class="GtkCheckButton" id="enclosewithcharacters"> + <property name="label" translatable="yes" context="optformataidspage|enclosewithcharacters">Enclose with characters</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">False</property> + <property name="tooltip-text" translatable="yes" context="optformataidspage|enclosewithcharacters|tooltip_text">When enabled you can enclose selected text with parentheses, square brackets, curly braces or double/single quotation marks when pressing the respective button.</property> + <property name="use-underline">True</property> + <property name="draw-indicator">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="enclosewithcharacters-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="extended_tip|enclosewithcharacters">Specifies that you can enclose selected text with parentheses, square brackets, curly braces or double/single quotation marks when pressing the respective button.</property> + </object> + </child> + </object> + <packing> + <property name="left-attach">1</property> + <property name="top-attach">0</property> + </packing> + </child> + <child> + <object class="GtkImage" id="lockenclosewithcharacters"> + <property name="can-focus">False</property> + <property name="no-show-all">True</property> + <property name="halign">center</property> + <property name="valign">center</property> + <property name="icon-name">res/lock.png</property> + <child internal-child="accessible"> + <object class="AtkObject" id="lockenclosewithcharacters-atkobject"> + <property name="AtkObject::accessible-description">Specifies that you can enclose selected text with parentheses, square brackets, curly braces or quotation marks when pressing the respective button.</property> + </object> + </child> + </object> + <packing> + <property name="left-attach">0</property> + <property name="top-attach">0</property> + </packing> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="autocomplete"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="label" translatable="yes" context="optformataidspage|autocomplete">Auto complete</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> </object> <packing> <property name="left-attach">1</property>