/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* 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 <vcl/field.hxx>
#include <vcl/fixed.hxx>
#include <vcl/settings.hxx>
#include <vcl/weld.hxx>
#include <i18nlangtag/mslangid.hxx>
#include <unotools/lingucfg.hxx>
#include <editeng/unolingu.hxx>
#include <svx/dlgutil.hxx>
#include <linguistic/lngprops.hxx>
#include <linguistic/misc.hxx>
#include <sfx2/sfxuno.hxx>
#include <sfx2/dispatch.hxx>
#include <tools/urlobj.hxx>
#include <o3tl/make_unique.hxx>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <comphelper/processfactory.hxx>
#include <com/sun/star/linguistic2/LinguServiceManager.hpp>
#include <com/sun/star/linguistic2/XSpellChecker.hpp>
#include <com/sun/star/linguistic2/XProofreader.hpp>
#include <com/sun/star/linguistic2/XHyphenator.hpp>
#include <com/sun/star/linguistic2/XThesaurus.hpp>
#include <com/sun/star/linguistic2/XAvailableLocales.hpp>
#include <com/sun/star/lang/XServiceDisplayName.hpp>
#include <com/sun/star/frame/XStorable.hpp>
#include <com/sun/star/ucb/CommandAbortedException.hpp>
#include <unotools/extendedsecurityoptions.hxx>
#include <svtools/svlbitm.hxx>
#include <svtools/treelistbox.hxx>
#include <svtools/treelistentry.hxx>
#include <svtools/langhelp.hxx>
#include <svl/eitem.hxx>
#include <svl/intitem.hxx>
#include <sfx2/viewfrm.hxx>
#include <vcl/svapp.hxx>
#include <sal/log.hxx>
#include <svx/svxdlg.hxx>
#include <editeng/optitems.hxx>
#include <optlingu.hxx>
#include <dialmgr.hxx>
#include <strings.hrc>
#include <ucbhelper/content.hxx>
#include <vector>
#include <map>
using namespace ::ucbhelper;
using namespace ::com::sun::star;
using namespace css::lang;
using namespace css::uno;
using namespace css::linguistic2;
using namespace css::beans;
#define CBCOL_FIRST 0
#define CBCOL_SECOND 1
static const sal_Char cSpell[] = SN_SPELLCHECKER;
static const sal_Char cGrammar[] = SN_GRAMMARCHECKER;
static const sal_Char cHyph[] = SN_HYPHENATOR;
static const sal_Char cThes[] = SN_THESAURUS;
// static ----------------------------------------------------------------
static std::vector< LanguageType > lcl_LocaleSeqToLangSeq( const Sequence< Locale > &rSeq )
{
sal_Int32 nLen = rSeq.getLength();
std::vector<LanguageType> aRes;
aRes.reserve(nLen);
const Locale *pSeq = rSeq.getConstArray();
for (sal_Int32 i = 0; i < nLen; ++i)
{
aRes.push_back( LanguageTag::convertToLanguageType( pSeq[i] ) );
}
return aRes;
}
static bool lcl_SeqHasLang( const std::vector< LanguageType > &rSeq, LanguageType nLang )
{
for (auto const & i : rSeq)
if (i == nLang)
return true;
return false;
}
static sal_Int32 lcl_SeqGetEntryPos(
const Sequence< OUString > &rSeq, const OUString &rEntry )
{
sal_Int32 i;
sal_Int32 nLen = rSeq.getLength();
const OUString *pItem = rSeq.getConstArray();
for (i = 0; i < nLen; ++i)
{
if (rEntry == pItem[i])
break;
}
return i < nLen ? i : -1;
}
bool KillFile_Impl( const OUString& rURL )
{
bool bRet = true;
try
{
Content aCnt( rURL, uno::Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
aCnt.executeCommand( "delete", Any( true ) );
}
catch( css::ucb::CommandAbortedException& )
{
SAL_WARN( "cui.options", "KillFile: CommandAbortedException" );
bRet = false;
}
catch( ... )
{
SAL_WARN( "cui.options", "KillFile: Any other exception" );
bRet = false;
}
return bRet;
}
// 0x 0p 0t 0c nn
// p: 1 -> parent
// t: 1 -> spell, 2 -> hyph, 3 -> thes, 4 -> grammar
// c: 1 -> checked 0 -> unchecked
// n: index
#define TYPE_SPELL sal_uInt8(1)
#define TYPE_GRAMMAR sal_uInt8(2)
#define TYPE_HYPH sal_uInt8(3)
#define TYPE_THES sal_uInt8(4)
class ModuleUserData_Impl
{
bool bParent;
bool bIsChecked;
sal_uInt8 nType;
sal_uInt8 nIndex;
OUString sImplName;
public:
ModuleUserData_Impl( const OUString& sImpName, bool bIsParent, bool bChecked, sal_uInt8 nSetType, sal_uInt8 nSetIndex ) :
bParent(bIsParent),
bIsChecked(bChecked),
nType(nSetType),
nIndex(nSetIndex),
sImplName(sImpName)
{
}
bool IsParent() const {return bParent;}
sal_uInt8 GetType() const {return nType;}
bool IsChecked() const {return bIsChecked;}
sal_uInt8 GetIndex() const {return nIndex;}
const OUString& GetImplName() const {return sImplName;}
};
// User for user-dictionaries (XDictionary interface)
class DicUserData
{
sal_uLong nVal;
public:
explicit DicUserData( sal_uLong nUserData ) : nVal( nUserData ) {}
DicUserData( sal_uInt16 nEID,
bool bChecked, bool bEditable, bool bDeletable );
sal_uLong GetUserData() const { return nVal; }
sal_uInt16 GetEntryId() const { return static_cast<sal_uInt16>(nVal >> 16); }
bool IsChecked() const { return static_cast<bool>((nVal >> 8) & 0x01); }
bool IsDeletable() const { return static_cast<bool>((nVal >> 10) & 0x01); }
};
DicUserData::DicUserData(
sal_uInt16 nEID,
bool bChecked, bool bEditable, bool bDeletable )
{
DBG_ASSERT( nEID < 65000, "Entry Id out of range" );
nVal = (static_cast<sal_uLong>(0xFFFF & nEID) << 16) |
(static_cast<sal_uLong>(bChecked ? 1 : 0) << 8) |
(static_cast<sal_uLong>(bEditable ? 1 : 0) << 9) |
(static_cast<sal_uLong>(bDeletable ? 1 : 0) << 10);
}
// class BrwString_Impl -------------------------------------------------
static void lcl_SetCheckButton( SvTreeListEntry* pEntry, bool bCheck )
{
SvLBoxButton* pItem = static_cast<SvLBoxButton*>(pEntry->GetFirstItem(SvLBoxItemType::Button));
DBG_ASSERT(pItem,"SetCheckButton:Item not found");
if (pItem && pItem->GetType() == SvLBoxItemType::Button)
{
if (bCheck)
pItem->SetStateChecked();
else
pItem->SetStateUnchecked();
}
}
class BrwStringDic_Impl : public SvLBoxString
{
public:
explicit BrwStringDic_Impl( const OUString& rStr ) : SvLBoxString( rStr ) {}
virtual void Paint(const Point& rPos, SvTreeListBox& rOutDev, vcl::RenderContext& rRenderContext,
const SvViewDataEntry* pView, const SvTreeListEntry& rEntry) override;
};
void BrwStringDic_Impl::Paint(const Point& rPos, SvTreeListBox& /*rDev*/, vcl::RenderContext& rRenderContext,
const SvViewDataEntry* /*pView*/, const SvTreeListEntry& rEntry)
{
ModuleUserData_Impl* pData = static_cast<ModuleUserData_Impl*>(rEntry.GetUserData());
Point aPos(rPos);
rRenderContext.Push(PushFlags::FONT);
if (pData->IsParent())
{
vcl::Font aFont(rRenderContext.GetFont());
aFont.SetWeight(WEIGHT_BOLD);
rRenderContext.SetFont(aFont);
aPos.setX( 0 );
}
else
aPos.AdjustX(5 );
rRenderContext.DrawText(aPos, GetText());
rRenderContext.Pop();
}
/*--------------------------------------------------
Entry IDs for options listbox of dialog
--------------------------------------------------*/
enum EID_OPTIONS
{
EID_SPELL_AUTO,
EID_GRAMMAR_AUTO,
EID_CAPITAL_WORDS,
EID_WORDS_WITH_DIGITS,
EID_SPELL_SPECIAL,
EID_NUM_MIN_WORDLEN,
EID_NUM_PRE_BREAK,
EID_NUM_POST_BREAK,
EID_HYPH_AUTO,
EID_HYPH_SPECIAL
};
//! this array must have an entry for every value of EID_OPTIONS.
// It is used to get the respective property name.
static const char * aEidToPropName[] =
{
UPN_IS_SPELL_AUTO, // EID_SPELL_AUTO
UPN_IS_GRAMMAR_AUTO, // EID_GRAMMAR_AUTO
UPN_IS_SPELL_UPPER_CASE, // EID_CAPITAL_WORDS
UPN_IS_SPELL_WITH_DIGITS, // EID_WORDS_WITH_DIGITS
UPN_IS_SPELL_SPECIAL, // EID_SPELL_SPECIAL
UPN_HYPH_MIN_WORD_LENGTH, // EID_NUM_MIN_WORDLEN,
UPN_HYPH_MIN_LEADING, // EID_NUM_PRE_BREAK
UPN_HYPH_MIN_TRAILING, // EID_NUM_POST_BREAK
UPN_IS_HYPH_AUTO, // EID_HYPH_AUTO
UPN_IS_HYPH_SPECIAL // EID_HYPH_SPECIAL
};
static inline OUString lcl_GetPropertyName( EID_OPTIONS eEntryId )
{
DBG_ASSERT( static_cast<unsigned int>(eEntryId) < SAL_N_ELEMENTS(aEidToPropName), "index out of range" );
return OUString::createFromAscii( aEidToPropName[ static_cast<int>(eEntryId) ] );
}
class OptionsBreakSet : public weld::GenericDialogController
{
std::unique_ptr<weld::Widget> m_xBeforeFrame;
std::unique_ptr<weld::Widget> m_xAfterFrame;
std::unique_ptr<weld::Widget> m_xMinimalFrame;
std::unique_ptr<weld::SpinButton> m_xBreakNF;
public:
OptionsBreakSet(weld::Window* pParent, sal_uInt16 nRID)
: GenericDialogController(pParent, "cui/ui/breaknumberoption.ui", "BreakNumberOption")
, m_xBeforeFrame(m_xBuilder->weld_widget("beforeframe"))
, m_xAfterFrame(m_xBuilder->weld_widget("afterframe"))
, m_xMinimalFrame(m_xBuilder->weld_widget("miniframe"))
{
assert(EID_NUM_PRE_BREAK == nRID || EID_NUM_POST_BREAK == nRID || EID_NUM_MIN_WORDLEN == nRID); //unexpected ID
if (nRID == EID_NUM_PRE_BREAK)
{
m_xBeforeFrame->show();
m_xBreakNF = m_xBuilder->weld_spin_button("beforebreak");
}
else if(nRID == EID_NUM_POST_BREAK)
{
m_xAfterFrame->show();
m_xBreakNF = m_xBuilder->weld_spin_button("afterbreak");
}
else if(nRID == EID_NUM_MIN_WORDLEN)
{
m_xMinimalFrame->show();
m_xBreakNF = m_xBuilder->weld_spin_button("wordlength");
}
}
weld::SpinButton& GetNumericFld()
{
return *m_xBreakNF;
}
};
// class OptionsUserData -------------------------------------------------
class OptionsUserData
{
sal_uLong nVal;
public:
explicit OptionsUserData( sal_uLong nUserData ) : nVal( nUserData ) {}
OptionsUserData( sal_uInt16 nEID,
bool bHasNV, sal_uInt16 nNumVal,
bool bCheckable, bool bChecked );
sal_uLong GetUserData() const { return nVal; }
sal_uInt16 GetEntryId() const { return static_cast<sal_uInt16>(nVal >> 16); }
bool HasNumericValue() const { return static_cast<bool>((nVal >> 10) & 0x01); }
sal_uInt16 GetNumericValue() const { return static_cast<sal_uInt16>(nVal & 0xFF); }
bool IsCheckable() const { return static_cast<bool>((nVal >> 9) & 0x01); }
bool IsModified() const { return static_cast<bool>((nVal >> 11) & 0x01); }
void SetNumericValue( sal_uInt8 nNumVal );
};
OptionsUserData::OptionsUserData( sal_uInt16 nEID,
bool bHasNV, sal_uInt16 nNumVal,
bool bCheckable, bool bChecked )
{
DBG_ASSERT( nEID < 65000, "Entry Id out of range" );
DBG_ASSERT( nNumVal < 256, "value out of range" );
nVal = (static_cast<sal_uLong>(0xFFFF & nEID) << 16) |
(static_cast<sal_uLong>(bHasNV ? 1 : 0) << 10) |
(static_cast<sal_uLong>(bCheckable ? 1 : 0) << 9) |
(static_cast<sal_uLong>(bChecked ? 1 : 0) << 8) |
static_cast<sal_uLong>(0xFF & nNumVal);
}
void OptionsUserData::SetNumericValue( sal_uInt8 nNumVal )
{
if (HasNumericValue() && (GetNumericValue() != nNumVal))
{
nVal &= 0xffffff00;
nVal |= nNumVal;
nVal |= sal_uLong(1) << 11; // mark as modified
}
}
// class BrwString_Impl -------------------------------------------------
class BrwString_Impl : public SvLBoxString
{
public:
explicit BrwString_Impl( const OUString& rStr ) : SvLBoxString( rStr ) {}
virtual void Paint(const Point& rPos, SvTreeListBox& rOutDev, vcl::RenderContext& rRenderContext,
const SvViewDataEntry* pView, const SvTreeListEntry& rEntry) override;
};
void BrwString_Impl::Paint(const Point& rPos, SvTreeListBox& /*rDev*/, vcl::RenderContext& rRenderContext,
const SvViewDataEntry* /*pView*/, const SvTreeListEntry& rEntry)
{
Point aPos(rPos);
aPos.AdjustX(20 );
rRenderContext.DrawText(aPos, GetText());
if (rEntry.GetUserData())
{
Point aNewPos(aPos);
aNewPos.AdjustX(rRenderContext.GetTextWidth(GetText()) );
rRenderContext.Push(PushFlags::FONT);
vcl::Font aFont(rRenderContext.GetFont());
aFont.SetWeight(WEIGHT_BOLD);
//??? convert the lower byte from the user date into a string
OptionsUserData aData(reinterpret_cast<sal_uLong>(rEntry.GetUserData()));
if (aData.HasNumericValue())
{
OUString sTxt = " " + OUString::number(aData.GetNumericValue());
rRenderContext.SetFont(aFont);
rRenderContext.DrawText(aNewPos, sTxt);
}
rRenderContext.Pop();
}
}
// ServiceInfo_Impl ----------------------------------------------------
struct ServiceInfo_Impl
{
OUString sDisplayName;
OUString sSpellImplName;
OUString sHyphImplName;
OUString sThesImplName;
OUString sGrammarImplName;
uno::Reference< XSpellChecker > xSpell;
uno::Reference< XHyphenator > xHyph;
uno::Reference< XThesaurus > xThes;
uno::Reference< XProofreader > xGrammar;
bool bConfigured;
ServiceInfo_Impl() : bConfigured(false) {}
};
typedef std::vector< ServiceInfo_Impl > ServiceInfoArr;
typedef std::map< LanguageType, Sequence< OUString > > LangImplNameTable;
// SvxLinguData_Impl ----------------------------------------------------
class SvxLinguData_Impl
{
//contains services and implementation names sorted by implementation names
ServiceInfoArr aDisplayServiceArr;
sal_uLong nDisplayServices;
Sequence< Locale > aAllServiceLocales;
LangImplNameTable aCfgSpellTable;
LangImplNameTable aCfgHyphTable;
LangImplNameTable aCfgThesTable;
LangImplNameTable aCfgGrammarTable;
uno::Reference< XLinguServiceManager2 > xLinguSrvcMgr;
static bool AddRemove( Sequence< OUString > &rConfigured,
const OUString &rImplName, bool bAdd );
public:
SvxLinguData_Impl();
uno::Reference<XLinguServiceManager2> & GetManager() { return xLinguSrvcMgr; }
void SetChecked( const Sequence< OUString > &rConfiguredServices );
void Reconfigure( const OUString &rDisplayName, bool bEnable );
const Sequence<Locale> & GetAllSupportedLocales() const { return aAllServiceLocales; }
LangImplNameTable & GetSpellTable() { return aCfgSpellTable; }
LangImplNameTable & GetHyphTable() { return aCfgHyphTable; }
LangImplNameTable & GetThesTable() { return aCfgThesTable; }
LangImplNameTable & GetGrammarTable() { return aCfgGrammarTable; }
ServiceInfoArr & GetDisplayServiceArray() { return aDisplayServiceArr; }
const sal_uLong & GetDisplayServiceCount() const { return nDisplayServices; }
void SetDisplayServiceCount( sal_uLong nVal ) { nDisplayServices = nVal; }
// returns the list of service implementation names for the specified
// language and service (TYPE_SPELL, TYPE_HYPH, TYPE_THES) sorted in
// the proper order for the SvxEditModulesDlg (the ones from the
// configuration (keeping that order!) first and then the other ones.
// I.e. the ones available but not configured in arbitrary order).
// They available ones may contain names that do not(!) support that
// language.
Sequence< OUString > GetSortedImplNames( LanguageType nLang, sal_uInt8 nType );
ServiceInfo_Impl * GetInfoByImplName( const OUString &rSvcImplName );
};
static sal_Int32 lcl_SeqGetIndex( const Sequence< OUString > &rSeq, const OUString &rTxt )
{
sal_Int32 nRes = -1;
sal_Int32 nLen = rSeq.getLength();
const OUString *pString = rSeq.getConstArray();
for (sal_Int32 i = 0; i < nLen && nRes == -1; ++i)
{
if (pString[i] == rTxt)
nRes = i;
}
return nRes;
}
Sequence< OUString > SvxLinguData_Impl::GetSortedImplNames( LanguageType nLang, sal_uInt8 nType )
{
LangImplNameTable *pTable = nullptr;
switch (nType)
{
case TYPE_SPELL : pTable = &aCfgSpellTable; break;
case TYPE_HYPH : pTable = &aCfgHyphTable; break;
case TYPE_THES : pTable = &aCfgThesTable; break;
case TYPE_GRAMMAR : pTable = &aCfgGrammarTable; break;
}
Sequence< OUString > aRes;
if (!pTable)
{
SAL_WARN( "cui.options", "unknown linguistic type" );
return aRes;
}
if (pTable->count( nLang ))
aRes = (*pTable)[ nLang ]; // add configured services
sal_Int32 nIdx = aRes.getLength();
DBG_ASSERT( static_cast<sal_Int32>(nDisplayServices) >= nIdx, "size mismatch" );
aRes.realloc( nDisplayServices );
OUString *pRes = aRes.getArray();
// add not configured services
for (sal_Int32 i = 0; i < static_cast<sal_Int32>(nDisplayServices); ++i)
{
const ServiceInfo_Impl &rInfo = aDisplayServiceArr[ i ];
OUString aImplName;
switch (nType)
{
case TYPE_SPELL : aImplName = rInfo.sSpellImplName; break;
case TYPE_HYPH : aImplName = rInfo.sHyphImplName; break;
case TYPE_THES : aImplName = rInfo.sThesImplName; break;
case TYPE_GRAMMAR : aImplName = rInfo.sGrammarImplName; break;
}
if (!aImplName.isEmpty() && (lcl_SeqGetIndex( aRes, aImplName) == -1)) // name not yet added
{
DBG_ASSERT( nIdx < aRes.getLength(), "index out of range" );
if (nIdx < aRes.getLength())
pRes[ nIdx++ ] = aImplName;
}
}
// don't forget to put aRes back to its actual size just in case you allocated too much
// since all of the names may have already been added
// otherwise you get duplicate entries in the edit dialog
aRes.realloc( nIdx );
return aRes;
}
ServiceInfo_Impl * SvxLinguData_Impl::GetInfoByImplName( const OUString &rSvcImplName )
{
for (sal_uLong i = 0; i < nDisplayServices; ++i)
{
ServiceInfo_Impl &rTmp = aDisplayServiceArr[ i ];
if (rTmp.sSpellImplName == rSvcImplName ||
rTmp.sHyphImplName == rSvcImplName ||
rTmp.sThesImplName == rSvcImplName ||
rTmp.sGrammarImplName == rSvcImplName)
{
return &rTmp;
}
}
return nullptr;
}
static void lcl_MergeLocales(Sequence< Locale >& aAllLocales, const Sequence< Locale >& rAdd)
{
const Locale* pAdd = rAdd.getConstArray();
Sequence<Locale> aLocToAdd(rAdd.getLength());
const Locale* pAllLocales = aAllLocales.getConstArray();
Locale* pLocToAdd = aLocToAdd.getArray();
sal_Int32 nFound = 0;
sal_Int32 i;
for(i = 0; i < rAdd.getLength(); i++)
{
bool bFound = false;
for(sal_Int32 j = 0; j < aAllLocales.getLength() && !bFound; j++)
{
bFound = pAdd[i].Language == pAllLocales[j].Language &&
pAdd[i].Country == pAllLocales[j].Country &&
pAdd[i].Variant == pAllLocales[j].Variant;
}
if(!bFound)
{
pLocToAdd[nFound++] = pAdd[i];
}
}
sal_Int32 nLength = aAllLocales.getLength();
aAllLocales.realloc( nLength + nFound);
Locale* pAllLocales2 = aAllLocales.getArray();
for(i = 0; i < nFound; i++)
pAllLocales2[nLength++] = pLocToAdd[i];
}
static void lcl_MergeDisplayArray(
SvxLinguData_Impl &rData,
const ServiceInfo_Impl &rToAdd )
{
sal_uLong nCnt = 0;
ServiceInfoArr &rSvcInfoArr = rData.GetDisplayServiceArray();
sal_uLong nEntries = rData.GetDisplayServiceCount();
for (sal_uLong i = 0; i < nEntries; ++i)
{
ServiceInfo_Impl* pEntry = &rSvcInfoArr[i];
if (pEntry && pEntry->sDisplayName == rToAdd.sDisplayName)
{
if(rToAdd.xSpell.is())
{
DBG_ASSERT( !pEntry->xSpell.is() &&
pEntry->sSpellImplName.isEmpty(),
"merge conflict" );
pEntry->sSpellImplName = rToAdd.sSpellImplName;
pEntry->xSpell = rToAdd.xSpell;
}
if(rToAdd.xGrammar.is())
{
DBG_ASSERT( !pEntry->xGrammar.is() &&
pEntry->sGrammarImplName.isEmpty(),
"merge conflict" );
pEntry->sGrammarImplName = rToAdd.sGrammarImplName;
pEntry->xGrammar = rToAdd.xGrammar;
}
if(rToAdd.xHyph.is())
{
DBG_ASSERT( !pEntry->xHyph.is() &&
pEntry->sHyphImplName.isEmpty(),
"merge conflict" );
pEntry->sHyphImplName = rToAdd.sHyphImplName;
pEntry->xHyph = rToAdd.xHyph;
}
if(rToAdd.xThes.is())
{
DBG_ASSERT( !pEntry->xThes.is() &&
pEntry->sThesImplName.isEmpty(),
"merge conflict" );
pEntry->sThesImplName = rToAdd.sThesImplName;
pEntry->xThes = rToAdd.xThes;
}
return ;
}
++nCnt;
}
rData.GetDisplayServiceArray().push_back( rToAdd );
rData.SetDisplayServiceCount( nCnt + 1 );
}
SvxLinguData_Impl::SvxLinguData_Impl() :
nDisplayServices (0)
{
uno::Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
xLinguSrvcMgr = LinguServiceManager::create(xContext);
const Locale& rCurrentLocale = Application::GetSettings().GetLanguageTag().getLocale();
Sequence<Any> aArgs(2);//second arguments has to be empty!
aArgs.getArray()[0] <<= LinguMgr::GetLinguPropertySet();
//read spell checker
Sequence< OUString > aSpellNames = xLinguSrvcMgr->getAvailableServices(
cSpell, Locale() );
const OUString* pSpellNames = aSpellNames.getConstArray();
sal_Int32 nIdx;
for(nIdx = 0; nIdx < aSpellNames.getLength(); nIdx++)
{
ServiceInfo_Impl aInfo;
aInfo.sSpellImplName = pSpellNames[nIdx];
aInfo.xSpell.set(
xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aInfo.sSpellImplName, aArgs, xContext), UNO_QUERY);
uno::Reference<XServiceDisplayName> xDispName(aInfo.xSpell, UNO_QUERY);
if(xDispName.is())
aInfo.sDisplayName = xDispName->getServiceDisplayName( rCurrentLocale );
const Sequence< Locale > aLocales( aInfo.xSpell->getLocales() );
//! suppress display of entries with no supported languages (see feature 110994)
if (aLocales.getLength())
{
lcl_MergeLocales( aAllServiceLocales, aLocales );
lcl_MergeDisplayArray( *this, aInfo );
}
}
//read grammar checker
Sequence< OUString > aGrammarNames = xLinguSrvcMgr->getAvailableServices(
cGrammar, Locale() );
const OUString* pGrammarNames = aGrammarNames.getConstArray();
for(nIdx = 0; nIdx < aGrammarNames.getLength(); nIdx++)
{
ServiceInfo_Impl aInfo;
aInfo.sGrammarImplName = pGrammarNames[nIdx];
aInfo.xGrammar.set(
xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aInfo.sGrammarImplName, aArgs, xContext), UNO_QUERY);
uno::Reference<XServiceDisplayName> xDispName(aInfo.xGrammar, UNO_QUERY);
if(xDispName.is())
aInfo.sDisplayName = xDispName->getServiceDisplayName( rCurrentLocale );
const Sequence< Locale > aLocales( aInfo.xGrammar->getLocales() );
//! suppress display of entries with no supported languages (see feature 110994)
if (aLocales.getLength())
{
lcl_MergeLocales( aAllServiceLocales, aLocales );
lcl_MergeDisplayArray( *this, aInfo );
}
}
//read hyphenator
Sequence< OUString > aHyphNames = xLinguSrvcMgr->getAvailableServices(
cHyph, Locale() );
const OUString* pHyphNames = aHyphNames.getConstArray();
for(nIdx = 0; nIdx < aHyphNames.getLength(); nIdx++)
{
ServiceInfo_Impl aInfo;
aInfo.sHyphImplName = pHyphNames[nIdx];
aInfo.xHyph.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aInfo.sHyphImplName, aArgs, xContext), UNO_QUERY);
uno::Reference<XServiceDisplayName> xDispName(aInfo.xHyph, UNO_QUERY);
if(xDispName.is())
aInfo.sDisplayName = xDispName->getServiceDisplayName( rCurrentLocale );
const Sequence< Locale > aLocales( aInfo.xHyph->getLocales() );
//! suppress display of entries with no supported languages (see feature 110994)
if (aLocales.getLength())
{
lcl_MergeLocales( aAllServiceLocales, aLocales );
lcl_MergeDisplayArray( *this, aInfo );
}
}
//read thesauri
Sequence< OUString > aThesNames = xLinguSrvcMgr->getAvailableServices(
cThes, Locale() );
const OUString* pThesNames = aThesNames.getConstArray();
for(nIdx = 0; nIdx < aThesNames.getLength(); nIdx++)
{
ServiceInfo_Impl aInfo;
aInfo.sThesImplName = pThesNames[nIdx];
aInfo.xThes.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aInfo.sThesImplName, aArgs, xContext), UNO_QUERY);
uno::Reference<XServiceDisplayName> xDispName(aInfo.xThes, UNO_QUERY);
if(xDispName.is())
aInfo.sDisplayName = xDispName->getServiceDisplayName( rCurrentLocale );
const Sequence< Locale > aLocales( aInfo.xThes->getLocales() );
//! suppress display of entries with no supported languages (see feature 110994)
if (aLocales.getLength())
{
lcl_MergeLocales( aAllServiceLocales, aLocales );
lcl_MergeDisplayArray( *this, aInfo );
}
}
Sequence< OUString > aCfgSvcs;
const Locale* pAllLocales = aAllServiceLocales.getConstArray();
for(sal_Int32 nLocale = 0; nLocale < aAllServiceLocales.getLength(); nLocale++)
{
LanguageType nLang = LanguageTag::convertToLanguageType( pAllLocales[nLocale] );
aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(cSpell, pAllLocales[nLocale]);
SetChecked( aCfgSvcs );
if (aCfgSvcs.getLength())
aCfgSpellTable[ nLang ] = aCfgSvcs;
aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(cGrammar, pAllLocales[nLocale]);
SetChecked( aCfgSvcs );
if (aCfgSvcs.getLength())
aCfgGrammarTable[ nLang ] = aCfgSvcs;
aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(cHyph, pAllLocales[nLocale]);
SetChecked( aCfgSvcs );
if (aCfgSvcs.getLength())
aCfgHyphTable[ nLang ] = aCfgSvcs;
aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(cThes, pAllLocales[nLocale]);
SetChecked( aCfgSvcs );
if (aCfgSvcs.getLength())
aCfgThesTable[ nLang ] = aCfgSvcs;
}
}
void SvxLinguData_Impl::SetChecked(const Sequence<OUString>& rConfiguredServices)
{
const OUString* pConfiguredServices = rConfiguredServices.getConstArray();
for(sal_Int32 n = 0; n < rConfiguredServices.getLength(); n++)
{
for (sal_uLong i = 0; i < nDisplayServices; ++i)
{
ServiceInfo_Impl* pEntry = &aDisplayServiceArr[i];
if (pEntry && !pEntry->bConfigured)
{
const OUString &rSrvcImplName = pConfiguredServices[n];
if (!rSrvcImplName.isEmpty() &&
(pEntry->sSpellImplName == rSrvcImplName ||
pEntry->sGrammarImplName == rSrvcImplName ||
pEntry->sHyphImplName == rSrvcImplName ||
pEntry->sThesImplName == rSrvcImplName))
{
pEntry->bConfigured = true;
break;
}
}
}
}
}
bool SvxLinguData_Impl::AddRemove(
Sequence< OUString > &rConfigured,
const OUString &rImplName, bool bAdd )
{
bool bRet = false; // modified?
sal_Int32 nEntries = rConfigured.getLength();
sal_Int32 nPos = lcl_SeqGetEntryPos(rConfigured, rImplName);
if (bAdd && nPos < 0) // add new entry
{
rConfigured.realloc( ++nEntries );
OUString *pConfigured = rConfigured.getArray();
pConfigured[nEntries - 1] = rImplName;
bRet = true;
}
else if (!bAdd && nPos >= 0) // remove existing entry
{
OUString *pConfigured = rConfigured.getArray();
for (sal_Int32 i = nPos; i < nEntries - 1; ++i)
pConfigured[i] = pConfigured[i + 1];
rConfigured.realloc(--nEntries);
bRet = true;
}
return bRet;
}
void SvxLinguData_Impl::Reconfigure( const OUString &rDisplayName, bool bEnable )
{
DBG_ASSERT( !rDisplayName.isEmpty(), "empty DisplayName" );
ServiceInfo_Impl *pInfo = nullptr;
ServiceInfo_Impl *pTmp = nullptr;
for (sal_uLong i = 0; i < nDisplayServices; ++i)
{
pTmp = &aDisplayServiceArr[i];
if (pTmp && pTmp->sDisplayName == rDisplayName)
{
pInfo = pTmp;
break;
}
}
DBG_ASSERT( pInfo, "DisplayName entry not found" );
if (pInfo)
{
pInfo->bConfigured = bEnable;
Sequence< Locale > aLocales;
const Locale *pLocale = nullptr;
sal_Int32 nLocales = 0;
sal_Int32 i;
// update configured spellchecker entries
if (pInfo->xSpell.is())
{
aLocales = pInfo->xSpell->getLocales();
pLocale = aLocales.getConstArray();
nLocales = aLocales.getLength();
for (i = 0; i < nLocales; ++i)
{
LanguageType nLang = LanguageTag::convertToLanguageType( pLocale[i] );
if (!aCfgSpellTable.count( nLang ) && bEnable)
aCfgSpellTable[ nLang ] = Sequence< OUString >();
if (aCfgSpellTable.count( nLang ))
AddRemove( aCfgSpellTable[ nLang ], pInfo->sSpellImplName, bEnable );
}
}
// update configured grammar checker entries
if (pInfo->xGrammar.is())
{
aLocales = pInfo->xGrammar->getLocales();
pLocale = aLocales.getConstArray();
nLocales = aLocales.getLength();
for (i = 0; i < nLocales; ++i)
{
LanguageType nLang = LanguageTag::convertToLanguageType( pLocale[i] );
if (!aCfgGrammarTable.count( nLang ) && bEnable)
aCfgGrammarTable[ nLang ] = Sequence< OUString >();
if (aCfgGrammarTable.count( nLang ))
AddRemove( aCfgGrammarTable[ nLang ], pInfo->sGrammarImplName, bEnable );
}
}
// update configured hyphenator entries
if (pInfo->xHyph.is())
{
aLocales = pInfo->xHyph->getLocales();
pLocale = aLocales.getConstArray();
nLocales = aLocales.getLength();
for (i = 0; i < nLocales; ++i)
{
LanguageType nLang = LanguageTag::convertToLanguageType( pLocale[i] );
if (!aCfgHyphTable.count( nLang ) && bEnable)
aCfgHyphTable[ nLang ] = Sequence< OUString >();
if (aCfgHyphTable.count( nLang ))
AddRemove( aCfgHyphTable[ nLang ], pInfo->sHyphImplName, bEnable );
}
}
// update configured spellchecker entries
if (pInfo->xThes.is())
{
aLocales = pInfo->xThes->getLocales();
pLocale = aLocales.getConstArray();
nLocales = aLocales.getLength();
for (i = 0; i < nLocales; ++i)
{
LanguageType nLang = LanguageTag::convertToLanguageType( pLocale[i] );
if (!aCfgThesTable.count( nLang ) && bEnable)
aCfgThesTable[ nLang ] = Sequence< OUString >();
if (aCfgThesTable.count( nLang ))
AddRemove( aCfgThesTable[ nLang ], pInfo->sThesImplName, bEnable );
}
}
}
}
// class SvxLinguTabPage -------------------------------------------------
SvxLinguTabPage::SvxLinguTabPage( vcl::Window* pParent, const SfxItemSet& rSet ) :
SfxTabPage(pParent, "OptLinguPage", "cui/ui/optlingupage.ui", &rSet),
sCapitalWords (CuiResId(RID_SVXSTR_CAPITAL_WORDS)),
sWordsWithDigits(CuiResId(RID_SVXSTR_WORDS_WITH_DIGITS)),
sSpellSpecial (CuiResId(RID_SVXSTR_SPELL_SPECIAL)),
sSpellAuto (CuiResId(RID_SVXSTR_SPELL_AUTO)),
sGrammarAuto (CuiResId(RID_SVXSTR_GRAMMAR_AUTO)),
sNumMinWordlen (CuiResId(RID_SVXSTR_NUM_MIN_WORDLEN)),
sNumPreBreak (CuiResId(RID_SVXSTR_NUM_PRE_BREAK)),
sNumPostBreak (CuiResId(RID_SVXSTR_NUM_POST_BREAK)),
sHyphAuto (CuiResId(RID_SVXSTR_HYPH_AUTO)),
sHyphSpecial (CuiResId(RID_SVXSTR_HYPH_SPECIAL))
{
get(m_pLinguModulesFT, "lingumodulesft");
get(m_pLinguModulesCLB, "lingumodules");
get(m_pLinguModulesEditPB, "lingumodulesedit");
get(m_pLinguDicsFT, "lingudictsft");
get(m_pLinguDicsCLB, "lingudicts");
get(m_pLinguDicsNewPB, "lingudictsnew");
get(m_pLinguDicsEditPB, "lingudictsedit");
get(m_pLinguDicsDelPB, "lingudictsdelete");
get(m_pLinguOptionsCLB, "linguoptions");
get(m_pLinguOptionsEditPB, "linguoptionsedit");
get(m_pMoreDictsLink, "moredictslink");
m_pLinguModulesCLB->set_height_request(m_pLinguModulesCLB->GetTextHeight() * 3);
m_pLinguDicsCLB->set_height_request(m_pLinguDicsCLB->GetTextHeight() * 5);
m_pLinguOptionsCLB->set_height_request(m_pLinguOptionsCLB->GetTextHeight() * 5);
m_pLinguModulesCLB->SetStyle( m_pLinguModulesCLB->GetStyle()|WB_CLIPCHILDREN|WB_HSCROLL );
m_pLinguModulesCLB->SetForceMakeVisible(true);
m_pLinguModulesCLB->SetHighlightRange();
m_pLinguModulesCLB->SetSelectHdl( LINK( this, SvxLinguTabPage, SelectHdl_Impl ));
m_pLinguModulesCLB->SetDoubleClickHdl(LINK(this, SvxLinguTabPage, BoxDoubleClickHdl_Impl));
m_pLinguModulesCLB->SetCheckButtonHdl(LINK(this, SvxLinguTabPage, BoxCheckButtonHdl_Impl));
m_pLinguModulesEditPB->SetClickHdl( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
m_pLinguOptionsEditPB->SetClickHdl( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
m_pLinguDicsCLB->SetStyle( m_pLinguDicsCLB->GetStyle()|WB_CLIPCHILDREN|WB_HSCROLL );
m_pLinguDicsCLB->SetForceMakeVisible(true);
m_pLinguDicsCLB->SetHighlightRange();
m_pLinguDicsCLB->SetSelectHdl( LINK( this, SvxLinguTabPage, SelectHdl_Impl ));
m_pLinguDicsCLB->SetCheckButtonHdl(LINK(this, SvxLinguTabPage, BoxCheckButtonHdl_Impl));
m_pLinguDicsNewPB->SetClickHdl( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
m_pLinguDicsEditPB->SetClickHdl( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
m_pLinguDicsDelPB->SetClickHdl( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
m_pLinguOptionsCLB->SetStyle( m_pLinguOptionsCLB->GetStyle()|WB_CLIPCHILDREN|WB_HSCROLL );
m_pLinguOptionsCLB->SetForceMakeVisible(true);
m_pLinguOptionsCLB->SetHighlightRange();
m_pLinguOptionsCLB->SetSelectHdl( LINK( this, SvxLinguTabPage, SelectHdl_Impl ));
m_pLinguOptionsCLB->SetDoubleClickHdl(LINK(this, SvxLinguTabPage, BoxDoubleClickHdl_Impl));
if ( SvtExtendedSecurityOptions().GetOpenHyperlinkMode() == SvtExtendedSecurityOptions::OPEN_NEVER )
m_pMoreDictsLink->Hide();
xProp = LinguMgr::GetLinguPropertySet();
xDicList.set( LinguMgr::GetDictionaryList(), UNO_QUERY );
if (xDicList.is())
{
// keep references to all **currently** available dictionaries,
// since the diclist may get changed meanwhile (e.g. through the API).
// We want the dialog to operate on the same set of dictionaries it
// was started with.
// Also we have to take care to not lose the last reference when
// someone else removes a dictionary from the list.
// removed dics will be replaced by NULL new entries be added to the end
// Thus we may use indices as consistent references.
aDics = xDicList->getDictionaries();
UpdateDicBox_Impl();
}
else
{
m_pLinguDicsFT->Disable();
m_pLinguDicsCLB->Disable();
m_pLinguDicsNewPB->Disable();
m_pLinguDicsEditPB->Disable();
m_pLinguDicsDelPB->Disable();
}
}
SvxLinguTabPage::~SvxLinguTabPage()
{
disposeOnce();
}
void SvxLinguTabPage::dispose()
{
pLinguData.reset();
m_pLinguModulesFT.clear();
m_pLinguModulesCLB.clear();
m_pLinguModulesEditPB.clear();
m_pLinguDicsFT.clear();
m_pLinguDicsCLB.clear();
m_pLinguDicsNewPB.clear();
m_pLinguDicsEditPB.clear();
m_pLinguDicsDelPB.clear();
m_pLinguOptionsCLB.clear();
m_pLinguOptionsEditPB.clear();
m_pMoreDictsLink.clear();
SfxTabPage::dispose();
}
VclPtr<SfxTabPage> SvxLinguTabPage::Create( TabPageParent pParent,
const SfxItemSet* rAttrSet )
{
return VclPtr<SvxLinguTabPage>::Create( pParent.pParent, *rAttrSet );
}
bool SvxLinguTabPage::FillItemSet( SfxItemSet* rCoreSet )
{
bool bModified = true; // !!!!
// if not HideGroups was called with GROUP_MODULES...
if (m_pLinguModulesCLB->IsVisible())
{
DBG_ASSERT( pLinguData, "pLinguData not yet initialized" );
if (!pLinguData)
pLinguData.reset( new SvxLinguData_Impl );
// update spellchecker configuration entries
const LangImplNameTable *pTable = &pLinguData->GetSpellTable();
for (auto const& elem : *pTable)
{
LanguageType nLang = elem.first;
const Sequence< OUString > aImplNames(elem.second);
uno::Reference< XLinguServiceManager2 > xMgr( pLinguData->GetManager() );
Locale aLocale( LanguageTag::convertToLocale(nLang) );
if (xMgr.is())
xMgr->setConfiguredServices( cSpell, aLocale, aImplNames );
}
// update grammar checker configuration entries
pTable = &pLinguData->GetGrammarTable();
for (auto const& elem : *pTable)
{
LanguageType nLang = elem.first;
const Sequence< OUString > aImplNames(elem.second);
uno::Reference< XLinguServiceManager2 > xMgr( pLinguData->GetManager() );
Locale aLocale( LanguageTag::convertToLocale(nLang) );
if (xMgr.is())
xMgr->setConfiguredServices( cGrammar, aLocale, aImplNames );
}
// update hyphenator configuration entries
pTable = &pLinguData->GetHyphTable();
for (auto const& elem : *pTable)
{
LanguageType nLang = elem.first;
const Sequence< OUString > aImplNames(elem.second);
uno::Reference< XLinguServiceManager2 > xMgr( pLinguData->GetManager() );
Locale aLocale( LanguageTag::convertToLocale(nLang) );
if (xMgr.is())
xMgr->setConfiguredServices( cHyph, aLocale, aImplNames );
}
// update thesaurus configuration entries
pTable = &pLinguData->GetThesTable();
for (auto const& elem : *pTable)
{
LanguageType nLang = elem.first;
const Sequence< OUString > aImplNames(elem.second);
uno::Reference< XLinguServiceManager2 > xMgr( pLinguData->GetManager() );
Locale aLocale( LanguageTag::convertToLocale(nLang) );
if (xMgr.is())
xMgr->setConfiguredServices( cThes, aLocale, aImplNames );
}
}
// activate dictionaries according to checkbox state
Sequence< OUString > aActiveDics;
sal_Int32 nActiveDics = 0;
sal_uLong nEntries = m_pLinguDicsCLB->GetEntryCount();
for (sal_uLong i = 0; i < nEntries; ++i)
{
sal_Int32 nDics = aDics.getLength();
aActiveDics.realloc( nDics );
OUString *pActiveDic = aActiveDics.getArray();
SvTreeListEntry *pEntry = m_pLinguDicsCLB->GetEntry( i );
if (pEntry)
{
DicUserData aData( reinterpret_cast<sal_uLong>(pEntry->GetUserData()) );
if (aData.GetEntryId() < nDics)
{
bool bChecked = m_pLinguDicsCLB->IsChecked( i );
uno::Reference< XDictionary > xDic( aDics.getConstArray()[ i ] );
if (xDic.is())
{
if (LinguMgr::GetIgnoreAllList() == xDic)
bChecked = true;
xDic->setActive( bChecked );
if (bChecked)
{
OUString aDicName( xDic->getName() );
pActiveDic[ nActiveDics++ ] = aDicName;
}
}
}
}
}
aActiveDics.realloc( nActiveDics );
Any aTmp;
aTmp <<= aActiveDics;
SvtLinguConfig aLngCfg;
aLngCfg.SetProperty( UPH_ACTIVE_DICTIONARIES, aTmp );
nEntries = m_pLinguOptionsCLB->GetEntryCount();
for (sal_uLong j = 0; j < nEntries; ++j)
{
SvTreeListEntry *pEntry = m_pLinguOptionsCLB->GetEntry( j );
OptionsUserData aData( reinterpret_cast<sal_uLong>(pEntry->GetUserData()) );
OUString aPropName( lcl_GetPropertyName( static_cast<EID_OPTIONS>(aData.GetEntryId()) ) );
Any aAny;
if (aData.IsCheckable())
{
bool bChecked = m_pLinguOptionsCLB->IsChecked( j );
aAny <<= bChecked;
}
else if (aData.HasNumericValue())
{
sal_Int16 nVal = aData.GetNumericValue();
aAny <<= nVal;
}
if (xProp.is())
xProp->setPropertyValue( aPropName, aAny );
aLngCfg.SetProperty( aPropName, aAny );
}
SvTreeListEntry *pPreBreakEntry = m_pLinguOptionsCLB->GetEntry( sal_uLong(EID_NUM_PRE_BREAK) );
SvTreeListEntry *pPostBreakEntry = m_pLinguOptionsCLB->GetEntry( sal_uLong(EID_NUM_POST_BREAK) );
DBG_ASSERT( pPreBreakEntry, "NULL Pointer" );
DBG_ASSERT( pPostBreakEntry, "NULL Pointer" );
if (pPreBreakEntry && pPostBreakEntry)
{
OptionsUserData aPreBreakData( reinterpret_cast<sal_uLong>(pPreBreakEntry->GetUserData()) );
OptionsUserData aPostBreakData( reinterpret_cast<sal_uLong>(pPostBreakEntry->GetUserData()) );
if ( aPreBreakData.IsModified() || aPostBreakData.IsModified() )
{
SfxHyphenRegionItem aHyp( GetWhich( SID_ATTR_HYPHENREGION ) );
aHyp.GetMinLead() = static_cast<sal_uInt8>(aPreBreakData.GetNumericValue());
aHyp.GetMinTrail() = static_cast<sal_uInt8>(aPostBreakData.GetNumericValue());
rCoreSet->Put( aHyp );
}
}
// automatic spell checking
bool bNewAutoCheck = m_pLinguOptionsCLB->IsChecked( sal_uLong(EID_SPELL_AUTO) );
const SfxPoolItem* pOld = GetOldItem( *rCoreSet, SID_AUTOSPELL_CHECK );
if ( !pOld || static_cast<const SfxBoolItem*>(pOld)->GetValue() != bNewAutoCheck )
{
rCoreSet->Put( SfxBoolItem( GetWhich( SID_AUTOSPELL_CHECK ),
bNewAutoCheck ) );
bModified = true;
}
return bModified;
}
sal_uLong SvxLinguTabPage::GetDicUserData( const uno::Reference< XDictionary > &rxDic, sal_uInt16 nIdx )
{
sal_uLong nRes = 0;
DBG_ASSERT( rxDic.is(), "dictionary not supplied" );
if (rxDic.is())
{
uno::Reference< frame::XStorable > xStor( rxDic, UNO_QUERY );
bool bChecked = rxDic->isActive();
bool bEditable = !xStor.is() || !xStor->isReadonly();
bool bDeletable = bEditable;
nRes = DicUserData( nIdx,
bChecked, bEditable, bDeletable ).GetUserData();
}
return nRes;
}
void SvxLinguTabPage::AddDicBoxEntry(
const uno::Reference< XDictionary > &rxDic,
sal_uInt16 nIdx )
{
m_pLinguDicsCLB->SetUpdateMode(false);
OUString aTxt( ::GetDicInfoStr( rxDic->getName(),
LanguageTag( rxDic->getLocale() ).getLanguageType(),
DictionaryType_NEGATIVE == rxDic->getDictionaryType() ) );
m_pLinguDicsCLB->InsertEntry( aTxt ); // append at end
SvTreeListEntry* pEntry = m_pLinguDicsCLB->GetEntry( m_pLinguDicsCLB->GetEntryCount() - 1 );
DBG_ASSERT( pEntry, "failed to add entry" );
if (pEntry)
{
DicUserData aData( GetDicUserData( rxDic, nIdx ) );
pEntry->SetUserData( reinterpret_cast<void *>(aData.GetUserData()) );
lcl_SetCheckButton( pEntry, aData.IsChecked() );
}
m_pLinguDicsCLB->SetUpdateMode(true);
}
void SvxLinguTabPage::UpdateDicBox_Impl()
{
m_pLinguDicsCLB->SetUpdateMode(false);
m_pLinguDicsCLB->Clear();
sal_Int32 nDics = aDics.getLength();
const uno::Reference< XDictionary > *pDic = aDics.getConstArray();
for (sal_Int32 i = 0; i < nDics; ++i)
{
const uno::Reference< XDictionary > &rDic = pDic[i];
if (rDic.is())
AddDicBoxEntry( rDic, static_cast<sal_uInt16>(i) );
}
m_pLinguDicsCLB->SetUpdateMode(true);
}
void SvxLinguTabPage::UpdateModulesBox_Impl()
{
if (pLinguData)
{
const ServiceInfoArr &rAllDispSrvcArr = pLinguData->GetDisplayServiceArray();
const sal_uLong nDispSrvcCount = pLinguData->GetDisplayServiceCount();
m_pLinguModulesCLB->Clear();
for (sal_uLong i = 0; i < nDispSrvcCount; ++i)
{
const ServiceInfo_Impl &rInfo = rAllDispSrvcArr[i];
m_pLinguModulesCLB->InsertEntry( rInfo.sDisplayName );
SvTreeListEntry* pEntry = m_pLinguModulesCLB->GetEntry(i);
pEntry->SetUserData( const_cast<ServiceInfo_Impl *>(&rInfo) );
m_pLinguModulesCLB->CheckEntryPos( i, rInfo.bConfigured );
}
m_pLinguModulesEditPB->Enable( nDispSrvcCount > 0 );
}
}
void SvxLinguTabPage::Reset( const SfxItemSet* rSet )
{
// if not HideGroups was called with GROUP_MODULES...
if (m_pLinguModulesCLB->IsVisible())
{
if (!pLinguData)
pLinguData.reset( new SvxLinguData_Impl );
UpdateModulesBox_Impl();
}
// get data from configuration
SvtLinguConfig aLngCfg;
m_pLinguOptionsCLB->SetUpdateMode(false);
m_pLinguOptionsCLB->Clear();
SvTreeList *pModel = m_pLinguOptionsCLB->GetModel();
sal_Int16 nVal = 0;
bool bVal = false;
sal_uLong nUserData = 0;
SvTreeListEntry* pEntry = CreateEntry( sSpellAuto, CBCOL_FIRST );
aLngCfg.GetProperty( UPN_IS_SPELL_AUTO ) >>= bVal;
const SfxPoolItem* pItem = GetItem( *rSet, SID_AUTOSPELL_CHECK );
if (pItem)
bVal = static_cast<const SfxBoolItem *>(pItem)->GetValue();
nUserData = OptionsUserData( EID_SPELL_AUTO, false, 0, true, bVal).GetUserData();
pEntry->SetUserData( reinterpret_cast<void *>(nUserData) );
pModel->Insert( pEntry );
lcl_SetCheckButton( pEntry, bVal );
pEntry = CreateEntry( sGrammarAuto, CBCOL_FIRST );
aLngCfg.GetProperty( UPN_IS_GRAMMAR_AUTO ) >>= bVal;
nUserData = OptionsUserData( EID_GRAMMAR_AUTO, false, 0, true, bVal).GetUserData();
pEntry->SetUserData( reinterpret_cast<void *>(nUserData) );
pModel->Insert( pEntry );
lcl_SetCheckButton( pEntry, bVal );
pEntry = CreateEntry( sCapitalWords, CBCOL_FIRST );
aLngCfg.GetProperty( UPN_IS_SPELL_UPPER_CASE ) >>= bVal;
nUserData = OptionsUserData( EID_CAPITAL_WORDS, false, 0, true, bVal).GetUserData();
pEntry->SetUserData( reinterpret_cast<void *>(nUserData) );
pModel->Insert( pEntry );
lcl_SetCheckButton( pEntry, bVal );
pEntry = CreateEntry( sWordsWithDigits, CBCOL_FIRST );
aLngCfg.GetProperty( UPN_IS_SPELL_WITH_DIGITS ) >>= bVal;
nUserData = OptionsUserData( EID_WORDS_WITH_DIGITS, false, 0, true, bVal).GetUserData();
pEntry->SetUserData( reinterpret_cast<void *>(nUserData) );
pModel->Insert( pEntry );
lcl_SetCheckButton( pEntry, bVal );
pEntry = CreateEntry( sSpellSpecial, CBCOL_FIRST );
aLngCfg.GetProperty( UPN_IS_SPELL_SPECIAL ) >>= bVal;
nUserData = OptionsUserData( EID_SPELL_SPECIAL, false, 0, true, bVal).GetUserData();
pEntry->SetUserData( reinterpret_cast<void *>(nUserData) );
pModel->Insert( pEntry );
lcl_SetCheckButton( pEntry, bVal );
pEntry = CreateEntry( sNumMinWordlen, CBCOL_SECOND );
aLngCfg.GetProperty( UPN_HYPH_MIN_WORD_LENGTH ) >>= nVal;
nUserData = OptionsUserData( EID_NUM_MIN_WORDLEN, true, static_cast<sal_uInt16>(nVal), false, false).GetUserData();
pEntry->SetUserData( reinterpret_cast<void *>(nUserData) );
pModel->Insert( pEntry );
const SfxHyphenRegionItem *pHyp = nullptr;
sal_uInt16 nWhich = GetWhich( SID_ATTR_HYPHENREGION );
if ( rSet->GetItemState( nWhich, false ) == SfxItemState::SET )
pHyp = &static_cast<const SfxHyphenRegionItem &>( rSet->Get( nWhich ) );
pEntry = CreateEntry( sNumPreBreak, CBCOL_SECOND );
aLngCfg.GetProperty( UPN_HYPH_MIN_LEADING ) >>= nVal;
if (pHyp)
nVal = static_cast<sal_Int16>(pHyp->GetMinLead());
nUserData = OptionsUserData( EID_NUM_PRE_BREAK, true, static_cast<sal_uInt16>(nVal), false, false).GetUserData();
pEntry->SetUserData( reinterpret_cast<void *>(nUserData) );
pModel->Insert( pEntry );
pEntry = CreateEntry( sNumPostBreak, CBCOL_SECOND );
aLngCfg.GetProperty( UPN_HYPH_MIN_TRAILING ) >>= nVal;
if (pHyp)
nVal = static_cast<sal_Int16>(pHyp->GetMinTrail());
nUserData = OptionsUserData( EID_NUM_POST_BREAK, true, static_cast<sal_uInt16>(nVal), false, false).GetUserData();
pEntry->SetUserData( reinterpret_cast<void *>(nUserData) );
pModel->Insert( pEntry );
pEntry = CreateEntry( sHyphAuto, CBCOL_FIRST );
aLngCfg.GetProperty( UPN_IS_HYPH_AUTO ) >>= bVal;
nUserData = OptionsUserData( EID_HYPH_AUTO, false, 0, true, bVal).GetUserData();
pEntry->SetUserData( reinterpret_cast<void *>(nUserData) );
pModel->Insert( pEntry );
lcl_SetCheckButton( pEntry, bVal );
pEntry = CreateEntry( sHyphSpecial, CBCOL_FIRST );
aLngCfg.GetProperty( UPN_IS_HYPH_SPECIAL ) >>= bVal;
nUserData = OptionsUserData( EID_HYPH_SPECIAL, false, 0, true, bVal).GetUserData();
pEntry->SetUserData( reinterpret_cast<void *>(nUserData) );
pModel->Insert( pEntry );
lcl_SetCheckButton( pEntry, bVal );
m_pLinguOptionsCLB->SetUpdateMode(true);
}
IMPL_LINK( SvxLinguTabPage, BoxDoubleClickHdl_Impl, SvTreeListBox *, pBox, bool )
{
if (pBox == m_pLinguModulesCLB)
{
//! in order to avoid a bug causing a GPF when double clicking
//! on a module entry and exiting the "Edit Modules" dialog
//! after that.
Application::PostUserEvent( LINK(
this, SvxLinguTabPage, PostDblClickHdl_Impl ), nullptr, true);
}
else if (pBox == m_pLinguOptionsCLB)
{
ClickHdl_Impl(m_pLinguOptionsEditPB);
}
return false;
}
IMPL_LINK_NOARG(SvxLinguTabPage, PostDblClickHdl_Impl, void*, void)
{
ClickHdl_Impl(m_pLinguModulesEditPB);
}
IMPL_LINK( SvxLinguTabPage, BoxCheckButtonHdl_Impl, SvTreeListBox *, pBox, void )
{
if (pBox == m_pLinguModulesCLB)
{
DBG_ASSERT( pLinguData, "NULL pointer, LinguData missing" );
sal_uLong nPos = m_pLinguModulesCLB->GetSelectedEntryPos();
if (nPos != TREELIST_ENTRY_NOTFOUND && pLinguData)
{
pLinguData->Reconfigure( m_pLinguModulesCLB->GetText( nPos ),
m_pLinguModulesCLB->IsChecked( nPos ) );
}
}
else if (pBox == m_pLinguDicsCLB)
{
sal_uLong nPos = m_pLinguDicsCLB->GetSelectedEntryPos();
if (nPos != TREELIST_ENTRY_NOTFOUND)
{
const uno::Reference< XDictionary > &rDic = aDics.getConstArray()[ nPos ];
if (LinguMgr::GetIgnoreAllList() == rDic)
{
SvTreeListEntry* pEntry = m_pLinguDicsCLB->GetEntry( nPos );
if (pEntry)
lcl_SetCheckButton( pEntry, true );
}
}
}
}
IMPL_LINK( SvxLinguTabPage, ClickHdl_Impl, Button *, pBtn, void )
{
if (m_pLinguModulesEditPB == pBtn)
{
if (!pLinguData)
pLinguData.reset( new SvxLinguData_Impl );
SvxLinguData_Impl aOldLinguData( *pLinguData );
ScopedVclPtrInstance< SvxEditModulesDlg > aDlg( this, *pLinguData );
if (aDlg->Execute() != RET_OK)
*pLinguData = aOldLinguData;
// evaluate new status of 'bConfigured' flag
sal_uLong nLen = pLinguData->GetDisplayServiceCount();
for (sal_uLong i = 0; i < nLen; ++i)
pLinguData->GetDisplayServiceArray()[i].bConfigured = false;
const Locale* pAllLocales = pLinguData->GetAllSupportedLocales().getConstArray();
sal_Int32 nLocales = pLinguData->GetAllSupportedLocales().getLength();
for (sal_Int32 k = 0; k < nLocales; ++k)
{
LanguageType nLang = LanguageTag::convertToLanguageType( pAllLocales[k] );
if (pLinguData->GetSpellTable().count( nLang ))
pLinguData->SetChecked( pLinguData->GetSpellTable()[ nLang ] );
if (pLinguData->GetGrammarTable().count( nLang ))
pLinguData->SetChecked( pLinguData->GetGrammarTable()[ nLang ] );
if (pLinguData->GetHyphTable().count( nLang ))
pLinguData->SetChecked( pLinguData->GetHyphTable()[ nLang ] );
if (pLinguData->GetThesTable().count( nLang ))
pLinguData->SetChecked( pLinguData->GetThesTable()[ nLang ] );
}
// show new status of modules
UpdateModulesBox_Impl();
}
else if (m_pLinguDicsNewPB == pBtn)
{
SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
ScopedVclPtr<AbstractSvxNewDictionaryDialog> aDlg(pFact->CreateSvxNewDictionaryDialog(GetFrameWeld()));
uno::Reference< XDictionary > xNewDic;
if ( aDlg->Execute() == RET_OK )
xNewDic.set( aDlg->GetNewDictionary(), UNO_QUERY );
if ( xNewDic.is() )
{
// add new dics to the end
sal_Int32 nLen = aDics.getLength();
aDics.realloc( nLen + 1 );
aDics.getArray()[ nLen ] = xNewDic;
AddDicBoxEntry( xNewDic, static_cast<sal_uInt16>(nLen) );
}
}
else if (m_pLinguDicsEditPB == pBtn)
{
SvTreeListEntry *pEntry = m_pLinguDicsCLB->GetCurEntry();
if (pEntry)
{
DicUserData aData( reinterpret_cast<sal_uLong>(pEntry->GetUserData()) );
sal_uInt16 nDicPos = aData.GetEntryId();
sal_Int32 nDics = aDics.getLength();
if (nDicPos < nDics)
{
uno::Reference< XDictionary > xDic;
xDic = aDics.getConstArray()[ nDicPos ];
if (xDic.is())
{
SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
ScopedVclPtr<VclAbstractDialog> aDlg(pFact->CreateSvxEditDictionaryDialog( this, xDic->getName() ));
aDlg->Execute();
}
}
}
}
else if (m_pLinguDicsDelPB == pBtn)
{
std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetFrameWeld(), "cui/ui/querydeletedictionarydialog.ui"));
std::unique_ptr<weld::MessageDialog> xQuery(xBuilder->weld_message_dialog("QueryDeleteDictionaryDialog"));
if (RET_NO == xQuery->run())
return;
SvTreeListEntry *pEntry = m_pLinguDicsCLB->GetCurEntry();
if (pEntry)
{
DicUserData aData( reinterpret_cast<sal_uLong>(pEntry->GetUserData()) );
sal_uInt16 nDicPos = aData.GetEntryId();
sal_Int32 nDics = aDics.getLength();
if (nDicPos < nDics)
{
uno::Reference< XDictionary > xDic;
xDic = aDics.getConstArray()[ nDicPos ];
if (xDic.is())
{
if (LinguMgr::GetIgnoreAllList() == xDic)
xDic->clear();
else
{
if (xDicList.is())
xDicList->removeDictionary( xDic );
uno::Reference< frame::XStorable > xStor( xDic, UNO_QUERY );
if ( xStor->hasLocation() && !xStor->isReadonly() )
{
OUString sURL = xStor->getLocation();
INetURLObject aObj(sURL);
DBG_ASSERT( aObj.GetProtocol() == INetProtocol::File,
"non-file URLs cannot be deleted" );
if ( aObj.GetProtocol() == INetProtocol::File )
{
KillFile_Impl( aObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
}
}
aDics.getArray()[ nDicPos ] = nullptr;
// remove entry from checklistbox
sal_uLong nCnt = m_pLinguDicsCLB->GetEntryCount();
for (sal_uLong i = 0; i < nCnt; ++i)
{
SvTreeListEntry *pDicEntry = m_pLinguDicsCLB->GetEntry( i );
DBG_ASSERT( pDicEntry, "missing entry" );
if (pDicEntry)
{
DicUserData aDicData( reinterpret_cast<sal_uLong>(pDicEntry->GetUserData()) );
if (aDicData.GetEntryId() == nDicPos )
{
m_pLinguDicsCLB->RemoveEntry( i );
break;
}
}
}
DBG_ASSERT( nCnt > m_pLinguDicsCLB->GetEntryCount(),
"remove failed ?");
}
}
}
}
}
else if (m_pLinguOptionsEditPB == pBtn)
{
SvTreeListEntry *pEntry = m_pLinguOptionsCLB->GetCurEntry();
DBG_ASSERT( pEntry, "no entry selected" );
if (pEntry)
{
OptionsUserData aData( reinterpret_cast<sal_uLong>(pEntry->GetUserData()) );
if(aData.HasNumericValue())
{
sal_uInt16 nRID = aData.GetEntryId();
OptionsBreakSet aDlg(GetFrameWeld(), nRID);
aDlg.GetNumericFld().set_value(aData.GetNumericValue());
if (RET_OK == aDlg.run())
{
long nVal = static_cast<long>(aDlg.GetNumericFld().get_value());
if (-1 != nVal && aData.GetNumericValue() != nVal)
{
aData.SetNumericValue( static_cast<sal_uInt8>(nVal) ); //! sets IsModified !
pEntry->SetUserData( reinterpret_cast<void *>(aData.GetUserData()) );
m_pLinguOptionsCLB->Invalidate();
}
}
}
}
}
else
{
OSL_FAIL( "pBtn unexpected value" );
}
}
IMPL_LINK( SvxLinguTabPage, SelectHdl_Impl, SvTreeListBox*, pBox, void )
{
if (m_pLinguModulesCLB == pBox)
{
}
else if (m_pLinguDicsCLB == pBox)
{
SvTreeListEntry *pEntry = pBox->GetCurEntry();
if (pEntry)
{
DicUserData aData( reinterpret_cast<sal_uLong>( pEntry->GetUserData() ) );
// always allow to edit (i.e. at least view the content of the dictionary)
m_pLinguDicsEditPB->Enable( /*aData.IsEditable()*/ );
m_pLinguDicsDelPB->Enable( aData.IsDeletable() );
}
}
else if (m_pLinguOptionsCLB == pBox)
{
SvTreeListEntry *pEntry = pBox->GetCurEntry();
if (pEntry)
{
OptionsUserData aData( reinterpret_cast<sal_uLong>( pEntry->GetUserData() ) );
m_pLinguOptionsEditPB->Enable( aData.HasNumericValue() );
}
}
else
{
OSL_FAIL( "pBox unexpected value" );
}
}
SvTreeListEntry* SvxLinguTabPage::CreateEntry( OUString& rTxt, sal_uInt16 nCol )
{
SvTreeListEntry* pEntry = new SvTreeListEntry;
if (!m_xCheckButtonData)
m_xCheckButtonData.reset(new SvLBoxButtonData(m_pLinguOptionsCLB));
if (CBCOL_FIRST == nCol)
pEntry->AddItem(o3tl::make_unique<SvLBoxButton>(SvLBoxButtonKind::EnabledCheckbox, m_xCheckButtonData.get()));
if (CBCOL_SECOND == nCol)
pEntry->AddItem(o3tl::make_unique<SvLBoxString>("")); // empty column
pEntry->AddItem(o3tl::make_unique<SvLBoxContextBmp>(Image(), Image(), false));
pEntry->AddItem(o3tl::make_unique<BrwString_Impl>(rTxt));
return pEntry;
}
void SvxLinguTabPage::HideGroups( sal_uInt16 nGrp )
{
if ( 0 != ( GROUP_MODULES & nGrp ) )
{
m_pLinguModulesFT->Hide();
m_pLinguModulesCLB->Hide();
m_pLinguModulesEditPB->Hide();
if ( SvtExtendedSecurityOptions().GetOpenHyperlinkMode()
!= SvtExtendedSecurityOptions::OPEN_NEVER )
{
m_pMoreDictsLink->Show();
}
}
}
SvxEditModulesDlg::SvxEditModulesDlg(vcl::Window* pParent, SvxLinguData_Impl& rData)
: ModalDialog( pParent, "EditModulesDialog",
"cui/ui/editmodulesdialog.ui")
, sSpell(CuiResId(RID_SVXSTR_SPELL))
, sHyph(CuiResId(RID_SVXSTR_HYPH))
, sThes(CuiResId(RID_SVXSTR_THES))
, sGrammar(CuiResId(RID_SVXSTR_GRAMMAR))
, rLinguData(rData)
{
get(m_pClosePB, "close");
get(m_pMoreDictsLink, "moredictslink");
get(m_pBackPB, "back");
get(m_pPrioDownPB, "down");
get(m_pPrioUpPB, "up");
get(m_pModulesCLB, "lingudicts");
Size aListSize(m_pModulesCLB->LogicToPixel(Size(166, 120), MapMode(MapUnit::MapAppFont)));
m_pModulesCLB->set_height_request(aListSize.Height());
m_pModulesCLB->set_width_request(aListSize.Width());
get(m_pLanguageLB, "language");
m_pLanguageLB->SetStyle(m_pLanguageLB->GetStyle() | WB_SORT);
pDefaultLinguData.reset( new SvxLinguData_Impl( rLinguData ) );
m_pModulesCLB->SetStyle( m_pModulesCLB->GetStyle()|WB_CLIPCHILDREN|WB_HSCROLL );
m_pModulesCLB->SetForceMakeVisible(true);
m_pModulesCLB->SetHighlightRange();
m_pModulesCLB->SetSelectHdl( LINK( this, SvxEditModulesDlg, SelectHdl_Impl ));
m_pModulesCLB->SetCheckButtonHdl( LINK( this, SvxEditModulesDlg, BoxCheckButtonHdl_Impl) );
m_pClosePB->SetClickHdl( LINK( this, SvxEditModulesDlg, ClickHdl_Impl ));
m_pPrioUpPB->SetClickHdl( LINK( this, SvxEditModulesDlg, UpDownHdl_Impl ));
m_pPrioDownPB->SetClickHdl( LINK( this, SvxEditModulesDlg, UpDownHdl_Impl ));
m_pBackPB->SetClickHdl( LINK( this, SvxEditModulesDlg, BackHdl_Impl ));
// in case of not installed language modules
m_pPrioUpPB->Enable( false );
m_pPrioDownPB->Enable( false );
if ( SvtExtendedSecurityOptions().GetOpenHyperlinkMode() == SvtExtendedSecurityOptions::OPEN_NEVER )
m_pMoreDictsLink->Hide();
//fill language box
std::vector< LanguageType > aAvailLang;
uno::Reference< XAvailableLocales > xAvail( rLinguData.GetManager(), UNO_QUERY );
if (xAvail.is())
{
aAvailLang = lcl_LocaleSeqToLangSeq(
xAvail->getAvailableLocales( cSpell ) );
}
const Sequence< Locale >& rLoc = rLinguData.GetAllSupportedLocales();
const Locale* pLocales = rLoc.getConstArray();
m_pLanguageLB->Clear();
for(long i = 0; i < rLoc.getLength(); i++)
{
LanguageType nLang = LanguageTag::convertToLanguageType( pLocales[i] );
m_pLanguageLB->InsertLanguage( nLang, lcl_SeqHasLang( aAvailLang, nLang ) );
}
LanguageType eSysLang = MsLangId::getSystemLanguage();
m_pLanguageLB->SelectLanguage( eSysLang );
if(!m_pLanguageLB->IsLanguageSelected( eSysLang ) )
m_pLanguageLB->SelectEntryPos(0);
m_pLanguageLB->SetSelectHdl( LINK( this, SvxEditModulesDlg, LangSelectListBoxHdl_Impl ));
LangSelectHdl_Impl(m_pLanguageLB);
}
SvxEditModulesDlg::~SvxEditModulesDlg()
{
disposeOnce();
}
void SvxEditModulesDlg::dispose()
{
pDefaultLinguData.reset();
m_pLanguageLB.clear();
for(sal_uLong i = 0; i < m_pModulesCLB->GetEntryCount(); i++)
delete static_cast<ModuleUserData_Impl*>(m_pModulesCLB->GetEntry(i)->GetUserData());
m_pModulesCLB.clear();
m_pPrioUpPB.clear();
m_pPrioDownPB.clear();
m_pBackPB.clear();
m_pMoreDictsLink.clear();
m_pClosePB.clear();
ModalDialog::dispose();
}
SvTreeListEntry* SvxEditModulesDlg::CreateEntry( OUString& rTxt, sal_uInt16 nCol )
{
SvTreeListEntry* pEntry = new SvTreeListEntry;
if (!m_xCheckButtonData )
{
m_xCheckButtonData.reset(new SvLBoxButtonData(m_pModulesCLB));
m_xCheckButtonData->SetLink( LINK( this, SvxEditModulesDlg, BoxCheckButtonHdl_Impl2 ) );
}
if (CBCOL_FIRST == nCol)
pEntry->AddItem(o3tl::make_unique<SvLBoxButton>(SvLBoxButtonKind::EnabledCheckbox, m_xCheckButtonData.get()));
if (CBCOL_SECOND == nCol)
pEntry->AddItem(o3tl::make_unique<SvLBoxString>("")); // empty column
pEntry->AddItem(o3tl::make_unique<SvLBoxContextBmp>(Image(), Image(), false));
pEntry->AddItem(o3tl::make_unique<BrwStringDic_Impl>(rTxt));
return pEntry;
}
IMPL_LINK( SvxEditModulesDlg, SelectHdl_Impl, SvTreeListBox*, pBox, void )
{
if (m_pModulesCLB == pBox)
{
SvTreeListEntry *pEntry = pBox->GetCurEntry();
if (pEntry)
{
bool bDisableUp = true;
bool bDisableDown = true;
ModuleUserData_Impl* pData = static_cast<ModuleUserData_Impl*>(pEntry->GetUserData());
if(!pData->IsParent() && pData->GetType() != TYPE_HYPH)
{
sal_uLong nCurPos = static_cast<SvxCheckListBox*>(pBox)->GetSelectedEntryPos();
if(nCurPos < pBox->GetEntryCount() - 1)
{
bDisableDown = static_cast<ModuleUserData_Impl*>(pBox->
GetEntry(nCurPos + 1)->GetUserData())->IsParent();
}
if(nCurPos > 1)
{
bDisableUp = static_cast<ModuleUserData_Impl*>(pBox->
GetEntry(nCurPos - 1)->GetUserData())->IsParent();
}
}
m_pPrioUpPB->Enable(!bDisableUp);
m_pPrioDownPB->Enable(!bDisableDown);
}
}
else
{
OSL_FAIL( "pBox unexpected value" );
}
}
IMPL_LINK_NOARG( SvxEditModulesDlg, BoxCheckButtonHdl_Impl2, SvLBoxButtonData*, void )
{
BoxCheckButtonHdl_Impl(nullptr);
}
IMPL_LINK_NOARG( SvxEditModulesDlg, BoxCheckButtonHdl_Impl, SvTreeListBox *, void )
{
SvTreeListEntry *pCurEntry = m_pModulesCLB->GetCurEntry();
if (pCurEntry)
{
ModuleUserData_Impl* pData = static_cast<ModuleUserData_Impl *>(
pCurEntry->GetUserData());
if (!pData->IsParent() && pData->GetType() == TYPE_HYPH)
{
// make hyphenator checkboxes function as radio-buttons
// (at most one box may be checked)
SvTreeListEntry *pEntry = m_pModulesCLB->First();
while (pEntry)
{
pData = static_cast<ModuleUserData_Impl*>(pEntry->GetUserData());
if (!pData->IsParent() &&
pData->GetType() == TYPE_HYPH &&
pEntry != pCurEntry)
{
lcl_SetCheckButton( pEntry, false );
m_pModulesCLB->InvalidateEntry( pEntry );
}
pEntry = m_pModulesCLB->Next( pEntry );
}
}
}
}
IMPL_LINK( SvxEditModulesDlg, LangSelectListBoxHdl_Impl, ListBox&, rBox, void )
{
LangSelectHdl_Impl(&rBox);
}
void SvxEditModulesDlg::LangSelectHdl_Impl(ListBox const * pBox)
{
LanguageType eCurLanguage = m_pLanguageLB->GetSelectedLanguage();
static Locale aLastLocale;
Locale aCurLocale( LanguageTag::convertToLocale( eCurLanguage));
SvTreeList *pModel = m_pModulesCLB->GetModel();
if (pBox)
{
// save old probably changed settings
// before switching to new language entries
LanguageType nLang = LanguageTag::convertToLanguageType( aLastLocale );
sal_Int32 nStart = 0, nLocalIndex = 0;
Sequence< OUString > aChange;
bool bChanged = false;
for(sal_uLong i = 0; i < m_pModulesCLB->GetEntryCount(); i++)
{
SvTreeListEntry *pEntry = m_pModulesCLB->GetEntry(i);
ModuleUserData_Impl* pData = static_cast<ModuleUserData_Impl*>(pEntry->GetUserData());
if(pData->IsParent())
{
if(bChanged)
{
LangImplNameTable *pTable = nullptr;
sal_uInt8 nType = pData->GetType();
switch (nType - 1)
{
case TYPE_SPELL : pTable = &rLinguData.GetSpellTable(); break;
case TYPE_GRAMMAR : pTable = &rLinguData.GetGrammarTable(); break;
case TYPE_HYPH : pTable = &rLinguData.GetHyphTable(); break;
case TYPE_THES : pTable = &rLinguData.GetThesTable(); break;
}
if (pTable)
{
aChange.realloc(nStart);
(*pTable)[ nLang ] = aChange;
}
}
nLocalIndex = nStart = 0;
aChange.realloc(m_pModulesCLB->GetEntryCount());
bChanged = false;
}
else
{
OUString* pChange = aChange.getArray();
pChange[nStart] = pData->GetImplName();
bChanged |= pData->GetIndex() != nLocalIndex ||
pData->IsChecked() != m_pModulesCLB->IsChecked(i);
if(m_pModulesCLB->IsChecked(i))
nStart++;
++nLocalIndex;
}
}
if(bChanged)
{
aChange.realloc(nStart);
rLinguData.GetThesTable()[ nLang ] = aChange;
}
}
for(sal_uLong i = 0; i < m_pModulesCLB->GetEntryCount(); i++)
delete static_cast<ModuleUserData_Impl*>(m_pModulesCLB->GetEntry(i)->GetUserData());
// display entries for new selected language
m_pModulesCLB->Clear();
if(LANGUAGE_DONTKNOW != eCurLanguage)
{
sal_uLong n;
ServiceInfo_Impl* pInfo;
// spellchecker entries
SvTreeListEntry* pEntry = CreateEntry( sSpell, CBCOL_SECOND );
ModuleUserData_Impl* pUserData = new ModuleUserData_Impl(
OUString(), true, false, TYPE_SPELL, 0 );
pEntry->SetUserData( static_cast<void *>(pUserData) );
pModel->Insert( pEntry );
Sequence< OUString > aNames( rLinguData.GetSortedImplNames( eCurLanguage, TYPE_SPELL ) );
const OUString *pName = aNames.getConstArray();
sal_uLong nNames = static_cast<sal_uLong>(aNames.getLength());
sal_Int32 nLocalIndex = 0; // index relative to parent
for (n = 0; n < nNames; ++n)
{
OUString aImplName;
bool bIsSuppLang = false;
pInfo = rLinguData.GetInfoByImplName( pName[n] );
if (pInfo)
{
bIsSuppLang = pInfo->xSpell.is() &&
pInfo->xSpell->hasLocale( aCurLocale );
aImplName = pInfo->sSpellImplName;
}
if (!aImplName.isEmpty() && bIsSuppLang)
{
OUString aTxt( pInfo->sDisplayName );
SvTreeListEntry* pNewEntry = CreateEntry( aTxt, CBCOL_FIRST );
LangImplNameTable &rTable = rLinguData.GetSpellTable();
const bool bHasLang = rTable.count( eCurLanguage );
if (!bHasLang)
{
SAL_INFO( "cui.options", "language entry missing" ); // only relevant if all languages found should be supported
}
const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0;
lcl_SetCheckButton( pNewEntry, bCheck );
pUserData = new ModuleUserData_Impl( aImplName, false,
bCheck, TYPE_SPELL, static_cast<sal_uInt8>(nLocalIndex++) );
pNewEntry->SetUserData( static_cast<void *>(pUserData) );
pModel->Insert( pNewEntry );
}
}
// grammar checker entries
pEntry = CreateEntry( sGrammar, CBCOL_SECOND );
pUserData = new ModuleUserData_Impl( OUString(), true, false, TYPE_GRAMMAR, 0 );
pEntry->SetUserData( static_cast<void *>(pUserData) );
pModel->Insert( pEntry );
aNames = rLinguData.GetSortedImplNames( eCurLanguage, TYPE_GRAMMAR );
pName = aNames.getConstArray();
nNames = static_cast<sal_uLong>(aNames.getLength());
nLocalIndex = 0;
for (n = 0; n < nNames; ++n)
{
OUString aImplName;
bool bIsSuppLang = false;
pInfo = rLinguData.GetInfoByImplName( pName[n] );
if (pInfo)
{
bIsSuppLang = pInfo->xGrammar.is() &&
pInfo->xGrammar->hasLocale( aCurLocale );
aImplName = pInfo->sGrammarImplName;
}
if (!aImplName.isEmpty() && bIsSuppLang)
{
OUString aTxt( pInfo->sDisplayName );
SvTreeListEntry* pNewEntry = CreateEntry( aTxt, CBCOL_FIRST );
LangImplNameTable &rTable = rLinguData.GetGrammarTable();
const bool bHasLang = rTable.count( eCurLanguage );
if (!bHasLang)
{
SAL_INFO( "cui.options", "language entry missing" ); // only relevant if all languages found should be supported
}
const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0;
lcl_SetCheckButton( pNewEntry, bCheck );
pUserData = new ModuleUserData_Impl( aImplName, false,
bCheck, TYPE_GRAMMAR, static_cast<sal_uInt8>(nLocalIndex++) );
pNewEntry->SetUserData( static_cast<void *>(pUserData) );
pModel->Insert( pNewEntry );
}
}
// hyphenator entries
pEntry = CreateEntry( sHyph, CBCOL_SECOND );
pUserData = new ModuleUserData_Impl( OUString(), true, false, TYPE_HYPH, 0 );
pEntry->SetUserData( static_cast<void *>(pUserData) );
pModel->Insert( pEntry );
aNames = rLinguData.GetSortedImplNames( eCurLanguage, TYPE_HYPH );
pName = aNames.getConstArray();
nNames = static_cast<sal_uLong>(aNames.getLength());
nLocalIndex = 0;
for (n = 0; n < nNames; ++n)
{
OUString aImplName;
bool bIsSuppLang = false;
pInfo = rLinguData.GetInfoByImplName( pName[n] );
if (pInfo)
{
bIsSuppLang = pInfo->xHyph.is() &&
pInfo->xHyph->hasLocale( aCurLocale );
aImplName = pInfo->sHyphImplName;
}
if (!aImplName.isEmpty() && bIsSuppLang)
{
OUString aTxt( pInfo->sDisplayName );
SvTreeListEntry* pNewEntry = CreateEntry( aTxt, CBCOL_FIRST );
LangImplNameTable &rTable = rLinguData.GetHyphTable();
const bool bHasLang = rTable.count( eCurLanguage );
if (!bHasLang)
{
SAL_INFO( "cui.options", "language entry missing" ); // only relevant if all languages found should be supported
}
const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0;
lcl_SetCheckButton( pNewEntry, bCheck );
pUserData = new ModuleUserData_Impl( aImplName, false,
bCheck, TYPE_HYPH, static_cast<sal_uInt8>(nLocalIndex++) );
pNewEntry->SetUserData( static_cast<void *>(pUserData) );
pModel->Insert( pNewEntry );
}
}
// thesaurus entries
pEntry = CreateEntry( sThes, CBCOL_SECOND );
pUserData = new ModuleUserData_Impl( OUString(), true, false, TYPE_THES, 0 );
pEntry->SetUserData( static_cast<void *>(pUserData) );
pModel->Insert( pEntry );
aNames = rLinguData.GetSortedImplNames( eCurLanguage, TYPE_THES );
pName = aNames.getConstArray();
nNames = static_cast<sal_uLong>(aNames.getLength());
nLocalIndex = 0;
for (n = 0; n < nNames; ++n)
{
OUString aImplName;
bool bIsSuppLang = false;
pInfo = rLinguData.GetInfoByImplName( pName[n] );
if (pInfo)
{
bIsSuppLang = pInfo->xThes.is() &&
pInfo->xThes->hasLocale( aCurLocale );
aImplName = pInfo->sThesImplName;
}
if (!aImplName.isEmpty() && bIsSuppLang)
{
OUString aTxt( pInfo->sDisplayName );
SvTreeListEntry* pNewEntry = CreateEntry( aTxt, CBCOL_FIRST );
LangImplNameTable &rTable = rLinguData.GetThesTable();
const bool bHasLang = rTable.count( eCurLanguage );
if (!bHasLang)
{
SAL_INFO( "cui.options", "language entry missing" ); // only relevant if all languages found should be supported
}
const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0;
lcl_SetCheckButton( pNewEntry, bCheck );
pUserData = new ModuleUserData_Impl( aImplName, false,
bCheck, TYPE_THES, static_cast<sal_uInt8>(nLocalIndex++) );
pNewEntry->SetUserData( static_cast<void *>(pUserData) );
pModel->Insert( pNewEntry );
}
}
}
aLastLocale = aCurLocale;
}
IMPL_LINK( SvxEditModulesDlg, UpDownHdl_Impl, Button *, pBtn, void )
{
bool bUp = m_pPrioUpPB == pBtn;
sal_uLong nCurPos = m_pModulesCLB->GetSelectedEntryPos();
SvTreeListEntry* pEntry;
if (nCurPos != TREELIST_ENTRY_NOTFOUND &&
nullptr != (pEntry = m_pModulesCLB->GetEntry(nCurPos)))
{
m_pModulesCLB->SetUpdateMode(false);
SvTreeList *pModel = m_pModulesCLB->GetModel();
ModuleUserData_Impl* pData = static_cast<ModuleUserData_Impl*>(pEntry->GetUserData());
OUString aStr(m_pModulesCLB->GetEntryText(pEntry));
SvTreeListEntry* pToInsert = CreateEntry( aStr, CBCOL_FIRST );
pToInsert->SetUserData( static_cast<void *>(pData));
bool bIsChecked = m_pModulesCLB->IsChecked(nCurPos);
pModel->Remove(pEntry);
sal_uLong nDestPos = bUp ? nCurPos - 1 : nCurPos + 1;
pModel->Insert(pToInsert, nDestPos);
m_pModulesCLB->CheckEntryPos(nDestPos, bIsChecked );
m_pModulesCLB->SelectEntryPos(nDestPos );
SelectHdl_Impl(m_pModulesCLB);
m_pModulesCLB->SetUpdateMode(true);
}
}
IMPL_LINK_NOARG(SvxEditModulesDlg, ClickHdl_Impl, Button*, void)
{
// store language config
LangSelectHdl_Impl(m_pLanguageLB);
EndDialog( RET_OK );
}
IMPL_LINK_NOARG(SvxEditModulesDlg, BackHdl_Impl, Button*, void)
{
rLinguData = *pDefaultLinguData;
LangSelectHdl_Impl(nullptr);
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V560 A part of conditional expression is always true: pEntry.
↑ V560 A part of conditional expression is always true: pEntry.
↑ V560 A part of conditional expression is always true: pTmp.