diff options
author | Michael Stahl <michael.stahl@allotropia.de> | 2024-02-27 12:36:54 +0100 |
---|---|---|
committer | Michael Stahl <michael.stahl@allotropia.de> | 2024-03-04 11:04:21 +0100 |
commit | a1647e26e1ac290fcf5ccf3e3ee3e4d4f3a40a95 (patch) | |
tree | 96948ae96fcee86980a8afe7a47776bf48df759f | |
parent | 1b06a77743a2718e937cc6f6ff71060bb6d75a2d (diff) |
Revert "sw: revert Select All improvements"
This reverts commit 6eb71b1778d8bc44ec642f3e61096350e4c868dc.
-rw-r--r-- | sw/inc/crsrsh.hxx | 14 | ||||
-rw-r--r-- | sw/inc/doc.hxx | 1 | ||||
-rw-r--r-- | sw/inc/undobj.hxx | 12 | ||||
-rw-r--r-- | sw/qa/extras/odfimport/odfimport.cxx | 4 | ||||
-rw-r--r-- | sw/qa/extras/uiwriter/data/table-at-end-of-cell.fodt | 219 | ||||
-rw-r--r-- | sw/qa/extras/uiwriter/uiwriter.cxx | 22 | ||||
-rw-r--r-- | sw/qa/extras/uiwriter/uiwriter2.cxx | 18 | ||||
-rw-r--r-- | sw/source/core/crsr/crsrsh.cxx | 321 | ||||
-rw-r--r-- | sw/source/core/docnode/ndtbl.cxx | 287 | ||||
-rw-r--r-- | sw/source/core/edit/eddel.cxx | 36 | ||||
-rw-r--r-- | sw/source/core/edit/edglss.cxx | 14 | ||||
-rw-r--r-- | sw/source/core/undo/undobj.cxx | 22 | ||||
-rw-r--r-- | sw/source/core/undo/unins.cxx | 4 | ||||
-rw-r--r-- | sw/source/core/undo/untblk.cxx | 6 | ||||
-rw-r--r-- | sw/source/uibase/wrtsh/move.cxx | 46 | ||||
-rw-r--r-- | sw/source/uibase/wrtsh/select.cxx | 36 |
16 files changed, 835 insertions, 227 deletions
diff --git a/sw/inc/crsrsh.hxx b/sw/inc/crsrsh.hxx index a0205ffe4d52..26e6895e88cd 100644 --- a/sw/inc/crsrsh.hxx +++ b/sw/inc/crsrsh.hxx @@ -326,7 +326,7 @@ public: // only for usage in special cases allowed! void ExtendedSelectAll(bool bFootnotes = true); /// If ExtendedSelectAll() was called and selection didn't change since then. - bool ExtendedSelectedAll(); + ::std::optional<::std::pair<SwNode const*, ::std::vector<SwTableNode*>>> ExtendedSelectedAll() const; enum class StartsWith { None, Table, HiddenPara }; /// If document body starts with a table or starts/ends with hidden paragraph. StartsWith StartsWith_(); @@ -586,8 +586,11 @@ public: // fields etc. OUString GetSelText() const; - // Check of SPoint or Mark of current cursor are placed within a table. - inline const SwTableNode* IsCursorInTable() const; + /// Check if Point of current cursor is placed within a table. + const SwTableNode* IsCursorInTable() const; + bool MoveOutOfTable(); + bool TrySelectOuterTable(); + bool MoveStartText(); bool IsCursorInFootnote() const; @@ -901,11 +904,6 @@ inline bool SwCursorShell::IsMultiSelection() const return m_pCurrentCursor->GetNext() != m_pCurrentCursor; } -inline const SwTableNode* SwCursorShell::IsCursorInTable() const -{ - return m_pCurrentCursor->GetNode().FindTableNode(); -} - inline bool SwCursorShell::IsCursorPtAtEnd() const { return m_pCurrentCursor->End() == m_pCurrentCursor->GetPoint(); diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx index 83651fc8fcb2..66ec563e7a14 100644 --- a/sw/inc/doc.hxx +++ b/sw/inc/doc.hxx @@ -1189,6 +1189,7 @@ public: sal_uInt16 nCnt = 1, bool bBehind = true ); // Delete Columns/Rows in table. + void DelTable(SwTableNode * pTable); bool DeleteRowCol( const SwSelBoxes& rBoxes, bool bColumn = false ); void DeleteRow( const SwCursor& rCursor ); void DeleteCol( const SwCursor& rCursor ); diff --git a/sw/inc/undobj.hxx b/sw/inc/undobj.hxx index 71d9c511591d..42b14f7859e5 100644 --- a/sw/inc/undobj.hxx +++ b/sw/inc/undobj.hxx @@ -21,6 +21,7 @@ #include <vector> #include <memory> +#include <optional> #include <svl/undo.hxx> #include <tools/solar.h> @@ -177,12 +178,11 @@ protected: const sal_uLong* pEndNdIdx = nullptr, bool bForceCreateFrames = false); - // These two methods move the SPoint back/forth from PaM. With it - // a range can be spanned for Undo/Redo. (In this case the SPoint - // is before the manipulated range!!) - // The flag indicates if there is content before the SPoint. - static bool MovePtBackward( SwPaM& rPam ); - static void MovePtForward( SwPaM& rPam, bool bMvBkwrd ); + // These two methods save and restore the Point of PaM. + // If the point cannot be moved, a "backup" is created on the previous node. + // Either way, it will not be moved by inserting at its original position. + static ::std::optional<SwNodeIndex> MovePtBackward(SwPaM& rPam); + static void MovePtForward(SwPaM& rPam, ::std::optional<SwNodeIndex> && oMvBkwrd); // Before moving stuff into UndoNodes-Array care has to be taken that // the content-bearing attributes are removed from the nodes-array. diff --git a/sw/qa/extras/odfimport/odfimport.cxx b/sw/qa/extras/odfimport/odfimport.cxx index 3fa5321389e4..dc9bc44679e6 100644 --- a/sw/qa/extras/odfimport/odfimport.cxx +++ b/sw/qa/extras/odfimport/odfimport.cxx @@ -590,6 +590,8 @@ DECLARE_ODFIMPORT_TEST(testFdo37606, "fdo37606.odt") pWrtShell->SelAll(); // Selects the whole table. pWrtShell->SelAll(); // Selects the whole document. + pShellCursor = pWrtShell->getShellCursor(false); + SwTextNode& rStart = dynamic_cast<SwTextNode&>(pShellCursor->Start()->nNode.GetNode()); CPPUNIT_ASSERT_EQUAL(OUString("A1"), rStart.GetText()); @@ -655,11 +657,11 @@ DECLARE_ODFIMPORT_TEST(testFdo69862, "fdo69862.odt") SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument *>(mxComponent.get()); CPPUNIT_ASSERT(pTextDoc); SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell(); - SwShellCursor* pShellCursor = pWrtShell->getShellCursor(false); pWrtShell->SelAll(); // Selects A1. pWrtShell->SelAll(); // Selects the whole table. pWrtShell->SelAll(); // Selects the whole document. + SwShellCursor* pShellCursor = pWrtShell->getShellCursor(false); SwTextNode& rStart = dynamic_cast<SwTextNode&>(pShellCursor->Start()->nNode.GetNode()); // This was "Footnote.", as Ctrl-A also selected footnotes, but it should not. CPPUNIT_ASSERT_EQUAL(OUString("A1"), rStart.GetText()); diff --git a/sw/qa/extras/uiwriter/data/table-at-end-of-cell.fodt b/sw/qa/extras/uiwriter/data/table-at-end-of-cell.fodt new file mode 100644 index 000000000000..4e18f7dc2ce4 --- /dev/null +++ b/sw/qa/extras/uiwriter/data/table-at-end-of-cell.fodt @@ -0,0 +1,219 @@ +<?xml version='1.0' encoding='UTF-8'?> +<office:document xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:meta><meta:creation-date>2023-06-15T12:29:51.722401974</meta:creation-date><dc:date>2023-06-15T12:30:57.494419372</dc:date><meta:editing-duration>PT1M13S</meta:editing-duration><meta:editing-cycles>1</meta:editing-cycles><meta:document-statistic meta:table-count="2" meta:image-count="0" meta:object-count="0" meta:page-count="1" meta:paragraph-count="0" meta:word-count="0" meta:character-count="0" meta:non-whitespace-character-count="0"/><meta:generator>LibreOfficeDev/7.6.0.0.alpha0$Linux_X86_64 LibreOffice_project/2e5dbe93649ec8043e9da75ddc01c486dbbf18e0</meta:generator></office:meta> + <office:font-face-decls> + <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Lohit Devanagari1" svg:font-family="'Lohit Devanagari'" style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="Noto Sans CJK SC" svg:font-family="'Noto Sans CJK SC'" style:font-family-generic="system" style:font-pitch="variable"/> + </office:font-face-decls> + <office:styles> + <style:default-style style:family="graphic"> + <style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.3cm" draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" draw:start-line-spacing-vertical="0.283cm" draw:end-line-spacing-horizontal="0.283cm" draw:end-line-spacing-vertical="0.283cm" style:flow-with-text="false"/> + <style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" loext:tab-stop-distance="0cm" style:writing-mode="lr-tb" style:font-independent-line-spacing="false"> + <style:tab-stops/> + </style:paragraph-properties> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="de" fo:country="DE" style:letter-kerning="true" style:font-name-asian="Noto Sans CJK SC" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lohit Devanagari1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN"/> + </style:default-style> + <style:default-style style:family="paragraph"> + <style:paragraph-properties fo:orphans="2" fo:widows="2" fo:hyphenation-ladder-count="no-limit" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="1.251cm" style:writing-mode="page"/> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="de" fo:country="DE" style:letter-kerning="true" style:font-name-asian="Noto Sans CJK SC" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Lohit Devanagari1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="5" loext:hyphenation-zone="no-limit"/> + </style:default-style> + <style:default-style style:family="table"> + <style:table-properties table:border-model="collapsing"/> + </style:default-style> + <style:default-style style:family="table-row"> + <style:table-row-properties fo:keep-together="auto"/> + </style:default-style> + <style:style style:name="Standard" style:family="paragraph" style:class="text"/> + <style:style style:name="Table_20_Contents" style:display-name="Table Contents" style:family="paragraph" style:parent-style-name="Standard" style:class="extra"> + <style:paragraph-properties fo:orphans="0" fo:widows="0" text:number-lines="false" text:line-number="0"/> + </style:style> + <text:outline-style style:name="Outline"> + <text:outline-level-style text:level="1" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="2" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="3" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="4" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="5" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="6" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="7" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="8" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="9" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="10" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + </text:outline-style> + <text:notes-configuration text:note-class="footnote" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document"/> + <text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0"/> + <text:linenumbering-configuration text:number-lines="false" text:offset="0.499cm" style:num-format="1" text:number-position="left" text:increment="5"/> + <loext:theme loext:name="Office Theme"> + <loext:color-table loext:name="LibreOffice"> + <loext:color loext:name="dk1" loext:color="#000000"/> + <loext:color loext:name="lt1" loext:color="#ffffff"/> + <loext:color loext:name="dk2" loext:color="#000000"/> + <loext:color loext:name="lt2" loext:color="#ffffff"/> + <loext:color loext:name="accent1" loext:color="#18a303"/> + <loext:color loext:name="accent2" loext:color="#0369a3"/> + <loext:color loext:name="accent3" loext:color="#a33e03"/> + <loext:color loext:name="accent4" loext:color="#8e03a3"/> + <loext:color loext:name="accent5" loext:color="#c99c00"/> + <loext:color loext:name="accent6" loext:color="#c9211e"/> + <loext:color loext:name="hlink" loext:color="#0000ee"/> + <loext:color loext:name="folHlink" loext:color="#551a8b"/> + </loext:color-table> + </loext:theme> + </office:styles> + <office:automatic-styles> + <style:style style:name="Table1" style:family="table"> + <style:table-properties style:width="17cm" table:align="margins"/> + </style:style> + <style:style style:name="Table1.A" style:family="table-column"> + <style:table-column-properties style:column-width="8.5cm" style:rel-column-width="32767*"/> + </style:style> + <style:style style:name="Table1.A1" style:family="table-cell"> + <style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.5pt solid #000000" fo:border-right="none" fo:border-top="0.5pt solid #000000" fo:border-bottom="0.5pt solid #000000"/> + </style:style> + <style:style style:name="Table1.B1" style:family="table-cell"> + <style:table-cell-properties fo:padding="0.097cm" fo:border="0.5pt solid #000000"/> + </style:style> + <style:style style:name="Table1.A2" style:family="table-cell"> + <style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.5pt solid #000000" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.5pt solid #000000"/> + </style:style> + <style:style style:name="Table1.B2" style:family="table-cell"> + <style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.5pt solid #000000" fo:border-right="0.5pt solid #000000" fo:border-top="none" fo:border-bottom="0.5pt solid #000000"/> + </style:style> + <style:style style:name="Table2" style:family="table"> + <style:table-properties style:width="8.306cm" table:align="margins"/> + </style:style> + <style:style style:name="Table2.A" style:family="table-column"> + <style:table-column-properties style:column-width="4.154cm" style:rel-column-width="32767*"/> + </style:style> + <style:style style:name="Table2.A1" style:family="table-cell"> + <style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.5pt solid #000000" fo:border-right="none" fo:border-top="0.5pt solid #000000" fo:border-bottom="0.5pt solid #000000"/> + </style:style> + <style:style style:name="Table2.B1" style:family="table-cell"> + <style:table-cell-properties fo:padding="0.097cm" fo:border="0.5pt solid #000000"/> + </style:style> + <style:style style:name="Table2.A2" style:family="table-cell"> + <style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.5pt solid #000000" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.5pt solid #000000"/> + </style:style> + <style:style style:name="Table2.B2" style:family="table-cell"> + <style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.5pt solid #000000" fo:border-right="0.5pt solid #000000" fo:border-top="none" fo:border-bottom="0.5pt solid #000000"/> + </style:style> + <style:style style:name="Table2" style:family="table"> + <style:table-properties style:width="8.306cm" table:align="margins"/> + </style:style> + <style:style style:name="Table2.A" style:family="table-column"> + <style:table-column-properties style:column-width="4.154cm" style:rel-column-width="32767*"/> + </style:style> + <style:style style:name="Table2.A1" style:family="table-cell"> + <style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.5pt solid #000000" fo:border-right="none" fo:border-top="0.5pt solid #000000" fo:border-bottom="0.5pt solid #000000"/> + </style:style> + <style:style style:name="Table2.B1" style:family="table-cell"> + <style:table-cell-properties fo:padding="0.097cm" fo:border="0.5pt solid #000000"/> + </style:style> + <style:style style:name="Table2.A2" style:family="table-cell"> + <style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.5pt solid #000000" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.5pt solid #000000"/> + </style:style> + <style:style style:name="Table2.B2" style:family="table-cell"> + <style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.5pt solid #000000" fo:border-right="0.5pt solid #000000" fo:border-top="none" fo:border-bottom="0.5pt solid #000000"/> + </style:style> + <style:page-layout style:name="pm1"> + <style:page-layout-properties fo:page-width="21.001cm" fo:page-height="29.7cm" style:num-format="1" style:print-orientation="portrait" fo:margin-top="2cm" fo:margin-bottom="2cm" fo:margin-left="2cm" fo:margin-right="2cm" style:writing-mode="lr-tb" style:footnote-max-height="0cm" loext:margin-gutter="0cm"> + <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/> + </style:page-layout-properties> + <style:header-style/> + <style:footer-style/> + </style:page-layout> + </office:automatic-styles> + <office:master-styles> + <style:master-page style:name="Standard" style:page-layout-name="pm1"/> + </office:master-styles> + <office:body> + <office:text> + <text:sequence-decls> + <text:sequence-decl text:display-outline-level="0" text:name="Illustration"/> + <text:sequence-decl text:display-outline-level="0" text:name="Table"/> + <text:sequence-decl text:display-outline-level="0" text:name="Text"/> + <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/> + <text:sequence-decl text:display-outline-level="0" text:name="Figure"/> + </text:sequence-decls> + <table:table table:name="Table1" table:style-name="Table1"> + <table:table-column table:style-name="Table1.A" table:number-columns-repeated="2"/> + <table:table-row> + <table:table-cell table:style-name="Table1.A1" office:value-type="string"> + <text:p text:style-name="Table_20_Contents"/> + </table:table-cell> + <table:table-cell table:style-name="Table1.B1" office:value-type="string"> + <text:p text:style-name="Table_20_Contents"/> + </table:table-cell> + </table:table-row> + <table:table-row> + <table:table-cell table:style-name="Table1.A2" office:value-type="string"> + <text:p text:style-name="Table_20_Contents"/> + </table:table-cell> + <table:table-cell table:style-name="Table1.B2" office:value-type="string"> + <text:p text:style-name="Standard"/> + <table:table table:name="Table2" table:style-name="Table2"> + <table:table-column table:style-name="Table2.A" table:number-columns-repeated="2"/> + <table:table-row> + <table:table-cell table:style-name="Table2.A1" office:value-type="string"> + <text:p text:style-name="Table_20_Contents"/> + </table:table-cell> + <table:table-cell table:style-name="Table2.B1" office:value-type="string"> + <text:p text:style-name="Table_20_Contents"/> + </table:table-cell> + </table:table-row> + <table:table-row> + <table:table-cell table:style-name="Table2.A2" office:value-type="string"> + <text:p text:style-name="Table_20_Contents"/> + </table:table-cell> + <table:table-cell table:style-name="Table2.B2" office:value-type="string"> + <text:p text:style-name="Table_20_Contents"/> + </table:table-cell> + </table:table-row> + </table:table> + </table:table-cell> + </table:table-row> + </table:table> + <text:p text:style-name="Standard"/> + </office:text> + </office:body> +</office:document>
\ No newline at end of file diff --git a/sw/qa/extras/uiwriter/uiwriter.cxx b/sw/qa/extras/uiwriter/uiwriter.cxx index 3df7f5e8b75d..cdb6a3634552 100644 --- a/sw/qa/extras/uiwriter/uiwriter.cxx +++ b/sw/qa/extras/uiwriter/uiwriter.cxx @@ -942,6 +942,23 @@ void SwUiWriterTest::testTdf67238() CPPUNIT_ASSERT(!((rTable.GetTableBox("C3"))->GetFrameFormat()->GetProtect()).IsContentProtected()); } +CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf155685) +{ + SwDoc* pDoc = createDoc("table-at-end-of-cell.fodt"); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->GoNextCell(); + pWrtShell->GoNextCell(); + pWrtShell->GoNextCell(); + pWrtShell->SelAll(); + pWrtShell->Delete(); + // this crashed + pWrtShell->Undo(); + pWrtShell->Undo(); + pWrtShell->Redo(); + // this crashed + pWrtShell->Redo(); +} + void SwUiWriterTest::testFdo75110() { SwDoc* pDoc = createDoc("fdo75110.odt"); @@ -8082,6 +8099,7 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf133982) lcl_dispatchCommand(mxComponent, ".uno:SelectAll", {}); lcl_dispatchCommand(mxComponent, ".uno:SelectAll", {}); lcl_dispatchCommand(mxComponent, ".uno:SelectAll", {}); + lcl_dispatchCommand(mxComponent, ".uno:SelectAll", {}); //Without the fix in place, it would have crashed here lcl_dispatchCommand(mxComponent, ".uno:Cut", {}); @@ -8141,10 +8159,12 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf114973) { SwDoc* const pDoc = createDoc("tdf114973.fodt"); + SwWrtShell* const pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->SttEndDoc(true); + lcl_dispatchCommand(mxComponent, ".uno:SelectAll", {}); Scheduler::ProcessEventsToIdle(); - SwWrtShell* const pWrtShell = pDoc->GetDocShell()->GetWrtShell(); // bug: cursor jumped into header CPPUNIT_ASSERT(!pWrtShell->IsInHeaderFooter()); diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx b/sw/qa/extras/uiwriter/uiwriter2.cxx index f2a358d46b25..702efd1c2dff 100644 --- a/sw/qa/extras/uiwriter/uiwriter2.cxx +++ b/sw/qa/extras/uiwriter/uiwriter2.cxx @@ -23,6 +23,10 @@ #include <i18nlangtag/languagetag.hxx> #include <vcl/scheduler.hxx> #include <vcl/settings.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/viewfrm.hxx> +#include <svx/svxids.hrc> +#include <view.hxx> #include <ndtxt.hxx> #include <swdtflvr.hxx> #include <wrtsh.hxx> @@ -256,6 +260,20 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf101534) CPPUNIT_ASSERT(aSet.HasItem(RES_LR_SPACE)); } +CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testExtendedSelectAllHang) +{ + SwDoc* const pDoc = createDoc(); + SwWrtShell* const pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + + pWrtShell->InsertFootnote(""); + pWrtShell->StartOfSection(); + SwView* pView = pDoc->GetDocShell()->GetView(); + SfxStringItem aLangString(SID_LANGUAGE_STATUS, "Default_Spanish (Bolivia)"); + // this looped + pView->GetViewFrame()->GetDispatcher()->ExecuteList(SID_LANGUAGE_STATUS, SfxCallMode::SYNCHRON, + { &aLangString }); +} + CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testRedlineMoveInsertInDelete) { loadURL("private:factory/swriter", nullptr); diff --git a/sw/source/core/crsr/crsrsh.cxx b/sw/source/core/crsr/crsrsh.cxx index 2258d39a8422..e58821c60808 100644 --- a/sw/source/core/crsr/crsrsh.cxx +++ b/sw/source/core/crsr/crsrsh.cxx @@ -581,54 +581,322 @@ bool SwCursorShell::SttEndDoc( bool bStt ) return bRet; } +const SwTableNode* SwCursorShell::IsCursorInTable() const +{ + if (m_pTableCursor) + { // find the table that has the selected boxes + return m_pTableCursor->GetSelectedBoxes()[0]->GetSttNd()->FindTableNode(); + } + return m_pCurrentCursor->GetNode().FindTableNode(); +} + +// fun cases to consider: +// * outermost table +// - into para => SA/ESA +// - into prev/next table => continue... +// - no prev/next => done +// * inner table +// - into containing cell => SA/ESA +// - into prev/next of containing cell +// + into para +// + into table nested in prev/next cell +// - out of table -> as above +// => iterate in one direction until a node is reached that is a parent or a sibling of a parent of the current table +// - parent reached => SA/ESA depending +// - not in parent but in *prev/next* sibling of outer cell => TrySelectOuterTable +// - not in parent but in *prev/next* sibling of outer table => TrySelectOuterTable +// => select-all cannot select a sequence of table with no para at same level; only 1 table +// - no parent, no prev/next => TrySelectOuterTable + +bool SwCursorShell::MoveOutOfTable() +{ + SwPosition const point(*getShellCursor(false)->GetPoint()); + SwPosition const mark(*getShellCursor(false)->GetMark()); + + for (auto const fnMove : {&fnMoveBackward, &fnMoveForward}) + { + Push(); + SwCursor *const pCursor(getShellCursor(false)); + + pCursor->Normalize(fnMove == &fnMoveBackward); + pCursor->DeleteMark(); + SwTableNode const*const pTable(pCursor->GetPoint()->nNode.GetNode().FindTableNode()); + assert(pTable); + while (MovePara(GoInContent, *fnMove)) + { + SwStartNode const*const pBox(pCursor->GetPoint()->nNode.GetNode().FindTableBoxStartNode()); + if (!pBox) + { + Pop(SwCursorShell::PopMode::DeleteStack); + return true; // moved to paragraph at top-level of text + } + if (pBox->GetIndex() < pTable->GetIndex() + && pTable->EndOfSectionIndex() < pBox->EndOfSectionIndex()) + { + Pop(SwCursorShell::PopMode::DeleteStack); + return true; // pBox contains start position (pTable) + } + } + + Pop(SwCursorShell::PopMode::DeleteCurrent); + // FIXME: Pop doesn't restore original cursor if nested tables + *getShellCursor(false)->GetPoint() = point; + getShellCursor(false)->SetMark(); + *getShellCursor(false)->GetMark() = mark; + } + return false; +} + +bool SwCursorShell::TrySelectOuterTable() +{ + assert(m_pTableCursor); + SwTableNode const& rInnerTable(*m_pTableCursor->GetPoint()->nNode.GetNode().FindTableNode()); + SwNodes const& rNodes(rInnerTable.GetNodes()); + SwTableNode const*const pOuterTable(rInnerTable.GetNodes()[rInnerTable.GetIndex()-1]->FindTableNode()); + if (!pOuterTable) + { + return false; + } + + // manually select boxes of pOuterTable + SwNodeIndex firstCell(*pOuterTable, +1); + SwNodeIndex lastCell(*rNodes[pOuterTable->EndOfSectionIndex()-1]->StartOfSectionNode()); + SwSelBoxes aNew; + pOuterTable->GetTable().CreateSelection(&firstCell.GetNode(), &lastCell.GetNode(), + aNew, SwTable::SEARCH_NONE, false); + // set table cursor to 1st / last content which may be in inner table + SwContentNode *const pStart = rNodes.GoNext(&firstCell); + assert(pStart); // must at least find the previous point node + lastCell = *lastCell.GetNode().EndOfSectionNode(); + SwContentNode *const pEnd = SwNodes::GoPrevious(&lastCell); + assert(pEnd); // must at least find the previous point node + delete m_pTableCursor; + m_pTableCursor = new SwShellTableCursor(*this, SwPosition(*pStart, 0), Point(), + SwPosition(*pEnd, 0), Point()); + m_pTableCursor->ActualizeSelection( aNew ); + m_pTableCursor->IsCursorMovedUpdate(); // clear this so GetCursor() doesn't recreate our SwSelBoxes + + // this will update m_pCurrentCursor based on m_pTableCursor + UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY); + + return true; +} + +/// find XText start node +static SwStartNode const* FindTextStart(SwPosition const& rPos) +{ + SwStartNode const* pStartNode(rPos.nNode.GetNode().StartOfSectionNode()); + while (pStartNode && (pStartNode->IsSectionNode() || pStartNode->IsTableNode())) + { + pStartNode = pStartNode->StartOfSectionNode(); + } + return pStartNode; +} + +static SwStartNode const* FindParentText(SwShellCursor const& rCursor) +{ + // find closest section containing both start and end - ignore Sections + SwStartNode const* pStartNode(FindTextStart(*rCursor.Start())); + SwEndNode const* pEndNode(FindTextStart(*rCursor.End())->EndOfSectionNode()); + while (pStartNode->EndOfSectionNode()->GetIndex() < pEndNode->GetIndex()) + { + pStartNode = pStartNode->StartOfSectionNode(); + } + while (pStartNode->GetIndex() < pEndNode->StartOfSectionNode()->GetIndex()) + { + pEndNode = pEndNode->StartOfSectionNode()->StartOfSectionNode()->EndOfSectionNode(); + } + assert(pStartNode->EndOfSectionNode() == pEndNode); + + return (pStartNode->IsSectionNode() || pStartNode->IsTableNode()) + ? FindTextStart(SwPosition(*pStartNode)) + : pStartNode; +} + +bool SwCursorShell::MoveStartText() +{ + SwPosition const old(*m_pCurrentCursor->GetPoint()); + SwStartNode const*const pStartNode(FindParentText(*getShellCursor(false))); + assert(pStartNode); + SwTableNode const*const pTable(pStartNode->FindTableNode()); + *m_pCurrentCursor->GetPoint() = SwPosition(*pStartNode); + GetDoc()->GetNodes().GoNext(&m_pCurrentCursor->GetPoint()->nNode); + m_pCurrentCursor->GetPoint()->nContent.Assign(m_pCurrentCursor->GetPoint()->nNode.GetNode().GetContentNode(), 0); + while (m_pCurrentCursor->GetPoint()->nNode.GetNode().FindTableNode() != pTable + && (!pTable || pTable->GetIndex() < m_pCurrentCursor->GetPoint()->nNode.GetNode().FindTableNode()->GetIndex()) + && MoveOutOfTable()); + UpdateCursor(SwCursorShell::SCROLLWIN|SwCursorShell::CHKRANGE|SwCursorShell::READONLY); + return old != *m_pCurrentCursor->GetPoint(); +} + +// select all inside the current XText, with table or hidden para at start/end void SwCursorShell::ExtendedSelectAll(bool bFootnotes) { + // find common ancestor node of both ends of cursor + SwStartNode const*const pStartNode(FindParentText(*getShellCursor(false))); + assert(pStartNode); + if (IsTableMode()) + { // convert m_pTableCursor to m_pCurrentCursor after determining pStartNode + TableCursorToCursor(); + } SwNodes& rNodes = GetDoc()->GetNodes(); + m_pCurrentCursor->Normalize(true); SwPosition* pPos = m_pCurrentCursor->GetPoint(); - pPos->nNode = bFootnotes ? rNodes.GetEndOfPostIts() : rNodes.GetEndOfAutotext(); + pPos->nNode = bFootnotes ? rNodes.GetEndOfPostIts() : static_cast<SwNode const&>(*pStartNode); pPos->nContent.Assign( rNodes.GoNext( &pPos->nNode ), 0 ); pPos = m_pCurrentCursor->GetMark(); - pPos->nNode = rNodes.GetEndOfContent(); + pPos->nNode = bFootnotes ? rNodes.GetEndOfContent() : static_cast<SwNode const&>(*pStartNode->EndOfSectionNode()); SwContentNode* pCNd = SwNodes::GoPrevious( &pPos->nNode ); pPos->nContent.Assign( pCNd, pCNd ? pCNd->Len() : 0 ); } -bool SwCursorShell::ExtendedSelectedAll() +static typename SwCursorShell::StartsWith StartsWith(SwStartNode const& rStart) +{ + for (auto i = rStart.GetIndex() + 1; i < rStart.EndOfSectionIndex(); ++i) + { + SwNode const& rNode(*rStart.GetNodes()[i]); + switch (rNode.GetNodeType()) + { + case SwNodeType::Section: + continue; + case SwNodeType::Table: + return SwCursorShell::StartsWith::Table; + case SwNodeType::Text: + if (rNode.GetTextNode()->IsHidden()) + { + return SwCursorShell::StartsWith::HiddenPara; + } + return SwCursorShell::StartsWith::None; + default: + return SwCursorShell::StartsWith::None; + } + } + return SwCursorShell::StartsWith::None; +} + +static typename SwCursorShell::StartsWith EndsWith(SwStartNode const& rStart) +{ + for (auto i = rStart.EndOfSectionIndex() - 1; rStart.GetIndex() < i; --i) + { + SwNode const& rNode(*rStart.GetNodes()[i]); + switch (rNode.GetNodeType()) + { + case SwNodeType::End: + if (rNode.StartOfSectionNode()->IsTableNode()) + { + return SwCursorShell::StartsWith::Table; + } +//TODO buggy SwUndoRedline in testTdf137503? assert(rNode.StartOfSectionNode()->IsSectionNode()); + break; + case SwNodeType::Text: + if (rNode.GetTextNode()->IsHidden()) + { + return SwCursorShell::StartsWith::HiddenPara; + } + return SwCursorShell::StartsWith::None; + default: + return SwCursorShell::StartsWith::None; + } + } + return SwCursorShell::StartsWith::None; +} + +// return the node that is the start of the extended selection (to include table +// or section start nodes; looks like extending for end nodes is not required) +::std::optional<::std::pair<SwNode const*, ::std::vector<SwTableNode*>>> +SwCursorShell::ExtendedSelectedAll() const { + if (m_pTableCursor) + { + return {}; + } + SwNodes& rNodes = GetDoc()->GetNodes(); - SwNodeIndex nNode = rNodes.GetEndOfAutotext(); + SwShellCursor const*const pShellCursor = getShellCursor(false); + SwStartNode const* pStartNode(FindParentText(*pShellCursor)); + + SwNodeIndex nNode(*pStartNode); SwContentNode* pStart = rNodes.GoNext(&nNode); + if (!pStart) + { + return {}; + } - nNode = rNodes.GetEndOfContent(); + nNode = *pStartNode->EndOfSectionNode(); SwContentNode* pEnd = SwNodes::GoPrevious(&nNode); - - if (!pStart || !pEnd) - return false; + if (!pEnd) + { + return {}; + } SwPosition aStart(*pStart, 0); SwPosition aEnd(*pEnd, pEnd->Len()); - SwShellCursor* pShellCursor = getShellCursor(false); - return aStart == *pShellCursor->Start() && aEnd == *pShellCursor->End(); + if (!(aStart == *pShellCursor->Start() && aEnd == *pShellCursor->End())) + { + return {}; + } + + auto const ends(::EndsWith(*pStartNode)); + if (::StartsWith(*pStartNode) == StartsWith::None + && ends == StartsWith::None) + { + return {}; // "ordinary" selection will work + } + + ::std::vector<SwTableNode*> tablesAtEnd; + if (ends == StartsWith::Table) + { + SwNode * pLastNode(rNodes[pStartNode->EndOfSectionIndex() - 1]); + while (pLastNode->IsEndNode()) + { + SwNode *const pNode(pLastNode->StartOfSectionNode()); + if (pNode->IsTableNode()) + { + tablesAtEnd.push_back(pNode->GetTableNode()); + pLastNode = rNodes[pNode->GetIndex() - 1]; + } + else if (pNode->IsSectionNode()) + { + pLastNode = rNodes[pLastNode->GetIndex() - 1]; + } + } + assert(!tablesAtEnd.empty()); + } + + // tdf#133990 ensure directly containing section is included in SwUndoDelete + while (pStartNode->IsSectionNode() + && pStartNode->GetIndex() == pStartNode->StartOfSectionNode()->GetIndex() + 1 + && pStartNode->EndOfSectionNode()->GetIndex() + 1 == pStartNode->StartOfSectionNode()->EndOfSectionNode()->GetIndex()) + { + pStartNode = pStartNode->StartOfSectionNode(); + } + + // pStartNode is the node that fully contains the selection - the first + // node of the selection is the first node inside pStartNode + return ::std::make_pair(rNodes[pStartNode->GetIndex() + 1], tablesAtEnd); } typename SwCursorShell::StartsWith SwCursorShell::StartsWith_() { - SwNodes& rNodes = GetDoc()->GetNodes(); - SwNodeIndex nNode(rNodes.GetEndOfExtras()); - SwContentNode* pContentNode = rNodes.GoNext(&nNode); - if (pContentNode->FindTableNode()) + SwShellCursor const*const pShellCursor = getShellCursor(false); + // first, check if this is invalid; ExtendedSelectAll(true) may result in + // a) an ordinary selection that is valid + // b) a selection that is extended + // c) a selection that is invalid and will cause FindParentText to loop + SwNode const& rEndOfExtras(GetDoc()->GetNodes().GetEndOfExtras()); + if (pShellCursor->Start()->nNode.GetIndex() <= rEndOfExtras.GetIndex() + && rEndOfExtras.GetIndex() < pShellCursor->End()->nNode.GetIndex()) { - return StartsWith::Table; + return StartsWith::None; // *very* extended, no ExtendedSelectedAll handling! } - if (pContentNode->GetTextNode()->IsHidden()) + SwStartNode const*const pStartNode(FindParentText(*pShellCursor)); + if (auto const ret = ::StartsWith(*pStartNode); ret != StartsWith::None) { - return StartsWith::HiddenPara; + return ret; } - nNode = rNodes.GetEndOfContent(); - pContentNode = SwNodes::GoPrevious(&nNode); - if (pContentNode->GetTextNode()->IsHidden()) + if (auto const ret = ::EndsWith(*pStartNode); ret != StartsWith::None) { - return StartsWith::HiddenPara; + return ret; } return StartsWith::None; } @@ -1483,8 +1751,8 @@ void SwCursorShell::VisPortChgd( const SwRect & rRect ) /** Set the cursor back into content. - This should only be called if the cursor was move somewhere else (e.g. when - deleting a border). The new position is calculated from its current position + This should only be called if the cursor was moved (e.g. when deleting a + text frame). The new position is calculated from its current position in the layout. */ void SwCursorShell::UpdateCursorPos() @@ -1496,7 +1764,7 @@ void SwCursorShell::UpdateCursorPos() if (isInHiddenTextFrame(pShellCursor) && !ExtendedSelectedAll()) { - SwCursorMoveState aTmpState( MV_NONE ); + SwCursorMoveState aTmpState(MV_SETONLYTEXT); aTmpState.m_bSetInReadOnly = IsReadOnlyAvailable(); GetLayout()->GetCursorOfst( pShellCursor->GetPoint(), pShellCursor->GetPtPos(), &aTmpState ); @@ -2285,7 +2553,7 @@ bool SwCursorShell::Pop(PopMode const eDelete, if (PopMode::DeleteCurrent == eDelete) { - SwCursorSaveState aSaveState( *m_pCurrentCursor ); + ::std::optional<SwCursorSaveState> oSaveState( *m_pCurrentCursor ); // If the visible SSelection was not changed const Point& rPoint = pOldStack->GetPtPos(); @@ -2313,6 +2581,7 @@ bool SwCursorShell::Pop(PopMode const eDelete, !m_pCurrentCursor->IsSelOvr( SwCursorSelOverFlags::Toggle | SwCursorSelOverFlags::ChangePos ) ) { + oSaveState.reset(); // prevent UAF UpdateCursor(); // update current cursor if (m_pTableCursor) { // tdf#106929 ensure m_pCurrentCursor ring is recreated from table @@ -2394,6 +2663,8 @@ void SwCursorShell::ShowCursor() { if( !m_bBasicHideCursor ) { + comphelper::FlagRestorationGuard g(mbSelectAll, StartsWith_() != StartsWith::None && ExtendedSelectedAll()); + m_bSVCursorVis = true; m_pCurrentCursor->SetShowTextInputFieldOverlay( true ); diff --git a/sw/source/core/docnode/ndtbl.cxx b/sw/source/core/docnode/ndtbl.cxx index b12fc72228e2..379c0a7666be 100644 --- a/sw/source/core/docnode/ndtbl.cxx +++ b/sw/source/core/docnode/ndtbl.cxx @@ -1933,6 +1933,166 @@ void SwDoc::DeleteCol( const SwCursor& rCursor ) GetIDocumentUndoRedo().EndUndo(SwUndoId::COL_DELETE, nullptr); } +void SwDoc::DelTable(SwTableNode *const pTableNd) +{ + { + // tdf#156267 remove DdeBookmarks before deleting nodes + SwDataChanged aTmp(SwPaM(*pTableNd, *pTableNd->EndOfSectionNode())); + } + + bool bNewTextNd = false; + // Is it alone in a FlyFrame? + SwNodeIndex aIdx( *pTableNd, -1 ); + const SwStartNode* pSttNd = aIdx.GetNode().GetStartNode(); + if( pSttNd ) + { + const sal_uLong nTableEnd = pTableNd->EndOfSectionIndex() + 1; + const sal_uLong nSectEnd = pSttNd->EndOfSectionIndex(); + if( nTableEnd == nSectEnd ) + { + if( SwFlyStartNode == pSttNd->GetStartNodeType() ) + { + SwFrameFormat* pFormat = pSttNd->GetFlyFormat(); + if( pFormat ) + { + // That's the FlyFormat we're looking for + getIDocumentLayoutAccess().DelLayoutFormat( pFormat ); + return; + } + } + // No Fly? Thus Header or Footer: always leave a TextNode + // We can forget about Undo then! + bNewTextNd = true; + } + } + + // No Fly? Then it is a Header or Footer, so keep always a TextNode + ++aIdx; + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().ClearRedo(); + SwPaM aPaM( *pTableNd->EndOfSectionNode(), aIdx.GetNode() ); + + if( bNewTextNd ) + { + const SwNodeIndex aTmpIdx( *pTableNd->EndOfSectionNode(), 1 ); + GetNodes().MakeTextNode( aTmpIdx, + getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD ) ); + } + + // Save the cursors (UNO and otherwise) + SwPaM const* pSavePaM(nullptr); + SwPaM forwardPaM{SwNodeIndex(*pTableNd->EndOfSectionNode())}; + if (forwardPaM.Move(fnMoveForward, GoInNode)) + { + pSavePaM = &forwardPaM; + } + SwPaM backwardPaM{SwNodeIndex(*pTableNd)}; + if (backwardPaM.Move(fnMoveBackward, GoInNode)) + { + if (pSavePaM == nullptr + // try to stay in the same outer table cell + || (forwardPaM.GetPoint()->nNode.GetNode().FindTableNode() != pTableNd->StartOfSectionNode()->FindTableNode() + && forwardPaM.GetPoint()->nNode.GetNode().StartOfSectionIndex() + < backwardPaM.GetPoint()->nNode.GetNode().StartOfSectionIndex())) + { + pSavePaM = &backwardPaM; + } + } + assert(pSavePaM); // due to bNewTextNd this must succeed + { + SwPaM const tmpPaM(*pTableNd, *pTableNd->EndOfSectionNode()); + ::PaMCorrAbs(tmpPaM, *pSavePaM->GetPoint()); + } + + // Move hard PageBreaks to the succeeding Node + bool bSavePageBreak = false, bSavePageDesc = false; + sal_uLong nNextNd = pTableNd->EndOfSectionIndex()+1; + SwContentNode* pNextNd = GetNodes()[ nNextNd ]->GetContentNode(); + if( pNextNd ) + { + SwFrameFormat* pTableFormat = pTableNd->GetTable().GetFrameFormat(); + const SfxPoolItem *pItem; + if( SfxItemState::SET == pTableFormat->GetItemState( RES_PAGEDESC, + false, &pItem ) ) + { + pNextNd->SetAttr( *pItem ); + bSavePageDesc = true; + } + + if( SfxItemState::SET == pTableFormat->GetItemState( RES_BREAK, + false, &pItem ) ) + { + pNextNd->SetAttr( *pItem ); + bSavePageBreak = true; + } + } + std::unique_ptr<SwUndoDelete> pUndo(new SwUndoDelete(aPaM, SwDeleteFlags::Default)); + if( bNewTextNd ) + pUndo->SetTableDelLastNd(); + pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc ); + pUndo->SetTableName(pTableNd->GetTable().GetFrameFormat()->GetName()); + GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) ); + } + else + { + if( bNewTextNd ) + { + const SwNodeIndex aTmpIdx( *pTableNd->EndOfSectionNode(), 1 ); + GetNodes().MakeTextNode( aTmpIdx, + getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD ) ); + } + + // Save the cursors (UNO and otherwise) + SwPaM const* pSavePaM(nullptr); + SwPaM forwardPaM{SwNodeIndex(*pTableNd->EndOfSectionNode())}; + if (forwardPaM.Move(fnMoveForward, GoInNode)) + { + pSavePaM = &forwardPaM; + } + SwPaM backwardPaM{SwNodeIndex(*pTableNd)}; + if (backwardPaM.Move(fnMoveBackward, GoInNode)) + { + if (pSavePaM == nullptr + // try to stay in the same outer table cell + || (forwardPaM.GetPoint()->nNode.GetNode().FindTableNode() != pTableNd->StartOfSectionNode()->FindTableNode() + && forwardPaM.GetPoint()->nNode.GetNode().StartOfSectionIndex() + < backwardPaM.GetPoint()->nNode.GetNode().StartOfSectionIndex())) + { + pSavePaM = &backwardPaM; + } + } + assert(pSavePaM); // due to bNewTextNd this must succeed + { + SwPaM const tmpPaM(*pTableNd, *pTableNd->EndOfSectionNode()); + ::PaMCorrAbs(tmpPaM, *pSavePaM->GetPoint()); + } + + // Move hard PageBreaks to the succeeding Node + SwContentNode* pNextNd = GetNodes()[ pTableNd->EndOfSectionIndex()+1 ]->GetContentNode(); + if( pNextNd ) + { + SwFrameFormat* pTableFormat = pTableNd->GetTable().GetFrameFormat(); + const SfxPoolItem *pItem; + if( SfxItemState::SET == pTableFormat->GetItemState( RES_PAGEDESC, + false, &pItem ) ) + pNextNd->SetAttr( *pItem ); + + if( SfxItemState::SET == pTableFormat->GetItemState( RES_BREAK, + false, &pItem ) ) + pNextNd->SetAttr( *pItem ); + } + + pTableNd->DelFrames(); + getIDocumentContentOperations().DeleteSection( pTableNd ); + } + + GetDocShell()->GetFEShell()->UpdateTableStyleFormatting(); + + getIDocumentState().SetModified(); + getIDocumentFieldsAccess().SetFieldsDirty( true, nullptr, 0 ); +} + bool SwDoc::DeleteRowCol( const SwSelBoxes& rBoxes, bool bColumn ) { if( ::HasProtectedCells( rBoxes )) @@ -1966,132 +2126,7 @@ bool SwDoc::DeleteRowCol( const SwSelBoxes& rBoxes, bool bColumn ) aSelBoxes[0]->GetSttIdx()-1 == nTmpIdx1 && nTmpIdx2 == pTableNd->EndOfSectionIndex() ) { - bool bNewTextNd = false; - // Is it alone in a FlyFrame? - SwNodeIndex aIdx( *pTableNd, -1 ); - const SwStartNode* pSttNd = aIdx.GetNode().GetStartNode(); - if( pSttNd ) - { - const sal_uLong nTableEnd = pTableNd->EndOfSectionIndex() + 1; - const sal_uLong nSectEnd = pSttNd->EndOfSectionIndex(); - if( nTableEnd == nSectEnd ) - { - if( SwFlyStartNode == pSttNd->GetStartNodeType() ) - { - SwFrameFormat* pFormat = pSttNd->GetFlyFormat(); - if( pFormat ) - { - // That's the FlyFormat we're looking for - getIDocumentLayoutAccess().DelLayoutFormat( pFormat ); - return true; - } - } - // No Fly? Thus Header or Footer: always leave a TextNode - // We can forget about Undo then! - bNewTextNd = true; - } - } - - // No Fly? Then it is a Header or Footer, so keep always a TextNode - ++aIdx; - if (GetIDocumentUndoRedo().DoesUndo()) - { - GetIDocumentUndoRedo().ClearRedo(); - SwPaM aPaM( *pTableNd->EndOfSectionNode(), aIdx.GetNode() ); - - if( bNewTextNd ) - { - const SwNodeIndex aTmpIdx( *pTableNd->EndOfSectionNode(), 1 ); - GetNodes().MakeTextNode( aTmpIdx, - getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD ) ); - } - - // Save the cursors (UNO and otherwise) - SwPaM aSavePaM( SwNodeIndex( *pTableNd->EndOfSectionNode() ) ); - if( ! aSavePaM.Move( fnMoveForward, GoInNode ) ) - { - *aSavePaM.GetMark() = SwPosition( *pTableNd ); - aSavePaM.Move( fnMoveBackward, GoInNode ); - } - { - SwPaM const tmpPaM(*pTableNd, *pTableNd->EndOfSectionNode()); - ::PaMCorrAbs(tmpPaM, *aSavePaM.GetMark()); - } - - // Move hard PageBreaks to the succeeding Node - bool bSavePageBreak = false, bSavePageDesc = false; - sal_uLong nNextNd = pTableNd->EndOfSectionIndex()+1; - SwContentNode* pNextNd = GetNodes()[ nNextNd ]->GetContentNode(); - if( pNextNd ) - { - SwFrameFormat* pTableFormat = pTableNd->GetTable().GetFrameFormat(); - const SfxPoolItem *pItem; - if( SfxItemState::SET == pTableFormat->GetItemState( RES_PAGEDESC, - false, &pItem ) ) - { - pNextNd->SetAttr( *pItem ); - bSavePageDesc = true; - } - - if( SfxItemState::SET == pTableFormat->GetItemState( RES_BREAK, - false, &pItem ) ) - { - pNextNd->SetAttr( *pItem ); - bSavePageBreak = true; - } - } - std::unique_ptr<SwUndoDelete> pUndo(new SwUndoDelete(aPaM, SwDeleteFlags::Default)); - if( bNewTextNd ) - pUndo->SetTableDelLastNd(); - pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc ); - pUndo->SetTableName(pTableNd->GetTable().GetFrameFormat()->GetName()); - GetIDocumentUndoRedo().AppendUndo( std::move(pUndo) ); - } - else - { - if( bNewTextNd ) - { - const SwNodeIndex aTmpIdx( *pTableNd->EndOfSectionNode(), 1 ); - GetNodes().MakeTextNode( aTmpIdx, - getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD ) ); - } - - // Save the cursors (UNO and otherwise) - SwPaM aSavePaM( SwNodeIndex( *pTableNd->EndOfSectionNode() ) ); - if( ! aSavePaM.Move( fnMoveForward, GoInNode ) ) - { - *aSavePaM.GetMark() = SwPosition( *pTableNd ); - aSavePaM.Move( fnMoveBackward, GoInNode ); - } - { - SwPaM const tmpPaM(*pTableNd, *pTableNd->EndOfSectionNode()); - ::PaMCorrAbs(tmpPaM, *aSavePaM.GetMark()); - } - - // Move hard PageBreaks to the succeeding Node - SwContentNode* pNextNd = GetNodes()[ pTableNd->EndOfSectionIndex()+1 ]->GetContentNode(); - if( pNextNd ) - { - SwFrameFormat* pTableFormat = pTableNd->GetTable().GetFrameFormat(); - const SfxPoolItem *pItem; - if( SfxItemState::SET == pTableFormat->GetItemState( RES_PAGEDESC, - false, &pItem ) ) - pNextNd->SetAttr( *pItem ); - - if( SfxItemState::SET == pTableFormat->GetItemState( RES_BREAK, - false, &pItem ) ) - pNextNd->SetAttr( *pItem ); - } - - pTableNd->DelFrames(); - getIDocumentContentOperations().DeleteSection( pTableNd ); - } - - GetDocShell()->GetFEShell()->UpdateTableStyleFormatting(); - - getIDocumentState().SetModified(); - getIDocumentFieldsAccess().SetFieldsDirty( true, nullptr, 0 ); - + DelTable(pTableNd); return true; } diff --git a/sw/source/core/edit/eddel.cxx b/sw/source/core/edit/eddel.cxx index aa56a85ae43f..e16b8256b611 100644 --- a/sw/source/core/edit/eddel.cxx +++ b/sw/source/core/edit/eddel.cxx @@ -42,7 +42,9 @@ void SwEditShell::DeleteSel(SwPaM& rPam, bool const isArtificialSelection, bool *const pUndo) { - bool bSelectAll = StartsWith_() != SwCursorShell::StartsWith::None && ExtendedSelectedAll(); + auto const oSelectAll(StartsWith_() != SwCursorShell::StartsWith::None + ? ExtendedSelectedAll() + : ::std::optional<::std::pair<SwNode const*, ::std::vector<SwTableNode *>>>{}); // only for selections if (!rPam.HasMark() || (*rPam.GetPoint() == *rPam.GetMark() @@ -58,7 +60,7 @@ void SwEditShell::DeleteSel(SwPaM& rPam, bool const isArtificialSelection, bool // 3. Point and Mark are at the document start and end, Point is in a table: delete selection as usual if( rPam.GetNode().FindTableNode() && rPam.GetNode().StartOfSectionNode() != - rPam.GetNode(false).StartOfSectionNode() && !bSelectAll ) + rPam.GetNode(false).StartOfSectionNode() && !oSelectAll) { // group the Undo in the table if( pUndo && !*pUndo ) @@ -102,30 +104,34 @@ void SwEditShell::DeleteSel(SwPaM& rPam, bool const isArtificialSelection, bool { std::unique_ptr<SwPaM> pNewPam; SwPaM * pPam = &rPam; - if (bSelectAll) + if (oSelectAll) { - assert(dynamic_cast<SwShellCursor*>(&rPam)); // must be corrected pam - pNewPam.reset(new SwPaM(*rPam.GetMark(), *rPam.GetPoint())); - // Selection starts at the first para of the first cell, but we - // want to delete the table node before the first cell as well. - while (SwTableNode const* pTableNode = - pNewPam->Start()->nNode.GetNode().StartOfSectionNode()->FindTableNode()) + if (!oSelectAll->second.empty()) { - pNewPam->Start()->nNode = *pTableNode; + SwRewriter aRewriter; + aRewriter.AddRule(UndoArg1, SwResId(STR_MULTISEL)); + GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::DELETE, &aRewriter); } - // tdf#133990 ensure section is included in SwUndoDelete - while (SwSectionNode const* pSectionNode = - pNewPam->Start()->nNode.GetNode().StartOfSectionNode()->FindSectionNode()) + // tdf#155685 tables at the end must be deleted separately + for (SwTableNode *const pTable : oSelectAll->second) { - pNewPam->Start()->nNode = *pSectionNode; + GetDoc()->DelTable(pTable); } - pNewPam->Start()->nContent.Assign(nullptr, 0); + assert(dynamic_cast<SwShellCursor*>(&rPam)); // must be corrected pam + pNewPam.reset(new SwPaM(*rPam.GetMark(), *rPam.GetPoint())); + // Selection starts at the first para of the first cell, but we + // want to delete the table node before the first cell as well. + *pNewPam->Start() = SwPosition(*oSelectAll->first); pPam = pNewPam.get(); } // delete everything GetDoc()->getIDocumentContentOperations().DeleteAndJoin(*pPam, isArtificialSelection ? SwDeleteFlags::ArtificialSelection : SwDeleteFlags::Default); SaveTableBoxContent( pPam->GetPoint() ); + if (oSelectAll && !oSelectAll->second.empty()) + { + GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::END, nullptr); + } } // Selection is not needed anymore diff --git a/sw/source/core/edit/edglss.cxx b/sw/source/core/edit/edglss.cxx index 0d27b7c7a960..bad2bb719a86 100644 --- a/sw/source/core/edit/edglss.cxx +++ b/sw/source/core/edit/edglss.cxx @@ -203,7 +203,9 @@ bool SwEditShell::CopySelToDoc( SwDoc* pInsDoc ) bool bColSel = GetCursor_()->IsColumnSelection(); if( bColSel && pInsDoc->IsClipBoard() ) pInsDoc->SetColumnSelection( true ); - bool bSelectAll = StartsWith_() != SwCursorShell::StartsWith::None && ExtendedSelectedAll(); + auto const oSelectAll(StartsWith_() != SwCursorShell::StartsWith::None + ? ExtendedSelectedAll() + : ::std::optional<::std::pair<SwNode const*, ::std::vector<SwTableNode*>>>{}); { for(SwPaM& rPaM : GetCursor()->GetRingContainer()) { @@ -227,18 +229,12 @@ bool SwEditShell::CopySelToDoc( SwDoc* pInsDoc ) // for the purpose of copying, our shell cursor is not touched. // (Otherwise we would have to restore it.) SwPaM aPaM(*rPaM.GetMark(), *rPaM.GetPoint()); - if (bSelectAll) + if (oSelectAll) { // Selection starts at the first para of the first cell, // but we want to copy the table and the start node before // the first cell as well. - // tdf#133982 tables can be nested - while (SwTableNode const* pTableNode = - aPaM.Start()->nNode.GetNode().StartOfSectionNode()->FindTableNode()) - { - aPaM.Start()->nNode = *pTableNode; - } - aPaM.Start()->nContent.Assign(nullptr, 0); + *aPaM.Start() = SwPosition(*oSelectAll->first); } bRet = GetDoc()->getIDocumentContentOperations().CopyRange( aPaM, aPos, /*bCopyAll=*/false, /*bCheckPos=*/true, /*bCopyText=*/false ) || bRet; } diff --git a/sw/source/core/undo/undobj.cxx b/sw/source/core/undo/undobj.cxx index 336e447a94c6..8ff858013b72 100644 --- a/sw/source/core/undo/undobj.cxx +++ b/sw/source/core/undo/undobj.cxx @@ -798,30 +798,26 @@ void SwUndoSaveContent::MoveFromUndoNds( SwDoc& rDoc, sal_uLong nNodeIdx, } } -// These two methods move the Point of Pam backwards/forwards. With that, one -// can span an area for a Undo/Redo. (The Point is then positioned in front of -// the area to manipulate!) -// The flag indicates if there is still content in front of Point. -bool SwUndoSaveContent::MovePtBackward( SwPaM& rPam ) +// These two methods save and restore the Point of PaM. +// If the point cannot be moved, a "backup" is created on the previous node. +// Either way, returned, inserting at its original position will not move it. +::std::optional<SwNodeIndex> SwUndoSaveContent::MovePtBackward(SwPaM & rPam) { rPam.SetMark(); if( rPam.Move( fnMoveBackward )) - return true; + return {}; - // If there is no content onwards, set Point simply to the previous position - // (Node and Content, so that Content will be detached!) - --rPam.GetPoint()->nNode; - rPam.GetPoint()->nContent.Assign( nullptr, 0 ); - return false; + return { SwNodeIndex(rPam.GetPoint()->nNode, -1) }; } -void SwUndoSaveContent::MovePtForward( SwPaM& rPam, bool bMvBkwrd ) +void SwUndoSaveContent::MovePtForward(SwPaM& rPam, ::std::optional<SwNodeIndex> && oMvBkwrd) { // Was there content before this position? - if( bMvBkwrd ) + if (!oMvBkwrd) rPam.Move( fnMoveForward ); else { + *rPam.GetPoint() = SwPosition(*oMvBkwrd); ++rPam.GetPoint()->nNode; SwContentNode* pCNd = rPam.GetContentNode(); if( pCNd ) diff --git a/sw/source/core/undo/unins.cxx b/sw/source/core/undo/unins.cxx index f1f7f48188aa..ff3f4777329c 100644 --- a/sw/source/core/undo/unins.cxx +++ b/sw/source/core/undo/unins.cxx @@ -328,7 +328,7 @@ void SwUndoInsert::RedoImpl(::sw::UndoRedoContext & rContext) if( nLen ) { - const bool bMvBkwrd = MovePtBackward( *pPam ); + ::std::optional<SwNodeIndex> oMvBkwrd = MovePtBackward(*pPam); if (maText) { @@ -355,7 +355,7 @@ void SwUndoInsert::RedoImpl(::sw::UndoRedoContext & rContext) nNode = pPam->GetMark()->nNode.GetIndex(); nContent = pPam->GetMark()->nContent.GetIndex(); - MovePtForward( *pPam, bMvBkwrd ); + MovePtForward(*pPam, ::std::move(oMvBkwrd)); pPam->Exchange(); if( pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineFlags() )) { diff --git a/sw/source/core/undo/untblk.cxx b/sw/source/core/undo/untblk.cxx index 449f41795697..01561018ec56 100644 --- a/sw/source/core/undo/untblk.cxx +++ b/sw/source/core/undo/untblk.cxx @@ -357,15 +357,15 @@ void SwUndoInserts::RedoImpl(::sw::UndoRedoContext & rContext) auto const pFlysAtInsPos(sw::GetFlysAnchoredAt(*pDoc, rPam.GetPoint()->nNode.GetIndex())); - const bool bMvBkwrd = MovePtBackward(rPam); + ::std::optional<SwNodeIndex> oMvBkwrd = MovePtBackward(rPam); // re-insert content again (first detach m_pUndoNodeIndex!) sal_uLong const nMvNd = m_pUndoNodeIndex->GetIndex(); m_pUndoNodeIndex.reset(); MoveFromUndoNds(*pDoc, nMvNd, *rPam.GetMark()); - if (m_nDeleteTextNodes != 0) + if (m_nDeleteTextNodes != 0 || oMvBkwrd) { - MovePtForward(rPam, bMvBkwrd); + MovePtForward(rPam, ::std::move(oMvBkwrd)); } rPam.Exchange(); diff --git a/sw/source/uibase/wrtsh/move.cxx b/sw/source/uibase/wrtsh/move.cxx index 76f4baedaba5..b0dcdc522de7 100644 --- a/sw/source/uibase/wrtsh/move.cxx +++ b/sw/source/uibase/wrtsh/move.cxx @@ -218,12 +218,25 @@ bool SwWrtShell::GoStart( bool bKeepArea, bool *pMoveTable, *pMoveTable = false; return true; } + SwTableNode const*const pTable(getShellCursor(false)->GetPoint()->nNode.GetNode().FindTableNode()); + assert(pTable); if( MoveTable( GotoCurrTable, fnTableStart ) || bDontMoveRegion ) { if ( pMoveTable ) *pMoveTable = true; return true; } + else if (SwCursor const*const pCursor = getShellCursor(false); + pTable->GetNodes()[pTable->GetIndex()+1]->EndOfSectionIndex() + < pCursor->GetPoint()->nNode.GetNode().GetIndex() + && pMoveTable != nullptr // only set by SelAll() + // problem: cursor isn't inside 1st cell, and didn't move there + // workaround: try to move cursor outside of table for SelAll() + && MoveOutOfTable()) + { + assert(!*pMoveTable); + return true; + } else if( bBoxSelection && pMoveTable ) { // JP 09.01.96: We have a box selection (or an empty cell) @@ -258,15 +271,40 @@ bool SwWrtShell::GoStart( bool bKeepArea, bool *pMoveTable, else if ( bKeepArea ) return true; } - // Regions ??? + + // first try to move to the start of the current SwSection return SwCursorShell::MoveRegion( GotoCurrRegionAndSkip, fnRegionStart ) || - SwCursorShell::SttEndDoc(true); + (pMoveTable != nullptr + // move to start of text - if in different table, move out + ? MoveStartText() + // TODO who needs SttEndDoc for other case? + : SwCursorShell::SttEndDoc(true)); } bool SwWrtShell::GoEnd(bool bKeepArea, const bool *pMoveTable) { - if ( pMoveTable && *pMoveTable ) - return MoveTable( GotoCurrTable, fnTableEnd ); + if (pMoveTable && *pMoveTable) // only in SelAll() + { + SwTableNode const*const pTable(getShellCursor(false)->GetPoint()->nNode.GetNode().FindTableNode()); + assert(pTable); + if (MoveTable(GotoCurrTable, fnTableEnd)) + { + return true; + } + else if (SwCursor const*const pCursor = getShellCursor(false); + pCursor->GetPoint()->nNode.GetNode().GetIndex() + < pTable->GetNodes()[pTable->EndOfSectionIndex()-1]->StartOfSectionIndex() + // problem: cursor isn't inside 1st cell, and didn't move there + // workaround: try to move cursor outside of table for SelAll() + && MoveOutOfTable()) + { + return true; + } + else + { + return false; + } + } if ( IsCursorInTable() ) { diff --git a/sw/source/uibase/wrtsh/select.cxx b/sw/source/uibase/wrtsh/select.cxx index f26bb97bc8f4..17d4c068416a 100644 --- a/sw/source/uibase/wrtsh/select.cxx +++ b/sw/source/uibase/wrtsh/select.cxx @@ -141,7 +141,10 @@ void SwWrtShell::SelAll() bool bHasWholeTabSelection = HasWholeTabSelection(); bool bIsCursorInTable = IsCursorInTable(); - if (!bHasWholeTabSelection) + if (!bHasWholeTabSelection + && ( !bIsCursorInTable + || getShellCursor(false)->GetNode(false).FindTableNode() == nullptr + || !ExtendedSelectedAll())) // ESA inside table -> else branch { if ( IsSelection() && IsCursorPtAtEnd() ) SwapPam(); @@ -157,30 +160,35 @@ void SwWrtShell::SelAll() bIsFullSel &= !MoveSection( GoCurrSection, fnSectionEnd); Pop(SwCursorShell::PopMode::DeleteCurrent); GoStart(true, &bMoveTable, false, !bIsFullSel); + SttSelect(); + GoEnd(true, &bMoveTable); } else { - EnterStdMode(); - SttEndDoc(true); + if (MoveOutOfTable()) + { // select outer text + EnterStdMode(); // delete m_pTableCursor +// GoStart(true, &bMoveTable, false, true); + MoveSection(GoCurrSection, fnSectionStart); // don't move into prev table + SttSelect(); + MoveSection(GoCurrSection, fnSectionEnd); // don't move to different cell + } + else + { + TrySelectOuterTable(); + } } - SttSelect(); - GoEnd(true, &bMoveTable); bool bNeedsExtendedSelectAll = StartsWith_() != StartsWith::None; - // If the cursor was in a table, then we only need the extended select - // all if the whole table is already selected, to still allow selecting - // only a single cell or a single table before selecting the whole - // document. + // the GoEnd() could have created a table selection, if so avoid ESA. if (bNeedsExtendedSelectAll && bIsCursorInTable) - bNeedsExtendedSelectAll = bHasWholeTabSelection; + { + bNeedsExtendedSelectAll = !HasWholeTabSelection(); + } if (bNeedsExtendedSelectAll) { - // Disable table cursor to make sure getShellCursor() returns m_pCurrentCursor, not m_pTableCursor. - if (IsTableMode()) - TableCursorToCursor(); - // Do the extended select all on m_pCurrentCursor. ExtendedSelectAll(/*bFootnotes =*/ false); } |