/src/libreoffice/svx/source/dialog/rubydialog.cxx
Line | Count | Source (jump to first uncovered line) |
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 <comphelper/diagnose_ex.hxx> |
23 | | #include <comphelper/processfactory.hxx> |
24 | | |
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> |
51 | | |
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; |
60 | | |
61 | | SFX_IMPL_CHILDWINDOW(SvxRubyChildWindow, SID_RUBY_DIALOG); |
62 | | |
63 | | namespace |
64 | | { |
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; |
70 | | |
71 | | } // end anonymous namespace |
72 | | |
73 | | SvxRubyChildWindow::SvxRubyChildWindow(vcl::Window* _pParent, sal_uInt16 nId, |
74 | | SfxBindings* pBindings, SfxChildWinInfo const* pInfo) |
75 | 0 | : SfxChildWindow(_pParent, nId) |
76 | 0 | { |
77 | 0 | auto xDlg = std::make_shared<SvxRubyDialog>(pBindings, this, _pParent->GetFrameWeld()); |
78 | 0 | SetController(xDlg); |
79 | 0 | xDlg->Initialize(pInfo); |
80 | 0 | } |
81 | | |
82 | 0 | SfxChildWinInfo SvxRubyChildWindow::GetInfo() const { return SfxChildWindow::GetInfo(); } |
83 | | |
84 | | class SvxRubyData_Impl : public cppu::WeakImplHelper<css::view::XSelectionChangeListener> |
85 | | { |
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; |
92 | | bool bDisposing; |
93 | | |
94 | | public: |
95 | | SvxRubyData_Impl(); |
96 | | virtual ~SvxRubyData_Impl() override; |
97 | | |
98 | | void SetController(const Reference<XController>& xCtrl); |
99 | | Reference<XModel> const& GetModel() |
100 | 0 | { |
101 | 0 | if (!xController.is()) |
102 | 0 | xModel = nullptr; |
103 | 0 | else |
104 | 0 | xModel = xController->getModel(); |
105 | 0 | return xModel; |
106 | 0 | } |
107 | 0 | bool HasSelectionChanged() const { return bHasSelectionChanged; } |
108 | 0 | bool IsDisposing() const { return bDisposing; } |
109 | | Reference<XRubySelection> const& GetRubySelection() |
110 | 0 | { |
111 | 0 | xSelection.set(xController, UNO_QUERY); |
112 | 0 | return xSelection; |
113 | 0 | } |
114 | | void UpdateRubyValues() |
115 | 0 | { |
116 | 0 | if (!xSelection.is()) |
117 | 0 | aRubyValues.realloc(0); |
118 | 0 | else |
119 | 0 | aRubyValues = xSelection->getRubyList(false); |
120 | 0 | bHasSelectionChanged = false; |
121 | 0 | } |
122 | 0 | Sequence<PropertyValues>& GetRubyValues() { return aRubyValues; } |
123 | | void AssertOneEntry(); |
124 | | |
125 | | virtual void SAL_CALL selectionChanged(const css::lang::EventObject& aEvent) override; |
126 | | virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; |
127 | | |
128 | 0 | bool IsSelectionGrouped() { return aRubyValues.getLength() < 2; } |
129 | | |
130 | | void MakeSelectionGrouped() |
131 | 0 | { |
132 | 0 | if (aRubyValues.getLength() < 2) |
133 | 0 | { |
134 | 0 | return; |
135 | 0 | } |
136 | | |
137 | 0 | OUString sBaseTmp; |
138 | 0 | OUStringBuffer aBaseString; |
139 | 0 | for (const PropertyValues& rVals : aRubyValues) |
140 | 0 | { |
141 | 0 | sBaseTmp.clear(); |
142 | 0 | for (const PropertyValue& rVal : rVals) |
143 | 0 | { |
144 | 0 | if (rVal.Name == cRubyBaseText) |
145 | 0 | { |
146 | 0 | rVal.Value >>= sBaseTmp; |
147 | 0 | } |
148 | 0 | } |
149 | |
|
150 | 0 | aBaseString.append(sBaseTmp); |
151 | 0 | } |
152 | |
|
153 | 0 | Sequence<PropertyValues> aNewRubyValues{ 1 }; |
154 | 0 | PropertyValues* pNewRubyValues = aNewRubyValues.getArray(); |
155 | | |
156 | | // Copy some reasonable style values from the previous ruby array |
157 | 0 | pNewRubyValues[0] = aRubyValues[0]; |
158 | 0 | for (const PropertyValues& rVals : aRubyValues) |
159 | 0 | { |
160 | 0 | for (const PropertyValue& rVal : rVals) |
161 | 0 | { |
162 | 0 | if (rVal.Name == cRubyText) |
163 | 0 | { |
164 | 0 | rVal.Value >>= sBaseTmp; |
165 | 0 | if (!sBaseTmp.isEmpty()) |
166 | 0 | { |
167 | 0 | pNewRubyValues[0] = rVals; |
168 | 0 | break; |
169 | 0 | } |
170 | 0 | } |
171 | 0 | } |
172 | 0 | } |
173 | |
|
174 | 0 | PropertyValue* pNewValues = pNewRubyValues[0].getArray(); |
175 | 0 | for (sal_Int32 i = 0; i < pNewRubyValues[0].getLength(); ++i) |
176 | 0 | { |
177 | 0 | if (pNewValues[i].Name == cRubyBaseText) |
178 | 0 | { |
179 | 0 | sBaseTmp = aBaseString; |
180 | 0 | pNewValues[i].Value <<= sBaseTmp; |
181 | 0 | } |
182 | 0 | else if (pNewValues[i].Name == cRubyText) |
183 | 0 | { |
184 | 0 | sBaseTmp.clear(); |
185 | 0 | pNewValues[i].Value <<= sBaseTmp; |
186 | 0 | } |
187 | 0 | } |
188 | |
|
189 | 0 | aRubyValues = std::move(aNewRubyValues); |
190 | 0 | } |
191 | | |
192 | | bool IsSelectionMono() |
193 | 0 | { |
194 | 0 | if (!xBreak.is()) |
195 | 0 | { |
196 | | // Cannot continue if BreakIterator is not available |
197 | | // Disable the button |
198 | 0 | return true; |
199 | 0 | } |
200 | | |
201 | | // Locale does not matter in this case; default ICU BreakIterator is sufficient |
202 | 0 | Locale aLocale; |
203 | |
|
204 | 0 | OUString sBaseTmp; |
205 | 0 | return std::all_of( |
206 | 0 | aRubyValues.begin(), aRubyValues.end(), [&](const PropertyValues& rVals) { |
207 | 0 | return !std::any_of(rVals.begin(), rVals.end(), [&](const PropertyValue& rVal) { |
208 | 0 | if (rVal.Name == cRubyBaseText) |
209 | 0 | { |
210 | 0 | rVal.Value >>= sBaseTmp; |
211 | 0 | sal_Int32 nDone = 0; |
212 | 0 | auto nPos = xBreak->nextCharacters( |
213 | 0 | sBaseTmp, 0, aLocale, css::i18n::CharacterIteratorMode::SKIPCELL, 1, |
214 | 0 | nDone); |
215 | 0 | return nPos < sBaseTmp.getLength(); |
216 | 0 | } |
217 | | |
218 | 0 | return false; |
219 | 0 | }); |
220 | 0 | }); |
221 | 0 | } |
222 | | |
223 | | void MakeSelectionMono() |
224 | 0 | { |
225 | 0 | if (!xBreak.is()) |
226 | 0 | { |
227 | | // Cannot continue if BreakIterator is not available |
228 | 0 | return; |
229 | 0 | } |
230 | | |
231 | | // Locale does not matter in this case; default ICU BreakIterator is sufficient |
232 | 0 | Locale aLocale; |
233 | |
|
234 | 0 | OUString sBaseTmp; |
235 | | |
236 | | // Count the grapheme clusters |
237 | 0 | sal_Int32 nTotalGraphemeClusters = 0; |
238 | 0 | for (const PropertyValues& rVals : aRubyValues) |
239 | 0 | { |
240 | 0 | for (const PropertyValue& rVal : rVals) |
241 | 0 | { |
242 | 0 | if (rVal.Name == cRubyBaseText) |
243 | 0 | { |
244 | 0 | rVal.Value >>= sBaseTmp; |
245 | |
|
246 | 0 | sal_Int32 nPos = 0; |
247 | 0 | while (nPos < sBaseTmp.getLength()) |
248 | 0 | { |
249 | 0 | sal_Int32 nDone = 0; |
250 | 0 | nPos = xBreak->nextCharacters(sBaseTmp, nPos, aLocale, |
251 | 0 | css::i18n::CharacterIteratorMode::SKIPCELL, 1, |
252 | 0 | nDone); |
253 | 0 | ++nTotalGraphemeClusters; |
254 | 0 | } |
255 | 0 | } |
256 | 0 | } |
257 | 0 | } |
258 | | |
259 | | // Put each grapheme cluster in its own entry |
260 | 0 | Sequence<PropertyValues> aNewRubyValues{ nTotalGraphemeClusters }; |
261 | 0 | PropertyValues* pNewRubyValues = aNewRubyValues.getArray(); |
262 | |
|
263 | 0 | sal_Int32 nCurrGraphemeCluster = 0; |
264 | 0 | for (const PropertyValues& rVals : aRubyValues) |
265 | 0 | { |
266 | 0 | for (const PropertyValue& rVal : rVals) |
267 | 0 | { |
268 | 0 | if (rVal.Name == cRubyBaseText) |
269 | 0 | { |
270 | 0 | rVal.Value >>= sBaseTmp; |
271 | |
|
272 | 0 | sal_Int32 nPos = 0; |
273 | 0 | while (nPos < sBaseTmp.getLength()) |
274 | 0 | { |
275 | 0 | sal_Int32 nDone = 0; |
276 | 0 | auto nNextPos = xBreak->nextCharacters( |
277 | 0 | sBaseTmp, nPos, aLocale, css::i18n::CharacterIteratorMode::SKIPCELL, 1, |
278 | 0 | nDone); |
279 | |
|
280 | 0 | PropertyValues& rNewVals = pNewRubyValues[nCurrGraphemeCluster++]; |
281 | | |
282 | | // Initialize new property values with values from current run |
283 | 0 | rNewVals = rVals; |
284 | |
|
285 | 0 | PropertyValue* aNewVals = rNewVals.getArray(); |
286 | 0 | for (sal_Int32 i = 0; i < rNewVals.getLength(); ++i) |
287 | 0 | { |
288 | 0 | PropertyValue& rNewVal = aNewVals[i]; |
289 | |
|
290 | 0 | if (rNewVal.Name == cRubyText) |
291 | 0 | { |
292 | 0 | rNewVal.Value <<= OUString{}; |
293 | 0 | } |
294 | 0 | else if (rNewVal.Name == cRubyBaseText) |
295 | 0 | { |
296 | 0 | rNewVal.Value <<= sBaseTmp.copy(nPos, nNextPos - nPos); |
297 | 0 | } |
298 | 0 | } |
299 | |
|
300 | 0 | nPos = nNextPos; |
301 | 0 | } |
302 | 0 | } |
303 | 0 | } |
304 | 0 | } |
305 | |
|
306 | 0 | aRubyValues = std::move(aNewRubyValues); |
307 | 0 | } |
308 | | }; |
309 | | |
310 | | SvxRubyData_Impl::SvxRubyData_Impl() |
311 | 0 | : bHasSelectionChanged(false) |
312 | 0 | , bDisposing(false) |
313 | 0 | { |
314 | 0 | const Reference<XComponentContext>& xContext = ::comphelper::getProcessComponentContext(); |
315 | 0 | xBreak = css::i18n::BreakIterator::create(xContext); |
316 | 0 | } |
317 | | |
318 | 0 | SvxRubyData_Impl::~SvxRubyData_Impl() {} |
319 | | |
320 | | void SvxRubyData_Impl::SetController(const Reference<XController>& xCtrl) |
321 | 0 | { |
322 | 0 | if (xCtrl.get() == xController.get()) |
323 | 0 | return; |
324 | | |
325 | 0 | try |
326 | 0 | { |
327 | 0 | Reference<XSelectionSupplier> xSelSupp(xController, UNO_QUERY); |
328 | 0 | if (xSelSupp.is()) |
329 | 0 | xSelSupp->removeSelectionChangeListener(this); |
330 | |
|
331 | 0 | bHasSelectionChanged = true; |
332 | 0 | xController = xCtrl; |
333 | 0 | xSelSupp.set(xController, UNO_QUERY); |
334 | 0 | if (xSelSupp.is()) |
335 | 0 | xSelSupp->addSelectionChangeListener(this); |
336 | 0 | } |
337 | 0 | catch (const Exception&) |
338 | 0 | { |
339 | 0 | } |
340 | 0 | } |
341 | | |
342 | 0 | void SvxRubyData_Impl::selectionChanged(const EventObject&) { bHasSelectionChanged = true; } |
343 | | |
344 | | void SvxRubyData_Impl::disposing(const EventObject&) |
345 | 0 | { |
346 | 0 | try |
347 | 0 | { |
348 | 0 | Reference<XSelectionSupplier> xSelSupp(xController, UNO_QUERY); |
349 | 0 | if (xSelSupp.is()) |
350 | 0 | xSelSupp->removeSelectionChangeListener(this); |
351 | 0 | } |
352 | 0 | catch (const Exception&) |
353 | 0 | { |
354 | 0 | } |
355 | 0 | xController = nullptr; |
356 | 0 | bDisposing = true; |
357 | 0 | } |
358 | | |
359 | | void SvxRubyData_Impl::AssertOneEntry() |
360 | 0 | { |
361 | | //create one entry |
362 | 0 | if (!aRubyValues.hasElements()) |
363 | 0 | { |
364 | 0 | aRubyValues.realloc(1); |
365 | 0 | Sequence<PropertyValue>& rValues = aRubyValues.getArray()[0]; |
366 | 0 | rValues.realloc(5); |
367 | 0 | PropertyValue* pValues = rValues.getArray(); |
368 | 0 | pValues[0].Name = cRubyBaseText; |
369 | 0 | pValues[1].Name = cRubyText; |
370 | 0 | pValues[2].Name = cRubyAdjust; |
371 | 0 | pValues[3].Name = cRubyPosition; |
372 | 0 | pValues[4].Name = cRubyCharStyleName; |
373 | 0 | } |
374 | 0 | } |
375 | | |
376 | | SvxRubyDialog::SvxRubyDialog(SfxBindings* pBind, SfxChildWindow* pCW, weld::Window* pParent) |
377 | 0 | : SfxModelessDialogController(pBind, pCW, pParent, u"svx/ui/asianphoneticguidedialog.ui"_ustr, |
378 | 0 | u"AsianPhoneticGuideDialog"_ustr) |
379 | 0 | , nLastPos(0) |
380 | 0 | , nCurrentEdit(0) |
381 | 0 | , bModified(false) |
382 | 0 | , pBindings(pBind) |
383 | 0 | , m_pImpl(new SvxRubyData_Impl) |
384 | 0 | , m_xLeft1ED(m_xBuilder->weld_entry(u"Left1ED"_ustr)) |
385 | 0 | , m_xRight1ED(m_xBuilder->weld_entry(u"Right1ED"_ustr)) |
386 | 0 | , m_xLeft2ED(m_xBuilder->weld_entry(u"Left2ED"_ustr)) |
387 | 0 | , m_xRight2ED(m_xBuilder->weld_entry(u"Right2ED"_ustr)) |
388 | 0 | , m_xLeft3ED(m_xBuilder->weld_entry(u"Left3ED"_ustr)) |
389 | 0 | , m_xRight3ED(m_xBuilder->weld_entry(u"Right3ED"_ustr)) |
390 | 0 | , m_xLeft4ED(m_xBuilder->weld_entry(u"Left4ED"_ustr)) |
391 | 0 | , m_xRight4ED(m_xBuilder->weld_entry(u"Right4ED"_ustr)) |
392 | 0 | , m_xScrolledWindow(m_xBuilder->weld_scrolled_window(u"scrolledwindow"_ustr, true)) |
393 | 0 | , m_xAdjustLB(m_xBuilder->weld_combo_box(u"adjustlb"_ustr)) |
394 | 0 | , m_xPositionLB(m_xBuilder->weld_combo_box(u"positionlb"_ustr)) |
395 | 0 | , m_xCharStyleFT(m_xBuilder->weld_label(u"styleft"_ustr)) |
396 | 0 | , m_xCharStyleLB(m_xBuilder->weld_combo_box(u"stylelb"_ustr)) |
397 | 0 | , m_xStylistPB(m_xBuilder->weld_button(u"styles"_ustr)) |
398 | 0 | , m_xSelectionGroupPB(m_xBuilder->weld_button(u"selection-group"_ustr)) |
399 | 0 | , m_xSelectionMonoPB(m_xBuilder->weld_button(u"selection-mono"_ustr)) |
400 | 0 | , m_xApplyPB(m_xBuilder->weld_button(u"ok"_ustr)) |
401 | 0 | , m_xClosePB(m_xBuilder->weld_button(u"close"_ustr)) |
402 | 0 | , m_xContentArea(m_xDialog->weld_content_area()) |
403 | 0 | , m_xGrid(m_xBuilder->weld_widget(u"grid"_ustr)) |
404 | 0 | , m_xPreviewWin(new RubyPreview) |
405 | 0 | , m_xPreview(new weld::CustomWeld(*m_xBuilder, u"preview"_ustr, *m_xPreviewWin)) |
406 | 0 | { |
407 | 0 | m_xCharStyleLB->make_sorted(); |
408 | 0 | m_xPreviewWin->setRubyDialog(this); |
409 | 0 | m_xScrolledWindow->set_size_request(-1, m_xGrid->get_preferred_size().Height()); |
410 | 0 | m_xScrolledWindow->set_vpolicy(VclPolicyType::NEVER); |
411 | |
|
412 | 0 | aEditArr[0] = m_xLeft1ED.get(); |
413 | 0 | aEditArr[1] = m_xRight1ED.get(); |
414 | 0 | aEditArr[2] = m_xLeft2ED.get(); |
415 | 0 | aEditArr[3] = m_xRight2ED.get(); |
416 | 0 | aEditArr[4] = m_xLeft3ED.get(); |
417 | 0 | aEditArr[5] = m_xRight3ED.get(); |
418 | 0 | aEditArr[6] = m_xLeft4ED.get(); |
419 | 0 | aEditArr[7] = m_xRight4ED.get(); |
420 | |
|
421 | 0 | m_xSelectionGroupPB->connect_clicked(LINK(this, SvxRubyDialog, SelectionGroup_Impl)); |
422 | 0 | m_xSelectionMonoPB->connect_clicked(LINK(this, SvxRubyDialog, SelectionMono_Impl)); |
423 | 0 | m_xApplyPB->connect_clicked(LINK(this, SvxRubyDialog, ApplyHdl_Impl)); |
424 | 0 | m_xClosePB->connect_clicked(LINK(this, SvxRubyDialog, CloseHdl_Impl)); |
425 | 0 | m_xStylistPB->connect_clicked(LINK(this, SvxRubyDialog, StylistHdl_Impl)); |
426 | 0 | m_xAdjustLB->connect_changed(LINK(this, SvxRubyDialog, AdjustHdl_Impl)); |
427 | 0 | m_xPositionLB->connect_changed(LINK(this, SvxRubyDialog, PositionHdl_Impl)); |
428 | 0 | m_xCharStyleLB->connect_changed(LINK(this, SvxRubyDialog, CharStyleHdl_Impl)); |
429 | |
|
430 | 0 | Link<weld::ScrolledWindow&, void> aScrLk(LINK(this, SvxRubyDialog, ScrollHdl_Impl)); |
431 | 0 | m_xScrolledWindow->connect_vadjustment_changed(aScrLk); |
432 | |
|
433 | 0 | Link<weld::Entry&, void> aEditLk(LINK(this, SvxRubyDialog, EditModifyHdl_Impl)); |
434 | 0 | Link<weld::Widget&, void> aFocusLk(LINK(this, SvxRubyDialog, EditFocusHdl_Impl)); |
435 | 0 | Link<const KeyEvent&, bool> aKeyUpDownLk(LINK(this, SvxRubyDialog, KeyUpDownHdl_Impl)); |
436 | 0 | Link<const KeyEvent&, bool> aKeyTabUpDownLk(LINK(this, SvxRubyDialog, KeyUpDownTabHdl_Impl)); |
437 | 0 | for (sal_uInt16 i = 0; i < 8; i++) |
438 | 0 | { |
439 | 0 | aEditArr[i]->connect_changed(aEditLk); |
440 | 0 | aEditArr[i]->connect_focus_in(aFocusLk); |
441 | 0 | if (!i || 7 == i) |
442 | 0 | aEditArr[i]->connect_key_press(aKeyTabUpDownLk); |
443 | 0 | else |
444 | 0 | aEditArr[i]->connect_key_press(aKeyUpDownLk); |
445 | 0 | } |
446 | 0 | } |
447 | | |
448 | | SvxRubyDialog::~SvxRubyDialog() |
449 | 0 | { |
450 | 0 | ClearCharStyleList(); |
451 | 0 | EventObject aEvent; |
452 | 0 | m_pImpl->disposing(aEvent); |
453 | 0 | } |
454 | | |
455 | 0 | void SvxRubyDialog::ClearCharStyleList() { m_xCharStyleLB->clear(); } |
456 | | |
457 | | void SvxRubyDialog::Close() |
458 | 0 | { |
459 | 0 | if (IsClosing()) |
460 | 0 | return; |
461 | 0 | SfxViewFrame* pViewFrame = SfxViewFrame::Current(); |
462 | 0 | if (pViewFrame) |
463 | 0 | pViewFrame->ToggleChildWindow(SID_RUBY_DIALOG); |
464 | 0 | } |
465 | | |
466 | | void SvxRubyDialog::Activate() |
467 | 0 | { |
468 | 0 | SfxModelessDialogController::Activate(); |
469 | 0 | if (m_pImpl->IsDisposing()) |
470 | 0 | { |
471 | | // tdf#141967/tdf#152495 if Activate is called during tear down bail early |
472 | 0 | return; |
473 | 0 | } |
474 | | |
475 | | //get selection from current view frame |
476 | 0 | SfxViewFrame* pCurFrm = SfxViewFrame::Current(); |
477 | 0 | Reference<XController> xCtrl(pCurFrm ? pCurFrm->GetFrame().GetController() : nullptr); |
478 | 0 | m_pImpl->SetController(xCtrl); |
479 | 0 | if (!m_pImpl->HasSelectionChanged()) |
480 | 0 | return; |
481 | | |
482 | 0 | Reference<XRubySelection> xRubySel = m_pImpl->GetRubySelection(); |
483 | 0 | m_pImpl->UpdateRubyValues(); |
484 | 0 | EnableControls(xRubySel.is()); |
485 | 0 | if (xRubySel.is()) |
486 | 0 | { |
487 | 0 | Reference<XModel> xModel = m_pImpl->GetModel(); |
488 | 0 | const OUString sCharStyleSelect = m_xCharStyleLB->get_active_text(); |
489 | 0 | ClearCharStyleList(); |
490 | 0 | Reference<XStyleFamiliesSupplier> xSupplier(xModel, UNO_QUERY); |
491 | 0 | if (xSupplier.is()) |
492 | 0 | { |
493 | 0 | try |
494 | 0 | { |
495 | 0 | Reference<XNameAccess> xFam = xSupplier->getStyleFamilies(); |
496 | 0 | Any aChar = xFam->getByName(u"CharacterStyles"_ustr); |
497 | 0 | Reference<XNameContainer> xChar; |
498 | 0 | aChar >>= xChar; |
499 | 0 | Reference<XIndexAccess> xCharIdx(xChar, UNO_QUERY); |
500 | 0 | if (xCharIdx.is()) |
501 | 0 | { |
502 | 0 | OUString sUIName(u"DisplayName"_ustr); |
503 | 0 | for (sal_Int32 nStyle = 0; nStyle < xCharIdx->getCount(); nStyle++) |
504 | 0 | { |
505 | 0 | Any aStyle = xCharIdx->getByIndex(nStyle); |
506 | 0 | Reference<XStyle> xStyle; |
507 | 0 | aStyle >>= xStyle; |
508 | 0 | Reference<XPropertySet> xPrSet(xStyle, UNO_QUERY); |
509 | 0 | OUString sName, sCoreName; |
510 | 0 | if (xPrSet.is()) |
511 | 0 | { |
512 | 0 | Reference<XPropertySetInfo> xInfo = xPrSet->getPropertySetInfo(); |
513 | 0 | if (xInfo->hasPropertyByName(sUIName)) |
514 | 0 | { |
515 | 0 | Any aName = xPrSet->getPropertyValue(sUIName); |
516 | 0 | aName >>= sName; |
517 | 0 | } |
518 | 0 | } |
519 | 0 | if (xStyle.is()) |
520 | 0 | { |
521 | 0 | sCoreName = xStyle->getName(); |
522 | 0 | if (sName.isEmpty()) |
523 | 0 | sName = sCoreName; |
524 | 0 | } |
525 | 0 | if (!sName.isEmpty()) |
526 | 0 | { |
527 | 0 | m_xCharStyleLB->append(sCoreName, sName); |
528 | 0 | } |
529 | 0 | } |
530 | 0 | } |
531 | 0 | } |
532 | 0 | catch (const Exception&) |
533 | 0 | { |
534 | 0 | TOOLS_WARN_EXCEPTION("svx.dialog", "exception in style access"); |
535 | 0 | } |
536 | 0 | if (!sCharStyleSelect.isEmpty()) |
537 | 0 | m_xCharStyleLB->set_active_text(sCharStyleSelect); |
538 | 0 | } |
539 | 0 | m_xCharStyleLB->set_sensitive(xSupplier.is()); |
540 | 0 | m_xCharStyleFT->set_sensitive(xSupplier.is()); |
541 | 0 | } |
542 | 0 | Update(); |
543 | 0 | m_xPreviewWin->Invalidate(); |
544 | 0 | } |
545 | | |
546 | | void SvxRubyDialog::SetRubyText(sal_Int32 nPos, weld::Entry& rLeft, weld::Entry& rRight) |
547 | 0 | { |
548 | 0 | OUString sLeft, sRight; |
549 | 0 | const Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues(); |
550 | 0 | bool bEnable = aRubyValues.getLength() > nPos; |
551 | 0 | if (bEnable) |
552 | 0 | { |
553 | 0 | const Sequence<PropertyValue> aProps = aRubyValues.getConstArray()[nPos]; |
554 | 0 | for (const PropertyValue& rProp : aProps) |
555 | 0 | { |
556 | 0 | if (rProp.Name == cRubyBaseText) |
557 | 0 | rProp.Value >>= sLeft; |
558 | 0 | else if (rProp.Name == cRubyText) |
559 | 0 | rProp.Value >>= sRight; |
560 | 0 | } |
561 | 0 | } |
562 | 0 | else if (!nPos) |
563 | 0 | { |
564 | 0 | bEnable = true; |
565 | 0 | } |
566 | 0 | rLeft.set_sensitive(bEnable); |
567 | 0 | rRight.set_sensitive(bEnable); |
568 | 0 | rLeft.set_text(sLeft); |
569 | 0 | rRight.set_text(sRight); |
570 | 0 | rLeft.save_value(); |
571 | 0 | rRight.save_value(); |
572 | 0 | } |
573 | | |
574 | | void SvxRubyDialog::GetRubyText() |
575 | 0 | { |
576 | 0 | tools::Long nTempLastPos = GetLastPos(); |
577 | 0 | Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues(); |
578 | 0 | auto aRubyValuesRange = asNonConstRange(aRubyValues); |
579 | 0 | for (int i = 0; i < 8; i += 2) |
580 | 0 | { |
581 | 0 | if (aEditArr[i]->get_sensitive() |
582 | 0 | && (aEditArr[i]->get_value_changed_from_saved() |
583 | 0 | || aEditArr[i + 1]->get_value_changed_from_saved())) |
584 | 0 | { |
585 | 0 | DBG_ASSERT(aRubyValues.getLength() > (i / 2 + nTempLastPos), "wrong index"); |
586 | 0 | SetModified(true); |
587 | 0 | for (PropertyValue& propVal : asNonConstRange(aRubyValuesRange[i / 2 + nTempLastPos])) |
588 | 0 | { |
589 | 0 | if (propVal.Name == cRubyBaseText) |
590 | 0 | propVal.Value <<= aEditArr[i]->get_text(); |
591 | 0 | else if (propVal.Name == cRubyText) |
592 | 0 | propVal.Value <<= aEditArr[i + 1]->get_text(); |
593 | 0 | } |
594 | 0 | } |
595 | 0 | } |
596 | 0 | } |
597 | | |
598 | | void SvxRubyDialog::Update() |
599 | 0 | { |
600 | | // Only enable selection grouping options when they can be applied |
601 | 0 | m_xSelectionGroupPB->set_sensitive(!m_pImpl->IsSelectionGrouped()); |
602 | 0 | m_xSelectionMonoPB->set_sensitive(!m_pImpl->IsSelectionMono()); |
603 | |
|
604 | 0 | const Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues(); |
605 | 0 | sal_Int32 nLen = aRubyValues.getLength(); |
606 | 0 | m_xScrolledWindow->vadjustment_configure(0, 0, !nLen ? 1 : nLen, 1, 4, 4); |
607 | 0 | if (nLen > 4) |
608 | 0 | m_xScrolledWindow->set_vpolicy(VclPolicyType::ALWAYS); |
609 | 0 | else |
610 | 0 | m_xScrolledWindow->set_vpolicy(VclPolicyType::NEVER); |
611 | 0 | SetLastPos(0); |
612 | 0 | SetModified(false); |
613 | |
|
614 | 0 | sal_Int16 nAdjust = -1; |
615 | 0 | sal_Int16 nPosition = -1; |
616 | 0 | OUString sCharStyleName, sTmp; |
617 | 0 | bool bCharStyleEqual = true; |
618 | 0 | for (sal_Int32 nRuby = 0; nRuby < nLen; nRuby++) |
619 | 0 | { |
620 | 0 | const Sequence<PropertyValue>& rProps = aRubyValues.getConstArray()[nRuby]; |
621 | 0 | for (const PropertyValue& rProp : rProps) |
622 | 0 | { |
623 | 0 | if (nAdjust > -2 && rProp.Name == cRubyAdjust) |
624 | 0 | { |
625 | 0 | sal_Int16 nTmp = sal_Int16(); |
626 | 0 | rProp.Value >>= nTmp; |
627 | 0 | if (!nRuby) |
628 | 0 | nAdjust = nTmp; |
629 | 0 | else if (nAdjust != nTmp) |
630 | 0 | nAdjust = -2; |
631 | 0 | } |
632 | 0 | if (nPosition > -2 && rProp.Name == cRubyPosition) |
633 | 0 | { |
634 | 0 | sal_Int16 nTmp = sal_Int16(); |
635 | 0 | rProp.Value >>= nTmp; |
636 | 0 | if (!nRuby) |
637 | 0 | nPosition = nTmp; |
638 | 0 | else if (nPosition != nTmp) |
639 | 0 | nPosition = -2; |
640 | 0 | } |
641 | 0 | if (bCharStyleEqual && rProp.Name == cRubyCharStyleName) |
642 | 0 | { |
643 | 0 | rProp.Value >>= sTmp; |
644 | 0 | if (!nRuby) |
645 | 0 | sCharStyleName = sTmp; |
646 | 0 | else if (sCharStyleName != sTmp) |
647 | 0 | bCharStyleEqual = false; |
648 | 0 | } |
649 | 0 | } |
650 | 0 | } |
651 | 0 | if (!nLen) |
652 | 0 | { |
653 | | //enable selection if the ruby list is empty |
654 | 0 | nAdjust = 0; |
655 | 0 | nPosition = 0; |
656 | 0 | } |
657 | 0 | if (nAdjust > -1) |
658 | 0 | m_xAdjustLB->set_active(nAdjust); |
659 | 0 | else |
660 | 0 | m_xAdjustLB->set_active(-1); |
661 | 0 | if (nPosition > -1) |
662 | 0 | m_xPositionLB->set_active(nPosition); |
663 | 0 | if (!nLen || (bCharStyleEqual && sCharStyleName.isEmpty())) |
664 | 0 | sCharStyleName = "Rubies"; |
665 | 0 | if (!sCharStyleName.isEmpty()) |
666 | 0 | { |
667 | 0 | for (int i = 0, nEntryCount = m_xCharStyleLB->get_count(); i < nEntryCount; i++) |
668 | 0 | { |
669 | 0 | OUString sCoreName = m_xCharStyleLB->get_id(i); |
670 | 0 | if (sCharStyleName == sCoreName) |
671 | 0 | { |
672 | 0 | m_xCharStyleLB->set_active(i); |
673 | 0 | break; |
674 | 0 | } |
675 | 0 | } |
676 | 0 | } |
677 | 0 | else |
678 | 0 | m_xCharStyleLB->set_active(-1); |
679 | |
|
680 | 0 | ScrollHdl_Impl(*m_xScrolledWindow); |
681 | 0 | } |
682 | | |
683 | | void SvxRubyDialog::GetCurrentText(OUString& rBase, OUString& rRuby) |
684 | 0 | { |
685 | 0 | rBase = aEditArr[nCurrentEdit * 2]->get_text(); |
686 | 0 | rRuby = aEditArr[nCurrentEdit * 2 + 1]->get_text(); |
687 | 0 | } |
688 | | |
689 | | IMPL_LINK(SvxRubyDialog, ScrollHdl_Impl, weld::ScrolledWindow&, rScroll, void) |
690 | 0 | { |
691 | 0 | int nPos = rScroll.vadjustment_get_value(); |
692 | 0 | if (GetLastPos() != nPos) |
693 | 0 | { |
694 | 0 | GetRubyText(); |
695 | 0 | } |
696 | 0 | SetRubyText(nPos++, *m_xLeft1ED, *m_xRight1ED); |
697 | 0 | SetRubyText(nPos++, *m_xLeft2ED, *m_xRight2ED); |
698 | 0 | SetRubyText(nPos++, *m_xLeft3ED, *m_xRight3ED); |
699 | 0 | SetRubyText(nPos, *m_xLeft4ED, *m_xRight4ED); |
700 | 0 | SetLastPos(nPos - 3); |
701 | 0 | m_xPreviewWin->Invalidate(); |
702 | 0 | } |
703 | | |
704 | | IMPL_LINK_NOARG(SvxRubyDialog, SelectionGroup_Impl, weld::Button&, void) |
705 | 0 | { |
706 | 0 | m_pImpl->MakeSelectionGrouped(); |
707 | 0 | Update(); |
708 | 0 | } |
709 | | |
710 | | IMPL_LINK_NOARG(SvxRubyDialog, SelectionMono_Impl, weld::Button&, void) |
711 | 0 | { |
712 | 0 | m_pImpl->MakeSelectionMono(); |
713 | 0 | Update(); |
714 | 0 | } |
715 | | |
716 | | IMPL_LINK_NOARG(SvxRubyDialog, ApplyHdl_Impl, weld::Button&, void) |
717 | 0 | { |
718 | 0 | const Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues(); |
719 | 0 | if (!aRubyValues.hasElements()) |
720 | 0 | { |
721 | 0 | AssertOneEntry(); |
722 | 0 | PositionHdl_Impl(*m_xPositionLB); |
723 | 0 | AdjustHdl_Impl(*m_xAdjustLB); |
724 | 0 | CharStyleHdl_Impl(*m_xCharStyleLB); |
725 | 0 | } |
726 | 0 | GetRubyText(); |
727 | | //reset all edit fields - SaveValue is called |
728 | 0 | ScrollHdl_Impl(*m_xScrolledWindow); |
729 | |
|
730 | 0 | Reference<XRubySelection> xSelection = m_pImpl->GetRubySelection(); |
731 | 0 | if (IsModified() && xSelection.is()) |
732 | 0 | { |
733 | 0 | try |
734 | 0 | { |
735 | 0 | xSelection->setRubyList(aRubyValues, false); |
736 | 0 | } |
737 | 0 | catch (const Exception&) |
738 | 0 | { |
739 | 0 | TOOLS_WARN_EXCEPTION("svx.dialog", ""); |
740 | 0 | } |
741 | 0 | } |
742 | 0 | } |
743 | | |
744 | 0 | IMPL_LINK_NOARG(SvxRubyDialog, CloseHdl_Impl, weld::Button&, void) { Close(); } |
745 | | |
746 | | IMPL_LINK_NOARG(SvxRubyDialog, StylistHdl_Impl, weld::Button&, void) |
747 | 0 | { |
748 | 0 | std::unique_ptr<SfxBoolItem> pState; |
749 | 0 | SfxItemState eState = pBindings->QueryState(SID_STYLE_DESIGNER, pState); |
750 | 0 | if (eState <= SfxItemState::SET || !pState || !pState->GetValue()) |
751 | 0 | { |
752 | 0 | pBindings->GetDispatcher()->Execute(SID_STYLE_DESIGNER, |
753 | 0 | SfxCallMode::ASYNCHRON | SfxCallMode::RECORD); |
754 | 0 | } |
755 | 0 | } |
756 | | |
757 | | IMPL_LINK(SvxRubyDialog, AdjustHdl_Impl, weld::ComboBox&, rBox, void) |
758 | 0 | { |
759 | 0 | AssertOneEntry(); |
760 | 0 | sal_Int16 nAdjust = rBox.get_active(); |
761 | 0 | for (PropertyValues& rProps : asNonConstRange(m_pImpl->GetRubyValues())) |
762 | 0 | { |
763 | 0 | for (PropertyValue& propVal : asNonConstRange(rProps)) |
764 | 0 | { |
765 | 0 | if (propVal.Name == cRubyAdjust) |
766 | 0 | propVal.Value <<= nAdjust; |
767 | 0 | } |
768 | 0 | SetModified(true); |
769 | 0 | } |
770 | 0 | m_xPreviewWin->Invalidate(); |
771 | 0 | } |
772 | | |
773 | | IMPL_LINK(SvxRubyDialog, PositionHdl_Impl, weld::ComboBox&, rBox, void) |
774 | 0 | { |
775 | 0 | AssertOneEntry(); |
776 | 0 | sal_Int16 nPosition = rBox.get_active(); |
777 | 0 | for (PropertyValues& rProps : asNonConstRange(m_pImpl->GetRubyValues())) |
778 | 0 | { |
779 | 0 | for (PropertyValue& propVal : asNonConstRange(rProps)) |
780 | 0 | { |
781 | 0 | if (propVal.Name == cRubyPosition) |
782 | 0 | propVal.Value <<= nPosition; |
783 | 0 | } |
784 | 0 | SetModified(true); |
785 | 0 | } |
786 | 0 | m_xPreviewWin->Invalidate(); |
787 | 0 | } |
788 | | |
789 | | IMPL_LINK_NOARG(SvxRubyDialog, CharStyleHdl_Impl, weld::ComboBox&, void) |
790 | 0 | { |
791 | 0 | AssertOneEntry(); |
792 | 0 | OUString sStyleName; |
793 | 0 | if (m_xCharStyleLB->get_active() != -1) |
794 | 0 | sStyleName = m_xCharStyleLB->get_active_id(); |
795 | 0 | for (PropertyValues& rProps : asNonConstRange(m_pImpl->GetRubyValues())) |
796 | 0 | { |
797 | 0 | for (PropertyValue& propVal : asNonConstRange(rProps)) |
798 | 0 | { |
799 | 0 | if (propVal.Name == cRubyCharStyleName) |
800 | 0 | { |
801 | 0 | propVal.Value <<= sStyleName; |
802 | 0 | } |
803 | 0 | } |
804 | 0 | SetModified(true); |
805 | 0 | } |
806 | 0 | } |
807 | | |
808 | | IMPL_LINK(SvxRubyDialog, EditFocusHdl_Impl, weld::Widget&, rEdit, void) |
809 | 0 | { |
810 | 0 | for (sal_uInt16 i = 0; i < 8; i++) |
811 | 0 | { |
812 | 0 | if (&rEdit == aEditArr[i]) |
813 | 0 | { |
814 | 0 | nCurrentEdit = i / 2; |
815 | 0 | break; |
816 | 0 | } |
817 | 0 | } |
818 | 0 | m_xPreviewWin->Invalidate(); |
819 | 0 | } |
820 | | |
821 | | IMPL_LINK(SvxRubyDialog, EditModifyHdl_Impl, weld::Entry&, rEdit, void) |
822 | 0 | { |
823 | 0 | EditFocusHdl_Impl(rEdit); |
824 | 0 | } |
825 | | |
826 | | bool SvxRubyDialog::EditScrollHdl_Impl(sal_Int32 nParam) |
827 | 0 | { |
828 | 0 | bool bRet = false; |
829 | | //scroll forward |
830 | 0 | if (nParam > 0 && (aEditArr[7]->has_focus() || aEditArr[6]->has_focus())) |
831 | 0 | { |
832 | 0 | if (m_xScrolledWindow->vadjustment_get_upper() |
833 | 0 | > m_xScrolledWindow->vadjustment_get_value() |
834 | 0 | + m_xScrolledWindow->vadjustment_get_page_size()) |
835 | 0 | { |
836 | 0 | m_xScrolledWindow->vadjustment_set_value(m_xScrolledWindow->vadjustment_get_value() |
837 | 0 | + 1); |
838 | 0 | aEditArr[6]->grab_focus(); |
839 | 0 | bRet = true; |
840 | 0 | } |
841 | 0 | } |
842 | | //scroll backward |
843 | 0 | else if (m_xScrolledWindow->vadjustment_get_value() |
844 | 0 | && (aEditArr[0]->has_focus() || aEditArr[1]->has_focus())) |
845 | 0 | { |
846 | 0 | m_xScrolledWindow->vadjustment_set_value(m_xScrolledWindow->vadjustment_get_value() - 1); |
847 | 0 | aEditArr[1]->grab_focus(); |
848 | 0 | bRet = true; |
849 | 0 | } |
850 | 0 | if (bRet) |
851 | 0 | ScrollHdl_Impl(*m_xScrolledWindow); |
852 | 0 | return bRet; |
853 | 0 | } |
854 | | |
855 | | bool SvxRubyDialog::EditJumpHdl_Impl(sal_Int32 nParam) |
856 | 0 | { |
857 | 0 | bool bHandled = false; |
858 | 0 | sal_uInt16 nIndex = USHRT_MAX; |
859 | 0 | for (sal_uInt16 i = 0; i < 8; i++) |
860 | 0 | { |
861 | 0 | if (aEditArr[i]->has_focus()) |
862 | 0 | nIndex = i; |
863 | 0 | } |
864 | 0 | if (nIndex < 8) |
865 | 0 | { |
866 | 0 | if (nParam > 0) |
867 | 0 | { |
868 | 0 | if (nIndex < 6) |
869 | 0 | aEditArr[nIndex + 2]->grab_focus(); |
870 | 0 | else if (EditScrollHdl_Impl(nParam)) |
871 | 0 | aEditArr[nIndex]->grab_focus(); |
872 | 0 | } |
873 | 0 | else |
874 | 0 | { |
875 | 0 | if (nIndex > 1) |
876 | 0 | aEditArr[nIndex - 2]->grab_focus(); |
877 | 0 | else if (EditScrollHdl_Impl(nParam)) |
878 | 0 | aEditArr[nIndex]->grab_focus(); |
879 | 0 | } |
880 | 0 | bHandled = true; |
881 | 0 | } |
882 | 0 | return bHandled; |
883 | 0 | } |
884 | | |
885 | 0 | void SvxRubyDialog::AssertOneEntry() { m_pImpl->AssertOneEntry(); } |
886 | | |
887 | | void SvxRubyDialog::EnableControls(bool bEnable) |
888 | 0 | { |
889 | 0 | m_xContentArea->set_sensitive(bEnable); |
890 | 0 | m_xApplyPB->set_sensitive(bEnable); |
891 | 0 | } |
892 | | |
893 | | RubyPreview::RubyPreview() |
894 | 0 | : m_pParentDlg(nullptr) |
895 | 0 | { |
896 | 0 | } |
897 | | |
898 | 0 | RubyPreview::~RubyPreview() {} |
899 | | |
900 | | void RubyPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/) |
901 | 0 | { |
902 | 0 | rRenderContext.Push(vcl::PushFlags::ALL); |
903 | |
|
904 | 0 | rRenderContext.SetMapMode(MapMode(MapUnit::MapTwip)); |
905 | |
|
906 | 0 | Size aWinSize = rRenderContext.GetOutputSize(); |
907 | |
|
908 | 0 | const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); |
909 | 0 | svtools::ColorConfig aColorConfig; |
910 | |
|
911 | 0 | Color aNewTextColor(aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor); |
912 | 0 | Color aNewFillColor(rStyleSettings.GetWindowColor()); |
913 | |
|
914 | 0 | vcl::Font aFont = rRenderContext.GetFont(); |
915 | 0 | aFont.SetFontHeight(aWinSize.Height() / 4); |
916 | 0 | aFont.SetFillColor(aNewFillColor); |
917 | 0 | aFont.SetColor(aNewTextColor); |
918 | 0 | rRenderContext.SetFont(aFont); |
919 | |
|
920 | 0 | tools::Rectangle aRect(Point(0, 0), aWinSize); |
921 | 0 | rRenderContext.SetLineColor(); |
922 | 0 | rRenderContext.SetFillColor(aFont.GetFillColor()); |
923 | 0 | rRenderContext.DrawRect(aRect); |
924 | |
|
925 | 0 | OUString sBaseText, sRubyText; |
926 | 0 | m_pParentDlg->GetCurrentText(sBaseText, sRubyText); |
927 | |
|
928 | 0 | tools::Long nTextHeight = rRenderContext.GetTextHeight(); |
929 | 0 | tools::Long nBaseWidth = rRenderContext.GetTextWidth(sBaseText); |
930 | |
|
931 | 0 | vcl::Font aRubyFont(aFont); |
932 | 0 | aRubyFont.SetFontHeight(aRubyFont.GetFontHeight() * 70 / 100); |
933 | 0 | rRenderContext.SetFont(aRubyFont); |
934 | 0 | tools::Long nRubyWidth = rRenderContext.GetTextWidth(sRubyText); |
935 | 0 | rRenderContext.SetFont(aFont); |
936 | |
|
937 | 0 | RubyAdjust nAdjust = static_cast<RubyAdjust>(m_pParentDlg->m_xAdjustLB->get_active()); |
938 | | //use center if no adjustment is available |
939 | 0 | if (nAdjust > RubyAdjust_INDENT_BLOCK) |
940 | 0 | nAdjust = RubyAdjust_CENTER; |
941 | | |
942 | | //which part is stretched ? |
943 | 0 | bool bRubyStretch = nBaseWidth >= nRubyWidth; |
944 | |
|
945 | 0 | tools::Long nCenter = aWinSize.Width() / 2; |
946 | 0 | tools::Long nHalfWidth = std::max(nBaseWidth, nRubyWidth) / 2; |
947 | 0 | tools::Long nLeftStart = nCenter - nHalfWidth; |
948 | 0 | tools::Long nRightEnd = nCenter + nHalfWidth; |
949 | | |
950 | | // Default values for TOP or no selection |
951 | 0 | tools::Long nYRuby = aWinSize.Height() / 4 - nTextHeight / 2; |
952 | 0 | tools::Long nYBase = aWinSize.Height() * 3 / 4 - nTextHeight / 2; |
953 | |
|
954 | 0 | sal_Int16 nRubyPos = m_pParentDlg->m_xPositionLB->get_active(); |
955 | 0 | if (nRubyPos == 1) // BOTTOM |
956 | 0 | std::swap(nYRuby, nYBase); |
957 | 0 | else if (nRubyPos == 2) // RIGHT ( vertically ) |
958 | 0 | { |
959 | | // Align the ruby text and base text to the vertical center. |
960 | 0 | nYBase = (aWinSize.Height() - nTextHeight) / 2; |
961 | 0 | nYRuby = (aWinSize.Height() - nRubyWidth) / 2; |
962 | | |
963 | | // Align the ruby text at the right side of the base text |
964 | 0 | nAdjust = RubyAdjust_RIGHT; |
965 | 0 | nHalfWidth = nBaseWidth / 2; |
966 | 0 | nLeftStart = nCenter - nHalfWidth; |
967 | 0 | nRightEnd = nCenter + nHalfWidth + nRubyWidth + nTextHeight; |
968 | | // Render base text first, then render ruby text on the right. |
969 | 0 | bRubyStretch = true; |
970 | |
|
971 | 0 | aRubyFont.SetVertical(true); |
972 | 0 | aRubyFont.SetOrientation(2700_deg10); |
973 | 0 | } |
974 | |
|
975 | 0 | tools::Long nYOutput; |
976 | 0 | tools::Long nOutTextWidth; |
977 | 0 | OUString sOutputText; |
978 | |
|
979 | 0 | if (bRubyStretch) |
980 | 0 | { |
981 | 0 | rRenderContext.DrawText(Point(nLeftStart, nYBase), sBaseText); |
982 | 0 | nYOutput = nYRuby; |
983 | 0 | sOutputText = sRubyText; |
984 | 0 | nOutTextWidth = nRubyWidth; |
985 | 0 | rRenderContext.SetFont(aRubyFont); |
986 | 0 | } |
987 | 0 | else |
988 | 0 | { |
989 | 0 | rRenderContext.SetFont(aRubyFont); |
990 | 0 | rRenderContext.DrawText(Point(nLeftStart, nYRuby), sRubyText); |
991 | 0 | nYOutput = nYBase; |
992 | 0 | sOutputText = sBaseText; |
993 | 0 | nOutTextWidth = nBaseWidth; |
994 | 0 | rRenderContext.SetFont(aFont); |
995 | 0 | } |
996 | |
|
997 | 0 | switch (nAdjust) |
998 | 0 | { |
999 | 0 | case RubyAdjust_LEFT: |
1000 | 0 | rRenderContext.DrawText(Point(nLeftStart, nYOutput), sOutputText); |
1001 | 0 | break; |
1002 | 0 | case RubyAdjust_RIGHT: |
1003 | 0 | rRenderContext.DrawText(Point(nRightEnd - nOutTextWidth, nYOutput), sOutputText); |
1004 | 0 | break; |
1005 | 0 | case RubyAdjust_INDENT_BLOCK: |
1006 | 0 | { |
1007 | 0 | tools::Long nCharWidth = rRenderContext.GetTextWidth(u"X"_ustr); |
1008 | 0 | if (nOutTextWidth < (nRightEnd - nLeftStart - nCharWidth)) |
1009 | 0 | { |
1010 | 0 | nCharWidth /= 2; |
1011 | 0 | nLeftStart += nCharWidth; |
1012 | 0 | nRightEnd -= nCharWidth; |
1013 | 0 | } |
1014 | 0 | [[fallthrough]]; |
1015 | 0 | } |
1016 | 0 | case RubyAdjust_BLOCK: |
1017 | 0 | { |
1018 | 0 | if (sOutputText.getLength() > 1) |
1019 | 0 | { |
1020 | 0 | sal_Int32 nCount = sOutputText.getLength(); |
1021 | 0 | tools::Long nSpace |
1022 | 0 | = ((nRightEnd - nLeftStart) - rRenderContext.GetTextWidth(sOutputText)) |
1023 | 0 | / (nCount - 1); |
1024 | 0 | for (sal_Int32 i = 0; i < nCount; i++) |
1025 | 0 | { |
1026 | 0 | OUString sChar(sOutputText[i]); |
1027 | 0 | rRenderContext.DrawText(Point(nLeftStart, nYOutput), sChar); |
1028 | 0 | tools::Long nCharWidth = rRenderContext.GetTextWidth(sChar); |
1029 | 0 | nLeftStart += nCharWidth + nSpace; |
1030 | 0 | } |
1031 | 0 | break; |
1032 | 0 | } |
1033 | 0 | [[fallthrough]]; |
1034 | 0 | } |
1035 | 0 | case RubyAdjust_CENTER: |
1036 | 0 | rRenderContext.DrawText(Point(nCenter - nOutTextWidth / 2, nYOutput), sOutputText); |
1037 | 0 | break; |
1038 | 0 | default: |
1039 | 0 | break; |
1040 | 0 | } |
1041 | 0 | rRenderContext.Pop(); |
1042 | 0 | } |
1043 | | |
1044 | | void RubyPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea) |
1045 | 0 | { |
1046 | 0 | pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 40, |
1047 | 0 | pDrawingArea->get_text_height() * 7); |
1048 | 0 | CustomWidgetController::SetDrawingArea(pDrawingArea); |
1049 | 0 | } |
1050 | | |
1051 | | IMPL_LINK(SvxRubyDialog, KeyUpDownHdl_Impl, const KeyEvent&, rKEvt, bool) |
1052 | 0 | { |
1053 | 0 | bool bHandled = false; |
1054 | 0 | const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode(); |
1055 | 0 | sal_uInt16 nCode = rKeyCode.GetCode(); |
1056 | 0 | if (KEY_UP == nCode || KEY_DOWN == nCode) |
1057 | 0 | { |
1058 | 0 | sal_Int32 nParam = KEY_UP == nCode ? -1 : 1; |
1059 | 0 | bHandled = EditJumpHdl_Impl(nParam); |
1060 | 0 | } |
1061 | 0 | return bHandled; |
1062 | 0 | } |
1063 | | |
1064 | | IMPL_LINK(SvxRubyDialog, KeyUpDownTabHdl_Impl, const KeyEvent&, rKEvt, bool) |
1065 | 0 | { |
1066 | 0 | bool bHandled = false; |
1067 | 0 | const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode(); |
1068 | 0 | sal_uInt16 nMod = rKeyCode.GetModifier(); |
1069 | 0 | sal_uInt16 nCode = rKeyCode.GetCode(); |
1070 | 0 | if (nCode == KEY_TAB && (!nMod || KEY_SHIFT == nMod)) |
1071 | 0 | { |
1072 | 0 | sal_Int32 nParam = KEY_SHIFT == nMod ? -1 : 1; |
1073 | 0 | if (EditScrollHdl_Impl(nParam)) |
1074 | 0 | bHandled = true; |
1075 | 0 | } |
1076 | 0 | if (!bHandled) |
1077 | 0 | bHandled = KeyUpDownHdl_Impl(rKEvt); |
1078 | 0 | return bHandled; |
1079 | 0 | } |
1080 | | |
1081 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |