Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  rubydialog.cxx   Sprache: C

 
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <memory>
#include <sal/config.h>
#include <tools/debug.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <comphelper/processfactory.hxx>

#include <svx/rubydialog.hxx>
#include <sfx2/dispatch.hxx>
#include <sfx2/sfxsids.hrc>
#include <sfx2/viewfrm.hxx>
#include <sfx2/viewsh.hxx>
#include <svl/eitem.hxx>
#include <com/sun/star/frame/XController.hpp>
#include <com/sun/star/style/XStyle.hpp>
#include <com/sun/star/text/XRubySelection.hpp>
#include <com/sun/star/beans/PropertyValues.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/container/XNameContainer.hpp>
#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
#include <com/sun/star/text/RubyAdjust.hpp>
#include <com/sun/star/view/XSelectionChangeListener.hpp>
#include <com/sun/star/view/XSelectionSupplier.hpp>
#include <com/sun/star/i18n/BreakIterator.hpp>
#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
#include <cppuhelper/implbase.hxx>
#include <svtools/colorcfg.hxx>
#include <vcl/event.hxx>
#include <vcl/settings.hxx>
#include <vcl/svapp.hxx>
#include <rtl/ustrbuf.hxx>
#include <svl/itemset.hxx>

using namespace css::uno;
using namespace css::frame;
using namespace css::text;
using namespace css::beans;
using namespace css::style;
using namespace css::view;
using namespace css::lang;
using namespace css::container;

SFX_IMPL_CHILDWINDOW(SvxRubyChildWindow, SID_RUBY_DIALOG);

namespace
{
constexpr OUString cRubyBaseText = u"RubyBaseText"_ustr;
constexpr OUString cRubyText = u"RubyText"_ustr;
constexpr OUString cRubyAdjust = u"RubyAdjust"_ustr;
constexpr OUString cRubyPosition = u"RubyPosition"_ustr;
constexpr OUString cRubyCharStyleName = u"RubyCharStyleName"_ustr;

// end anonymous namespace

SvxRubyChildWindow::SvxRubyChildWindow(vcl::Window* _pParent, sal_uInt16 nId,
                                       SfxBindings* pBindings, SfxChildWinInfo const* pInfo)
    : SfxChildWindow(_pParent, nId)
{
    auto xDlg = std::make_shared<SvxRubyDialog>(pBindings, this, _pParent->GetFrameWeld());
    SetController(xDlg);
    xDlg->Initialize(pInfo);
}

SfxChildWinInfo SvxRubyChildWindow::GetInfo() const { return SfxChildWindow::GetInfo(); }

class SvxRubyData_Impl : public cppu::WeakImplHelper<css::view::XSelectionChangeListener>
{
    Reference<css::i18n::XBreakIterator> xBreak;
    Reference<XModel> xModel;
    Reference<XRubySelection> xSelection;
    Sequence<PropertyValues> aRubyValues;
    Reference<XController> xController;
    bool bHasSelectionChanged;
    bool bDisposing;

public:
    SvxRubyData_Impl();
    virtual ~SvxRubyData_Impl() override;

    void SetController(const Reference<XController>& xCtrl);
    Reference<XModel> const& GetModel()
    {
        if (!xController.is())
            xModel = nullptr;
        else
            xModel = xController->getModel();
        return xModel;
    }
    bool HasSelectionChanged() const { return bHasSelectionChanged; }
    bool IsDisposing() const { return bDisposing; }
    Reference<XRubySelection> const& GetRubySelection()
    {
        xSelection.set(xController, UNO_QUERY);
        return xSelection;
    }
    void UpdateRubyValues()
    {
        if (!xSelection.is())
            aRubyValues.realloc(0);
        else
            aRubyValues = xSelection->getRubyList(false);
        bHasSelectionChanged = false;
    }
    Sequence<PropertyValues>& GetRubyValues() { return aRubyValues; }
    void AssertOneEntry();

    virtual void SAL_CALL selectionChanged(const css::lang::EventObject& aEvent) override;
    virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override;

    bool IsSelectionGrouped() { return aRubyValues.getLength() < 2; }

    void MakeSelectionGrouped()
    {
        if (aRubyValues.getLength() < 2)
        {
            return;
        }

        OUString sBaseTmp;
        OUStringBuffer aBaseString;
        for (const PropertyValues& rVals : aRubyValues)
        {
            sBaseTmp.clear();
            for (const PropertyValue& rVal : rVals)
            {
                if (rVal.Name == cRubyBaseText)
                {
                    rVal.Value >>= sBaseTmp;
                }
            }

            aBaseString.append(sBaseTmp);
        }

        Sequence<PropertyValues> aNewRubyValues{ 1 };
        PropertyValues* pNewRubyValues = aNewRubyValues.getArray();

        // Copy some reasonable style values from the previous ruby array
        pNewRubyValues[0] = aRubyValues[0];
        for (const PropertyValues& rVals : aRubyValues)
        {
            for (const PropertyValue& rVal : rVals)
            {
                if (rVal.Name == cRubyText)
                {
                    rVal.Value >>= sBaseTmp;
                    if (!sBaseTmp.isEmpty())
                    {
                        pNewRubyValues[0] = rVals;
                        break;
                    }
                }
            }
        }

        PropertyValue* pNewValues = pNewRubyValues[0].getArray();
        for (sal_Int32 i = 0; i < pNewRubyValues[0].getLength(); ++i)
        {
            if (pNewValues[i].Name == cRubyBaseText)
            {
                sBaseTmp = aBaseString;
                pNewValues[i].Value <<= sBaseTmp;
            }
            else if (pNewValues[i].Name == cRubyText)
            {
                sBaseTmp.clear();
                pNewValues[i].Value <<= sBaseTmp;
            }
        }

        aRubyValues = std::move(aNewRubyValues);
    }

    bool IsSelectionMono()
    {
        if (!xBreak.is())
        {
            // Cannot continue if BreakIterator is not available
            // Disable the button
            return true;
        }

        // Locale does not matter in this case; default ICU BreakIterator is sufficient
        Locale aLocale;

        OUString sBaseTmp;
        return std::all_of(
            aRubyValues.begin(), aRubyValues.end(), [&](const PropertyValues& rVals) {
                return !std::any_of(rVals.begin(), rVals.end(), [&](const PropertyValue& rVal) {
                    if (rVal.Name == cRubyBaseText)
                    {
                        rVal.Value >>= sBaseTmp;
                        sal_Int32 nDone = 0;
                        auto nPos = xBreak->nextCharacters(
                            sBaseTmp, 0, aLocale, css::i18n::CharacterIteratorMode::SKIPCELL, 1,
                            nDone);
                        return nPos < sBaseTmp.getLength();
                    }

                    return false;
                });
            });
    }

    void MakeSelectionMono()
    {
        if (!xBreak.is())
        {
            // Cannot continue if BreakIterator is not available
            return;
        }

        // Locale does not matter in this case; default ICU BreakIterator is sufficient
        Locale aLocale;

        OUString sBaseTmp;

        // Count the grapheme clusters
        sal_Int32 nTotalGraphemeClusters = 0;
        for (const PropertyValues& rVals : aRubyValues)
        {
            for (const PropertyValue& rVal : rVals)
            {
                if (rVal.Name == cRubyBaseText)
                {
                    rVal.Value >>= sBaseTmp;

                    sal_Int32 nPos = 0;
                    while (nPos < sBaseTmp.getLength())
                    {
                        sal_Int32 nDone = 0;
                        nPos = xBreak->nextCharacters(sBaseTmp, nPos, aLocale,
                                                      css::i18n::CharacterIteratorMode::SKIPCELL, 1,
                                                      nDone);
                        ++nTotalGraphemeClusters;
                    }
                }
            }
        }

        // Put each grapheme cluster in its own entry
        Sequence<PropertyValues> aNewRubyValues{ nTotalGraphemeClusters };
        PropertyValues* pNewRubyValues = aNewRubyValues.getArray();

        sal_Int32 nCurrGraphemeCluster = 0;
        for (const PropertyValues& rVals : aRubyValues)
        {
            for (const PropertyValue& rVal : rVals)
            {
                if (rVal.Name == cRubyBaseText)
                {
                    rVal.Value >>= sBaseTmp;

                    sal_Int32 nPos = 0;
                    while (nPos < sBaseTmp.getLength())
                    {
                        sal_Int32 nDone = 0;
                        auto nNextPos = xBreak->nextCharacters(
                            sBaseTmp, nPos, aLocale, css::i18n::CharacterIteratorMode::SKIPCELL, 1,
                            nDone);

                        PropertyValues& rNewVals = pNewRubyValues[nCurrGraphemeCluster++];

                        // Initialize new property values with values from current run
                        rNewVals = rVals;

                        PropertyValue* aNewVals = rNewVals.getArray();
                        for (sal_Int32 i = 0; i < rNewVals.getLength(); ++i)
                        {
                            PropertyValue& rNewVal = aNewVals[i];

                            if (rNewVal.Name == cRubyText)
                            {
                                rNewVal.Value <<= OUString{};
                            }
                            else if (rNewVal.Name == cRubyBaseText)
                            {
                                rNewVal.Value <<= sBaseTmp.copy(nPos, nNextPos - nPos);
                            }
                        }

                        nPos = nNextPos;
                    }
                }
            }
        }

        aRubyValues = std::move(aNewRubyValues);
    }
};

SvxRubyData_Impl::SvxRubyData_Impl()
    : bHasSelectionChanged(false)
    , bDisposing(false)
{
    const Reference<XComponentContext>& xContext = ::comphelper::getProcessComponentContext();
    xBreak = css::i18n::BreakIterator::create(xContext);
}

SvxRubyData_Impl::~SvxRubyData_Impl() {}

void SvxRubyData_Impl::SetController(const Reference<XController>& xCtrl)
{
    if (xCtrl.get() == xController.get())
        return;

    try
    {
        Reference<XSelectionSupplier> xSelSupp(xController, UNO_QUERY);
        if (xSelSupp.is())
            xSelSupp->removeSelectionChangeListener(this);

        bHasSelectionChanged = true;
        xController = xCtrl;
        xSelSupp.set(xController, UNO_QUERY);
        if (xSelSupp.is())
            xSelSupp->addSelectionChangeListener(this);
    }
    catch (const Exception&)
    {
    }
}

void SvxRubyData_Impl::selectionChanged(const EventObject&) { bHasSelectionChanged = true; }

void SvxRubyData_Impl::disposing(const EventObject&)
{
    try
    {
        Reference<XSelectionSupplier> xSelSupp(xController, UNO_QUERY);
        if (xSelSupp.is())
            xSelSupp->removeSelectionChangeListener(this);
    }
    catch (const Exception&)
    {
    }
    xController = nullptr;
    bDisposing = true;
}

void SvxRubyData_Impl::AssertOneEntry()
{
    //create one entry
    if (!aRubyValues.hasElements())
    {
        aRubyValues.realloc(1);
        Sequence<PropertyValue>& rValues = aRubyValues.getArray()[0];
        rValues.realloc(5);
        PropertyValue* pValues = rValues.getArray();
        pValues[0].Name = cRubyBaseText;
        pValues[1].Name = cRubyText;
        pValues[2].Name = cRubyAdjust;
        pValues[3].Name = cRubyPosition;
        pValues[4].Name = cRubyCharStyleName;
    }
}

SvxRubyDialog::SvxRubyDialog(SfxBindings* pBind, SfxChildWindow* pCW, weld::Window* pParent)
    : SfxModelessDialogController(pBind, pCW, pParent, u"svx/ui/asianphoneticguidedialog.ui"_ustr,
                                  u"AsianPhoneticGuideDialog"_ustr)
    , nLastPos(0)
    , nCurrentEdit(0)
    , bModified(false)
    , pBindings(pBind)
    , m_pImpl(new SvxRubyData_Impl)
    , m_xLeft1ED(m_xBuilder->weld_entry(u"Left1ED"_ustr))
    , m_xRight1ED(m_xBuilder->weld_entry(u"Right1ED"_ustr))
    , m_xLeft2ED(m_xBuilder->weld_entry(u"Left2ED"_ustr))
    , m_xRight2ED(m_xBuilder->weld_entry(u"Right2ED"_ustr))
    , m_xLeft3ED(m_xBuilder->weld_entry(u"Left3ED"_ustr))
    , m_xRight3ED(m_xBuilder->weld_entry(u"Right3ED"_ustr))
    , m_xLeft4ED(m_xBuilder->weld_entry(u"Left4ED"_ustr))
    , m_xRight4ED(m_xBuilder->weld_entry(u"Right4ED"_ustr))
    , m_xScrolledWindow(m_xBuilder->weld_scrolled_window(u"scrolledwindow"_ustr, true))
    , m_xAdjustLB(m_xBuilder->weld_combo_box(u"adjustlb"_ustr))
    , m_xPositionLB(m_xBuilder->weld_combo_box(u"positionlb"_ustr))
    , m_xCharStyleFT(m_xBuilder->weld_label(u"styleft"_ustr))
    , m_xCharStyleLB(m_xBuilder->weld_combo_box(u"stylelb"_ustr))
    , m_xStylistPB(m_xBuilder->weld_button(u"styles"_ustr))
    , m_xSelectionGroupPB(m_xBuilder->weld_button(u"selection-group"_ustr))
    , m_xSelectionMonoPB(m_xBuilder->weld_button(u"selection-mono"_ustr))
    , m_xApplyPB(m_xBuilder->weld_button(u"ok"_ustr))
    , m_xClosePB(m_xBuilder->weld_button(u"close"_ustr))
    , m_xContentArea(m_xDialog->weld_content_area())
    , m_xGrid(m_xBuilder->weld_widget(u"grid"_ustr))
    , m_xPreviewWin(new RubyPreview)
    , m_xPreview(new weld::CustomWeld(*m_xBuilder, u"preview"_ustr, *m_xPreviewWin))
{
    m_xCharStyleLB->make_sorted();
    m_xPreviewWin->setRubyDialog(this);
    m_xScrolledWindow->set_size_request(-1, m_xGrid->get_preferred_size().Height());
    m_xScrolledWindow->set_vpolicy(VclPolicyType::NEVER);

    aEditArr[0] = m_xLeft1ED.get();
    aEditArr[1] = m_xRight1ED.get();
    aEditArr[2] = m_xLeft2ED.get();
    aEditArr[3] = m_xRight2ED.get();
    aEditArr[4] = m_xLeft3ED.get();
    aEditArr[5] = m_xRight3ED.get();
    aEditArr[6] = m_xLeft4ED.get();
    aEditArr[7] = m_xRight4ED.get();

    m_xSelectionGroupPB->connect_clicked(LINK(this, SvxRubyDialog, SelectionGroup_Impl));
    m_xSelectionMonoPB->connect_clicked(LINK(this, SvxRubyDialog, SelectionMono_Impl));
    m_xApplyPB->connect_clicked(LINK(this, SvxRubyDialog, ApplyHdl_Impl));
    m_xClosePB->connect_clicked(LINK(this, SvxRubyDialog, CloseHdl_Impl));
    m_xStylistPB->connect_clicked(LINK(this, SvxRubyDialog, StylistHdl_Impl));
    m_xAdjustLB->connect_changed(LINK(this, SvxRubyDialog, AdjustHdl_Impl));
    m_xPositionLB->connect_changed(LINK(this, SvxRubyDialog, PositionHdl_Impl));
    m_xCharStyleLB->connect_changed(LINK(this, SvxRubyDialog, CharStyleHdl_Impl));

    Link<weld::ScrolledWindow&, void> aScrLk(LINK(this, SvxRubyDialog, ScrollHdl_Impl));
    m_xScrolledWindow->connect_vadjustment_changed(aScrLk);

    Link<weld::Entry&, void> aEditLk(LINK(this, SvxRubyDialog, EditModifyHdl_Impl));
    Link<weld::Widget&, void> aFocusLk(LINK(this, SvxRubyDialog, EditFocusHdl_Impl));
    Link<const KeyEvent&, bool> aKeyUpDownLk(LINK(this, SvxRubyDialog, KeyUpDownHdl_Impl));
    Link<const KeyEvent&, bool> aKeyTabUpDownLk(LINK(this, SvxRubyDialog, KeyUpDownTabHdl_Impl));
    for (sal_uInt16 i = 0; i < 8; i++)
    {
        aEditArr[i]->connect_changed(aEditLk);
        aEditArr[i]->connect_focus_in(aFocusLk);
        if (!i || 7 == i)
            aEditArr[i]->connect_key_press(aKeyTabUpDownLk);
        else
            aEditArr[i]->connect_key_press(aKeyUpDownLk);
    }
}

SvxRubyDialog::~SvxRubyDialog()
{
    ClearCharStyleList();
    EventObject aEvent;
    m_pImpl->disposing(aEvent);
}

void SvxRubyDialog::ClearCharStyleList() { m_xCharStyleLB->clear(); }

void SvxRubyDialog::Close()
{
    if (IsClosing())
        return;
    SfxViewFrame* pViewFrame = SfxViewFrame::Current();
    if (pViewFrame)
        pViewFrame->ToggleChildWindow(SID_RUBY_DIALOG);
}

void SvxRubyDialog::Activate()
{
    SfxModelessDialogController::Activate();
    if (m_pImpl->IsDisposing())
    {
        // tdf#141967/tdf#152495 if Activate is called during tear down bail early
        return;
    }

    //get selection from current view frame
    SfxViewFrame* pCurFrm = SfxViewFrame::Current();
    Reference<XController> xCtrl(pCurFrm ? pCurFrm->GetFrame().GetController() : nullptr);
    m_pImpl->SetController(xCtrl);
    if (!m_pImpl->HasSelectionChanged())
        return;

    Reference<XRubySelection> xRubySel = m_pImpl->GetRubySelection();
    m_pImpl->UpdateRubyValues();
    EnableControls(xRubySel.is());
    if (xRubySel.is())
    {
        Reference<XModel> xModel = m_pImpl->GetModel();
        const OUString sCharStyleSelect = m_xCharStyleLB->get_active_text();
        ClearCharStyleList();
        Reference<XStyleFamiliesSupplier> xSupplier(xModel, UNO_QUERY);
        if (xSupplier.is())
        {
            try
            {
                Reference<XNameAccess> xFam = xSupplier->getStyleFamilies();
                Any aChar = xFam->getByName(u"CharacterStyles"_ustr);
                Reference<XNameContainer> xChar;
                aChar >>= xChar;
                Reference<XIndexAccess> xCharIdx(xChar, UNO_QUERY);
                if (xCharIdx.is())
                {
                    OUString sUIName(u"DisplayName"_ustr);
                    for (sal_Int32 nStyle = 0; nStyle < xCharIdx->getCount(); nStyle++)
                    {
                        Any aStyle = xCharIdx->getByIndex(nStyle);
                        Reference<XStyle> xStyle;
                        aStyle >>= xStyle;
                        Reference<XPropertySet> xPrSet(xStyle, UNO_QUERY);
                        OUString sName, sCoreName;
                        if (xPrSet.is())
                        {
                            Reference<XPropertySetInfo> xInfo = xPrSet->getPropertySetInfo();
                            if (xInfo->hasPropertyByName(sUIName))
                            {
                                Any aName = xPrSet->getPropertyValue(sUIName);
                                aName >>= sName;
                            }
                        }
                        if (xStyle.is())
                        {
                            sCoreName = xStyle->getName();
                            if (sName.isEmpty())
                                sName = sCoreName;
                        }
                        if (!sName.isEmpty())
                        {
                            m_xCharStyleLB->append(sCoreName, sName);
                        }
                    }
                }
            }
            catch (const Exception&)
            {
                TOOLS_WARN_EXCEPTION("svx.dialog""exception in style access");
            }
            if (!sCharStyleSelect.isEmpty())
                m_xCharStyleLB->set_active_text(sCharStyleSelect);
        }
        m_xCharStyleLB->set_sensitive(xSupplier.is());
        m_xCharStyleFT->set_sensitive(xSupplier.is());
    }
    Update();
    m_xPreviewWin->Invalidate();
}

void SvxRubyDialog::SetRubyText(sal_Int32 nPos, weld::Entry& rLeft, weld::Entry&&nbsp;rRight)
{
    OUString sLeft, sRight;
    const Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
    bool bEnable = aRubyValues.getLength() > nPos;
    if (bEnable)
    {
        const Sequence<PropertyValue> aProps = aRubyValues.getConstArray()[nPos];
        for (const PropertyValue& rProp : aProps)
        {
            if (rProp.Name == cRubyBaseText)
                rProp.Value >>= sLeft;
            else if (rProp.Name == cRubyText)
                rProp.Value >>= sRight;
        }
    }
    else if (!nPos)
    {
        bEnable = true;
    }
    rLeft.set_sensitive(bEnable);
    rRight.set_sensitive(bEnable);
    rLeft.set_text(sLeft);
    rRight.set_text(sRight);
    rLeft.save_value();
    rRight.save_value();
}

void SvxRubyDialog::GetRubyText()
{
    tools::Long nTempLastPos = GetLastPos();
    Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
    auto aRubyValuesRange = asNonConstRange(aRubyValues);
    for (int i = 0; i < 8; i += 2)
    {
        if (aEditArr[i]->get_sensitive()
            && (aEditArr[i]->get_value_changed_from_saved()
                || aEditArr[i + 1]->get_value_changed_from_saved()))
        {
            DBG_ASSERT(aRubyValues.getLength() > (i / 2 + nTempLastPos), "wrong index");
            SetModified(true);
            for (PropertyValue& propVal : asNonConstRange(aRubyValuesRange[i / 2 + nTempLastPos]))
            {
                if (propVal.Name == cRubyBaseText)
                    propVal.Value <<= aEditArr[i]->get_text();
                else if (propVal.Name == cRubyText)
                    propVal.Value <<= aEditArr[i + 1]->get_text();
            }
        }
    }
}

void SvxRubyDialog::Update()
{
    // Only enable selection grouping options when they can be applied
    m_xSelectionGroupPB->set_sensitive(!m_pImpl->IsSelectionGrouped());
    m_xSelectionMonoPB->set_sensitive(!m_pImpl->IsSelectionMono());

    const Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
    sal_Int32 nLen = aRubyValues.getLength();
    m_xScrolledWindow->vadjustment_configure(0, 0, !nLen ? 1 : nLen, 1, 4, 4);
    if (nLen > 4)
        m_xScrolledWindow->set_vpolicy(VclPolicyType::ALWAYS);
    else
        m_xScrolledWindow->set_vpolicy(VclPolicyType::NEVER);
    SetLastPos(0);
    SetModified(false);

    sal_Int16 nAdjust = -1;
    sal_Int16 nPosition = -1;
    OUString sCharStyleName, sTmp;
    bool bCharStyleEqual = true;
    for (sal_Int32 nRuby = 0; nRuby < nLen; nRuby++)
    {
        const Sequence<PropertyValue>& rProps = aRubyValues.getConstArray()[nRuby];
        for (const PropertyValue& rProp : rProps)
        {
            if (nAdjust > -2 && rProp.Name == cRubyAdjust)
            {
                sal_Int16 nTmp = sal_Int16();
                rProp.Value >>= nTmp;
                if (!nRuby)
                    nAdjust = nTmp;
                else if (nAdjust != nTmp)
                    nAdjust = -2;
            }
            if (nPosition > -2 && rProp.Name == cRubyPosition)
            {
                sal_Int16 nTmp = sal_Int16();
                rProp.Value >>= nTmp;
                if (!nRuby)
                    nPosition = nTmp;
                else if (nPosition != nTmp)
                    nPosition = -2;
            }
            if (bCharStyleEqual && rProp.Name == cRubyCharStyleName)
            {
                rProp.Value >>= sTmp;
                if (!nRuby)
                    sCharStyleName = sTmp;
                else if (sCharStyleName != sTmp)
                    bCharStyleEqual = false;
            }
        }
    }
    if (!nLen)
    {
        //enable selection if the ruby list is empty
        nAdjust = 0;
        nPosition = 0;
    }
    if (nAdjust > -1)
        m_xAdjustLB->set_active(nAdjust);
    else
        m_xAdjustLB->set_active(-1);
    if (nPosition > -1)
        m_xPositionLB->set_active(nPosition);
    if (!nLen || (bCharStyleEqual && sCharStyleName.isEmpty()))
        sCharStyleName = "Rubies";
    if (!sCharStyleName.isEmpty())
    {
        for (int i = 0, nEntryCount = m_xCharStyleLB->get_count(); i < nEntryCount; i++)
        {
            OUString sCoreName = m_xCharStyleLB->get_id(i);
            if (sCharStyleName == sCoreName)
            {
                m_xCharStyleLB->set_active(i);
                break;
            }
        }
    }
    else
        m_xCharStyleLB->set_active(-1);

    ScrollHdl_Impl(*m_xScrolledWindow);
}

void SvxRubyDialog::GetCurrentText(OUString& rBase, OUString& rRuby)
{
    rBase = aEditArr[nCurrentEdit * 2]->get_text();
    rRuby = aEditArr[nCurrentEdit * 2 + 1]->get_text();
}

IMPL_LINK(SvxRubyDialog, ScrollHdl_Impl, weld::ScrolledWindow&, rScroll, void)
{
    int nPos = rScroll.vadjustment_get_value();
    if (GetLastPos() != nPos)
    {
        GetRubyText();
    }
    SetRubyText(nPos++, *m_xLeft1ED, *m_xRight1ED);
    SetRubyText(nPos++, *m_xLeft2ED, *m_xRight2ED);
    SetRubyText(nPos++, *m_xLeft3ED, *m_xRight3ED);
    SetRubyText(nPos, *m_xLeft4ED, *m_xRight4ED);
    SetLastPos(nPos - 3);
    m_xPreviewWin->Invalidate();
}

IMPL_LINK_NOARG(SvxRubyDialog, SelectionGroup_Impl, weld::Button&, void)
{
    m_pImpl->MakeSelectionGrouped();
    Update();
}

IMPL_LINK_NOARG(SvxRubyDialog, SelectionMono_Impl, weld::Button&, void)
{
    m_pImpl->MakeSelectionMono();
    Update();
}

IMPL_LINK_NOARG(SvxRubyDialog, ApplyHdl_Impl, weld::Button&, void)
{
    const Sequence<PropertyValues>& aRubyValues = m_pImpl->GetRubyValues();
    if (!aRubyValues.hasElements())
    {
        AssertOneEntry();
        PositionHdl_Impl(*m_xPositionLB);
        AdjustHdl_Impl(*m_xAdjustLB);
        CharStyleHdl_Impl(*m_xCharStyleLB);
    }
    GetRubyText();
    //reset all edit fields - SaveValue is called
    ScrollHdl_Impl(*m_xScrolledWindow);

    Reference<XRubySelection> xSelection = m_pImpl->GetRubySelection();
    if (IsModified() && xSelection.is())
    {
        try
        {
            xSelection->setRubyList(aRubyValues, false);
        }
        catch (const Exception&)
        {
            TOOLS_WARN_EXCEPTION("svx.dialog""");
        }
    }
}

IMPL_LINK_NOARG(SvxRubyDialog, CloseHdl_Impl, weld::Button&, void) { Close(); }

IMPL_LINK_NOARG(SvxRubyDialog, StylistHdl_Impl, weld::Button&, void)
{
    std::unique_ptr<SfxBoolItem> pState;
    SfxItemState eState = pBindings->QueryState(SID_STYLE_DESIGNER, pState);
    if (eState <= SfxItemState::SET || !pState || !pState->GetValue())
    {
        pBindings->GetDispatcher()->Execute(SID_STYLE_DESIGNER,
                                            SfxCallMode::ASYNCHRON | SfxCallMode::RECORD);
    }
}

IMPL_LINK(SvxRubyDialog, AdjustHdl_Impl, weld::ComboBox&, rBox, void)
{
    AssertOneEntry();
    sal_Int16 nAdjust = rBox.get_active();
    for (PropertyValues& rProps : asNonConstRange(m_pImpl->GetRubyValues()))
    {
        for (PropertyValue& propVal : asNonConstRange(rProps))
        {
            if (propVal.Name == cRubyAdjust)
                propVal.Value <<= nAdjust;
        }
        SetModified(true);
    }
    m_xPreviewWin->Invalidate();
}

IMPL_LINK(SvxRubyDialog, PositionHdl_Impl, weld::ComboBox&, rBox, void)
{
    AssertOneEntry();
    sal_Int16 nPosition = rBox.get_active();
    for (PropertyValues& rProps : asNonConstRange(m_pImpl->GetRubyValues()))
    {
        for (PropertyValue& propVal : asNonConstRange(rProps))
        {
            if (propVal.Name == cRubyPosition)
                propVal.Value <<= nPosition;
        }
        SetModified(true);
    }
    m_xPreviewWin->Invalidate();
}

IMPL_LINK_NOARG(SvxRubyDialog, CharStyleHdl_Impl, weld::ComboBox&, void)
{
    AssertOneEntry();
    OUString sStyleName;
    if (m_xCharStyleLB->get_active() != -1)
        sStyleName = m_xCharStyleLB->get_active_id();
    for (PropertyValues& rProps : asNonConstRange(m_pImpl->GetRubyValues()))
    {
        for (PropertyValue& propVal : asNonConstRange(rProps))
        {
            if (propVal.Name == cRubyCharStyleName)
            {
                propVal.Value <<= sStyleName;
            }
        }
        SetModified(true);
    }
}

IMPL_LINK(SvxRubyDialog, EditFocusHdl_Impl, weld::Widget&, rEdit, void)
{
    for (sal_uInt16 i = 0; i < 8; i++)
    {
        if (&rEdit == aEditArr[i])
        {
            nCurrentEdit = i / 2;
            break;
        }
    }
    m_xPreviewWin->Invalidate();
}

IMPL_LINK(SvxRubyDialog, EditModifyHdl_Impl, weld::Entry&, rEdit, void)
{
    EditFocusHdl_Impl(rEdit);
}

bool SvxRubyDialog::EditScrollHdl_Impl(sal_Int32 nParam)
{
    bool bRet = false;
    //scroll forward
    if (nParam > 0 && (aEditArr[7]->has_focus() || aEditArr[6]->has_focus()))
    {
        if (m_xScrolledWindow->vadjustment_get_upper()
            > m_xScrolledWindow->vadjustment_get_value()
                  + m_xScrolledWindow->vadjustment_get_page_size())
        {
            m_xScrolledWindow->vadjustment_set_value(m_xScrolledWindow->vadjustment_get_value()
                                                     + 1);
            aEditArr[6]->grab_focus();
            bRet = true;
        }
    }
    //scroll backward
    else if (m_xScrolledWindow->vadjustment_get_value()
             && (aEditArr[0]->has_focus() || aEditArr[1]->has_focus()))
    {
        m_xScrolledWindow->vadjustment_set_value(m_xScrolledWindow->vadjustment_get_value() - 1);
        aEditArr[1]->grab_focus();
        bRet = true;
    }
    if (bRet)
        ScrollHdl_Impl(*m_xScrolledWindow);
    return bRet;
}

bool SvxRubyDialog::EditJumpHdl_Impl(sal_Int32 nParam)
{
    bool bHandled = false;
    sal_uInt16 nIndex = USHRT_MAX;
    for (sal_uInt16 i = 0; i < 8; i++)
    {
        if (aEditArr[i]->has_focus())
            nIndex = i;
    }
    if (nIndex < 8)
    {
        if (nParam > 0)
        {
            if (nIndex < 6)
                aEditArr[nIndex + 2]->grab_focus();
            else if (EditScrollHdl_Impl(nParam))
                aEditArr[nIndex]->grab_focus();
        }
        else
        {
            if (nIndex > 1)
                aEditArr[nIndex - 2]->grab_focus();
            else if (EditScrollHdl_Impl(nParam))
                aEditArr[nIndex]->grab_focus();
        }
        bHandled = true;
    }
    return bHandled;
}

void SvxRubyDialog::AssertOneEntry() { m_pImpl->AssertOneEntry(); }

void SvxRubyDialog::EnableControls(bool bEnable)
{
    m_xContentArea->set_sensitive(bEnable);
    m_xApplyPB->set_sensitive(bEnable);
}

RubyPreview::RubyPreview()
    : m_pParentDlg(nullptr)
{
}

RubyPreview::~RubyPreview() {}

void RubyPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/)
{
    rRenderContext.Push(vcl::PushFlags::ALL);

    rRenderContext.SetMapMode(MapMode(MapUnit::MapTwip));

    Size aWinSize = rRenderContext.GetOutputSize();

    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
    svtools::ColorConfig aColorConfig;

    Color aNewTextColor(aColorConfig.GetColorValue(svtools::FONTCOLOR).nColor);
    Color aNewFillColor(rStyleSettings.GetWindowColor());

    vcl::Font aFont = rRenderContext.GetFont();
    aFont.SetFontHeight(aWinSize.Height() / 4);
    aFont.SetFillColor(aNewFillColor);
    aFont.SetColor(aNewTextColor);
    rRenderContext.SetFont(aFont);

    tools::Rectangle aRect(Point(0, 0), aWinSize);
    rRenderContext.SetLineColor();
    rRenderContext.SetFillColor(aFont.GetFillColor());
    rRenderContext.DrawRect(aRect);

    OUString sBaseText, sRubyText;
    m_pParentDlg->GetCurrentText(sBaseText, sRubyText);

    tools::Long nTextHeight = rRenderContext.GetTextHeight();
    tools::Long nBaseWidth = rRenderContext.GetTextWidth(sBaseText);

    vcl::Font aRubyFont(aFont);
    aRubyFont.SetFontHeight(aRubyFont.GetFontHeight() * 70 / 100);
    rRenderContext.SetFont(aRubyFont);
    tools::Long nRubyWidth = rRenderContext.GetTextWidth(sRubyText);
    rRenderContext.SetFont(aFont);

    RubyAdjust nAdjust = static_cast<RubyAdjust>(m_pParentDlg->m_xAdjustLB->get_active());
    //use center if no adjustment is available
    if (nAdjust > RubyAdjust_INDENT_BLOCK)
        nAdjust = RubyAdjust_CENTER;

    //which part is stretched ?
    bool bRubyStretch = nBaseWidth >= nRubyWidth;

    tools::Long nCenter = aWinSize.Width() / 2;
    tools::Long nHalfWidth = std::max(nBaseWidth, nRubyWidth) / 2;
    tools::Long nLeftStart = nCenter - nHalfWidth;
    tools::Long nRightEnd = nCenter + nHalfWidth;

    // Default values for TOP or no selection
    tools::Long nYRuby = aWinSize.Height() / 4 - nTextHeight / 2;
    tools::Long nYBase = aWinSize.Height() * 3 / 4 - nTextHeight / 2;

    sal_Int16 nRubyPos = m_pParentDlg->m_xPositionLB->get_active();
    if (nRubyPos == 1) // BOTTOM
        std::swap(nYRuby, nYBase);
    else if (nRubyPos == 2) // RIGHT ( vertically )
    {
        // Align the ruby text and base text to the vertical center.
        nYBase = (aWinSize.Height() - nTextHeight) / 2;
        nYRuby = (aWinSize.Height() - nRubyWidth) / 2;

        // Align the ruby text at the right side of the base text
        nAdjust = RubyAdjust_RIGHT;
        nHalfWidth = nBaseWidth / 2;
        nLeftStart = nCenter - nHalfWidth;
        nRightEnd = nCenter + nHalfWidth + nRubyWidth + nTextHeight;
        // Render base text first, then render ruby text on the right.
        bRubyStretch = true;

        aRubyFont.SetVertical(true);
        aRubyFont.SetOrientation(2700_deg10);
    }

    tools::Long nYOutput;
    tools::Long nOutTextWidth;
    OUString sOutputText;

    if (bRubyStretch)
    {
        rRenderContext.DrawText(Point(nLeftStart, nYBase), sBaseText);
        nYOutput = nYRuby;
        sOutputText = sRubyText;
        nOutTextWidth = nRubyWidth;
        rRenderContext.SetFont(aRubyFont);
    }
    else
    {
        rRenderContext.SetFont(aRubyFont);
        rRenderContext.DrawText(Point(nLeftStart, nYRuby), sRubyText);
        nYOutput = nYBase;
        sOutputText = sBaseText;
        nOutTextWidth = nBaseWidth;
        rRenderContext.SetFont(aFont);
    }

    switch (nAdjust)
    {
        case RubyAdjust_LEFT:
            rRenderContext.DrawText(Point(nLeftStart, nYOutput), sOutputText);
            break;
        case RubyAdjust_RIGHT:
            rRenderContext.DrawText(Point(nRightEnd - nOutTextWidth, nYOutput), sOutputText);
            break;
        case RubyAdjust_INDENT_BLOCK:
        {
            tools::Long nCharWidth = rRenderContext.GetTextWidth(u"X"_ustr);
            if (nOutTextWidth < (nRightEnd - nLeftStart - nCharWidth))
            {
                nCharWidth /= 2;
                nLeftStart += nCharWidth;
                nRightEnd -= nCharWidth;
            }
            [[fallthrough]];
        }
        case RubyAdjust_BLOCK:
        {
            if (sOutputText.getLength() > 1)
            {
                sal_Int32 nCount = sOutputText.getLength();
                tools::Long nSpace
                    = ((nRightEnd - nLeftStart) - rRenderContext.GetTextWidth(sOutputText))
                      / (nCount - 1);
                for (sal_Int32 i = 0; i < nCount; i++)
                {
                    OUString sChar(sOutputText[i]);
                    rRenderContext.DrawText(Point(nLeftStart, nYOutput), sChar);
                    tools::Long nCharWidth = rRenderContext.GetTextWidth(sChar);
                    nLeftStart += nCharWidth + nSpace;
                }
                break;
            }
            [[fallthrough]];
        }
        case RubyAdjust_CENTER:
            rRenderContext.DrawText(Point(nCenter - nOutTextWidth / 2, nYOutput), sOutputText);
            break;
        default:
            break;
    }
    rRenderContext.Pop();
}

void RubyPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
{
    pDrawingArea->set_size_request(pDrawingArea->get_approximate_digit_width() * 40,
                                   pDrawingArea->get_text_height() * 7);
    CustomWidgetController::SetDrawingArea(pDrawingArea);
}

IMPL_LINK(SvxRubyDialog, KeyUpDownHdl_Impl, const KeyEvent&, rKEvt, bool)
{
    bool bHandled = false;
    const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
    sal_uInt16 nCode = rKeyCode.GetCode();
    if (KEY_UP == nCode || KEY_DOWN == nCode)
    {
        sal_Int32 nParam = KEY_UP == nCode ? -1 : 1;
        bHandled = EditJumpHdl_Impl(nParam);
    }
    return bHandled;
}

IMPL_LINK(SvxRubyDialog, KeyUpDownTabHdl_Impl, const KeyEvent&, rKEvt, bool)
{
    bool bHandled = false;
    const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
    sal_uInt16 nMod = rKeyCode.GetModifier();
    sal_uInt16 nCode = rKeyCode.GetCode();
    if (nCode == KEY_TAB && (!nMod || KEY_SHIFT == nMod))
    {
        sal_Int32 nParam = KEY_SHIFT == nMod ? -1 : 1;
        if (EditScrollHdl_Impl(nParam))
            bHandled = true;
    }
    if (!bHandled)
        bHandled = KeyUpDownHdl_Impl(rKEvt);
    return bHandled;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=96 H=91 G=93

¤ Dauer der Verarbeitung: 0.11 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge