basctl/sdi/baside.sdi | 6 basctl/source/basicide/baside2.cxx | 6 basctl/source/basicide/basides1.cxx | 7 basctl/source/basicide/unomodel.cxx | 51 ++ basctl/source/basicide/unomodel.hxx | 3 basctl/uiconfig/basicide/menubar/menubar.xml | 2 include/sfx2/sfxsids.hrc | 1 include/vcl/textview.hxx | 3 officecfg/registry/data/org/openoffice/Office/Accelerators.xcu | 6 officecfg/registry/data/org/openoffice/Office/UI/BasicIDECommands.xcu | 5 sfx2/sdi/sfx.sdi | 16 svx/source/tbxctrls/tbunosearchcontrollers.cxx | 20 - vcl/source/edit/textview.cxx | 177 ++++++++++ 13 files changed, 298 insertions(+), 5 deletions(-)
New commits: commit 22b5007e2740e1f461968f3c8e919326eb4d4785 Author: Rafael Lima <rafael.palma.l...@gmail.com> AuthorDate: Sat Jan 13 22:26:48 2024 +0100 Commit: Andreas Heinisch <andreas.heini...@yahoo.de> CommitDate: Thu Feb 1 13:37:28 2024 +0100 tdf#140004 Toggle comment in the Basic IDE This patch adds the "toggle comment" functionality to the Basic IDE. The shortcut Ctrl + Alt + C is used to execute it. It works similarly to other code editors such as Kate and VSCode. Change-Id: Ifdae42b3729cc909baf87c729fe8c3cdf6428184 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162005 Reviewed-by: Andreas Heinisch <andreas.heini...@yahoo.de> Tested-by: Andreas Heinisch <andreas.heini...@yahoo.de> diff --git a/basctl/sdi/baside.sdi b/basctl/sdi/baside.sdi index 74b425cf6db4..34f34a6362e2 100644 --- a/basctl/sdi/baside.sdi +++ b/basctl/sdi/baside.sdi @@ -688,6 +688,12 @@ shell basctl_Shell ExecMethod = ExecuteDialog; StateMethod = GetState; ] + + SID_TOGGLE_COMMENT + [ + StateMethod = GetState; + ExecMethod = ExecuteGlobal; + ] } interface BasicIDEDocument diff --git a/basctl/source/basicide/baside2.cxx b/basctl/source/basicide/baside2.cxx index db9b109f7947..62bbaa799815 100644 --- a/basctl/source/basicide/baside2.cxx +++ b/basctl/source/basicide/baside2.cxx @@ -1066,6 +1066,12 @@ void ModulWindow::ExecuteGlobal (SfxRequest& rReq) GetDispatcher()->Execute(SID_GOTOLINE); } break; + + case SID_TOGGLE_COMMENT: + { + GetEditView()->ToggleComment(); + } + break; } } diff --git a/basctl/source/basicide/basides1.cxx b/basctl/source/basicide/basides1.cxx index 8052845983f3..6fe3b9a562f6 100644 --- a/basctl/source/basicide/basides1.cxx +++ b/basctl/source/basicide/basides1.cxx @@ -1235,6 +1235,13 @@ void Shell::GetState(SfxItemSet &rSet) rSet.DisableItem( nWh ); } break; + case SID_TOGGLE_COMMENT: + { + // Only available in a ModulWindow if the document can be edited + if (pCurWin && (!dynamic_cast<ModulWindow*>(pCurWin.get()) || pCurWin->IsReadOnly())) + rSet.DisableItem(nWh); + } + break; case SID_GOTOLINE: { // if this is not a module window hide the diff --git a/basctl/uiconfig/basicide/menubar/menubar.xml b/basctl/uiconfig/basicide/menubar/menubar.xml index d649f968c8d9..bf41ce562bec 100644 --- a/basctl/uiconfig/basicide/menubar/menubar.xml +++ b/basctl/uiconfig/basicide/menubar/menubar.xml @@ -55,6 +55,7 @@ <menu:menuitem menu:id=".uno:Paste"/> <menu:menuseparator/> <menu:menuitem menu:id=".uno:SelectAll"/> + <menu:menuitem menu:id=".uno:ToggleComment"/> <menu:menuseparator/> <menu:menuitem menu:id="vnd.sun.star.findbar:FocusToFindbar"/> <menu:menuitem menu:id=".uno:SearchDialog"/> @@ -177,4 +178,3 @@ </menu:menupopup> </menu:menu> </menu:menubar> - diff --git a/include/sfx2/sfxsids.hrc b/include/sfx2/sfxsids.hrc index 4c8a080c1b2f..176e500c55b3 100644 --- a/include/sfx2/sfxsids.hrc +++ b/include/sfx2/sfxsids.hrc @@ -670,6 +670,7 @@ class SvxZoomItem; #define SID_BASICIDE_WATCH TypedWhichId<SfxBoolItem>( SID_BASICIDE_START + 55 ) #define SID_BASICIDE_STACK TypedWhichId<SfxBoolItem>( SID_BASICIDE_START + 56 ) #define SID_BASICIDE_COLOR_SCHEME_DLG ( SID_BASICIDE_START + 57 ) +#define SID_TOGGLE_COMMENT ( SID_BASICIDE_START + 58 ) #define SID_OPTIONS_TREEDIALOG ( SID_BASICIDE_START + 862) #define SID_OPTIONS_SECURITY ( SID_BASICIDE_START + 863) diff --git a/include/vcl/textview.hxx b/include/vcl/textview.hxx index 84a89e8c58d8..0de1f7c0d5a9 100644 --- a/include/vcl/textview.hxx +++ b/include/vcl/textview.hxx @@ -222,6 +222,9 @@ public: bool IndentBlock(); bool UnindentBlock(); + + // Used in the Basic IDE to toggle comment on a block of code + void ToggleComment(); }; #endif diff --git a/officecfg/registry/data/org/openoffice/Office/Accelerators.xcu b/officecfg/registry/data/org/openoffice/Office/Accelerators.xcu index 2265ec7c436a..50f3cd1cccf7 100644 --- a/officecfg/registry/data/org/openoffice/Office/Accelerators.xcu +++ b/officecfg/registry/data/org/openoffice/Office/Accelerators.xcu @@ -371,6 +371,12 @@ Ctrl+Shift+e aka E_SHIFT_MOD1 under GTK/IBUS is for some emoji thing </node> <node oor:name="Modules"> <node oor:name="com.sun.star.script.BasicIDE" oor:op="replace"> + <node oor:name="C_MOD1_MOD2" oor:op="replace"> + <prop oor:name="Command"> + <value xml:lang="x-no-translate">L10N SHORTCUTS - NO TRANSLATE</value> + <value xml:lang="en-US">.uno:ToggleComment</value> + </prop> + </node> <node oor:name="F5" oor:op="replace"> <prop oor:name="Command"> <value xml:lang="x-no-translate">L10N SHORTCUTS - NO TRANSLATE</value> diff --git a/officecfg/registry/data/org/openoffice/Office/UI/BasicIDECommands.xcu b/officecfg/registry/data/org/openoffice/Office/UI/BasicIDECommands.xcu index 97832553e20f..c63bbb215fd2 100644 --- a/officecfg/registry/data/org/openoffice/Office/UI/BasicIDECommands.xcu +++ b/officecfg/registry/data/org/openoffice/Office/UI/BasicIDECommands.xcu @@ -18,6 +18,11 @@ <value xml:lang="en-US">Line Numbers</value> </prop> </node> + <node oor:name=".uno:ToggleComment" oor:op="replace"> + <prop oor:name="Label" oor:type="xs:string"> + <value xml:lang="en-US">Toggle Comment</value> + </prop> + </node> <node oor:name=".uno:InsertFormRadio" oor:op="replace"> <prop oor:name="Label" oor:type="xs:string"> <value xml:lang="en-US">Form Option Button</value> diff --git a/sfx2/sdi/sfx.sdi b/sfx2/sdi/sfx.sdi index 9c2b72d5f443..5d26a161c817 100644 --- a/sfx2/sdi/sfx.sdi +++ b/sfx2/sdi/sfx.sdi @@ -2393,6 +2393,22 @@ SfxBoolItem ShowLines SID_SHOWLINES GroupId = SfxGroupId::Macro; ] +SfxVoidItem ToggleComment SID_TOGGLE_COMMENT +() +[ + AutoUpdate = TRUE, + FastCall = FALSE, + ReadOnlyDoc = TRUE, + Toggle = FALSE, + Container = FALSE, + RecordAbsolute = FALSE, + RecordPerSet; + + AccelConfig = TRUE, + MenuConfig = TRUE, + ToolBoxConfig = TRUE, + GroupId = SfxGroupId::Macro; +] SfxVoidItem RunMacro SID_RUNMACRO () diff --git a/vcl/source/edit/textview.cxx b/vcl/source/edit/textview.cxx index ad1d28d1997b..331f69fb914d 100644 --- a/vcl/source/edit/textview.cxx +++ b/vcl/source/edit/textview.cxx @@ -20,6 +20,7 @@ #include <memory> #include <i18nutil/searchopt.hxx> #include <o3tl/deleter.hxx> +#include <o3tl/string_view.hxx> #include <utility> #include <vcl/textview.hxx> #include <vcl/texteng.hxx> @@ -2234,5 +2235,181 @@ bool TextView::UnindentBlock() return ImpIndentBlock( false ); } +void TextView::ToggleComment() +{ + /* To determines whether to add or remove comment markers, the rule is: + * - If any of the lines in the selection does not start with a comment character "'" + * or "REM" then the selection is commented + * - Otherwise, the selection is uncommented (i.e. if all of the lines start with a + * comment marker "'" or "REM") + * - Empty lines, or lines with only blank spaces or tabs are ignored + */ + + TextEngine* pEngine = GetTextEngine(); + TextSelection aSel = GetSelection(); + sal_uInt32 nStartPara = aSel.GetStart().GetPara(); + sal_uInt32 nEndPara = aSel.GetEnd().GetPara(); + + // True = Comment character will be added; False = Comment marker will be removed + bool bAddCommentChar = false; + + // Indicates whether any change has been made + bool bChanged = false; + + // Indicates whether the selection is downwards (normal) or upwards (reversed) + bool bSelReversed = false; + + if (nEndPara < nStartPara) + { + std::swap(nStartPara, nEndPara); + bSelReversed = true; + } + + for (sal_uInt32 n = nStartPara; n <= nEndPara; n++) + { + OUString sText = pEngine->GetText(n).trim(); + + // Empty lines or lines with only blank spaces and tabs are ignored + if (sText.isEmpty()) + continue; + + if (!sText.startsWith("'") && !sText.startsWithIgnoreAsciiCase("REM")) + { + bAddCommentChar = true; + break; + } + + // Notice that a REM comment is only actually a comment if: + // a) There is no subsequent character or + // b) The subsequent character is a blank space or a tab + OUString sRest; + if (sText.startsWithIgnoreAsciiCase("REM", &sRest)) + { + if (sRest.getLength() > 0 && !sRest.startsWith(" ") && !sRest.startsWith(" ")) + { + bAddCommentChar = true; + break; + } + } + } + + if (bAddCommentChar) + { + // For each line, determine the first position where there is a character that is not + // a blank space or a tab; the comment marker will be the smallest such position + size_t nCommentPos = std::string::npos; + + for (sal_uInt32 n = nStartPara; n <= nEndPara; n++) + { + OUString sText = pEngine->GetText(n); + std::u16string_view sLine(sText); + sal_uInt32 nCharPos = sLine.find_first_not_of(u" "); + + // Update the position where to place the comment marker + if (nCharPos < nCommentPos) + nCommentPos = nCharPos; + + // If the comment position is zero, then there's no more need to keep searching + if (nCommentPos == 0) + break; + } + + // Insert the comment marker in all lines (except empty lines) + for (sal_uInt32 n = nStartPara; n <= nEndPara; n++) + { + OUString sText = pEngine->GetText(n); + std::u16string_view sLine(sText); + if (o3tl::trim(sLine).length() > 0) + { + pEngine->ImpInsertText(TextPaM(n, nCommentPos), "' "); + bChanged = true; + } + } + } + else + { + // For each line, find the first comment marker and remove it + for (sal_uInt32 nPara = nStartPara; nPara <= nEndPara; nPara++) + { + OUString sText = pEngine->GetText(nPara); + if (!sText.isEmpty()) + { + // Determine the position of the comment marker and check whether it's + // a single quote "'" or a "REM" comment + sal_Int32 nQuotePos = sText.indexOf("'"); + sal_Int32 nRemPos = sText.toAsciiUpperCase().indexOf("REM"); + + // An empty line or a line with only blank spaces or tabs needs to be skipped + if (nQuotePos == -1 && nRemPos == -1) + continue; + + // nRemPos only refers to a comment if the subsequent character is a blank space or tab + const sal_Int32 nRemSub = nRemPos + 3; + if (nRemPos != -1 && nRemPos < sText.getLength() - 3 && + sText.indexOf(" ", nRemSub) != nRemSub && + sText.indexOf(" ", nRemSub) != nRemSub) + { + nRemPos = -1; + } + + // True = comment uses single quote; False = comment uses REM + bool bQuoteComment = true; + + // Start and end positions to be removed + sal_Int32 nStartPos = nQuotePos; + sal_Int32 nEndPos = nStartPos + 1; + + if (nQuotePos == -1) + bQuoteComment = false; + else if (nRemPos != -1 && nRemPos < nQuotePos) + bQuoteComment = false; + + if (!bQuoteComment) + { + nStartPos = nRemPos; + nEndPos = nStartPos + 3; + } + + // Check if the next character is a blank space or a tab + if (sText.indexOf(" ", nEndPos) == nEndPos || sText.indexOf(" ", nEndPos) == nEndPos) + nEndPos++; + + // Remove the comment marker + pEngine->ImpDeleteText(TextSelection(TextPaM(nPara, nStartPos), TextPaM(nPara, nEndPos))); + bChanged = true; + } + } + } + + // Update selection if there was a selection in the first place + if (bChanged) + { + TextPaM aNewStart; + if (!bSelReversed) + aNewStart = TextPaM(nStartPara, std::min(aSel.GetStart().GetIndex(), + pEngine->GetText(nStartPara).getLength())); + else + aNewStart = TextPaM(nStartPara, std::min(aSel.GetEnd().GetIndex(), + pEngine->GetText(nEndPara).getLength())); + + if (HasSelection()) + { + TextPaM aNewEnd; + if (!bSelReversed) + aNewEnd = TextPaM(nEndPara, pEngine->GetText(nEndPara).getLength()); + else + aNewEnd = TextPaM(nEndPara, pEngine->GetText(nStartPara).getLength()); + + TextSelection aNewSel(aNewStart, aNewEnd); + ImpSetSelection(aNewSel); + } + else + { + TextSelection aNewSel(aNewStart, aNewStart); + ImpSetSelection(aNewSel); + } + } +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit 7bcce4180d11f6f49a71f681eeefc556fc2302ba Author: Rafael Lima <rafael.palma.l...@gmail.com> AuthorDate: Thu Jan 25 23:54:39 2024 +0100 Commit: Andreas Heinisch <andreas.heini...@yahoo.de> CommitDate: Thu Feb 1 13:37:16 2024 +0100 tdf#131641 Enter selected text in the search bar (Basic IDE) This patch makes the selected text in the code editor be automatically inserted in the search bar. Change-Id: Ibbe64aa3375a5a47dedb762001ed4b99f4b22e46 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162548 Reviewed-by: Andreas Heinisch <andreas.heini...@yahoo.de> Tested-by: Andreas Heinisch <andreas.heini...@yahoo.de> diff --git a/basctl/source/basicide/unomodel.cxx b/basctl/source/basicide/unomodel.cxx index 5d3946b426c6..180bf3d17fa7 100644 --- a/basctl/source/basicide/unomodel.cxx +++ b/basctl/source/basicide/unomodel.cxx @@ -19,6 +19,7 @@ #include "basdoc.hxx" +#include <basidesh.hxx> #include <iderdll.hxx> #include <com/sun/star/io/IOException.hpp> #include <comphelper/sequence.hxx> @@ -29,6 +30,41 @@ #include "unomodel.hxx" + +namespace { + +// Implements XEnumeration to hold a single selected portion of text +// This will actually only hold a single string value +class SelectionEnumeration : public ::cppu::WeakImplHelper<css::container::XEnumeration> +{ +private: + OUString m_sText; + bool m_bHasElements; + +public: + explicit SelectionEnumeration(OUString& sSelectedText) + : m_sText(sSelectedText) + , m_bHasElements(true) {} + + virtual sal_Bool SAL_CALL hasMoreElements() override + { + return m_bHasElements; + } + + virtual css::uno::Any SAL_CALL nextElement() override + { + if (m_bHasElements) + { + m_bHasElements = false; + return css::uno::Any(m_sText); + } + + throw css::container::NoSuchElementException(); + } +}; + +} // End of unnamed namespace + namespace basctl { @@ -114,6 +150,21 @@ void SIDEModel::notImplemented() throw io::IOException("Can't store IDE model" ); } +// XModel +css::uno::Reference< css::uno::XInterface > SAL_CALL SIDEModel::getCurrentSelection() +{ + SolarMutexGuard aGuard; + uno::Reference<container::XEnumeration> xEnum; + Shell* pShell = GetShell(); + + if (pShell) + { + OUString sText = GetShell()->GetSelectionText(false); + xEnum = new SelectionEnumeration(sText); + } + return xEnum; +} + } // namespace basctl extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* diff --git a/basctl/source/basicide/unomodel.hxx b/basctl/source/basicide/unomodel.hxx index b47873005699..9b0289032660 100644 --- a/basctl/source/basicide/unomodel.hxx +++ b/basctl/source/basicide/unomodel.hxx @@ -53,6 +53,9 @@ public: const css::uno::Sequence< css::beans::PropertyValue >& seqArguments ) override; virtual void SAL_CALL storeToURL( const OUString& sURL, const css::uno::Sequence< css::beans::PropertyValue >& seqArguments ) override; + + // XModel + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getCurrentSelection() override; }; } // namespace basctl diff --git a/svx/source/tbxctrls/tbunosearchcontrollers.cxx b/svx/source/tbxctrls/tbunosearchcontrollers.cxx index f8c4436443bc..2f23bfaa97f4 100644 --- a/svx/source/tbxctrls/tbunosearchcontrollers.cxx +++ b/svx/source/tbxctrls/tbunosearchcontrollers.cxx @@ -45,6 +45,7 @@ #include <com/sun/star/text/XTextRange.hpp> #include <com/sun/star/text/XTextViewCursorSupplier.hpp> #include <com/sun/star/ui/XUIElement.hpp> +#include <com/sun/star/container/XEnumeration.hpp> #include <com/sun/star/util/URL.hpp> #include <com/sun/star/util/URLTransformer.hpp> #include <com/sun/star/util/SearchAlgorithms.hpp> @@ -253,11 +254,22 @@ void FindTextFieldControl::SetTextToSelected_Impl() else { uno::Reference<frame::XModel> xModel(xController->getModel(), uno::UNO_SET_THROW); - uno::Reference<container::XIndexAccess> xIndexAccess(xModel->getCurrentSelection(), uno::UNO_QUERY_THROW); - if (xIndexAccess->getCount() > 0) + uno::Reference<uno::XInterface> xSelection = xModel->getCurrentSelection(); + uno::Reference<container::XIndexAccess> xIndexAccess(xSelection, uno::UNO_QUERY); + if (xIndexAccess.is()) { - uno::Reference<text::XTextRange> xTextRange(xIndexAccess->getByIndex(0), uno::UNO_QUERY_THROW); - aString = xTextRange->getString(); + if (xIndexAccess->getCount() > 0) + { + uno::Reference<text::XTextRange> xTextRange(xIndexAccess->getByIndex(0), uno::UNO_QUERY_THROW); + aString = xTextRange->getString(); + } + } + else + { + // The Basic IDE returns a XEnumeration with a single item + uno::Reference<container::XEnumeration> xEnum(xSelection, uno::UNO_QUERY_THROW); + if (xEnum->hasMoreElements()) + xEnum->nextElement() >>= aString; } } }