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;
             }
         }
     }

Reply via email to