2 * This file is part of the LibreOffice project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This file incorporates work covered by the following license notice:
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
21 #include <tools/debug.hxx>
22 #include <comphelper/diagnose_ex.hxx>
23 #include <comphelper/processfactory.hxx>
25 #include <svx/rubydialog.hxx>
26 #include <sfx2/dispatch.hxx>
27 #include <sfx2/sfxsids.hrc>
28 #include <sfx2/viewfrm.hxx>
29 #include <sfx2/viewsh.hxx>
30 #include <svl/eitem.hxx>
31 #include <com/sun/star/frame/XController.hpp>
32 #include <com/sun/star/style/XStyle.hpp>
33 #include <com/sun/star/text/XRubySelection.hpp>
34 #include <com/sun/star/beans/PropertyValues.hpp>
35 #include <com/sun/star/beans/XPropertySet.hpp>
36 #include <com/sun/star/beans/XPropertySetInfo.hpp>
37 #include <com/sun/star/container/XNameContainer.hpp>
38 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
39 #include <com/sun/star/text/RubyAdjust.hpp>
40 #include <com/sun/star/view/XSelectionChangeListener.hpp>
41 #include <com/sun/star/view/XSelectionSupplier.hpp>
42 #include <com/sun/star/i18n/BreakIterator.hpp>
43 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
44 #include <cppuhelper/implbase.hxx>
45 #include <svtools/colorcfg.hxx>
46 #include <vcl/event.hxx>
47 #include <vcl/settings.hxx>
48 #include <vcl/svapp.hxx>
49 #include <rtl/ustrbuf.hxx>
50 #include <svl/itemset.hxx>
52 using namespace css::uno
;
53 using namespace css::frame
;
54 using namespace css::text
;
55 using namespace css::beans
;
56 using namespace css::style
;
57 using namespace css::view
;
58 using namespace css::lang
;
59 using namespace css::container
;
61 SFX_IMPL_CHILDWINDOW(SvxRubyChildWindow
, SID_RUBY_DIALOG
);
65 constexpr OUString cRubyBaseText
= u
"RubyBaseText"_ustr
;
66 constexpr OUString cRubyText
= u
"RubyText"_ustr
;
67 constexpr OUString cRubyAdjust
= u
"RubyAdjust"_ustr
;
68 constexpr OUString cRubyPosition
= u
"RubyPosition"_ustr
;
69 constexpr OUString cRubyCharStyleName
= u
"RubyCharStyleName"_ustr
;
71 } // end anonymous namespace
73 SvxRubyChildWindow::SvxRubyChildWindow(vcl::Window
* _pParent
, sal_uInt16 nId
,
74 SfxBindings
* pBindings
, SfxChildWinInfo
const* pInfo
)
75 : SfxChildWindow(_pParent
, nId
)
77 auto xDlg
= std::make_shared
<SvxRubyDialog
>(pBindings
, this, _pParent
->GetFrameWeld());
79 xDlg
->Initialize(pInfo
);
82 SfxChildWinInfo
SvxRubyChildWindow::GetInfo() const { return SfxChildWindow::GetInfo(); }
84 class SvxRubyData_Impl
: public cppu::WeakImplHelper
<css::view::XSelectionChangeListener
>
86 Reference
<css::i18n::XBreakIterator
> xBreak
;
87 Reference
<XModel
> xModel
;
88 Reference
<XRubySelection
> xSelection
;
89 Sequence
<PropertyValues
> aRubyValues
;
90 Reference
<XController
> xController
;
91 bool bHasSelectionChanged
;
96 virtual ~SvxRubyData_Impl() override
;
98 void SetController(const Reference
<XController
>& xCtrl
);
99 Reference
<XModel
> const& GetModel()
101 if (!xController
.is())
104 xModel
= xController
->getModel();
107 bool HasSelectionChanged() const { return bHasSelectionChanged
; }
108 bool IsDisposing() const { return bDisposing
; }
109 Reference
<XRubySelection
> const& GetRubySelection()
111 xSelection
.set(xController
, UNO_QUERY
);
114 void UpdateRubyValues()
116 if (!xSelection
.is())
117 aRubyValues
.realloc(0);
119 aRubyValues
= xSelection
->getRubyList(false);
120 bHasSelectionChanged
= false;
122 Sequence
<PropertyValues
>& GetRubyValues() { return aRubyValues
; }
123 void AssertOneEntry();
125 virtual void SAL_CALL
selectionChanged(const css::lang::EventObject
& aEvent
) override
;
126 virtual void SAL_CALL
disposing(const css::lang::EventObject
& Source
) override
;
128 bool IsSelectionGrouped() { return aRubyValues
.getLength() < 2; }
130 void MakeSelectionGrouped()
132 if (aRubyValues
.getLength() < 2)
138 OUStringBuffer aBaseString
;
139 for (const PropertyValues
& rVals
: aRubyValues
)
142 for (const PropertyValue
& rVal
: rVals
)
144 if (rVal
.Name
== cRubyBaseText
)
146 rVal
.Value
>>= sBaseTmp
;
150 aBaseString
.append(sBaseTmp
);
153 Sequence
<PropertyValues
> aNewRubyValues
{ 1 };
154 PropertyValues
* pNewRubyValues
= aNewRubyValues
.getArray();
156 // Copy some reasonable style values from the previous ruby array
157 pNewRubyValues
[0] = aRubyValues
[0];
158 for (const PropertyValues
& rVals
: aRubyValues
)
160 for (const PropertyValue
& rVal
: rVals
)
162 if (rVal
.Name
== cRubyText
)
164 rVal
.Value
>>= sBaseTmp
;
165 if (!sBaseTmp
.isEmpty())
167 pNewRubyValues
[0] = rVals
;
174 PropertyValue
* pNewValues
= pNewRubyValues
[0].getArray();
175 for (sal_Int32 i
= 0; i
< pNewRubyValues
[0].getLength(); ++i
)
177 if (pNewValues
[i
].Name
== cRubyBaseText
)
179 sBaseTmp
= aBaseString
;
180 pNewValues
[i
].Value
<<= sBaseTmp
;
182 else if (pNewValues
[i
].Name
== cRubyText
)
185 pNewValues
[i
].Value
<<= sBaseTmp
;
189 aRubyValues
= std::move(aNewRubyValues
);
192 bool IsSelectionMono()
196 // Cannot continue if BreakIterator is not available
197 // Disable the button
201 // Locale does not matter in this case; default ICU BreakIterator is sufficient
206 aRubyValues
.begin(), aRubyValues
.end(), [&](const PropertyValues
& rVals
) {
207 return !std::any_of(rVals
.begin(), rVals
.end(), [&](const PropertyValue
& rVal
) {
208 if (rVal
.Name
== cRubyBaseText
)
210 rVal
.Value
>>= sBaseTmp
;
212 auto nPos
= xBreak
->nextCharacters(
213 sBaseTmp
, 0, aLocale
, css::i18n::CharacterIteratorMode::SKIPCELL
, 1,
215 return nPos
< sBaseTmp
.getLength();
223 void MakeSelectionMono()
227 // Cannot continue if BreakIterator is not available
231 // Locale does not matter in this case; default ICU BreakIterator is sufficient
236 // Count the grapheme clusters
237 sal_Int32 nTotalGraphemeClusters
= 0;
238 for (const PropertyValues
& rVals
: aRubyValues
)
240 for (const PropertyValue
& rVal
: rVals
)
242 if (rVal
.Name
== cRubyBaseText
)
244 rVal
.Value
>>= sBaseTmp
;
247 while (nPos
< sBaseTmp
.getLength())
250 nPos
= xBreak
->nextCharacters(sBaseTmp
, nPos
, aLocale
,
251 css::i18n::CharacterIteratorMode::SKIPCELL
, 1,
253 ++nTotalGraphemeClusters
;
259 // Put each grapheme cluster in its own entry
260 Sequence
<PropertyValues
> aNewRubyValues
{ nTotalGraphemeClusters
};
261 PropertyValues
* pNewRubyValues
= aNewRubyValues
.getArray();
263 sal_Int32 nCurrGraphemeCluster
= 0;
264 for (const PropertyValues
& rVals
: aRubyValues
)
266 for (const PropertyValue
& rVal
: rVals
)
268 if (rVal
.Name
== cRubyBaseText
)
270 rVal
.Value
>>= sBaseTmp
;
273 while (nPos
< sBaseTmp
.getLength())
276 auto nNextPos
= xBreak
->nextCharacters(
277 sBaseTmp
, nPos
, aLocale
, css::i18n::CharacterIteratorMode::SKIPCELL
, 1,
280 PropertyValues
& rNewVals
= pNewRubyValues
[nCurrGraphemeCluster
++];
282 // Initialize new property values with values from current run
285 PropertyValue
* aNewVals
= rNewVals
.getArray();
286 for (sal_Int32 i
= 0; i
< rNewVals
.getLength(); ++i
)
288 PropertyValue
& rNewVal
= aNewVals
[i
];
290 if (rNewVal
.Name
== cRubyText
)
292 rNewVal
.Value
<<= OUString
{};
294 else if (rNewVal
.Name
== cRubyBaseText
)
296 rNewVal
.Value
<<= sBaseTmp
.copy(nPos
, nNextPos
- nPos
);
306 aRubyValues
= std::move(aNewRubyValues
);
310 SvxRubyData_Impl::SvxRubyData_Impl()
311 : bHasSelectionChanged(false)
314 const Reference
<XComponentContext
>& xContext
= ::comphelper::getProcessComponentContext();
315 xBreak
= css::i18n::BreakIterator::create(xContext
);
318 SvxRubyData_Impl::~SvxRubyData_Impl() {}
320 void SvxRubyData_Impl::SetController(const Reference
<XController
>& xCtrl
)
322 if (xCtrl
.get() == xController
.get())
327 Reference
<XSelectionSupplier
> xSelSupp(xController
, UNO_QUERY
);
329 xSelSupp
->removeSelectionChangeListener(this);
331 bHasSelectionChanged
= true;
333 xSelSupp
.set(xController
, UNO_QUERY
);
335 xSelSupp
->addSelectionChangeListener(this);
337 catch (const Exception
&)
342 void SvxRubyData_Impl::selectionChanged(const EventObject
&) { bHasSelectionChanged
= true; }
344 void SvxRubyData_Impl::disposing(const EventObject
&)
348 Reference
<XSelectionSupplier
> xSelSupp(xController
, UNO_QUERY
);
350 xSelSupp
->removeSelectionChangeListener(this);
352 catch (const Exception
&)
355 xController
= nullptr;
359 void SvxRubyData_Impl::AssertOneEntry()
362 if (!aRubyValues
.hasElements())
364 aRubyValues
.realloc(1);
365 Sequence
<PropertyValue
>& rValues
= aRubyValues
.getArray()[0];
367 PropertyValue
* pValues
= rValues
.getArray();
368 pValues
[0].Name
= cRubyBaseText
;
369 pValues
[1].Name
= cRubyText
;
370 pValues
[2].Name
= cRubyAdjust
;
371 pValues
[3].Name
= cRubyPosition
;
372 pValues
[4].Name
= cRubyCharStyleName
;
376 SvxRubyDialog::SvxRubyDialog(SfxBindings
* pBind
, SfxChildWindow
* pCW
, weld::Window
* pParent
)
377 : SfxModelessDialogController(pBind
, pCW
, pParent
, u
"svx/ui/asianphoneticguidedialog.ui"_ustr
,
378 u
"AsianPhoneticGuideDialog"_ustr
)
383 , m_pImpl(new SvxRubyData_Impl
)
384 , m_xLeft1ED(m_xBuilder
->weld_entry(u
"Left1ED"_ustr
))
385 , m_xRight1ED(m_xBuilder
->weld_entry(u
"Right1ED"_ustr
))
386 , m_xLeft2ED(m_xBuilder
->weld_entry(u
"Left2ED"_ustr
))
387 , m_xRight2ED(m_xBuilder
->weld_entry(u
"Right2ED"_ustr
))
388 , m_xLeft3ED(m_xBuilder
->weld_entry(u
"Left3ED"_ustr
))
389 , m_xRight3ED(m_xBuilder
->weld_entry(u
"Right3ED"_ustr
))
390 , m_xLeft4ED(m_xBuilder
->weld_entry(u
"Left4ED"_ustr
))
391 , m_xRight4ED(m_xBuilder
->weld_entry(u
"Right4ED"_ustr
))
392 , m_xScrolledWindow(m_xBuilder
->weld_scrolled_window(u
"scrolledwindow"_ustr
, true))
393 , m_xAdjustLB(m_xBuilder
->weld_combo_box(u
"adjustlb"_ustr
))
394 , m_xPositionLB(m_xBuilder
->weld_combo_box(u
"positionlb"_ustr
))
395 , m_xCharStyleFT(m_xBuilder
->weld_label(u
"styleft"_ustr
))
396 , m_xCharStyleLB(m_xBuilder
->weld_combo_box(u
"stylelb"_ustr
))
397 , m_xStylistPB(m_xBuilder
->weld_button(u
"styles"_ustr
))
398 , m_xSelectionGroupPB(m_xBuilder
->weld_button(u
"selection-group"_ustr
))
399 , m_xSelectionMonoPB(m_xBuilder
->weld_button(u
"selection-mono"_ustr
))
400 , m_xApplyPB(m_xBuilder
->weld_button(u
"ok"_ustr
))
401 , m_xClosePB(m_xBuilder
->weld_button(u
"close"_ustr
))
402 , m_xContentArea(m_xDialog
->weld_content_area())
403 , m_xGrid(m_xBuilder
->weld_widget(u
"grid"_ustr
))
404 , m_xPreviewWin(new RubyPreview
)
405 , m_xPreview(new weld::CustomWeld(*m_xBuilder
, u
"preview"_ustr
, *m_xPreviewWin
))
407 m_xCharStyleLB
->make_sorted();
408 m_xPreviewWin
->setRubyDialog(this);
409 m_xScrolledWindow
->set_size_request(-1, m_xGrid
->get_preferred_size().Height());
410 m_xScrolledWindow
->set_vpolicy(VclPolicyType::NEVER
);
412 aEditArr
[0] = m_xLeft1ED
.get();
413 aEditArr
[1] = m_xRight1ED
.get();
414 aEditArr
[2] = m_xLeft2ED
.get();
415 aEditArr
[3] = m_xRight2ED
.get();
416 aEditArr
[4] = m_xLeft3ED
.get();
417 aEditArr
[5] = m_xRight3ED
.get();
418 aEditArr
[6] = m_xLeft4ED
.get();
419 aEditArr
[7] = m_xRight4ED
.get();
421 m_xSelectionGroupPB
->connect_clicked(LINK(this, SvxRubyDialog
, SelectionGroup_Impl
));
422 m_xSelectionMonoPB
->connect_clicked(LINK(this, SvxRubyDialog
, SelectionMono_Impl
));
423 m_xApplyPB
->connect_clicked(LINK(this, SvxRubyDialog
, ApplyHdl_Impl
));
424 m_xClosePB
->connect_clicked(LINK(this, SvxRubyDialog
, CloseHdl_Impl
));
425 m_xStylistPB
->connect_clicked(LINK(this, SvxRubyDialog
, StylistHdl_Impl
));
426 m_xAdjustLB
->connect_changed(LINK(this, SvxRubyDialog
, AdjustHdl_Impl
));
427 m_xPositionLB
->connect_changed(LINK(this, SvxRubyDialog
, PositionHdl_Impl
));
428 m_xCharStyleLB
->connect_changed(LINK(this, SvxRubyDialog
, CharStyleHdl_Impl
));
430 Link
<weld::ScrolledWindow
&, void> aScrLk(LINK(this, SvxRubyDialog
, ScrollHdl_Impl
));
431 m_xScrolledWindow
->connect_vadjustment_changed(aScrLk
);
433 Link
<weld::Entry
&, void> aEditLk(LINK(this, SvxRubyDialog
, EditModifyHdl_Impl
));
434 Link
<weld::Widget
&, void> aFocusLk(LINK(this, SvxRubyDialog
, EditFocusHdl_Impl
));
435 Link
<const KeyEvent
&, bool> aKeyUpDownLk(LINK(this, SvxRubyDialog
, KeyUpDownHdl_Impl
));
436 Link
<const KeyEvent
&, bool> aKeyTabUpDownLk(LINK(this, SvxRubyDialog
, KeyUpDownTabHdl_Impl
));
437 for (sal_uInt16 i
= 0; i
< 8; i
++)
439 aEditArr
[i
]->connect_changed(aEditLk
);
440 aEditArr
[i
]->connect_focus_in(aFocusLk
);
442 aEditArr
[i
]->connect_key_press(aKeyTabUpDownLk
);
444 aEditArr
[i
]->connect_key_press(aKeyUpDownLk
);
448 SvxRubyDialog::~SvxRubyDialog()
450 ClearCharStyleList();
452 m_pImpl
->disposing(aEvent
);
455 void SvxRubyDialog::ClearCharStyleList() { m_xCharStyleLB
->clear(); }
457 void SvxRubyDialog::Close()
461 SfxViewFrame
* pViewFrame
= SfxViewFrame::Current();
463 pViewFrame
->ToggleChildWindow(SID_RUBY_DIALOG
);
466 void SvxRubyDialog::Activate()
468 SfxModelessDialogController::Activate();
469 if (m_pImpl
->IsDisposing())
471 // tdf#141967/tdf#152495 if Activate is called during tear down bail early
475 //get selection from current view frame
476 SfxViewFrame
* pCurFrm
= SfxViewFrame::Current();
477 Reference
<XController
> xCtrl(pCurFrm
? pCurFrm
->GetFrame().GetController() : nullptr);
478 m_pImpl
->SetController(xCtrl
);
479 if (!m_pImpl
->HasSelectionChanged())
482 Reference
<XRubySelection
> xRubySel
= m_pImpl
->GetRubySelection();
483 m_pImpl
->UpdateRubyValues();
484 EnableControls(xRubySel
.is());
487 Reference
<XModel
> xModel
= m_pImpl
->GetModel();
488 const OUString sCharStyleSelect
= m_xCharStyleLB
->get_active_text();
489 ClearCharStyleList();
490 Reference
<XStyleFamiliesSupplier
> xSupplier(xModel
, UNO_QUERY
);
495 Reference
<XNameAccess
> xFam
= xSupplier
->getStyleFamilies();
496 Any aChar
= xFam
->getByName(u
"CharacterStyles"_ustr
);
497 Reference
<XNameContainer
> xChar
;
499 Reference
<XIndexAccess
> xCharIdx(xChar
, UNO_QUERY
);
502 OUString
sUIName(u
"DisplayName"_ustr
);
503 for (sal_Int32 nStyle
= 0; nStyle
< xCharIdx
->getCount(); nStyle
++)
505 Any aStyle
= xCharIdx
->getByIndex(nStyle
);
506 Reference
<XStyle
> xStyle
;
508 Reference
<XPropertySet
> xPrSet(xStyle
, UNO_QUERY
);
509 OUString sName
, sCoreName
;
512 Reference
<XPropertySetInfo
> xInfo
= xPrSet
->getPropertySetInfo();
513 if (xInfo
->hasPropertyByName(sUIName
))
515 Any aName
= xPrSet
->getPropertyValue(sUIName
);
521 sCoreName
= xStyle
->getName();
525 if (!sName
.isEmpty())
527 m_xCharStyleLB
->append(sCoreName
, sName
);
532 catch (const Exception
&)
534 TOOLS_WARN_EXCEPTION("svx.dialog", "exception in style access");
536 if (!sCharStyleSelect
.isEmpty())
537 m_xCharStyleLB
->set_active_text(sCharStyleSelect
);
539 m_xCharStyleLB
->set_sensitive(xSupplier
.is());
540 m_xCharStyleFT
->set_sensitive(xSupplier
.is());
543 m_xPreviewWin
->Invalidate();
546 void SvxRubyDialog::SetRubyText(sal_Int32 nPos
, weld::Entry
& rLeft
, weld::Entry
& rRight
)
548 OUString sLeft
, sRight
;
549 const Sequence
<PropertyValues
>& aRubyValues
= m_pImpl
->GetRubyValues();
550 bool bEnable
= aRubyValues
.getLength() > nPos
;
553 const Sequence
<PropertyValue
> aProps
= aRubyValues
.getConstArray()[nPos
];
554 for (const PropertyValue
& rProp
: aProps
)
556 if (rProp
.Name
== cRubyBaseText
)
557 rProp
.Value
>>= sLeft
;
558 else if (rProp
.Name
== cRubyText
)
559 rProp
.Value
>>= sRight
;
566 rLeft
.set_sensitive(bEnable
);
567 rRight
.set_sensitive(bEnable
);
568 rLeft
.set_text(sLeft
);
569 rRight
.set_text(sRight
);
574 void SvxRubyDialog::GetRubyText()
576 tools::Long nTempLastPos
= GetLastPos();
577 Sequence
<PropertyValues
>& aRubyValues
= m_pImpl
->GetRubyValues();
578 auto aRubyValuesRange
= asNonConstRange(aRubyValues
);
579 for (int i
= 0; i
< 8; i
+= 2)
581 if (aEditArr
[i
]->get_sensitive()
582 && (aEditArr
[i
]->get_value_changed_from_saved()
583 || aEditArr
[i
+ 1]->get_value_changed_from_saved()))
585 DBG_ASSERT(aRubyValues
.getLength() > (i
/ 2 + nTempLastPos
), "wrong index");
587 for (PropertyValue
& propVal
: asNonConstRange(aRubyValuesRange
[i
/ 2 + nTempLastPos
]))
589 if (propVal
.Name
== cRubyBaseText
)
590 propVal
.Value
<<= aEditArr
[i
]->get_text();
591 else if (propVal
.Name
== cRubyText
)
592 propVal
.Value
<<= aEditArr
[i
+ 1]->get_text();
598 void SvxRubyDialog::Update()
600 // Only enable selection grouping options when they can be applied
601 m_xSelectionGroupPB
->set_sensitive(!m_pImpl
->IsSelectionGrouped());
602 m_xSelectionMonoPB
->set_sensitive(!m_pImpl
->IsSelectionMono());
604 const Sequence
<PropertyValues
>& aRubyValues
= m_pImpl
->GetRubyValues();
605 sal_Int32 nLen
= aRubyValues
.getLength();
606 m_xScrolledWindow
->vadjustment_configure(0, 0, !nLen
? 1 : nLen
, 1, 4, 4);
608 m_xScrolledWindow
->set_vpolicy(VclPolicyType::ALWAYS
);
610 m_xScrolledWindow
->set_vpolicy(VclPolicyType::NEVER
);
614 sal_Int16 nAdjust
= -1;
615 sal_Int16 nPosition
= -1;
616 OUString sCharStyleName
, sTmp
;
617 bool bCharStyleEqual
= true;
618 for (sal_Int32 nRuby
= 0; nRuby
< nLen
; nRuby
++)
620 const Sequence
<PropertyValue
>& rProps
= aRubyValues
.getConstArray()[nRuby
];
621 for (const PropertyValue
& rProp
: rProps
)
623 if (nAdjust
> -2 && rProp
.Name
== cRubyAdjust
)
625 sal_Int16 nTmp
= sal_Int16();
626 rProp
.Value
>>= nTmp
;
629 else if (nAdjust
!= nTmp
)
632 if (nPosition
> -2 && rProp
.Name
== cRubyPosition
)
634 sal_Int16 nTmp
= sal_Int16();
635 rProp
.Value
>>= nTmp
;
638 else if (nPosition
!= nTmp
)
641 if (bCharStyleEqual
&& rProp
.Name
== cRubyCharStyleName
)
643 rProp
.Value
>>= sTmp
;
645 sCharStyleName
= sTmp
;
646 else if (sCharStyleName
!= sTmp
)
647 bCharStyleEqual
= false;
653 //enable selection if the ruby list is empty
658 m_xAdjustLB
->set_active(nAdjust
);
660 m_xAdjustLB
->set_active(-1);
662 m_xPositionLB
->set_active(nPosition
);
663 if (!nLen
|| (bCharStyleEqual
&& sCharStyleName
.isEmpty()))
664 sCharStyleName
= "Rubies";
665 if (!sCharStyleName
.isEmpty())
667 for (int i
= 0, nEntryCount
= m_xCharStyleLB
->get_count(); i
< nEntryCount
; i
++)
669 OUString sCoreName
= m_xCharStyleLB
->get_id(i
);
670 if (sCharStyleName
== sCoreName
)
672 m_xCharStyleLB
->set_active(i
);
678 m_xCharStyleLB
->set_active(-1);
680 ScrollHdl_Impl(*m_xScrolledWindow
);
683 void SvxRubyDialog::GetCurrentText(OUString
& rBase
, OUString
& rRuby
)
685 rBase
= aEditArr
[nCurrentEdit
* 2]->get_text();
686 rRuby
= aEditArr
[nCurrentEdit
* 2 + 1]->get_text();
689 IMPL_LINK(SvxRubyDialog
, ScrollHdl_Impl
, weld::ScrolledWindow
&, rScroll
, void)
691 int nPos
= rScroll
.vadjustment_get_value();
692 if (GetLastPos() != nPos
)
696 SetRubyText(nPos
++, *m_xLeft1ED
, *m_xRight1ED
);
697 SetRubyText(nPos
++, *m_xLeft2ED
, *m_xRight2ED
);
698 SetRubyText(nPos
++, *m_xLeft3ED
, *m_xRight3ED
);
699 SetRubyText(nPos
, *m_xLeft4ED
, *m_xRight4ED
);
700 SetLastPos(nPos
- 3);
701 m_xPreviewWin
->Invalidate();
704 IMPL_LINK_NOARG(SvxRubyDialog
, SelectionGroup_Impl
, weld::Button
&, void)
706 m_pImpl
->MakeSelectionGrouped();
710 IMPL_LINK_NOARG(SvxRubyDialog
, SelectionMono_Impl
, weld::Button
&, void)
712 m_pImpl
->MakeSelectionMono();
716 IMPL_LINK_NOARG(SvxRubyDialog
, ApplyHdl_Impl
, weld::Button
&, void)
718 const Sequence
<PropertyValues
>& aRubyValues
= m_pImpl
->GetRubyValues();
719 if (!aRubyValues
.hasElements())
722 PositionHdl_Impl(*m_xPositionLB
);
723 AdjustHdl_Impl(*m_xAdjustLB
);
724 CharStyleHdl_Impl(*m_xCharStyleLB
);
727 //reset all edit fields - SaveValue is called
728 ScrollHdl_Impl(*m_xScrolledWindow
);
730 Reference
<XRubySelection
> xSelection
= m_pImpl
->GetRubySelection();
731 if (IsModified() && xSelection
.is())
735 xSelection
->setRubyList(aRubyValues
, false);
737 catch (const Exception
&)
739 TOOLS_WARN_EXCEPTION("svx.dialog", "");
744 IMPL_LINK_NOARG(SvxRubyDialog
, CloseHdl_Impl
, weld::Button
&, void) { Close(); }
746 IMPL_LINK_NOARG(SvxRubyDialog
, StylistHdl_Impl
, weld::Button
&, void)
748 std::unique_ptr
<SfxBoolItem
> pState
;
749 SfxItemState eState
= pBindings
->QueryState(SID_STYLE_DESIGNER
, pState
);
750 if (eState
<= SfxItemState::SET
|| !pState
|| !pState
->GetValue())
752 pBindings
->GetDispatcher()->Execute(SID_STYLE_DESIGNER
,
753 SfxCallMode::ASYNCHRON
| SfxCallMode::RECORD
);
757 IMPL_LINK(SvxRubyDialog
, AdjustHdl_Impl
, weld::ComboBox
&, rBox
, void)
760 sal_Int16 nAdjust
= rBox
.get_active();
761 for (PropertyValues
& rProps
: asNonConstRange(m_pImpl
->GetRubyValues()))
763 for (PropertyValue
& propVal
: asNonConstRange(rProps
))
765 if (propVal
.Name
== cRubyAdjust
)
766 propVal
.Value
<<= nAdjust
;
770 m_xPreviewWin
->Invalidate();
773 IMPL_LINK(SvxRubyDialog
, PositionHdl_Impl
, weld::ComboBox
&, rBox
, void)
776 sal_Int16 nPosition
= rBox
.get_active();
777 for (PropertyValues
& rProps
: asNonConstRange(m_pImpl
->GetRubyValues()))
779 for (PropertyValue
& propVal
: asNonConstRange(rProps
))
781 if (propVal
.Name
== cRubyPosition
)
782 propVal
.Value
<<= nPosition
;
786 m_xPreviewWin
->Invalidate();
789 IMPL_LINK_NOARG(SvxRubyDialog
, CharStyleHdl_Impl
, weld::ComboBox
&, void)
793 if (m_xCharStyleLB
->get_active() != -1)
794 sStyleName
= m_xCharStyleLB
->get_active_id();
795 for (PropertyValues
& rProps
: asNonConstRange(m_pImpl
->GetRubyValues()))
797 for (PropertyValue
& propVal
: asNonConstRange(rProps
))
799 if (propVal
.Name
== cRubyCharStyleName
)
801 propVal
.Value
<<= sStyleName
;
808 IMPL_LINK(SvxRubyDialog
, EditFocusHdl_Impl
, weld::Widget
&, rEdit
, void)
810 for (sal_uInt16 i
= 0; i
< 8; i
++)
812 if (&rEdit
== aEditArr
[i
])
814 nCurrentEdit
= i
/ 2;
818 m_xPreviewWin
->Invalidate();
821 IMPL_LINK(SvxRubyDialog
, EditModifyHdl_Impl
, weld::Entry
&, rEdit
, void)
823 EditFocusHdl_Impl(rEdit
);
826 bool SvxRubyDialog::EditScrollHdl_Impl(sal_Int32 nParam
)
830 if (nParam
> 0 && (aEditArr
[7]->has_focus() || aEditArr
[6]->has_focus()))
832 if (m_xScrolledWindow
->vadjustment_get_upper()
833 > m_xScrolledWindow
->vadjustment_get_value()
834 + m_xScrolledWindow
->vadjustment_get_page_size())
836 m_xScrolledWindow
->vadjustment_set_value(m_xScrolledWindow
->vadjustment_get_value()
838 aEditArr
[6]->grab_focus();
843 else if (m_xScrolledWindow
->vadjustment_get_value()
844 && (aEditArr
[0]->has_focus() || aEditArr
[1]->has_focus()))
846 m_xScrolledWindow
->vadjustment_set_value(m_xScrolledWindow
->vadjustment_get_value() - 1);
847 aEditArr
[1]->grab_focus();
851 ScrollHdl_Impl(*m_xScrolledWindow
);
855 bool SvxRubyDialog::EditJumpHdl_Impl(sal_Int32 nParam
)
857 bool bHandled
= false;
858 sal_uInt16 nIndex
= USHRT_MAX
;
859 for (sal_uInt16 i
= 0; i
< 8; i
++)
861 if (aEditArr
[i
]->has_focus())
869 aEditArr
[nIndex
+ 2]->grab_focus();
870 else if (EditScrollHdl_Impl(nParam
))
871 aEditArr
[nIndex
]->grab_focus();
876 aEditArr
[nIndex
- 2]->grab_focus();
877 else if (EditScrollHdl_Impl(nParam
))
878 aEditArr
[nIndex
]->grab_focus();
885 void SvxRubyDialog::AssertOneEntry() { m_pImpl
->AssertOneEntry(); }
887 void SvxRubyDialog::EnableControls(bool bEnable
)
889 m_xContentArea
->set_sensitive(bEnable
);
890 m_xApplyPB
->set_sensitive(bEnable
);
893 RubyPreview::RubyPreview()
894 : m_pParentDlg(nullptr)
898 RubyPreview::~RubyPreview() {}
900 void RubyPreview::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& /*rRect*/)
902 rRenderContext
.Push(vcl::PushFlags::ALL
);
904 rRenderContext
.SetMapMode(MapMode(MapUnit::MapTwip
));
906 Size aWinSize
= rRenderContext
.GetOutputSize();
908 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
909 svtools::ColorConfig aColorConfig
;
911 Color
aNewTextColor(aColorConfig
.GetColorValue(svtools::FONTCOLOR
).nColor
);
912 Color
aNewFillColor(rStyleSettings
.GetWindowColor());
914 vcl::Font aFont
= rRenderContext
.GetFont();
915 aFont
.SetFontHeight(aWinSize
.Height() / 4);
916 aFont
.SetFillColor(aNewFillColor
);
917 aFont
.SetColor(aNewTextColor
);
918 rRenderContext
.SetFont(aFont
);
920 tools::Rectangle
aRect(Point(0, 0), aWinSize
);
921 rRenderContext
.SetLineColor();
922 rRenderContext
.SetFillColor(aFont
.GetFillColor());
923 rRenderContext
.DrawRect(aRect
);
925 OUString sBaseText
, sRubyText
;
926 m_pParentDlg
->GetCurrentText(sBaseText
, sRubyText
);
928 tools::Long nTextHeight
= rRenderContext
.GetTextHeight();
929 tools::Long nBaseWidth
= rRenderContext
.GetTextWidth(sBaseText
);
931 vcl::Font
aRubyFont(aFont
);
932 aRubyFont
.SetFontHeight(aRubyFont
.GetFontHeight() * 70 / 100);
933 rRenderContext
.SetFont(aRubyFont
);
934 tools::Long nRubyWidth
= rRenderContext
.GetTextWidth(sRubyText
);
935 rRenderContext
.SetFont(aFont
);
937 RubyAdjust nAdjust
= static_cast<RubyAdjust
>(m_pParentDlg
->m_xAdjustLB
->get_active());
938 //use center if no adjustment is available
939 if (nAdjust
> RubyAdjust_INDENT_BLOCK
)
940 nAdjust
= RubyAdjust_CENTER
;
942 //which part is stretched ?
943 bool bRubyStretch
= nBaseWidth
>= nRubyWidth
;
945 tools::Long nCenter
= aWinSize
.Width() / 2;
946 tools::Long nHalfWidth
= std::max(nBaseWidth
, nRubyWidth
) / 2;
947 tools::Long nLeftStart
= nCenter
- nHalfWidth
;
948 tools::Long nRightEnd
= nCenter
+ nHalfWidth
;
950 // Default values for TOP or no selection
951 tools::Long nYRuby
= aWinSize
.Height() / 4 - nTextHeight
/ 2;
952 tools::Long nYBase
= aWinSize
.Height() * 3 / 4 - nTextHeight
/ 2;
954 sal_Int16 nRubyPos
= m_pParentDlg
->m_xPositionLB
->get_active();
955 if (nRubyPos
== 1) // BOTTOM
956 std::swap(nYRuby
, nYBase
);
957 else if (nRubyPos
== 2) // RIGHT ( vertically )
959 // Align the ruby text and base text to the vertical center.
960 nYBase
= (aWinSize
.Height() - nTextHeight
) / 2;
961 nYRuby
= (aWinSize
.Height() - nRubyWidth
) / 2;
963 // Align the ruby text at the right side of the base text
964 nAdjust
= RubyAdjust_RIGHT
;
965 nHalfWidth
= nBaseWidth
/ 2;
966 nLeftStart
= nCenter
- nHalfWidth
;
967 nRightEnd
= nCenter
+ nHalfWidth
+ nRubyWidth
+ nTextHeight
;
968 // Render base text first, then render ruby text on the right.
971 aRubyFont
.SetVertical(true);
972 aRubyFont
.SetOrientation(2700_deg10
);
975 tools::Long nYOutput
;
976 tools::Long nOutTextWidth
;
977 OUString sOutputText
;
981 rRenderContext
.DrawText(Point(nLeftStart
, nYBase
), sBaseText
);
983 sOutputText
= sRubyText
;
984 nOutTextWidth
= nRubyWidth
;
985 rRenderContext
.SetFont(aRubyFont
);
989 rRenderContext
.SetFont(aRubyFont
);
990 rRenderContext
.DrawText(Point(nLeftStart
, nYRuby
), sRubyText
);
992 sOutputText
= sBaseText
;
993 nOutTextWidth
= nBaseWidth
;
994 rRenderContext
.SetFont(aFont
);
999 case RubyAdjust_LEFT
:
1000 rRenderContext
.DrawText(Point(nLeftStart
, nYOutput
), sOutputText
);
1002 case RubyAdjust_RIGHT
:
1003 rRenderContext
.DrawText(Point(nRightEnd
- nOutTextWidth
, nYOutput
), sOutputText
);
1005 case RubyAdjust_INDENT_BLOCK
:
1007 tools::Long nCharWidth
= rRenderContext
.GetTextWidth(u
"X"_ustr
);
1008 if (nOutTextWidth
< (nRightEnd
- nLeftStart
- nCharWidth
))
1011 nLeftStart
+= nCharWidth
;
1012 nRightEnd
-= nCharWidth
;
1016 case RubyAdjust_BLOCK
:
1018 if (sOutputText
.getLength() > 1)
1020 sal_Int32 nCount
= sOutputText
.getLength();
1022 = ((nRightEnd
- nLeftStart
) - rRenderContext
.GetTextWidth(sOutputText
))
1024 for (sal_Int32 i
= 0; i
< nCount
; i
++)
1026 OUString
sChar(sOutputText
[i
]);
1027 rRenderContext
.DrawText(Point(nLeftStart
, nYOutput
), sChar
);
1028 tools::Long nCharWidth
= rRenderContext
.GetTextWidth(sChar
);
1029 nLeftStart
+= nCharWidth
+ nSpace
;
1035 case RubyAdjust_CENTER
:
1036 rRenderContext
.DrawText(Point(nCenter
- nOutTextWidth
/ 2, nYOutput
), sOutputText
);
1041 rRenderContext
.Pop();
1044 void RubyPreview::SetDrawingArea(weld::DrawingArea
* pDrawingArea
)
1046 pDrawingArea
->set_size_request(pDrawingArea
->get_approximate_digit_width() * 40,
1047 pDrawingArea
->get_text_height() * 7);
1048 CustomWidgetController::SetDrawingArea(pDrawingArea
);
1051 IMPL_LINK(SvxRubyDialog
, KeyUpDownHdl_Impl
, const KeyEvent
&, rKEvt
, bool)
1053 bool bHandled
= false;
1054 const vcl::KeyCode
& rKeyCode
= rKEvt
.GetKeyCode();
1055 sal_uInt16 nCode
= rKeyCode
.GetCode();
1056 if (KEY_UP
== nCode
|| KEY_DOWN
== nCode
)
1058 sal_Int32 nParam
= KEY_UP
== nCode
? -1 : 1;
1059 bHandled
= EditJumpHdl_Impl(nParam
);
1064 IMPL_LINK(SvxRubyDialog
, KeyUpDownTabHdl_Impl
, const KeyEvent
&, rKEvt
, bool)
1066 bool bHandled
= false;
1067 const vcl::KeyCode
& rKeyCode
= rKEvt
.GetKeyCode();
1068 sal_uInt16 nMod
= rKeyCode
.GetModifier();
1069 sal_uInt16 nCode
= rKeyCode
.GetCode();
1070 if (nCode
== KEY_TAB
&& (!nMod
|| KEY_SHIFT
== nMod
))
1072 sal_Int32 nParam
= KEY_SHIFT
== nMod
? -1 : 1;
1073 if (EditScrollHdl_Impl(nParam
))
1077 bHandled
= KeyUpDownHdl_Impl(rKEvt
);
1081 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */