1 /*
2 * This file is part of the LibreOffice project.
3 *
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/.
7 *
8 * This file incorporates work covered by the following license notice:
9 *
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 .
17 */
18
19 #include <memory>
20 #include <sal/config.h>
21 #include <tools/debug.hxx>
22 #include <tools/diagnose_ex.h>
23
24 #include <svx/rubydialog.hxx>
25 #include <sfx2/dispatch.hxx>
26 #include <sfx2/sfxsids.hrc>
27 #include <sfx2/viewfrm.hxx>
28 #include <sfx2/viewsh.hxx>
29 #include <svl/eitem.hxx>
30 #include <com/sun/star/frame/XController.hpp>
31 #include <com/sun/star/style/XStyle.hpp>
32 #include <com/sun/star/text/XRubySelection.hpp>
33 #include <com/sun/star/beans/PropertyValues.hpp>
34 #include <com/sun/star/beans/XPropertySet.hpp>
35 #include <com/sun/star/beans/XPropertySetInfo.hpp>
36 #include <com/sun/star/container/XNameContainer.hpp>
37 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
38 #include <com/sun/star/text/RubyAdjust.hpp>
39 #include <com/sun/star/view/XSelectionChangeListener.hpp>
40 #include <com/sun/star/view/XSelectionSupplier.hpp>
41 #include <cppuhelper/implbase.hxx>
42 #include <svtools/colorcfg.hxx>
43 #include <vcl/event.hxx>
44 #include <vcl/settings.hxx>
45 #include <vcl/svapp.hxx>
46
47 using namespace css::uno;
48 using namespace css::frame;
49 using namespace css::text;
50 using namespace css::beans;
51 using namespace css::style;
52 using namespace css::view;
53 using namespace css::lang;
54 using namespace css::container;
55
56 SFX_IMPL_CHILDWINDOW(SvxRubyChildWindow, SID_RUBY_DIALOG);
57
58 namespace
59 {
60 constexpr OUStringLiteral cRubyBaseText = u"RubyBaseText";
61 constexpr OUStringLiteral cRubyText = u"RubyText";
62 constexpr OUStringLiteral cRubyAdjust = u"RubyAdjust";
63 constexpr OUStringLiteral cRubyPosition = u"RubyPosition";
64 constexpr OUStringLiteral cRubyCharStyleName = u"RubyCharStyleName";
65
66 } // end anonymous namespace
67
SvxRubyChildWindow(vcl::Window * _pParent,sal_uInt16 nId,SfxBindings * pBindings,SfxChildWinInfo const * pInfo)68 SvxRubyChildWindow::SvxRubyChildWindow(vcl::Window* _pParent, sal_uInt16 nId,
69 SfxBindings* pBindings, SfxChildWinInfo const* pInfo)
70 : SfxChildWindow(_pParent, nId)
71 {
72 auto xDlg = std::make_shared<SvxRubyDialog>(pBindings, this, _pParent->GetFrameWeld());
73 SetController(xDlg);
74 xDlg->Initialize(pInfo);
75 }
76
GetInfo() const77 SfxChildWinInfo SvxRubyChildWindow::GetInfo() const { return SfxChildWindow::GetInfo(); }
78
79 class SvxRubyData_Impl : public cppu::WeakImplHelper<css::view::XSelectionChangeListener>
80 {
81 Reference<XModel> xModel;
82 Reference<XRubySelection> xSelection;
83 Sequence<PropertyValues> aRubyValues;
84 Reference<XController> xController;
85 bool bHasSelectionChanged;
86
87 public:
88 SvxRubyData_Impl();
89 virtual ~SvxRubyData_Impl() override;
90
91 void SetController(const Reference<XController>& xCtrl);
GetModel()92 Reference<XModel> const& GetModel()
93 {
94 if (!xController.is())
95 xModel = nullptr;
96 else
97 xModel = xController->getModel();
98 return xModel;
99 }
HasSelectionChanged() const100 bool HasSelectionChanged() const { return bHasSelectionChanged; }
GetRubySelection()101 Reference<XRubySelection> const& GetRubySelection()
102 {
103 xSelection.set(xController, UNO_QUERY);
104 return xSelection;
105 }
UpdateRubyValues()106 void UpdateRubyValues()
107 {
108 if (!xSelection.is())
109 aRubyValues.realloc(0);
110 else
111 aRubyValues = xSelection->getRubyList(false);
112 bHasSelectionChanged = false;
113 }
GetRubyValues()114 Sequence<PropertyValues>& GetRubyValues() { return aRubyValues; }
115 void AssertOneEntry();
116
117 virtual void SAL_CALL selectionChanged(const css::lang::EventObject& aEvent) override;
118 virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;
119 };
120
SvxRubyData_Impl()121 SvxRubyData_Impl::SvxRubyData_Impl()
122 : bHasSelectionChanged(false)
123 {
124 }
125
~SvxRubyData_Impl()126 SvxRubyData_Impl::~SvxRubyData_Impl() {}
127
SetController(const Reference<XController> & xCtrl)128 void SvxRubyData_Impl::SetController(const Reference<XController>& xCtrl)
129 {
130 if (xCtrl.get() == xController.get())
131 return;
132
133 try
134 {
135 Reference<XSelectionSupplier> xSelSupp(xController, UNO_QUERY);
136 if (xSelSupp.is())
137 xSelSupp->removeSelectionChangeListener(this);
138
139 bHasSelectionChanged = true;
140 xController = xCtrl;
141 xSelSupp.set(xController, UNO_QUERY);
142 if (xSelSupp.is())
143 xSelSupp->addSelectionChangeListener(this);
144 }
145 catch (const Exception&)
146 {
147 }
148 }
149
selectionChanged(const EventObject &)150 void SvxRubyData_Impl::selectionChanged(const EventObject&) { bHasSelectionChanged = true; }
151
disposing(const EventObject &)152 void SvxRubyData_Impl::disposing(const EventObject&)
153 {
154 try
155 {
156 Reference<XSelectionSupplier> xSelSupp(xController, UNO_QUERY);
157 if (xSelSupp.is())
158 xSelSupp->removeSelectionChangeListener(this);
159 }
160 catch (const Exception&)
161 {
162 }
163 xController = nullptr;
164 }
165
AssertOneEntry()166 void SvxRubyData_Impl::AssertOneEntry()
167 {
168 //create one entry
169 if (!aRubyValues.hasElements())
170 {
171 aRubyValues.realloc(1);
172 Sequence<PropertyValue>& rValues = aRubyValues.getArray()[0];
173 rValues.realloc(5);
174 PropertyValue* pValues = rValues.getArray();
175 pValues[0].Name = cRubyBaseText;
176 pValues[1].Name = cRubyText;
177 pValues[2].Name = cRubyAdjust;
178 pValues[3].Name = cRubyPosition;
179 pValues[4].Name = cRubyCharStyleName;
180 }
181 }
182
SvxRubyDialog(SfxBindings * pBind,SfxChildWindow * pCW,weld::Window * pParent)183 SvxRubyDialog::SvxRubyDialog(SfxBindings* pBind, SfxChildWindow* pCW, weld::Window* pParent)
184 : SfxModelessDialogController(pBind, pCW, pParent, "svx/ui/asianphoneticguidedialog.ui",
185 "AsianPhoneticGuideDialog")
186 , nLastPos(0)
187 , nCurrentEdit(0)
188 , bModified(false)
189 , pBindings(pBind)
190 , m_pImpl(new SvxRubyData_Impl)
191 , m_xLeftFT(m_xBuilder->weld_label("basetextft"))
192 , m_xRightFT(m_xBuilder->weld_label("rubytextft"))
193 , m_xLeft1ED(m_xBuilder->weld_entry("Left1ED"))
194 , m_xRight1ED(m_xBuilder->weld_entry("Right1ED"))
195 , m_xLeft2ED(m_xBuilder->weld_entry("Left2ED"))
196 , m_xRight2ED(m_xBuilder->weld_entry("Right2ED"))
197 , m_xLeft3ED(m_xBuilder->weld_entry("Left3ED"))
198 , m_xRight3ED(m_xBuilder->weld_entry("Right3ED"))
199 , m_xLeft4ED(m_xBuilder->weld_entry("Left4ED"))
200 , m_xRight4ED(m_xBuilder->weld_entry("Right4ED"))
201 , m_xScrolledWindow(m_xBuilder->weld_scrolled_window("scrolledwindow", true))
202 , m_xAdjustLB(m_xBuilder->weld_combo_box("adjustlb"))
203 , m_xPositionLB(m_xBuilder->weld_combo_box("positionlb"))
204 , m_xCharStyleFT(m_xBuilder->weld_label("styleft"))
205 , m_xCharStyleLB(m_xBuilder->weld_combo_box("stylelb"))
206 , m_xStylistPB(m_xBuilder->weld_button("styles"))
207 , m_xApplyPB(m_xBuilder->weld_button("ok"))
208 , m_xClosePB(m_xBuilder->weld_button("close"))
209 , m_xContentArea(m_xDialog->weld_content_area())
210 , m_xGrid(m_xBuilder->weld_widget("grid"))
211 , m_xPreviewWin(new RubyPreview)
212 , m_xPreview(new weld::CustomWeld(*m_xBuilder, "preview", *m_xPreviewWin))
213 {
214 m_xCharStyleLB->make_sorted();
215 m_xPreviewWin->setRubyDialog(this);
216 m_xScrolledWindow->set_size_request(-1, m_xGrid->get_preferred_size().Height());
217 m_xScrolledWindow->set_vpolicy(VclPolicyType::NEVER);
218
219 aEditArr[0] = m_xLeft1ED.get();
220 aEditArr[1] = m_xRight1ED.get();
221 aEditArr[2] = m_xLeft2ED.get();
222 aEditArr[3] = m_xRight2ED.get();
223 aEditArr[4] = m_xLeft3ED.get();
224 aEditArr[5] = m_xRight3ED.get();
225 aEditArr[6] = m_xLeft4ED.get();
226 aEditArr[7] = m_xRight4ED.get();
227
228 m_xApplyPB->connect_clicked(LINK(this, SvxRubyDialog, ApplyHdl_Impl));
229 m_xClosePB->connect_clicked(LINK(this, SvxRubyDialog, CloseHdl_Impl));
230 m_xStylistPB->connect_clicked(LINK(this, SvxRubyDialog, StylistHdl_Impl));
231 m_xAdjustLB->connect_changed(LINK(this, SvxRubyDialog, AdjustHdl_Impl));
232 m_xPositionLB->connect_changed(LINK(this, SvxRubyDialog, PositionHdl_Impl));
233 m_xCharStyleLB->connect_changed(LINK(this, SvxRubyDialog, CharStyleHdl_Impl));
234
235 Link<weld::ScrolledWindow&, void> aScrLk(LINK(this, SvxRubyDialog, ScrollHdl_Impl));
236 m_xScrolledWindow->connect_vadjustment_changed(aScrLk);
237
238 Link<weld::Entry&, void> aEditLk(LINK(this, SvxRubyDialog, EditModifyHdl_Impl));
239 Link<weld::Widget&, void> aFocusLk(LINK(this, SvxRubyDialog, EditFocusHdl_Impl));
240 Link<const KeyEvent&, bool> aKeyUpDownLk(LINK(this, SvxRubyDialog, KeyUpDownHdl_Impl));
241 Link<const KeyEvent&, bool> aKeyTabUpDownLk(LINK(this, SvxRubyDialog, KeyUpDownTabHdl_Impl));
242 for (sal_uInt16 i = 0; i < 8; i++)
243 {
244 aEditArr[i]->connect_changed(aEditLk);
245 aEditArr[i]->connect_focus_in(aFocusLk);
246 if (!i || 7 == i)
247 aEditArr[i]->connect_key_press(aKeyTabUpDownLk);
248 else
249 aEditArr[i]->connect_key_press(aKeyUpDownLk);
250 }
251 }
252
~SvxRubyDialog()253 SvxRubyDialog::~SvxRubyDialog()
254 {
255 ClearCharStyleList();
256 EventObject aEvent;
257 m_pImpl->disposing(aEvent);
258 }
259
ClearCharStyleList()260 void SvxRubyDialog::ClearCharStyleList() { m_xCharStyleLB->clear(); }
261
Close()262 void SvxRubyDialog::Close()
263 {
264 if (IsClosing())
265 return;
266 SfxViewFrame* pViewFrame = SfxViewFrame::Current();
267 if (pViewFrame)
268 pViewFrame->ToggleChildWindow(SID_RUBY_DIALOG);
269 }
270
Activate()271 void SvxRubyDialog::Activate()
272 {
273 SfxModelessDialogController::Activate();
274 if (!m_xContentArea)
275 {
276 // tdf#141967 if Activate is called during tear down bail early
277 return;
278 }
279 //get selection from current view frame
280 SfxViewFrame* pCurFrm = SfxViewFrame::Current();
281 Reference<XController> xCtrl = pCurFrm->GetFrame().GetController();
282 m_pImpl->SetController(xCtrl);
283 if (!m_pImpl->HasSelectionChanged())
284 return;
285
286 Reference<XRubySelection> xRubySel = m_pImpl->GetRubySelection();
287 m_pImpl->UpdateRubyValues();
288 EnableControls(xRubySel.is());
289 if (xRubySel.is())
290 {
291 Reference<XModel> xModel = m_pImpl->GetModel();
292 const OUString sCharStyleSelect = m_xCharStyleLB->get_active_text();
293 ClearCharStyleList();
294 Reference<XStyleFamiliesSupplier> xSupplier(xModel, UNO_QUERY);
295 if (xSupplier.is())
296 {
297 try
298 {
299 Reference<XNameAccess> xFam = xSupplier->getStyleFamilies();
300 Any aChar = xFam->getByName("CharacterStyles");
301 Reference<XNameContainer> xChar;
302 aChar >>= xChar;
303 Reference<XIndexAccess> xCharIdx(xChar, UNO_QUERY);
304 if (xCharIdx.is())
305 {
306 OUString sUIName("DisplayName");
307 for (sal_Int32 nStyle = 0; nStyle < xCharIdx->getCount(); nStyle++)
308 {
309 Any aStyle = xCharIdx->getByIndex(nStyle);
310 Reference<XStyle> xStyle;
311 aStyle >>= xStyle;
312 Reference<XPropertySet> xPrSet(xStyle, UNO_QUERY);
313 OUString sName, sCoreName;
314 if (xPrSet.is())
315 {
316 Reference<XPropertySetInfo> xInfo = xPrSet->getPropertySetInfo();
317 if (xInfo->hasPropertyByName(sUIName))
318 {
319 Any aName = xPrSet->getPropertyValue(sUIName);
320 aName >>= sName;
321 }
322 }
323 if (xStyle.is())
324 {
325 sCoreName = xStyle->getName();
326 if (sName.isEmpty())
327 sName = sCoreName;
328 }
329 if (!sName.isEmpty())
330 {
331 m_xCharStyleLB->append(sCoreName, sName);
332 }
333 }
334 }
335 }
336 catch (const Exception&)
337 {
338 TOOLS_WARN_EXCEPTION("svx.dialog", "exception in style access");
339 }
340 if (!sCharStyleSelect.isEmpty())
341 m_xCharStyleLB->set_active_text(sCharStyleSelect);
342 }
343 m_xCharStyleLB->set_sensitive(xSupplier.is());
344 m_xCharStyleFT->set_sensitive(xSupplier.is());
345 }
346 Update();
347 m_xPreviewWin->Invalidate();
348 }
349
SetRubyText(sal_Int32 nPos,weld::Entry & rLeft,weld::Entry & rRight)350 void SvxRubyDialog::SetRubyText(sal_Int32 nPos, weld::Entry& rLeft, weld::Entry& rRight)
351 {
352 OUString sLeft, sRight;
353 const Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
354 bool bEnable = aRubyValues.getLength() > nPos;
355 if (bEnable)
356 {
357 const Sequence<PropertyValue> aProps = aRubyValues.getConstArray()[nPos];
358 for (const PropertyValue& rProp : aProps)
359 {
360 if (rProp.Name == cRubyBaseText)
361 rProp.Value >>= sLeft;
362 else if (rProp.Name == cRubyText)
363 rProp.Value >>= sRight;
364 }
365 }
366 else if (!nPos)
367 {
368 bEnable = true;
369 }
370 rLeft.set_sensitive(bEnable);
371 rRight.set_sensitive(bEnable);
372 rLeft.set_text(sLeft);
373 rRight.set_text(sRight);
374 rLeft.save_value();
375 rRight.save_value();
376 }
377
GetRubyText()378 void SvxRubyDialog::GetRubyText()
379 {
380 tools::Long nTempLastPos = GetLastPos();
381 for (int i = 0; i < 8; i += 2)
382 {
383 if (aEditArr[i]->get_sensitive()
384 && (aEditArr[i]->get_value_changed_from_saved()
385 || aEditArr[i + 1]->get_value_changed_from_saved()))
386 {
387 Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
388 DBG_ASSERT(aRubyValues.getLength() > (i / 2 + nTempLastPos), "wrong index");
389 SetModified(true);
390 Sequence<PropertyValue>& rProps = aRubyValues.getArray()[i / 2 + nTempLastPos];
391 for (PropertyValue& propVal : rProps)
392 {
393 if (propVal.Name == cRubyBaseText)
394 propVal.Value <<= aEditArr[i]->get_text();
395 else if (propVal.Name == cRubyText)
396 propVal.Value <<= aEditArr[i + 1]->get_text();
397 }
398 }
399 }
400 }
401
Update()402 void SvxRubyDialog::Update()
403 {
404 const Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
405 sal_Int32 nLen = aRubyValues.getLength();
406 m_xScrolledWindow->vadjustment_configure(0, 0, !nLen ? 1 : nLen, 1, 4, 4);
407 if (nLen > 4)
408 m_xScrolledWindow->set_vpolicy(VclPolicyType::ALWAYS);
409 else
410 m_xScrolledWindow->set_vpolicy(VclPolicyType::NEVER);
411 SetLastPos(0);
412 SetModified(false);
413
414 sal_Int16 nAdjust = -1;
415 sal_Int16 nPosition = -1;
416 OUString sCharStyleName, sTmp;
417 bool bCharStyleEqual = true;
418 for (sal_Int32 nRuby = 0; nRuby < nLen; nRuby++)
419 {
420 const Sequence<PropertyValue>& rProps = aRubyValues.getConstArray()[nRuby];
421 for (const PropertyValue& rProp : rProps)
422 {
423 if (nAdjust > -2 && rProp.Name == cRubyAdjust)
424 {
425 sal_Int16 nTmp = sal_Int16();
426 rProp.Value >>= nTmp;
427 if (!nRuby)
428 nAdjust = nTmp;
429 else if (nAdjust != nTmp)
430 nAdjust = -2;
431 }
432 if (nPosition > -2 && rProp.Name == cRubyPosition)
433 {
434 sal_Int16 nTmp = sal_Int16();
435 rProp.Value >>= nTmp;
436 if (!nRuby)
437 nPosition = nTmp;
438 else if (nPosition != nTmp)
439 nPosition = -2;
440 }
441 if (bCharStyleEqual && rProp.Name == cRubyCharStyleName)
442 {
443 rProp.Value >>= sTmp;
444 if (!nRuby)
445 sCharStyleName = sTmp;
446 else if (sCharStyleName != sTmp)
447 bCharStyleEqual = false;
448 }
449 }
450 }
451 if (!nLen)
452 {
453 //enable selection if the ruby list is empty
454 nAdjust = 0;
455 nPosition = 0;
456 }
457 if (nAdjust > -1)
458 m_xAdjustLB->set_active(nAdjust);
459 else
460 m_xAdjustLB->set_active(-1);
461 if (nPosition > -1)
462 m_xPositionLB->set_active(nPosition);
463 if (!nLen || (bCharStyleEqual && sCharStyleName.isEmpty()))
464 sCharStyleName = "Rubies";
465 if (!sCharStyleName.isEmpty())
466 {
467 for (int i = 0, nEntryCount = m_xCharStyleLB->get_count(); i < nEntryCount; i++)
468 {
469 OUString sCoreName = m_xCharStyleLB->get_id(i);
470 if (sCharStyleName == sCoreName)
471 {
472 m_xCharStyleLB->set_active(i);
473 break;
474 }
475 }
476 }
477 else
478 m_xCharStyleLB->set_active(-1);
479
480 ScrollHdl_Impl(*m_xScrolledWindow);
481 }
482
GetCurrentText(OUString & rBase,OUString & rRuby)483 void SvxRubyDialog::GetCurrentText(OUString& rBase, OUString& rRuby)
484 {
485 rBase = aEditArr[nCurrentEdit * 2]->get_text();
486 rRuby = aEditArr[nCurrentEdit * 2 + 1]->get_text();
487 }
488
IMPL_LINK(SvxRubyDialog,ScrollHdl_Impl,weld::ScrolledWindow &,rScroll,void)489 IMPL_LINK(SvxRubyDialog, ScrollHdl_Impl, weld::ScrolledWindow&, rScroll, void)
490 {
491 int nPos = rScroll.vadjustment_get_value();
492 if (GetLastPos() != nPos)
493 {
494 GetRubyText();
495 }
496 SetRubyText(nPos++, *m_xLeft1ED, *m_xRight1ED);
497 SetRubyText(nPos++, *m_xLeft2ED, *m_xRight2ED);
498 SetRubyText(nPos++, *m_xLeft3ED, *m_xRight3ED);
499 SetRubyText(nPos, *m_xLeft4ED, *m_xRight4ED);
500 SetLastPos(nPos - 3);
501 m_xPreviewWin->Invalidate();
502 }
503
IMPL_LINK_NOARG(SvxRubyDialog,ApplyHdl_Impl,weld::Button &,void)504 IMPL_LINK_NOARG(SvxRubyDialog, ApplyHdl_Impl, weld::Button&, void)
505 {
506 const Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
507 if (!aRubyValues.hasElements())
508 {
509 AssertOneEntry();
510 PositionHdl_Impl(*m_xPositionLB);
511 AdjustHdl_Impl(*m_xAdjustLB);
512 CharStyleHdl_Impl(*m_xCharStyleLB);
513 }
514 GetRubyText();
515 //reset all edit fields - SaveValue is called
516 ScrollHdl_Impl(*m_xScrolledWindow);
517
518 Reference<XRubySelection> xSelection = m_pImpl->GetRubySelection();
519 if (IsModified() && xSelection.is())
520 {
521 try
522 {
523 xSelection->setRubyList(aRubyValues, false);
524 }
525 catch (const Exception&)
526 {
527 TOOLS_WARN_EXCEPTION("svx.dialog", "");
528 }
529 }
530 }
531
IMPL_LINK_NOARG(SvxRubyDialog,CloseHdl_Impl,weld::Button &,void)532 IMPL_LINK_NOARG(SvxRubyDialog, CloseHdl_Impl, weld::Button&, void) { Close(); }
533
IMPL_LINK_NOARG(SvxRubyDialog,StylistHdl_Impl,weld::Button &,void)534 IMPL_LINK_NOARG(SvxRubyDialog, StylistHdl_Impl, weld::Button&, void)
535 {
536 std::unique_ptr<SfxPoolItem> pState;
537 SfxItemState eState = pBindings->QueryState(SID_STYLE_DESIGNER, pState);
538 if (eState <= SfxItemState::SET || !pState
539 || !static_cast<SfxBoolItem*>(pState.get())->GetValue())
540 {
541 pBindings->GetDispatcher()->Execute(SID_STYLE_DESIGNER,
542 SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
543 }
544 }
545
IMPL_LINK(SvxRubyDialog,AdjustHdl_Impl,weld::ComboBox &,rBox,void)546 IMPL_LINK(SvxRubyDialog, AdjustHdl_Impl, weld::ComboBox&, rBox, void)
547 {
548 AssertOneEntry();
549 sal_Int16 nAdjust = rBox.get_active();
550 Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
551 for (PropertyValues& rProps : aRubyValues)
552 {
553 for (PropertyValue& propVal : rProps)
554 {
555 if (propVal.Name == cRubyAdjust)
556 propVal.Value <<= nAdjust;
557 }
558 SetModified(true);
559 }
560 m_xPreviewWin->Invalidate();
561 }
562
IMPL_LINK(SvxRubyDialog,PositionHdl_Impl,weld::ComboBox &,rBox,void)563 IMPL_LINK(SvxRubyDialog, PositionHdl_Impl, weld::ComboBox&, rBox, void)
564 {
565 AssertOneEntry();
566 sal_Int16 nPosition = rBox.get_active();
567 Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
568 for (PropertyValues& rProps : aRubyValues)
569 {
570 for (PropertyValue& propVal : rProps)
571 {
572 if (propVal.Name == cRubyPosition)
573 propVal.Value <<= nPosition;
574 }
575 SetModified(true);
576 }
577 m_xPreviewWin->Invalidate();
578 }
579
IMPL_LINK_NOARG(SvxRubyDialog,CharStyleHdl_Impl,weld::ComboBox &,void)580 IMPL_LINK_NOARG(SvxRubyDialog, CharStyleHdl_Impl, weld::ComboBox&, void)
581 {
582 AssertOneEntry();
583 OUString sStyleName;
584 if (m_xCharStyleLB->get_active() != -1)
585 sStyleName = m_xCharStyleLB->get_active_id();
586 Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
587 for (PropertyValues& rProps : aRubyValues)
588 {
589 for (PropertyValue& propVal : rProps)
590 {
591 if (propVal.Name == cRubyCharStyleName)
592 {
593 propVal.Value <<= sStyleName;
594 }
595 }
596 SetModified(true);
597 }
598 }
599
IMPL_LINK(SvxRubyDialog,EditFocusHdl_Impl,weld::Widget &,rEdit,void)600 IMPL_LINK(SvxRubyDialog, EditFocusHdl_Impl, weld::Widget&, rEdit, void)
601 {
602 for (sal_uInt16 i = 0; i < 8; i++)
603 {
604 if (&rEdit == aEditArr[i])
605 {
606 nCurrentEdit = i / 2;
607 break;
608 }
609 }
610 m_xPreviewWin->Invalidate();
611 }
612
IMPL_LINK(SvxRubyDialog,EditModifyHdl_Impl,weld::Entry &,rEdit,void)613 IMPL_LINK(SvxRubyDialog, EditModifyHdl_Impl, weld::Entry&, rEdit, void)
614 {
615 EditFocusHdl_Impl(rEdit);
616 }
617
EditScrollHdl_Impl(sal_Int32 nParam)618 bool SvxRubyDialog::EditScrollHdl_Impl(sal_Int32 nParam)
619 {
620 bool bRet = false;
621 //scroll forward
622 if (nParam > 0 && (aEditArr[7]->has_focus() || aEditArr[6]->has_focus()))
623 {
624 if (m_xScrolledWindow->vadjustment_get_upper()
625 > m_xScrolledWindow->vadjustment_get_value()
626 + m_xScrolledWindow->vadjustment_get_page_size())
627 {
628 m_xScrolledWindow->vadjustment_set_value(m_xScrolledWindow->vadjustment_get_value()
629 + 1);
630 aEditArr[6]->grab_focus();
631 bRet = true;
632 }
633 }
634 //scroll backward
635 else if (m_xScrolledWindow->vadjustment_get_value()
636 && (aEditArr[0]->has_focus() || aEditArr[1]->has_focus()))
637 {
638 m_xScrolledWindow->vadjustment_set_value(m_xScrolledWindow->vadjustment_get_value() - 1);
639 aEditArr[1]->grab_focus();
640 bRet = true;
641 }
642 if (bRet)
643 ScrollHdl_Impl(*m_xScrolledWindow);
644 return bRet;
645 }
646
EditJumpHdl_Impl(sal_Int32 nParam)647 bool SvxRubyDialog::EditJumpHdl_Impl(sal_Int32 nParam)
648 {
649 bool bHandled = false;
650 sal_uInt16 nIndex = USHRT_MAX;
651 for (sal_uInt16 i = 0; i < 8; i++)
652 {
653 if (aEditArr[i]->has_focus())
654 nIndex = i;
655 }
656 if (nIndex < 8)
657 {
658 if (nParam > 0)
659 {
660 if (nIndex < 6)
661 aEditArr[nIndex + 2]->grab_focus();
662 else if (EditScrollHdl_Impl(nParam))
663 aEditArr[nIndex]->grab_focus();
664 }
665 else
666 {
667 if (nIndex > 1)
668 aEditArr[nIndex - 2]->grab_focus();
669 else if (EditScrollHdl_Impl(nParam))
670 aEditArr[nIndex]->grab_focus();
671 }
672 bHandled = true;
673 }
674 return bHandled;
675 }
676
AssertOneEntry()677 void SvxRubyDialog::AssertOneEntry() { m_pImpl->AssertOneEntry(); }
678
EnableControls(bool bEnable)679 void SvxRubyDialog::EnableControls(bool bEnable)
680 {
681 m_xContentArea->set_sensitive(bEnable);
682 m_xApplyPB->set_sensitive(bEnable);
683 }
684
RubyPreview()685 RubyPreview::RubyPreview()
686 : m_pParentDlg(nullptr)
687 {
688 }
689
~RubyPreview()690 RubyPreview::~RubyPreview() {}
691
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle &)692 void RubyPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/)
693 {
694 rRenderContext.Push(PushFlags::ALL);
695
696 rRenderContext.SetMapMode(MapMode(MapUnit::MapTwip));
697
698 Size aWinSize = rRenderContext.GetOutputSize();
699
700 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
701 svtools::ColorConfig aColorConfig;
702
703 Color aNewTextColor(aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor);
704 Color aNewFillColor(rStyleSettings.GetWindowColor());
705
706 vcl::Font aFont = rRenderContext.GetFont();
707 aFont.SetFontHeight(aWinSize.Height() / 4);
708 aFont.SetFillColor(aNewFillColor);
709 aFont.SetColor(aNewTextColor);
710 rRenderContext.SetFont(aFont);
711
712 tools::Rectangle aRect(Point(0, 0), aWinSize);
713 rRenderContext.SetLineColor();
714 rRenderContext.SetFillColor(aFont.GetFillColor());
715 rRenderContext.DrawRect(aRect);
716
717 OUString sBaseText, sRubyText;
718 m_pParentDlg->GetCurrentText(sBaseText, sRubyText);
719
720 tools::Long nTextHeight = rRenderContext.GetTextHeight();
721 tools::Long nBaseWidth = rRenderContext.GetTextWidth(sBaseText);
722
723 vcl::Font aRubyFont(aFont);
724 aRubyFont.SetFontHeight(aRubyFont.GetFontHeight() * 70 / 100);
725 rRenderContext.SetFont(aRubyFont);
726 tools::Long nRubyWidth = rRenderContext.GetTextWidth(sRubyText);
727 rRenderContext.SetFont(aFont);
728
729 RubyAdjust nAdjust = static_cast<RubyAdjust>(m_pParentDlg->m_xAdjustLB->get_active());
730 //use center if no adjustment is available
731 if (nAdjust > RubyAdjust_INDENT_BLOCK)
732 nAdjust = RubyAdjust_CENTER;
733
734 //which part is stretched ?
735 bool bRubyStretch = nBaseWidth >= nRubyWidth;
736
737 tools::Long nCenter = aWinSize.Width() / 2;
738 tools::Long nHalfWidth = std::max(nBaseWidth, nRubyWidth) / 2;
739 tools::Long nLeftStart = nCenter - nHalfWidth;
740 tools::Long nRightEnd = nCenter + nHalfWidth;
741
742 // Default values for TOP or no selection
743 tools::Long nYRuby = aWinSize.Height() / 4 - nTextHeight / 2;
744 tools::Long nYBase = aWinSize.Height() * 3 / 4 - nTextHeight / 2;
745
746 sal_Int16 nRubyPos = m_pParentDlg->m_xPositionLB->get_active();
747 if (nRubyPos == 1) // BOTTOM
748 {
749 tools::Long nTmp = nYRuby;
750 nYRuby = nYBase;
751 nYBase = nTmp;
752 }
753 else if (nRubyPos == 2) // RIGHT ( vertically )
754 {
755 // Align the ruby text and base text to the vertical center.
756 nYBase = (aWinSize.Height() - nTextHeight) / 2;
757 nYRuby = (aWinSize.Height() - nRubyWidth) / 2;
758
759 // Align the ruby text at the right side of the base text
760 nAdjust = RubyAdjust_RIGHT;
761 nHalfWidth = nBaseWidth / 2;
762 nLeftStart = nCenter - nHalfWidth;
763 nRightEnd = nCenter + nHalfWidth + nRubyWidth + nTextHeight;
764 // Render base text first, then render ruby text on the right.
765 bRubyStretch = true;
766
767 aRubyFont.SetVertical(true);
768 aRubyFont.SetOrientation(2700_deg10);
769 }
770
771 tools::Long nYOutput;
772 tools::Long nOutTextWidth;
773 OUString sOutputText;
774
775 if (bRubyStretch)
776 {
777 rRenderContext.DrawText(Point(nLeftStart, nYBase), sBaseText);
778 nYOutput = nYRuby;
779 sOutputText = sRubyText;
780 nOutTextWidth = nRubyWidth;
781 rRenderContext.SetFont(aRubyFont);
782 }
783 else
784 {
785 rRenderContext.SetFont(aRubyFont);
786 rRenderContext.DrawText(Point(nLeftStart, nYRuby), sRubyText);
787 nYOutput = nYBase;
788 sOutputText = sBaseText;
789 nOutTextWidth = nBaseWidth;
790 rRenderContext.SetFont(aFont);
791 }
792
793 switch (nAdjust)
794 {
795 case RubyAdjust_LEFT:
796 rRenderContext.DrawText(Point(nLeftStart, nYOutput), sOutputText);
797 break;
798 case RubyAdjust_RIGHT:
799 rRenderContext.DrawText(Point(nRightEnd - nOutTextWidth, nYOutput), sOutputText);
800 break;
801 case RubyAdjust_INDENT_BLOCK:
802 {
803 tools::Long nCharWidth = rRenderContext.GetTextWidth("X");
804 if (nOutTextWidth < (nRightEnd - nLeftStart - nCharWidth))
805 {
806 nCharWidth /= 2;
807 nLeftStart += nCharWidth;
808 nRightEnd -= nCharWidth;
809 }
810 [[fallthrough]];
811 }
812 case RubyAdjust_BLOCK:
813 {
814 if (sOutputText.getLength() > 1)
815 {
816 sal_Int32 nCount = sOutputText.getLength();
817 tools::Long nSpace
818 = ((nRightEnd - nLeftStart) - rRenderContext.GetTextWidth(sOutputText))
819 / (nCount - 1);
820 for (sal_Int32 i = 0; i < nCount; i++)
821 {
822 OUString sChar(sOutputText[i]);
823 rRenderContext.DrawText(Point(nLeftStart, nYOutput), sChar);
824 tools::Long nCharWidth = rRenderContext.GetTextWidth(sChar);
825 nLeftStart += nCharWidth + nSpace;
826 }
827 break;
828 }
829 [[fallthrough]];
830 }
831 case RubyAdjust_CENTER:
832 rRenderContext.DrawText(Point(nCenter - nOutTextWidth / 2, nYOutput), sOutputText);
833 break;
834 default:
835 break;
836 }
837 rRenderContext.Pop();
838 }
839
SetDrawingArea(weld::DrawingArea * pDrawingArea)840 void RubyPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
841 {
842 pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 40,
843 pDrawingArea->get_text_height() * 7);
844 CustomWidgetController::SetDrawingArea(pDrawingArea);
845 }
846
IMPL_LINK(SvxRubyDialog,KeyUpDownHdl_Impl,const KeyEvent &,rKEvt,bool)847 IMPL_LINK(SvxRubyDialog, KeyUpDownHdl_Impl, const KeyEvent&, rKEvt, bool)
848 {
849 bool bHandled = false;
850 const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
851 sal_uInt16 nCode = rKeyCode.GetCode();
852 if (KEY_UP == nCode || KEY_DOWN == nCode)
853 {
854 sal_Int32 nParam = KEY_UP == nCode ? -1 : 1;
855 bHandled = EditJumpHdl_Impl(nParam);
856 }
857 return bHandled;
858 }
859
IMPL_LINK(SvxRubyDialog,KeyUpDownTabHdl_Impl,const KeyEvent &,rKEvt,bool)860 IMPL_LINK(SvxRubyDialog, KeyUpDownTabHdl_Impl, const KeyEvent&, rKEvt, bool)
861 {
862 bool bHandled = false;
863 const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
864 sal_uInt16 nMod = rKeyCode.GetModifier();
865 sal_uInt16 nCode = rKeyCode.GetCode();
866 if (nCode == KEY_TAB && (!nMod || KEY_SHIFT == nMod))
867 {
868 sal_Int32 nParam = KEY_SHIFT == nMod ? -1 : 1;
869 if (EditScrollHdl_Impl(nParam))
870 bHandled = true;
871 }
872 if (!bHandled)
873 bHandled = KeyUpDownHdl_Impl(rKEvt);
874 return bHandled;
875 }
876
877 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
878