summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/svx/rubydialog.hxx3
-rw-r--r--svx/source/dialog/rubydialog.cxx76
-rw-r--r--svx/uiconfig/ui/asianphoneticguidedialog.ui669
-rw-r--r--sw/inc/doc.hxx2
-rw-r--r--sw/inc/rubylist.hxx1
-rw-r--r--sw/qa/core/uwriter.cxx295
-rw-r--r--sw/source/core/doc/docruby.cxx217
7 files changed, 865 insertions, 398 deletions
diff --git a/include/svx/rubydialog.hxx b/include/svx/rubydialog.hxx
index 655b4f2ae049..30b284ee0fbd 100644
--- a/include/svx/rubydialog.hxx
+++ b/include/svx/rubydialog.hxx
@@ -83,6 +83,8 @@ class SvxRubyDialog final : public SfxModelessDialogController
std::unique_ptr<weld::ComboBox> m_xCharStyleLB;
std::unique_ptr<weld::Button> m_xStylistPB;
+ std::unique_ptr<weld::Button> m_xSelectionGroupPB;
+
std::unique_ptr<weld::Button> m_xApplyPB;
std::unique_ptr<weld::Button> m_xClosePB;
@@ -92,6 +94,7 @@ class SvxRubyDialog final : public SfxModelessDialogController
std::unique_ptr<RubyPreview> m_xPreviewWin;
std::unique_ptr<weld::CustomWeld> m_xPreview;
+ DECL_LINK(SelectionGroup_Impl, weld::Button&, void);
DECL_LINK(ApplyHdl_Impl, weld::Button&, void);
DECL_LINK(CloseHdl_Impl, weld::Button&, void);
DECL_LINK(StylistHdl_Impl, weld::Button&, void);
diff --git a/svx/source/dialog/rubydialog.cxx b/svx/source/dialog/rubydialog.cxx
index e28fdb71d49e..f85a395029b0 100644
--- a/svx/source/dialog/rubydialog.cxx
+++ b/svx/source/dialog/rubydialog.cxx
@@ -43,6 +43,7 @@
#include <vcl/event.hxx>
#include <vcl/settings.hxx>
#include <vcl/svapp.hxx>
+#include <rtl/ustrbuf.hxx>
#include <svl/itemset.hxx>
using namespace css::uno;
@@ -119,6 +120,70 @@ public:
virtual void SAL_CALL selectionChanged(const css::lang::EventObject& aEvent) override;
virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
+
+ bool IsSelectionGrouped() { return aRubyValues.getLength() < 2; }
+
+ void MakeSelectionGrouped()
+ {
+ if (aRubyValues.getLength() < 2)
+ {
+ return;
+ }
+
+ OUString sBaseTmp;
+ OUStringBuffer aBaseString;
+ for (const PropertyValues& pVals : aRubyValues)
+ {
+ sBaseTmp.clear();
+ for (const PropertyValue& pVal : pVals)
+ {
+ if (pVal.Name == cRubyBaseText)
+ {
+ pVal.Value >>= sBaseTmp;
+ }
+ }
+
+ aBaseString.append(sBaseTmp);
+ }
+
+ Sequence<PropertyValues> aNewRubyValues{ 1 };
+ PropertyValues* pNewRubyValues = aNewRubyValues.getArray();
+
+ // Copy some reasonable style values from the previous ruby array
+ pNewRubyValues[0] = aRubyValues[0];
+ for (const PropertyValues& pVals : aRubyValues)
+ {
+ for (const PropertyValue& pVal : pVals)
+ {
+ if (pVal.Name == cRubyText)
+ {
+ pVal.Value >>= sBaseTmp;
+ if (!sBaseTmp.isEmpty())
+ {
+ pNewRubyValues[0] = pVals;
+ break;
+ }
+ }
+ }
+ }
+
+ PropertyValue* pNewValues = pNewRubyValues[0].getArray();
+ for (sal_Int32 i = 0; i < pNewRubyValues[0].getLength(); ++i)
+ {
+ if (pNewValues[i].Name == cRubyBaseText)
+ {
+ sBaseTmp = aBaseString;
+ pNewValues[i].Value <<= sBaseTmp;
+ }
+ else if (pNewValues[i].Name == cRubyText)
+ {
+ sBaseTmp.clear();
+ pNewValues[i].Value <<= sBaseTmp;
+ }
+ }
+
+ aRubyValues = std::move(aNewRubyValues);
+ }
};
SvxRubyData_Impl::SvxRubyData_Impl()
@@ -207,6 +272,7 @@ SvxRubyDialog::SvxRubyDialog(SfxBindings* pBind, SfxChildWindow* pCW, weld::Wind
, m_xCharStyleFT(m_xBuilder->weld_label(u"styleft"_ustr))
, m_xCharStyleLB(m_xBuilder->weld_combo_box(u"stylelb"_ustr))
, m_xStylistPB(m_xBuilder->weld_button(u"styles"_ustr))
+ , m_xSelectionGroupPB(m_xBuilder->weld_button(u"selection-group"_ustr))
, m_xApplyPB(m_xBuilder->weld_button(u"ok"_ustr))
, m_xClosePB(m_xBuilder->weld_button(u"close"_ustr))
, m_xContentArea(m_xDialog->weld_content_area())
@@ -228,6 +294,7 @@ SvxRubyDialog::SvxRubyDialog(SfxBindings* pBind, SfxChildWindow* pCW, weld::Wind
aEditArr[6] = m_xLeft4ED.get();
aEditArr[7] = m_xRight4ED.get();
+ m_xSelectionGroupPB->connect_clicked(LINK(this, SvxRubyDialog, SelectionGroup_Impl));
m_xApplyPB->connect_clicked(LINK(this, SvxRubyDialog, ApplyHdl_Impl));
m_xClosePB->connect_clicked(LINK(this, SvxRubyDialog, CloseHdl_Impl));
m_xStylistPB->connect_clicked(LINK(this, SvxRubyDialog, StylistHdl_Impl));
@@ -405,6 +472,9 @@ void SvxRubyDialog::GetRubyText()
void SvxRubyDialog::Update()
{
+ // Only enable selection grouping options when they can be applied
+ m_xSelectionGroupPB->set_sensitive(!m_pImpl->IsSelectionGrouped());
+
const Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
sal_Int32 nLen = aRubyValues.getLength();
m_xScrolledWindow->vadjustment_configure(0, 0, !nLen ? 1 : nLen, 1, 4, 4);
@@ -505,6 +575,12 @@ IMPL_LINK(SvxRubyDialog, ScrollHdl_Impl, weld::ScrolledWindow&, rScroll, void)
m_xPreviewWin->Invalidate();
}
+IMPL_LINK_NOARG(SvxRubyDialog, SelectionGroup_Impl, weld::Button&, void)
+{
+ m_pImpl->MakeSelectionGrouped();
+ Update();
+}
+
IMPL_LINK_NOARG(SvxRubyDialog, ApplyHdl_Impl, weld::Button&, void)
{
const Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
diff --git a/svx/uiconfig/ui/asianphoneticguidedialog.ui b/svx/uiconfig/ui/asianphoneticguidedialog.ui
index b70aee74127b..66a045d26ba7 100644
--- a/svx/uiconfig/ui/asianphoneticguidedialog.ui
+++ b/svx/uiconfig/ui/asianphoneticguidedialog.ui
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.38.2 -->
+<!-- Generated with glade 3.40.0 -->
<interface domain="svx">
<requires lib="gtk+" version="3.20"/>
<object class="GtkDialog" id="AsianPhoneticGuideDialog">
@@ -72,423 +72,468 @@
</packing>
</child>
<child>
- <object class="GtkBox" id="box1">
+ <!-- n-columns=2 n-rows=2 -->
+ <object class="GtkGrid" id="grid4">
<property name="visible">True</property>
<property name="can-focus">False</property>
- <property name="orientation">vertical</property>
- <property name="spacing">6</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">6</property>
<child>
- <!-- n-columns=2 n-rows=1 -->
- <object class="GtkGrid" id="grid3">
+ <object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can-focus">False</property>
- <property name="column-spacing">12</property>
- <property name="column-homogeneous">True</property>
- <child>
- <object class="GtkLabel" id="basetextft">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="label" translatable="yes" context="asianphoneticguidedialog|basetextft">Base text</property>
- <property name="use-underline">True</property>
- </object>
- <packing>
- <property name="left-attach">0</property>
- <property name="top-attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="rubytextft">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="label" translatable="yes" context="asianphoneticguidedialog|rubytextft">Ruby text</property>
- <property name="use-underline">True</property>
- </object>
- <packing>
- <property name="left-attach">1</property>
- <property name="top-attach">0</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkScrolledWindow" id="scrolledwindow">
- <property name="visible">True</property>
- <property name="can-focus">True</property>
<property name="hexpand">True</property>
- <property name="hscrollbar-policy">never</property>
- <property name="vscrollbar-policy">always</property>
- <property name="shadow-type">in</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
<child>
- <object class="GtkViewport" id="viewport1">
+ <object class="GtkScrolledWindow" id="scrolledwindow">
<property name="visible">True</property>
- <property name="can-focus">False</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="hscrollbar-policy">never</property>
+ <property name="vscrollbar-policy">always</property>
+ <property name="shadow-type">in</property>
<child>
- <!-- n-columns=1 n-rows=1 -->
- <object class="GtkGrid" id="grid">
+ <object class="GtkViewport" id="viewport1">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
- <!-- n-columns=2 n-rows=4 -->
- <object class="GtkGrid" id="grid1">
+ <!-- n-columns=1 n-rows=1 -->
+ <object class="GtkGrid" id="grid">
<property name="visible">True</property>
<property name="can-focus">False</property>
- <property name="hexpand">True</property>
- <property name="border-width">6</property>
- <property name="row-spacing">6</property>
- <property name="column-spacing">12</property>
<child>
- <object class="GtkEntry" id="Left2ED">
+ <!-- n-columns=2 n-rows=4 -->
+ <object class="GtkGrid" id="grid1">
<property name="visible">True</property>
- <property name="can-focus">True</property>
+ <property name="can-focus">False</property>
<property name="hexpand">True</property>
- <property name="activates-default">True</property>
- <property name="truncate-multiline">True</property>
- <child internal-child="accessible">
- <object class="AtkObject" id="Left2ED-atkobject">
- <property name="AtkObject::accessible-name" translatable="yes" context="asianphoneticguidedialog|Left2ED-atkobject">Base text</property>
- <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Left2ED">Displays the base text that you selected in the current file. If you want, you can modify the base text by entering new text here.</property>
+ <property name="border-width">6</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkEntry" id="Left2ED">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="Left2ED-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="asianphoneticguidedialog|Left2ED-atkobject">Base text</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Left2ED">Displays the base text that you selected in the current file. If you want, you can modify the base text by entering new text here.</property>
+ </object>
+ </child>
</object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
</child>
- </object>
- <packing>
- <property name="left-attach">0</property>
- <property name="top-attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="Left1ED">
- <property name="visible">True</property>
- <property name="can-focus">True</property>
- <property name="activates-default">True</property>
- <property name="truncate-multiline">True</property>
- <child internal-child="accessible">
- <object class="AtkObject" id="Left1ED-atkobject">
- <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Left1ED">Displays the base text that you selected in the current file. If you want, you can modify the base text by entering new text here.</property>
+ <child>
+ <object class="GtkEntry" id="Left1ED">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="Left1ED-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Left1ED">Displays the base text that you selected in the current file. If you want, you can modify the base text by entering new text here.</property>
+ </object>
+ </child>
</object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
</child>
- </object>
- <packing>
- <property name="left-attach">0</property>
- <property name="top-attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="Right1ED">
- <property name="visible">True</property>
- <property name="can-focus">True</property>
- <property name="hexpand">True</property>
- <property name="activates-default">True</property>
- <property name="truncate-multiline">True</property>
- <child internal-child="accessible">
- <object class="AtkObject" id="Right1ED-atkobject">
- <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Right1ED">Enter the text that you want to use as a pronunciation guide for the base text.</property>
+ <child>
+ <object class="GtkEntry" id="Right1ED">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="Right1ED-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Right1ED">Enter the text that you want to use as a pronunciation guide for the base text.</property>
+ </object>
+ </child>
</object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
</child>
- </object>
- <packing>
- <property name="left-attach">1</property>
- <property name="top-attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="Right2ED">
- <property name="visible">True</property>
- <property name="can-focus">True</property>
- <property name="activates-default">True</property>
- <property name="truncate-multiline">True</property>
- <child internal-child="accessible">
- <object class="AtkObject" id="Right2ED-atkobject">
- <property name="AtkObject::accessible-name" translatable="yes" context="asianphoneticguidedialog|Right2ED-atkobject">Ruby text</property>
- <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Right2ED">Enter the text that you want to use as a pronunciation guide for the base text.</property>
+ <child>
+ <object class="GtkEntry" id="Right2ED">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="Right2ED-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="asianphoneticguidedialog|Right2ED-atkobject">Ruby text</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Right2ED">Enter the text that you want to use as a pronunciation guide for the base text.</property>
+ </object>
+ </child>
</object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
</child>
- </object>
- <packing>
- <property name="left-attach">1</property>
- <property name="top-attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="Left3ED">
- <property name="visible">True</property>
- <property name="can-focus">True</property>
- <property name="activates-default">True</property>
- <property name="truncate-multiline">True</property>
- <child internal-child="accessible">
- <object class="AtkObject" id="Left3ED-atkobject">
- <property name="AtkObject::accessible-name" translatable="yes" context="asianphoneticguidedialog|Left3ED-atkobject">Base text</property>
- <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Left3ED">Displays the base text that you selected in the current file. If you want, you can modify the base text by entering new text here.</property>
+ <child>
+ <object class="GtkEntry" id="Left3ED">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="Left3ED-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="asianphoneticguidedialog|Left3ED-atkobject">Base text</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Left3ED">Displays the base text that you selected in the current file. If you want, you can modify the base text by entering new text here.</property>
+ </object>
+ </child>
</object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ </packing>
</child>
- </object>
- <packing>
- <property name="left-attach">0</property>
- <property name="top-attach">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="Right3ED">
- <property name="visible">True</property>
- <property name="can-focus">True</property>
- <property name="activates-default">True</property>
- <property name="truncate-multiline">True</property>
- <child internal-child="accessible">
- <object class="AtkObject" id="Right3ED-atkobject">
- <property name="AtkObject::accessible-name" translatable="yes" context="asianphoneticguidedialog|Right3ED-atkobject">Ruby text</property>
- <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Right3ED">Enter the text that you want to use as a pronunciation guide for the base text.</property>
+ <child>
+ <object class="GtkEntry" id="Right3ED">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="Right3ED-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="asianphoneticguidedialog|Right3ED-atkobject">Ruby text</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Right3ED">Enter the text that you want to use as a pronunciation guide for the base text.</property>
+ </object>
+ </child>
</object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">2</property>
+ </packing>
</child>
- </object>
- <packing>
- <property name="left-attach">1</property>
- <property name="top-attach">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="Right4ED">
- <property name="visible">True</property>
- <property name="can-focus">True</property>
- <property name="activates-default">True</property>
- <property name="truncate-multiline">True</property>
- <child internal-child="accessible">
- <object class="AtkObject" id="Right4ED-atkobject">
- <property name="AtkObject::accessible-name" translatable="yes" context="asianphoneticguidedialog|Right4ED-atkobject">Ruby text</property>
- <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Right4ED">Enter the text that you want to use as a pronunciation guide for the base text.</property>
+ <child>
+ <object class="GtkEntry" id="Right4ED">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="Right4ED-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="asianphoneticguidedialog|Right4ED-atkobject">Ruby text</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Right4ED">Enter the text that you want to use as a pronunciation guide for the base text.</property>
+ </object>
+ </child>
</object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">3</property>
+ </packing>
</child>
- </object>
- <packing>
- <property name="left-attach">1</property>
- <property name="top-attach">3</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="Left4ED">
- <property name="visible">True</property>
- <property name="can-focus">True</property>
- <property name="activates-default">True</property>
- <property name="truncate-multiline">True</property>
- <child internal-child="accessible">
- <object class="AtkObject" id="Left4ED-atkobject">
- <property name="AtkObject::accessible-name" translatable="yes" context="asianphoneticguidedialog|Left4ED-atkobject">Base text</property>
- <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Left4ED">Displays the base text that you selected in the current file. If you want, you can modify the base text by entering new text here.</property>
+ <child>
+ <object class="GtkEntry" id="Left4ED">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="activates-default">True</property>
+ <property name="truncate-multiline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="Left4ED-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="asianphoneticguidedialog|Left4ED-atkobject">Base text</property>
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|Left4ED">Displays the base text that you selected in the current file. If you want, you can modify the base text by entering new text here.</property>
+ </object>
+ </child>
</object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">3</property>
+ </packing>
</child>
</object>
<packing>
<property name="left-attach">0</property>
- <property name="top-attach">3</property>
+ <property name="top-attach">0</property>
</packing>
</child>
</object>
- <packing>
- <property name="left-attach">0</property>
- <property name="top-attach">0</property>
- </packing>
</child>
</object>
</child>
</object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <!-- n-columns=4 n-rows=2 -->
- <object class="GtkGrid" id="grid2">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="margin-top">6</property>
- <property name="row-spacing">6</property>
- <property name="column-spacing">12</property>
- <child>
- <object class="GtkLabel" id="label4">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="label" translatable="yes" context="asianphoneticguidedialog|label4">Alignment:</property>
- <property name="use-underline">True</property>
- <property name="mnemonic-widget">adjustlb</property>
- <property name="xalign">0</property>
- </object>
<packing>
- <property name="left-attach">0</property>
- <property name="top-attach">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="label5">
+ <!-- n-columns=4 n-rows=2 -->
+ <object class="GtkGrid" id="grid2">
<property name="visible">True</property>
<property name="can-focus">False</property>
- <property name="label" translatable="yes" context="asianphoneticguidedialog|label5">Position:</property>
- <property name="use-underline">True</property>
- <property name="mnemonic-widget">positionlb</property>
- <property name="xalign">0</property>
+ <property name="margin-top">6</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="asianphoneticguidedialog|label4">Alignment:</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">adjustlb</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="asianphoneticguidedialog|label5">Position:</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">positionlb</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="styleft">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="asianphoneticguidedialog|styleft">Character style for ruby text:</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">stylelb</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="stylelb">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="stylelb-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|stylelb">Select a character style for the ruby text.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">2</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="styles">
+ <property name="label" translatable="yes" context="asianphoneticguidedialog|styles">Styles</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="styles-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|styles">Opens the Styles deck of the Sidebar where you can select a character style for the ruby text.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">3</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="adjustlb">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <items>
+ <item translatable="yes" context="asianphoneticguidedialog|adjustlb">Left</item>
+ <item translatable="yes" context="asianphoneticguidedialog|adjustlb">Center</item>
+ <item translatable="yes" context="asianphoneticguidedialog|adjustlb">Right</item>
+ <item translatable="yes" context="asianphoneticguidedialog|adjustlb">0 1 0</item>
+ <item translatable="yes" context="asianphoneticguidedialog|adjustlb">1 2 1</item>
+ </items>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="adjustlb-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|adjustlb">Select the horizontal alignment for the ruby text.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="positionlb">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <items>
+ <item translatable="yes" context="asianphoneticguidedialog|positionlb">Top</item>
+ <item translatable="yes" context="asianphoneticguidedialog|positionlb">Bottom</item>
+ <item translatable="yes" context="asianphoneticguidedialog|positionlb">Right</item>
+ </items>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="positionlb-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|positionlb">Select where you want to place the ruby text.</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
</object>
<packing>
- <property name="left-attach">1</property>
- <property name="top-attach">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="styleft">
+ <object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can-focus">False</property>
- <property name="label" translatable="yes" context="asianphoneticguidedialog|styleft">Character style for ruby text:</property>
+ <property name="margin-top">6</property>
+ <property name="label" translatable="yes" context="asianphoneticguidedialog|label1">Preview:</property>
<property name="use-underline">True</property>
- <property name="mnemonic-widget">stylelb</property>
+ <property name="mnemonic-widget">preview</property>
<property name="xalign">0</property>
</object>
<packing>
- <property name="left-attach">2</property>
- <property name="top-attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkComboBoxText" id="stylelb">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="hexpand">True</property>
- <child internal-child="accessible">
- <object class="AtkObject" id="stylelb-atkobject">
- <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|stylelb">Select a character style for the ruby text.</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="left-attach">2</property>
- <property name="top-attach">1</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
</packing>
</child>
<child>
- <object class="GtkButton" id="styles">
- <property name="label" translatable="yes" context="asianphoneticguidedialog|styles">Styles</property>
+ <object class="GtkScrolledWindow" id="ctlFavoriteswin">
<property name="visible">True</property>
<property name="can-focus">True</property>
- <property name="receives-default">True</property>
- <property name="use-underline">True</property>
- <child internal-child="accessible">
- <object class="AtkObject" id="styles-atkobject">
- <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|styles">Opens the Styles deck of the Sidebar where you can select a character style for the ruby text.</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar-policy">never</property>
+ <property name="vscrollbar-policy">never</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkDrawingArea" id="preview">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ </child>
</object>
</child>
</object>
<packing>
- <property name="left-attach">3</property>
- <property name="top-attach">1</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">4</property>
</packing>
</child>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <!-- n-columns=2 n-rows=1 -->
+ <object class="GtkGrid" id="grid3">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="valign">start</property>
+ <property name="column-spacing">12</property>
+ <property name="column-homogeneous">True</property>
<child>
- <object class="GtkComboBoxText" id="adjustlb">
+ <object class="GtkLabel" id="basetextft">
<property name="visible">True</property>
<property name="can-focus">False</property>
- <items>
- <item translatable="yes" context="asianphoneticguidedialog|adjustlb">Left</item>
- <item translatable="yes" context="asianphoneticguidedialog|adjustlb">Center</item>
- <item translatable="yes" context="asianphoneticguidedialog|adjustlb">Right</item>
- <item translatable="yes" context="asianphoneticguidedialog|adjustlb">0 1 0</item>
- <item translatable="yes" context="asianphoneticguidedialog|adjustlb">1 2 1</item>
- </items>
- <child internal-child="accessible">
- <object class="AtkObject" id="adjustlb-atkobject">
- <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|adjustlb">Select the horizontal alignment for the ruby text.</property>
- </object>
- </child>
+ <property name="label" translatable="yes" context="asianphoneticguidedialog|basetextft">Base text</property>
+ <property name="use-underline">True</property>
</object>
<packing>
<property name="left-attach">0</property>
- <property name="top-attach">1</property>
+ <property name="top-attach">0</property>
</packing>
</child>
<child>
- <object class="GtkComboBoxText" id="positionlb">
+ <object class="GtkLabel" id="rubytextft">
<property name="visible">True</property>
<property name="can-focus">False</property>
- <items>
- <item translatable="yes" context="asianphoneticguidedialog|positionlb">Top</item>
- <item translatable="yes" context="asianphoneticguidedialog|positionlb">Bottom</item>
- <item translatable="yes" context="asianphoneticguidedialog|positionlb">Right</item>
- </items>
- <child internal-child="accessible">
- <object class="AtkObject" id="positionlb-atkobject">
- <property name="AtkObject::accessible-description" translatable="yes" context="asianphoneticguidedialog|extended_tip|positionlb">Select where you want to place the ruby text.</property>
- </object>
- </child>
+ <property name="label" translatable="yes" context="asianphoneticguidedialog|rubytextft">Ruby text</property>
+ <property name="use-underline">True</property>
</object>
<packing>
<property name="left-attach">1</property>
- <property name="top-attach">1</property>
+ <property name="top-attach">0</property>
</packing>
</child>
- <child>
- <placeholder/>
- </child>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">2</property>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="label1">
+ <object class="GtkButtonBox" id="dialog-action_area2">
<property name="visible">True</property>
<property name="can-focus">False</property>
- <property name="margin-top">6</property>
- <property name="label" translatable="yes" context="asianphoneticguidedialog|label1">Preview:</property>
- <property name="use-underline">True</property>
- <property name="mnemonic-widget">preview</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">4</property>
- </packing>
- </child>
- <child>
- <object class="GtkScrolledWindow" id="ctlFavoriteswin">
- <property name="visible">True</property>
- <property name="can-focus">True</property>
- <property name="hexpand">True</property>
- <property name="vexpand">True</property>
- <property name="hscrollbar-policy">never</property>
- <property name="vscrollbar-policy">never</property>
- <property name="shadow-type">in</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <property name="layout-style">start</property>
<child>
- <object class="GtkViewport">
+ <object class="GtkButton" id="selection-group">
+ <property name="label" translatable="yes" context="asianphoneticguidedialog|selectiongroup">_Group</property>
<property name="visible">True</property>
- <property name="can-focus">False</property>
- <child>
- <object class="GtkDrawingArea" id="preview">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="hexpand">True</property>
- <property name="vexpand">True</property>
- </object>
- </child>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
</object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
</child>
</object>
<packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">5</property>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
</packing>
</child>
+ <child>
+ <placeholder/>
+ </child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
- <property name="position">1</property>
+ <property name="position">0</property>
</packing>
</child>
</object>
diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index 1a4fff14b4c2..0274dd4976be 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -1591,7 +1591,7 @@ public:
// Interface for the list of Ruby - texts/attributes
static sal_uInt16 FillRubyList( const SwPaM& rPam, SwRubyList& rList );
- void SetRubyList( const SwPaM& rPam, const SwRubyList& rList );
+ void SetRubyList( SwPaM& rPam, const SwRubyList& rList );
void ReadLayoutCache( SvStream& rStream );
void WriteLayoutCache( SvStream& rStream );
diff --git a/sw/inc/rubylist.hxx b/sw/inc/rubylist.hxx
index b025686daae3..3542cbcb3738 100644
--- a/sw/inc/rubylist.hxx
+++ b/sw/inc/rubylist.hxx
@@ -27,7 +27,6 @@ class SwRubyListEntry
SwFormatRuby m_aRubyAttr;
public:
SwRubyListEntry() : m_aRubyAttr( OUString() ) {}
- ~SwRubyListEntry();
const OUString& GetText() const { return m_sText; }
void SetText( const OUString& rStr ) { m_sText = rStr; }
diff --git a/sw/qa/core/uwriter.cxx b/sw/qa/core/uwriter.cxx
index 3504a11130df..2e10ae43aa1c 100644
--- a/sw/qa/core/uwriter.cxx
+++ b/sw/qa/core/uwriter.cxx
@@ -132,6 +132,7 @@ public:
void testTdf92308();
void testTableCellComparison();
void testTdf156211();
+ void testFillRubyList();
void testSetRubyList();
CPPUNIT_TEST_SUITE(SwDocTest);
@@ -171,6 +172,7 @@ public:
CPPUNIT_TEST(testTdf92308);
CPPUNIT_TEST(testTableCellComparison);
CPPUNIT_TEST(testTdf156211);
+ CPPUNIT_TEST(testFillRubyList);
CPPUNIT_TEST(testSetRubyList);
CPPUNIT_TEST_SUITE_END();
@@ -1985,6 +1987,165 @@ void SwDocTest::testTdf156211()
CPPUNIT_ASSERT(!oSI.IsKashidaLine(TextFrameIndex{ 95 }));
}
+void SwDocTest::testFillRubyList()
+{
+ SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
+ SwPaM aPaM(aIdx);
+
+ SwTextNode* pTextNode = aPaM.GetPointNode().GetTextNode();
+ CPPUNIT_ASSERT(pTextNode);
+
+ auto& rOps = m_pDoc->getIDocumentContentOperations();
+
+ auto fnAppendJapanese = [&](const OUString& rText)
+ {
+ rOps.AppendTextNode(*aPaM.GetPoint());
+
+ SvxLanguageItem aCJKLangItem(LANGUAGE_JAPANESE, RES_CHRATR_CJK_LANGUAGE);
+ SvxLanguageItem aWestLangItem(LANGUAGE_ENGLISH_US, RES_CHRATR_LANGUAGE);
+ rOps.InsertPoolItem(aPaM, aCJKLangItem);
+ rOps.InsertPoolItem(aPaM, aWestLangItem);
+
+ rOps.InsertString(aPaM, rText);
+
+ aPaM.SetMark();
+ aPaM.GetPoint()->nContent = 0;
+
+ CPPUNIT_ASSERT_EQUAL(rText, aPaM.GetText());
+ };
+
+ auto fnAppendRuby = [](SwRubyList* rList, OUString aBase, OUString aRuby)
+ {
+ auto pEnt = std::make_unique<SwRubyListEntry>();
+ pEnt->SetText(std::move(aBase));
+ pEnt->SetRubyAttr(SwFormatRuby{ std::move(aRuby) });
+
+ rList->push_back(std::move(pEnt));
+ };
+
+ auto fnGetCombinedString = [&]
+ {
+ SwRubyList aRubies;
+ SwDoc::FillRubyList(aPaM, aRubies);
+
+ OUStringBuffer aTemp;
+
+ for (auto const& rRuby : aRubies)
+ {
+ aTemp.append(rRuby->GetText() + u"["_ustr + rRuby->GetRubyAttr().GetText() + u"]"_ustr);
+ }
+
+ return aTemp.toString();
+ };
+
+ // Single word without existing rubies
+ {
+ fnAppendJapanese(u"学校"_ustr);
+ CPPUNIT_ASSERT_EQUAL(u"学校[]"_ustr, fnGetCombinedString());
+ }
+
+ // Compound word without existing rubies
+ {
+ fnAppendJapanese(u"自動販売機"_ustr);
+ CPPUNIT_ASSERT_EQUAL(u"自動[]販売[]機[]"_ustr, fnGetCombinedString());
+ }
+
+ // Single word with existing rubies
+ {
+ fnAppendJapanese(u"学校"_ustr);
+
+ SwRubyList rList;
+ fnAppendRuby(&rList, u"学校"_ustr, u"がっこう"_ustr);
+
+ m_pDoc->SetRubyList(aPaM, rList);
+
+ CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]"_ustr, fnGetCombinedString());
+ }
+
+ // Compound word with existing rubies
+ {
+ fnAppendJapanese(u"自動販売機"_ustr);
+
+ SwRubyList rList;
+ fnAppendRuby(&rList, u"自動"_ustr, u"じどう"_ustr);
+ fnAppendRuby(&rList, u"販売"_ustr, u"はんばい"_ustr);
+ fnAppendRuby(&rList, u"機"_ustr, u"き"_ustr);
+
+ m_pDoc->SetRubyList(aPaM, rList);
+
+ CPPUNIT_ASSERT_EQUAL(u"自動[じどう]販売[はんばい]機[き]"_ustr, fnGetCombinedString());
+ }
+
+ // Compound word with existing rubies treated as a single word
+ {
+ fnAppendJapanese(u"自動販売機"_ustr);
+
+ SwRubyList rList;
+ fnAppendRuby(&rList, u"自動販売機"_ustr, u"じどうはんばいき"_ustr);
+ fnAppendRuby(&rList, u""_ustr, u""_ustr);
+ fnAppendRuby(&rList, u""_ustr, u""_ustr);
+
+ m_pDoc->SetRubyList(aPaM, rList);
+
+ CPPUNIT_ASSERT_EQUAL(u"自動販売機[じどうはんばいき]"_ustr, fnGetCombinedString());
+ }
+
+ // tdf#141466: Characteristic test from bug
+ {
+ fnAppendJapanese(u"学校に行きます。"_ustr);
+
+ SwRubyList rList;
+ fnAppendRuby(&rList, u"学校"_ustr, u"がっこう"_ustr);
+ fnAppendRuby(&rList, u"に"_ustr, u""_ustr);
+ fnAppendRuby(&rList, u"行"_ustr, u"い"_ustr);
+ fnAppendRuby(&rList, u"きます"_ustr, u""_ustr);
+ fnAppendRuby(&rList, u"。"_ustr, u""_ustr);
+
+ m_pDoc->SetRubyList(aPaM, rList);
+
+ CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]に[]行[い]き[]ます[]。[]"_ustr, fnGetCombinedString());
+ }
+
+ // tdf#107184: Characteristic test for ruby group mode editing
+ {
+ fnAppendJapanese(u"学校に行きます"_ustr);
+
+ SwRubyList rList;
+ fnAppendRuby(&rList, u"学校に行きます"_ustr, u"がっこうにいきます"_ustr);
+
+ m_pDoc->SetRubyList(aPaM, rList);
+
+ CPPUNIT_ASSERT_EQUAL(u"学校に行きます[がっこうにいきます]"_ustr, fnGetCombinedString());
+ }
+
+ // tdf#156543: Characteristic test for ruby mono mode editing
+ {
+ fnAppendJapanese(u"学校に行きます"_ustr);
+
+ SwRubyList rList;
+ fnAppendRuby(&rList, u"学"_ustr, u"がっ"_ustr);
+ fnAppendRuby(&rList, u"校"_ustr, u"こう"_ustr);
+ fnAppendRuby(&rList, u"に"_ustr, u""_ustr);
+ fnAppendRuby(&rList, u"行"_ustr, u"い"_ustr);
+ fnAppendRuby(&rList, u"き"_ustr, u""_ustr);
+ fnAppendRuby(&rList, u"ま"_ustr, u""_ustr);
+ fnAppendRuby(&rList, u"す"_ustr, u""_ustr);
+
+ m_pDoc->SetRubyList(aPaM, rList);
+
+ CPPUNIT_ASSERT_EQUAL(u"学[がっ]校[こう]に[]行[い]き[]ます[]"_ustr, fnGetCombinedString());
+ }
+
+ // Empty PaM
+ {
+ fnAppendJapanese(u"学校"_ustr);
+
+ aPaM.DeleteMark();
+
+ CPPUNIT_ASSERT_EQUAL(u"学校[]"_ustr, fnGetCombinedString());
+ }
+}
+
void SwDocTest::testSetRubyList()
{
SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1);
@@ -2057,7 +2218,11 @@ void SwDocTest::testSetRubyList()
SwRubyList rList;
fnAppendRuby(&rList, u"学校"_ustr, u"がっこう"_ustr);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aPaM.GetMark()->GetContentIndex());
m_pDoc->SetRubyList(aPaM, rList);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aPaM.GetMark()->GetContentIndex());
CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]"_ustr, fnGetCombinedString());
}
@@ -2073,7 +2238,11 @@ void SwDocTest::testSetRubyList()
fnAppendRuby(&rList, u"きます"_ustr, u""_ustr);
fnAppendRuby(&rList, u"。"_ustr, u""_ustr);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aPaM.GetMark()->GetContentIndex());
m_pDoc->SetRubyList(aPaM, rList);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aPaM.GetMark()->GetContentIndex());
CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]に行[い]きます。"_ustr, fnGetCombinedString());
}
@@ -2089,7 +2258,11 @@ void SwDocTest::testSetRubyList()
fnAppendRuby(&rList, u"きます"_ustr, u""_ustr);
fnAppendRuby(&rList, u"。"_ustr, u""_ustr);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aPaM.GetMark()->GetContentIndex());
m_pDoc->SetRubyList(aPaM, rList);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aPaM.GetMark()->GetContentIndex());
CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]に行[い]きます。"_ustr, fnGetCombinedString());
@@ -2101,10 +2274,132 @@ void SwDocTest::testSetRubyList()
fnAppendRuby(&rList2, u"ます"_ustr, u""_ustr);
fnAppendRuby(&rList2, u"。"_ustr, u""_ustr);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(8), aPaM.GetMark()->GetContentIndex());
m_pDoc->SetRubyList(aPaM, rList2);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
CPPUNIT_ASSERT_EQUAL(u"学校[がっこう]に来[き]ます。"_ustr, fnGetCombinedString());
}
+
+ // tdf#107184: Characteristic test for ruby group mode editing
+ {
+ fnAppendJapanese(u"学校に行きます"_ustr);
+
+ SwRubyList rList;
+ fnAppendRuby(&rList, u"学校に行きます"_ustr, u"がっこうにいきます"_ustr);
+
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
+ m_pDoc->SetRubyList(aPaM, rList);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
+
+ CPPUNIT_ASSERT_EQUAL(u"学校に行きます[がっこうにいきます]"_ustr, fnGetCombinedString());
+ }
+
+ // tdf#107184: Delete ruby in group mode after populating
+ {
+ fnAppendJapanese(u"学校に行きます"_ustr);
+
+ SwRubyList rList;
+ fnAppendRuby(&rList, u"学校に行きます"_ustr, u"がっこうにいきます"_ustr);
+
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
+ m_pDoc->SetRubyList(aPaM, rList);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
+
+ CPPUNIT_ASSERT_EQUAL(u"学校に行きます[がっこうにいきます]"_ustr, fnGetCombinedString());
+
+ SwRubyList rList2;
+ fnAppendRuby(&rList2, u"学校に行きます"_ustr, u""_ustr);
+
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
+ m_pDoc->SetRubyList(aPaM, rList2);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
+
+ CPPUNIT_ASSERT_EQUAL(u"学校に行きます"_ustr, fnGetCombinedString());
+ }
+
+ // tdf#156543: Characteristic test for ruby mono mode editing
+ {
+ fnAppendJapanese(u"学校に行きます"_ustr);
+
+ SwRubyList rList;
+ fnAppendRuby(&rList, u"学"_ustr, u"がっ"_ustr);
+ fnAppendRuby(&rList, u"校"_ustr, u"こう"_ustr);
+ fnAppendRuby(&rList, u"に"_ustr, u""_ustr);
+ fnAppendRuby(&rList, u"行"_ustr, u"い"_ustr);
+ fnAppendRuby(&rList, u"き"_ustr, u""_ustr);
+ fnAppendRuby(&rList, u"ま"_ustr, u""_ustr);
+ fnAppendRuby(&rList, u"す"_ustr, u"す"_ustr);
+
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
+ m_pDoc->SetRubyList(aPaM, rList);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aPaM.GetPoint()->GetContentIndex());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aPaM.GetMark()->GetContentIndex());
+
+ CPPUNIT_ASSERT_EQUAL(u"学[がっ]校[こう]に行[い]きます[す]"_ustr, fnGetCombinedString());
+ }
+
+ // Offset PaM - Combination of insert and replace
+ {
+ fnAppendJapanese(u"学校員"_ustr);
+
+ SwPosition aNewPos{ aPaM.GetPoint()->nNode, aPaM.GetPoint()->nContent };
+ const SwTextNode* pTNd = aNewPos.GetNode().GetTextNode();
+ pTNd->GoNext(&aNewPos, SwCursorSkipMode::Chars);
+
+ SwPaM aEmptyPaM{ aNewPos };
+ aEmptyPaM.SetMark();
+ aEmptyPaM.GetMark()->AdjustContent(1);
+
+ SwRubyList rList;
+ fnAppendRuby(&rList, u"森林"_ustr, u"しんりん"_ustr);
+ fnAppendRuby(&rList, u"海上"_ustr, u"かいじょう"_ustr);
+ fnAppendRuby(&rList, u"地面"_ustr, u"じめん"_ustr);
+
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aEmptyPaM.GetPoint()->GetContentIndex());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aEmptyPaM.GetMark()->GetContentIndex());
+ m_pDoc->SetRubyList(aEmptyPaM, rList);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aEmptyPaM.GetPoint()->GetContentIndex());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aEmptyPaM.GetMark()->GetContentIndex());
+
+ CPPUNIT_ASSERT_EQUAL(u"学森林[しんりん]海上[かいじょう]地面[じめん]員"_ustr,
+ fnGetCombinedString());
+ }
+
+ // Empty PaM - Should insert
+ {
+ fnAppendJapanese(u"学校"_ustr);
+
+ SwPosition aNewPos{ aPaM.GetPoint()->nNode, aPaM.GetPoint()->nContent };
+ const SwTextNode* pTNd = aNewPos.GetNode().GetTextNode();
+ pTNd->GoNext(&aNewPos, SwCursorSkipMode::Chars);
+
+ SwPaM aEmptyPaM{ aNewPos };
+ aEmptyPaM.SetMark();
+
+ SwRubyList rList;
+ fnAppendRuby(&rList, u"森林"_ustr, u"しんりん"_ustr);
+ fnAppendRuby(&rList, u"海上"_ustr, u"かいじょう"_ustr);
+ fnAppendRuby(&rList, u"地面"_ustr, u"じめん"_ustr);
+
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aEmptyPaM.GetPoint()->GetContentIndex());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aEmptyPaM.GetMark()->GetContentIndex());
+ m_pDoc->SetRubyList(aEmptyPaM, rList);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), aEmptyPaM.GetPoint()->GetContentIndex());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(7), aEmptyPaM.GetMark()->GetContentIndex());
+
+ CPPUNIT_ASSERT_EQUAL(u"学森林[しんりん]海上[かいじょう]地面[じめん]校"_ustr,
+ fnGetCombinedString());
+ }
}
CPPUNIT_TEST_SUITE_REGISTRATION(SwDocTest);
diff --git a/sw/source/core/doc/docruby.cxx b/sw/source/core/doc/docruby.cxx
index 90f4e771d993..15629c70325e 100644
--- a/sw/source/core/doc/docruby.cxx
+++ b/sw/source/core/doc/docruby.cxx
@@ -40,6 +40,8 @@
using namespace ::com::sun::star::i18n;
+constexpr int nMaxBaseTexts = 30;
+
/*
* Members in the list:
* - String - the orig text
@@ -78,9 +80,9 @@ sal_uInt16 SwDoc::FillRubyList( const SwPaM& rPam, SwRubyList& rList )
else
break;
}
- } while( 30 > rList.size() && *aPam.GetPoint() < *pEnd );
+ } while (nMaxBaseTexts > rList.size() && *aPam.GetPoint() < *pEnd);
}
- if( 30 <= rList.size() )
+ if (nMaxBaseTexts <= rList.size())
break;
_pStartCursor = _pStartCursor->GetNext();
} while( _pStartCursor != _pStartCursor2 );
@@ -88,95 +90,146 @@ sal_uInt16 SwDoc::FillRubyList( const SwPaM& rPam, SwRubyList& rList )
return rList.size();
}
-void SwDoc::SetRubyList( const SwPaM& rPam, const SwRubyList& rList )
+void SwDoc::SetRubyList(SwPaM& rPam, const SwRubyList& rList)
{
- GetIDocumentUndoRedo().StartUndo( SwUndoId::SETRUBYATTR, nullptr );
+ SwPaM aOrigPam{ *rPam.GetPoint(), *rPam.GetMark() };
+ aOrigPam.Normalize();
+
+ GetIDocumentUndoRedo().StartUndo(SwUndoId::SETRUBYATTR, nullptr);
const o3tl::sorted_vector<sal_uInt16> aDelArr{ RES_TXTATR_CJK_RUBY };
SwRubyList::size_type nListEntry = 0;
+ int nCurrBaseTexts = 0;
- const SwPaM *_pStartCursor = rPam.GetNext(),
- *_pStartCursor2 = _pStartCursor;
- bool bCheckEmpty = &rPam != _pStartCursor;
- do {
- auto [pStt, pEnd] = _pStartCursor->StartEnd(); // SwPosition*
- if( !bCheckEmpty || ( pStt != pEnd && *pStt != *pEnd ))
+ const SwPaM* pStartCursor = rPam.GetNext();
+ auto [pStt, pEnd] = pStartCursor->StartEnd();
+
+ bool bCheckEmpty = (&rPam == pStartCursor) || (pStt != pEnd && *pStt != *pEnd);
+
+ // Sequentially replace as many spans as possible
+ SwPaM aPam(*pStt);
+ while (bCheckEmpty && nListEntry < rList.size() && nCurrBaseTexts < nMaxBaseTexts)
+ {
+ if (pEnd != pStt)
{
+ aPam.SetMark();
+ *aPam.GetMark() = *pEnd;
+ }
- SwPaM aPam( *pStt );
- do {
- SwRubyListEntry aCheckEntry;
- if( pEnd != pStt )
- {
- aPam.SetMark();
- *aPam.GetMark() = *pEnd;
- }
- if( SelectNextRubyChars( aPam, aCheckEntry ))
- {
- const SwRubyListEntry* pEntry = rList[ nListEntry++ ].get();
- if( aCheckEntry.GetRubyAttr() != pEntry->GetRubyAttr() )
- {
- // set/reset the attribute
- if( !pEntry->GetRubyAttr().GetText().isEmpty() )
- {
- getIDocumentContentOperations().InsertPoolItem( aPam, pEntry->GetRubyAttr() );
- }
- else
- {
- ResetAttrs( aPam, true, aDelArr );
- }
- }
+ SwRubyListEntry aCheckEntry;
+ if (!SelectNextRubyChars(aPam, aCheckEntry))
+ {
+ // goto next paragraph
+ aPam.DeleteMark();
+ aPam.Move(fnMoveForward, GoInNode);
- if (aCheckEntry.GetText() != pEntry->GetText())
- {
- if (pEntry->GetText().isEmpty())
- {
- ResetAttrs(aPam, true, aDelArr);
- }
-
- // text is changed, so replace the original
- getIDocumentContentOperations().ReplaceRange(aPam, pEntry->GetText(),
- false);
- std::swap(*aPam.GetMark(), *aPam.GetPoint());
- }
+ if (*aPam.GetPoint() >= *pEnd)
+ {
+ break;
+ }
- aPam.DeleteMark();
- }
- else
- {
- if( *aPam.GetPoint() < *pEnd )
- {
- // goto next paragraph
- aPam.DeleteMark();
- aPam.Move( fnMoveForward, GoInNode );
- }
- else
- {
- const SwRubyListEntry* pEntry = rList[ nListEntry++ ].get();
-
- // set/reset the attribute
- if( !pEntry->GetRubyAttr().GetText().isEmpty() &&
- !pEntry->GetText().isEmpty() )
- {
- getIDocumentContentOperations().InsertString( aPam, pEntry->GetText() );
- aPam.SetMark();
- aPam.GetMark()->AdjustContent( -pEntry->GetText().getLength() );
- getIDocumentContentOperations().InsertPoolItem(
- aPam, pEntry->GetRubyAttr(), SetAttrMode::DONTEXPAND );
- }
- else
- break;
- aPam.DeleteMark();
- }
- }
- } while( nListEntry < rList.size() && *aPam.GetPoint() < *pEnd );
+ continue;
}
- if( 30 <= rList.size() )
- break;
- _pStartCursor = _pStartCursor->GetNext();
- } while( _pStartCursor != _pStartCursor2 );
- GetIDocumentUndoRedo().EndUndo( SwUndoId::SETRUBYATTR, nullptr );
+ ++nCurrBaseTexts;
+
+ const SwRubyListEntry* pEntry = rList[nListEntry++].get();
+ if (aCheckEntry.GetRubyAttr() != pEntry->GetRubyAttr())
+ {
+ // set/reset the attribute
+ if (!pEntry->GetRubyAttr().GetText().isEmpty())
+ {
+ getIDocumentContentOperations().InsertPoolItem(aPam, pEntry->GetRubyAttr());
+ }
+ else
+ {
+ ResetAttrs(aPam, true, aDelArr);
+ }
+ }
+
+ if (aCheckEntry.GetText() != pEntry->GetText())
+ {
+ if (pEntry->GetText().isEmpty())
+ {
+ ResetAttrs(aPam, true, aDelArr);
+ }
+
+ // text is changed, so replace the original
+ getIDocumentContentOperations().ReplaceRange(aPam, pEntry->GetText(), false);
+ aPam.Exchange();
+ }
+
+ aPam.DeleteMark();
+ }
+
+ // Delete any spans past the end of the ruby list
+ while (nListEntry == rList.size() && nCurrBaseTexts < nMaxBaseTexts)
+ {
+ if (pEnd != pStt)
+ {
+ aPam.SetMark();
+ *aPam.GetMark() = *pEnd;
+ }
+
+ SwRubyListEntry aCheckEntry;
+ if (!SelectNextRubyChars(aPam, aCheckEntry))
+ {
+ // goto next paragraph
+ aPam.DeleteMark();
+ aPam.Move(fnMoveForward, GoInNode);
+
+ if (*aPam.GetPoint() >= *pEnd)
+ {
+ break;
+ }
+
+ continue;
+ }
+
+ ++nCurrBaseTexts;
+
+ ResetAttrs(aPam, true, aDelArr);
+ getIDocumentContentOperations().DeleteRange(aPam);
+ aPam.Exchange();
+
+ aPam.DeleteMark();
+ }
+
+ // Insert any spans past the end of the base text list
+ sal_Int32 nTotalContentGrowth = 0;
+ while (nListEntry < rList.size())
+ {
+ const SwRubyListEntry* pEntry = rList[nListEntry++].get();
+
+ if (pEnd != pStt)
+ {
+ aPam.SetMark();
+ *aPam.GetMark() = *pEnd;
+ }
+
+ aPam.SetMark();
+ getIDocumentContentOperations().InsertString(aPam, pEntry->GetText());
+ nTotalContentGrowth += pEntry->GetText().getLength();
+
+ if (!pEntry->GetRubyAttr().GetText().isEmpty())
+ {
+ getIDocumentContentOperations().InsertPoolItem(aPam, pEntry->GetRubyAttr());
+ }
+
+ aPam.DeleteMark();
+ }
+
+ // Expand selection to account for insertion
+ rPam.Normalize();
+ rPam = SwPaM{ *aOrigPam.GetPoint(), *rPam.GetMark() };
+ if (*rPam.GetPoint() == *rPam.GetMark())
+ {
+ rPam.GetPoint()->AdjustContent(-nTotalContentGrowth);
+ }
+
+ rPam.Normalize();
+
+ GetIDocumentUndoRedo().EndUndo(SwUndoId::SETRUBYATTR, nullptr);
}
bool SwDoc::SelectNextRubyChars( SwPaM& rPam, SwRubyListEntry& rEntry )
@@ -320,8 +373,4 @@ bool SwDoc::SelectNextRubyChars( SwPaM& rPam, SwRubyListEntry& rEntry )
return rPam.HasMark();
}
-SwRubyListEntry::~SwRubyListEntry()
-{
-}
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */