xref: /aoo42x/main/cui/source/options/optlingu.cxx (revision 2ee96f1c)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_cui.hxx"
26 
27 // include ---------------------------------------------------------------
28 
29 #include <vcl/msgbox.hxx>
30 #include <vcl/field.hxx>
31 #include <vcl/fixed.hxx>
32 #include <tools/shl.hxx>
33 #include <tools/dynary.hxx>
34 #include <i18npool/mslangid.hxx>
35 #include <unotools/lingucfg.hxx>
36 #include <editeng/unolingu.hxx>
37 #include <svx/dlgutil.hxx>
38 #include <linguistic/lngprops.hxx>
39 #include <linguistic/misc.hxx>
40 #include <sfx2/sfxuno.hxx>
41 #include <sfx2/dispatch.hxx>
42 #include <tools/urlobj.hxx>
43 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
44 #include <comphelper/processfactory.hxx>
45 #include <com/sun/star/linguistic2/XSpellChecker.hpp>
46 #include <com/sun/star/linguistic2/XProofreader.hpp>
47 #include <com/sun/star/linguistic2/XHyphenator.hpp>
48 #include <com/sun/star/linguistic2/XThesaurus.hpp>
49 #include <com/sun/star/linguistic2/XAvailableLocales.hpp>
50 #include <com/sun/star/lang/XServiceDisplayName.hpp>
51 #include <com/sun/star/linguistic2/DictionaryListEventFlags.hpp>
52 #include <com/sun/star/linguistic2/DictionaryListEvent.hpp>
53 #include <com/sun/star/linguistic2/XDictionaryListEventListener.hpp>
54 #include <com/sun/star/linguistic2/XDictionaryList.hpp>
55 #include <com/sun/star/frame/XStorable.hpp>
56 #include <com/sun/star/ucb/CommandAbortedException.hpp>
57 #include <com/sun/star/system/XSystemShellExecute.hpp>
58 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
59 #include <unotools/extendedsecurityoptions.hxx>
60 #include <svtools/svlbox.hxx>
61 #include <svl/eitem.hxx>
62 #include <svl/intitem.hxx>
63 #include <sfx2/viewfrm.hxx>
64 #include <vcl/svapp.hxx>
65 #define _SVX_OPTLINGU_CXX
66 #include "optlingu.hrc"
67 
68 #include <svx/svxdlg.hxx>
69 #include <editeng/optitems.hxx>
70 #include "optlingu.hxx"
71 #include <dialmgr.hxx>
72 #include <cuires.hrc>
73 #include "helpid.hrc"
74 
75 #include <ucbhelper/content.hxx>
76 
77 #include <vector>
78 #include <map>
79 
80 
81 using namespace ::ucbhelper;
82 using namespace ::rtl;
83 using namespace ::com::sun::star;
84 using namespace ::com::sun::star::lang;
85 using namespace ::com::sun::star::uno;
86 using namespace ::com::sun::star::linguistic2;
87 using namespace ::com::sun::star::beans;
88 namespace css = com::sun::star;
89 
90 #define C2U(cChar) OUString::createFromAscii(cChar)
91 #define SVX_MAX_USERDICTS 20
92 #define CBCOL_FIRST		0
93 #define CBCOL_SECOND	1
94 #define CBCOL_BOTH		2
95 
96 static const sal_Char cSpell[]   = SN_SPELLCHECKER;
97 static const sal_Char cGrammar[] = SN_GRAMMARCHECKER;
98 static const sal_Char cHyph[]    = SN_HYPHENATOR;
99 static const sal_Char cThes[]    = SN_THESAURUS;
100 
101 // static ----------------------------------------------------------------
102 
103 static Sequence< sal_Int16 > lcl_LocaleSeqToLangSeq( const Sequence< Locale > &rSeq )
104 {
105     sal_Int32 nLen = rSeq.getLength();
106     Sequence< sal_Int16 > aRes( nLen );
107     sal_Int16 *pRes = aRes.getArray();
108     const Locale *pSeq = rSeq.getConstArray();
109     for (sal_Int32 i = 0;  i < nLen;  ++i)
110     {
111         pRes[i] = SvxLocaleToLanguage( pSeq[i] );
112     }
113     return aRes;
114 }
115 
116 
117 static sal_Bool lcl_SeqHasLang( const Sequence< sal_Int16 > &rSeq, sal_Int16 nLang )
118 {
119     sal_Int32 nLen = rSeq.getLength();
120     const sal_Int16 *pLang = rSeq.getConstArray();
121     sal_Int32 nPos = -1;
122     for (sal_Int32 i = 0;  i < nLen  &&  nPos < 0;  ++i)
123     {
124         if (nLang == pLang[i])
125             nPos = i;
126     }
127     return nPos < 0 ? sal_False : sal_True;
128 }
129 
130 
131 static sal_Int32 lcl_SeqGetEntryPos(
132 	const Sequence< OUString > &rSeq, const OUString &rEntry )
133 {
134 	sal_Int32 i;
135 	sal_Int32 nLen = rSeq.getLength();
136 	const OUString *pItem = rSeq.getConstArray();
137 	for (i = 0;  i < nLen;  ++i)
138 	{
139 		if (rEntry == pItem[i])
140 			break;
141 	}
142     return i < nLen ? i : -1;
143 }
144 
145 static void lcl_OpenURL( const ::rtl::OUString& rURL )
146 {
147     if ( rURL.getLength() > 0 )
148     {
149         try
150         {
151             uno::Reference< lang::XMultiServiceFactory > xSMGR =
152                 ::comphelper::getProcessServiceFactory();
153             uno::Reference< css::system::XSystemShellExecute > xSystemShell(
154                 xSMGR->createInstance( ::rtl::OUString(
155                     RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.system.SystemShellExecute" ) ) ),
156                 uno::UNO_QUERY_THROW );
157             if ( xSystemShell.is() )
158                 xSystemShell->execute( rURL, ::rtl::OUString(), css::system::SystemShellExecuteFlags::DEFAULTS );
159         }
160         catch( const uno::Exception& e )
161         {
162              OSL_TRACE( "Caught exception: %s\n thread terminated.\n",
163                 rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
164         }
165     }
166 }
167 
168 /*--------------------------------------------------
169 --------------------------------------------------*/
170 
171 static const sal_uInt16 nNameLen = 8;
172 
173 static sal_uInt16 pRanges[] =
174 {
175 	SID_ATTR_SPELL,
176 	SID_ATTR_SPELL,
177 	0
178 };
179 
180 sal_Bool KillFile_Impl( const String& rURL )
181 {
182 	sal_Bool bRet = sal_True;
183 	try
184 	{
185 		Content aCnt( rURL, uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () );
186 		aCnt.executeCommand( OUString::createFromAscii( "delete" ), makeAny( sal_Bool( sal_True ) ) );
187 	}
188 	catch( ::com::sun::star::ucb::CommandAbortedException& )
189 	{
190 		DBG_ERRORFILE( "KillFile: CommandAbortedException" );
191 		bRet = sal_False;
192 	}
193 	catch( ... )
194 	{
195 		DBG_ERRORFILE( "KillFile: Any other exception" );
196 		bRet = sal_False;
197 	}
198 
199 	return bRet;
200 }
201 /* -----------------------------27.11.00 14:07--------------------------------
202 
203  ---------------------------------------------------------------------------*/
204 // 0x 0p 0t 0c nn
205 // p: 1 -> parent
206 // t: 1 -> spell, 2 -> hyph, 3 -> thes, 4 -> grammar
207 // c: 1 -> checked 0 -> unchecked
208 // n: index
209 
210 #define TYPE_SPELL      (sal_uInt8)1
211 #define TYPE_GRAMMAR    (sal_uInt8)2
212 #define TYPE_HYPH       (sal_uInt8)3
213 #define TYPE_THES       (sal_uInt8)4
214 
215 class ModuleUserData_Impl
216 {
217 	sal_Bool bParent;
218 	sal_Bool bIsChecked;
219 	sal_uInt8 nType;
220 	sal_uInt8 nIndex;
221 	String	sImplName;
222 
223 public:
224 	ModuleUserData_Impl( String sImpName, sal_Bool bIsParent, sal_Bool bChecked, sal_uInt8 nSetType, sal_uInt8 nSetIndex ) :
225 		bParent(bIsParent),
226 		bIsChecked(bChecked),
227 		nType(nSetType),
228 		nIndex(nSetIndex),
229 		sImplName(sImpName)
230 		{
231 		}
232 	sal_Bool IsParent() const {return bParent;}
233 	sal_uInt8 GetType() const {return nType;}
234 	sal_Bool IsChecked() const {return bIsChecked;}
235 	sal_uInt8 GetIndex() const {return nIndex;}
236 	void SetIndex(sal_uInt8 nSet)  {nIndex = nSet;}
237 	const String& GetImplName() const {return sImplName;}
238 
239 };
240 
241 /*--------------------------------------------------
242 --------------------------------------------------*/
243 //
244 // User for user-dictionaries (XDictionary interface)
245 //
246 class DicUserData
247 {
248 	sal_uLong	nVal;
249 
250 public:
251 	DicUserData( sal_uLong nUserData ) : nVal( nUserData ) {}
252 	DicUserData( sal_uInt16 nEID,
253 				 sal_Bool bChecked, sal_Bool bEditable, sal_Bool bDeletable );
254 
255 	sal_uLong	GetUserData() const			{ return nVal; }
256 	sal_uInt16	GetEntryId() const			{ return (sal_uInt16)(nVal >> 16); }
257 	sal_Bool	IsChecked() const			{ return (sal_Bool)(nVal >>  8) & 0x01; }
258 	sal_Bool	IsEditable() const			{ return (sal_Bool)(nVal >>  9) & 0x01; }
259 	sal_Bool	IsDeletable() const			{ return (sal_Bool)(nVal >> 10) & 0x01; }
260 
261 	void	SetChecked( sal_Bool bVal );
262 };
263 
264 
265 DicUserData::DicUserData(
266 		sal_uInt16 nEID,
267 		sal_Bool bChecked, sal_Bool bEditable, sal_Bool bDeletable )
268 {
269 	DBG_ASSERT( nEID < 65000, "Entry Id out of range" );
270 	nVal =  ((sal_uLong)(0xFFFF & nEID)			<< 16) |
271 			((sal_uLong)(bChecked ? 1 : 0)		<<  8) |
272 			((sal_uLong)(bEditable ? 1 : 0)		<<  9) |
273 			((sal_uLong)(bDeletable ? 1 : 0)	<< 10);
274 }
275 
276 
277 void DicUserData::SetChecked( sal_Bool bVal )
278 {
279 	nVal &= ~(1UL << 8);
280 	nVal |=  (sal_uLong)(bVal ? 1 : 0) << 8;
281 }
282 
283 
284 // class BrwString_Impl -------------------------------------------------
285 
286 void lcl_SetCheckButton( SvLBoxEntry* pEntry, sal_Bool bCheck )
287 {
288 	SvLBoxButton* pItem = (SvLBoxButton*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON));
289 
290 	DBG_ASSERT(pItem,"SetCheckButton:Item not found");
291 	if (((SvLBoxItem*)pItem)->IsA() == SV_ITEM_ID_LBOXBUTTON)
292 	{
293 		if (bCheck)
294 			pItem->SetStateChecked();
295 		else
296 			pItem->SetStateUnchecked();
297 		//InvalidateEntry( pEntry );
298 	}
299 }
300 
301 
302 class BrwStringDic_Impl : public SvLBoxString
303 {
304 public:
305 
306 	BrwStringDic_Impl( SvLBoxEntry* pEntry, sal_uInt16 nFlags,
307 		const String& rStr ) : SvLBoxString( pEntry, nFlags, rStr ) {}
308 
309 	virtual void Paint( const Point& rPos, SvLBox& rDev, sal_uInt16 nFlags,
310 											SvLBoxEntry* pEntry);
311 };
312 
313 void BrwStringDic_Impl::Paint( const Point& rPos, SvLBox& rDev, sal_uInt16,
314 	SvLBoxEntry* pEntry )
315 {
316 	ModuleUserData_Impl* pData = (ModuleUserData_Impl*)pEntry->GetUserData();
317 	Point aPos(rPos);
318 	Font aOldFont( rDev.GetFont());
319 	if(pData->IsParent())
320 	{
321 		Font aFont( aOldFont );
322 		aFont.SetWeight( WEIGHT_BOLD );
323 		rDev.SetFont( aFont );
324 		aPos.X() = 0;
325 	}
326 	else
327 		aPos.X() += 5;
328 	rDev.DrawText( aPos, GetText() );
329 	rDev.SetFont( aOldFont );
330 }
331 
332 
333 /*--------------------------------------------------
334 --------------------------------------------------*/
335 
336 class OptionsBreakSet : public ModalDialog
337 {
338 	OKButton 		aOKPB;
339 	CancelButton	aCancelPB;
340     FixedLine       aValFL;
341 	NumericField	aValNF;
342 
343 public:
344 	OptionsBreakSet(Window* pParent, int nRID) :
345 			ModalDialog(pParent, CUI_RES(RID_SVXDLG_LNG_ED_NUM_PREBREAK )),
346 			aOKPB		(this, CUI_RES(BT_OK_PREBREAK)),
347 			aCancelPB	(this, CUI_RES(BT_CANCEL_PREBREAK)),
348             aValFL      (this, CUI_RES(FL_NUMVAL_PREBREAK)),
349 			aValNF		(this, CUI_RES(ED_PREBREAK))
350 	{
351 		DBG_ASSERT( STR_NUM_PRE_BREAK_DLG   == nRID	||
352 					STR_NUM_POST_BREAK_DLG  == nRID	||
353 					STR_NUM_MIN_WORDLEN_DLG == nRID, "unexpected RID" );
354 
355 		if (nRID != -1)
356             aValFL.SetText( String( CUI_RES(nRID) ) );
357 		FreeResource();
358 	}
359 
360 	NumericField& 	GetNumericFld()	{ return aValNF; }
361 };
362 
363 
364 /*--------------------------------------------------
365 	Entry IDs for options listbox of dialog
366 --------------------------------------------------*/
367 
368 enum EID_OPTIONS
369 {
370     EID_SPELL_AUTO,
371     EID_GRAMMAR_AUTO,
372 	EID_CAPITAL_WORDS,
373 	EID_WORDS_WITH_DIGITS,
374 	EID_CAPITALIZATION,
375 	EID_SPELL_SPECIAL,
376 	EID_NUM_MIN_WORDLEN,
377 	EID_NUM_PRE_BREAK,
378 	EID_NUM_POST_BREAK,
379 	EID_HYPH_AUTO,
380 	EID_HYPH_SPECIAL
381 };
382 
383 //! this array must have an entry for every value of EID_OPTIONS.
384 //  It is used to get the respective property name.
385 static const char * aEidToPropName[] =
386 {
387     UPN_IS_SPELL_AUTO,				// EID_SPELL_AUTO
388     UPN_IS_GRAMMAR_AUTO,            // EID_GRAMMAR_AUTO
389 	UPN_IS_SPELL_UPPER_CASE,		// EID_CAPITAL_WORDS
390 	UPN_IS_SPELL_WITH_DIGITS,		// EID_WORDS_WITH_DIGITS
391 	UPN_IS_SPELL_CAPITALIZATION,    // EID_CAPITALIZATION
392 	UPN_IS_SPELL_SPECIAL,			// EID_SPELL_SPECIAL
393 	UPN_HYPH_MIN_WORD_LENGTH,		// EID_NUM_MIN_WORDLEN,
394 	UPN_HYPH_MIN_LEADING,			// EID_NUM_PRE_BREAK
395 	UPN_HYPH_MIN_TRAILING,			// EID_NUM_POST_BREAK
396 	UPN_IS_HYPH_AUTO,				// EID_HYPH_AUTO
397 	UPN_IS_HYPH_SPECIAL				// EID_HYPH_SPECIAL
398 };
399 
400 
401 static inline String lcl_GetPropertyName( EID_OPTIONS eEntryId )
402 {
403 	DBG_ASSERT( (unsigned int) eEntryId < sizeof(aEidToPropName) / sizeof(aEidToPropName[0]), "index out of range" );
404 	return String::CreateFromAscii( aEidToPropName[ (int) eEntryId ] );
405 }
406 
407 // class OptionsUserData -------------------------------------------------
408 
409 class OptionsUserData
410 {
411 	sal_uLong	nVal;
412 
413 	void	SetModified();
414 
415 public:
416 	OptionsUserData( sal_uLong nUserData ) : nVal( nUserData ) {}
417 	OptionsUserData( sal_uInt16 nEID,
418 					 sal_Bool bHasNV, sal_uInt16 nNumVal,
419 					 sal_Bool bCheckable, sal_Bool bChecked );
420 
421 	sal_uLong	GetUserData() const			{ return nVal; }
422 	sal_uInt16	GetEntryId() const			{ return (sal_uInt16)(nVal >> 16); }
423 	sal_Bool	HasNumericValue() const		{ return (sal_Bool)(nVal >> 10) & 0x01; }
424 	sal_uInt16	GetNumericValue() const		{ return (sal_uInt16)(nVal & 0xFF); }
425 	sal_Bool	IsChecked() const			{ return (sal_Bool)(nVal >> 8) & 0x01; }
426 	sal_Bool	IsCheckable() const			{ return (sal_Bool)(nVal >> 9) & 0x01; }
427 	sal_Bool	IsModified() const			{ return (sal_Bool)(nVal >> 11) & 0x01; }
428 
429 	void	SetChecked( sal_Bool bVal );
430 	void	SetNumericValue( sal_uInt8 nNumVal );
431 };
432 
433 OptionsUserData::OptionsUserData( sal_uInt16 nEID,
434 		sal_Bool bHasNV, sal_uInt16 nNumVal,
435 		sal_Bool bCheckable, sal_Bool bChecked )
436 {
437 	DBG_ASSERT( nEID < 65000, "Entry Id out of range" );
438 	DBG_ASSERT( nNumVal < 256, "value out of range" );
439 	nVal =  ((sal_uLong)(0xFFFF & nEID)			<< 16) |
440 			((sal_uLong)(bHasNV ? 1 : 0)		<< 10) |
441 			((sal_uLong)(bCheckable ? 1 : 0)	<<  9) |
442 			((sal_uLong)(bChecked ? 1 : 0)		<<  8) |
443 			((sal_uLong)(0xFF & nNumVal));
444 }
445 
446 void OptionsUserData::SetChecked( sal_Bool bVal )
447 {
448 	if (IsCheckable()  &&  (IsChecked() != bVal))
449 	{
450 		nVal &= ~(1UL << 8);
451 		nVal |=  (sal_uLong)(bVal ? 1 : 0) << 8;
452 		SetModified();
453 	}
454 }
455 
456 void OptionsUserData::SetNumericValue( sal_uInt8 nNumVal )
457 {
458 //	DBG_ASSERT( nNumVal < 256, "value out of range" );
459 	if (HasNumericValue()  &&  (GetNumericValue() != nNumVal))
460 	{
461 		nVal &= 0xffffff00;
462 		nVal |= (nNumVal);
463 		SetModified();
464 	}
465 }
466 
467 void OptionsUserData::SetModified()
468 {
469 	nVal |=  (sal_uLong)1 << 11;
470 }
471 
472 // class BrwString_Impl -------------------------------------------------
473 
474 class BrwString_Impl : public SvLBoxString
475 {
476 public:
477 
478 	BrwString_Impl( SvLBoxEntry* pEntry, sal_uInt16 nFlags,
479 		const String& rStr ) : SvLBoxString( pEntry, nFlags, rStr ) {}
480 
481 	virtual void Paint( const Point& rPos, SvLBox& rDev, sal_uInt16 nFlags,
482 											SvLBoxEntry* pEntry);
483 };
484 
485 void BrwString_Impl::Paint( const Point& rPos, SvLBox& rDev, sal_uInt16,
486 	SvLBoxEntry* pEntry )
487 {
488 	Point aPos(rPos);
489 	aPos.X() += 20;
490 	rDev.DrawText( aPos, GetText() );
491 	if(pEntry->GetUserData())
492 	{
493 		Point aNewPos(aPos);
494 		aNewPos.X() += rDev.GetTextWidth(GetText());
495 		Font aOldFont( rDev.GetFont());
496 		Font aFont( aOldFont );
497 		aFont.SetWeight( WEIGHT_BOLD );
498 
499 //		sal_Bool bFett = sal_True;
500 //		sal_uInt16 nPos = 0;
501 		//??? das untere byte aus dem user data in string wandeln
502 		OptionsUserData aData( (sal_uLong) pEntry->GetUserData() );
503 		if(aData.HasNumericValue())
504 		{
505 			String sTxt( ' ' );
506 			sTxt +=  String::CreateFromInt32( aData.GetNumericValue() );
507 			rDev.SetFont( aFont );
508 			rDev.DrawText( aNewPos, sTxt );
509 		}
510 
511 //			if( STRING_NOTFOUND != nPos )
512 //				aNewPos.X() += rDev.GetTextWidth( sTxt );
513 
514 		rDev.SetFont( aOldFont );
515 	}
516 }
517 
518 // ServiceInfo_Impl ----------------------------------------------------
519 
520 struct ServiceInfo_Impl
521 {
522 	OUString					sDisplayName;
523 	OUString					sSpellImplName;
524 	OUString					sHyphImplName;
525 	OUString					sThesImplName;
526     OUString                    sGrammarImplName;
527     uno::Reference< XSpellChecker >     xSpell;
528     uno::Reference< XHyphenator >       xHyph;
529     uno::Reference< XThesaurus >        xThes;
530     uno::Reference< XProofreader >   	xGrammar;
531 	sal_Bool						bConfigured;
532 
533     ServiceInfo_Impl() : bConfigured(sal_False) {}
534 };
535 
536 typedef std::vector< ServiceInfo_Impl >                             ServiceInfoArr;
537 typedef std::map< sal_Int16 /*LanguageType*/, Sequence< OUString > >    LangImplNameTable;
538 
539 
540 // SvxLinguData_Impl ----------------------------------------------------
541 
542 class SvxLinguData_Impl
543 {
544     //contains services and implementation names sorted by implementation names
545 	ServiceInfoArr			   			aDisplayServiceArr;
546     sal_uLong                               nDisplayServices;
547 
548     Sequence< Locale >                  aAllServiceLocales;
549     LangImplNameTable                   aCfgSpellTable;
550     LangImplNameTable                   aCfgHyphTable;
551     LangImplNameTable                   aCfgThesTable;
552     LangImplNameTable                   aCfgGrammarTable;
553     uno::Reference< XMultiServiceFactory >   xMSF;
554     uno::Reference< XLinguServiceManager >   xLinguSrvcMgr;
555 
556 
557     sal_Bool    AddRemove( Sequence< OUString > &rConfigured,
558                            const OUString &rImplName, sal_Bool bAdd );
559 
560 public:
561 	SvxLinguData_Impl();
562     SvxLinguData_Impl( const SvxLinguData_Impl &rData );
563 	~SvxLinguData_Impl();
564 
565     SvxLinguData_Impl & operator = (const SvxLinguData_Impl &rData);
566 
567     uno::Reference<XLinguServiceManager> &   GetManager() { return xLinguSrvcMgr; }
568 
569     void SetChecked( const Sequence< OUString > &rConfiguredServices );
570     void Reconfigure( const OUString &rDisplayName, sal_Bool bEnable );
571 
572     const Sequence<Locale> &    GetAllSupportedLocales() { return aAllServiceLocales; }
573 
574     const LangImplNameTable &   GetSpellTable() const   { return aCfgSpellTable; }
575     LangImplNameTable &         GetSpellTable()         { return aCfgSpellTable; }
576     const LangImplNameTable &   GetHyphTable() const    { return aCfgHyphTable; }
577     LangImplNameTable &         GetHyphTable()          { return aCfgHyphTable; }
578     const LangImplNameTable &   GetThesTable() const    { return aCfgThesTable; }
579     LangImplNameTable &         GetThesTable()          { return aCfgThesTable; }
580     const LangImplNameTable &   GetGrammarTable() const { return aCfgGrammarTable; }
581     LangImplNameTable &         GetGrammarTable()       { return aCfgGrammarTable; }
582 
583     const ServiceInfoArr &      GetDisplayServiceArray() const  { return aDisplayServiceArr; }
584     ServiceInfoArr &            GetDisplayServiceArray()        { return aDisplayServiceArr; }
585 
586     const sal_uLong &   GetDisplayServiceCount() const          { return nDisplayServices; }
587     void            SetDisplayServiceCount( sal_uLong nVal )    { nDisplayServices = nVal; }
588 
589     // returns the list of service implementation names for the specified
590     // language and service (TYPE_SPELL, TYPE_HYPH, TYPE_THES) sorted in
591     // the proper order for the SvxEditModulesDlg (the ones from the
592     // configuration (keeping that order!) first and then the other ones.
593     // I.e. the ones available but not configured in arbitrary order).
594     // They available ones may contain names that do not(!) support that
595     // language.
596     Sequence< OUString > GetSortedImplNames( sal_Int16 nLang, sal_uInt8 nType );
597 
598     ServiceInfo_Impl * GetInfoByImplName( const OUString &rSvcImplName );
599 };
600 
601 
602 sal_Int32 lcl_SeqGetIndex( const Sequence< OUString > &rSeq, const OUString &rTxt )
603 {
604     sal_Int32 nRes = -1;
605     sal_Int32 nLen = rSeq.getLength();
606     const OUString *pString = rSeq.getConstArray();
607     for (sal_Int32 i = 0;  i < nLen  &&  nRes == -1;  ++i)
608     {
609         if (pString[i] == rTxt)
610             nRes = i;
611     }
612     return nRes;
613 }
614 
615 
616 Sequence< OUString > SvxLinguData_Impl::GetSortedImplNames( sal_Int16 nLang, sal_uInt8 nType )
617 {
618     LangImplNameTable *pTable = 0;
619     switch (nType)
620     {
621         case TYPE_SPELL     : pTable = &aCfgSpellTable; break;
622         case TYPE_HYPH      : pTable = &aCfgHyphTable; break;
623         case TYPE_THES      : pTable = &aCfgThesTable; break;
624         case TYPE_GRAMMAR   : pTable = &aCfgGrammarTable; break;
625     }
626     Sequence< OUString > aRes;
627     if (pTable->count( nLang ))
628         aRes = (*pTable)[ nLang ];      // add configured services
629     sal_Int32 nIdx = aRes.getLength();
630     DBG_ASSERT( (sal_Int32) nDisplayServices >= nIdx, "size mismatch" );
631     aRes.realloc( nDisplayServices );
632     OUString *pRes = aRes.getArray();
633 
634     // add not configured services
635     for (sal_Int32 i = 0;  i < (sal_Int32) nDisplayServices;  ++i)
636     {
637         const ServiceInfo_Impl &rInfo = aDisplayServiceArr[ i ];
638         OUString aImplName;
639         switch (nType)
640         {
641             case TYPE_SPELL     : aImplName = rInfo.sSpellImplName; break;
642             case TYPE_HYPH      : aImplName = rInfo.sHyphImplName; break;
643             case TYPE_THES      : aImplName = rInfo.sThesImplName; break;
644             case TYPE_GRAMMAR   : aImplName = rInfo.sGrammarImplName; break;
645         }
646 
647         if (aImplName.getLength()  &&  (lcl_SeqGetIndex( aRes, aImplName) == -1))    // name not yet added
648         {
649 			DBG_ASSERT( nIdx < aRes.getLength(), "index out of range" );
650 			if (nIdx < aRes.getLength())
651                 pRes[ nIdx++ ] = aImplName;
652         }
653     }
654     // don't forget to put aRes back to its actual size just in case you allocated too much
655     // since all of the names may have already been added
656     // otherwise you get duplicate entries in the edit dialog
657     aRes.realloc( nIdx );
658     return aRes;
659 }
660 
661 
662 ServiceInfo_Impl * SvxLinguData_Impl::GetInfoByImplName( const OUString &rSvcImplName )
663 {
664     ServiceInfo_Impl* pInfo = 0;
665     for (sal_uLong i = 0;  i < nDisplayServices  &&  !pInfo;  ++i)
666     {
667         ServiceInfo_Impl &rTmp = aDisplayServiceArr[ i ];
668         if (rTmp.sSpellImplName == rSvcImplName ||
669             rTmp.sHyphImplName  == rSvcImplName ||
670             rTmp.sThesImplName  == rSvcImplName ||
671             rTmp.sGrammarImplName == rSvcImplName)
672             pInfo = &rTmp;
673     }
674     return pInfo;
675 }
676 
677 
678 //-----------------------------------------------------------------------------
679 
680 void lcl_MergeLocales(Sequence< Locale >& aAllLocales, const Sequence< Locale >& rAdd)
681 {
682 	const Locale* pAdd = rAdd.getConstArray();
683 	Sequence<Locale> aLocToAdd(rAdd.getLength());
684 	const Locale* pAllLocales = aAllLocales.getConstArray();
685 	Locale* pLocToAdd = aLocToAdd.getArray();
686 	sal_Int32 nFound = 0;
687 	sal_Int32 i;
688 	for(i = 0; i < rAdd.getLength(); i++)
689 	{
690 		sal_Bool bFound = sal_False;
691 		for(sal_Int32 j = 0; j < aAllLocales.getLength() && !bFound; j++)
692 		{
693 			bFound = pAdd[i].Language == pAllLocales[j].Language &&
694 				pAdd[i].Country == pAllLocales[j].Country;
695 		}
696 		if(!bFound)
697 		{
698 			pLocToAdd[nFound++] = pAdd[i];
699 		}
700 	}
701 	sal_Int32 nLength = aAllLocales.getLength();
702 	aAllLocales.realloc( nLength + nFound);
703 	Locale* pAllLocales2 = aAllLocales.getArray();
704 	for(i = 0; i < nFound; i++)
705 		pAllLocales2[nLength++] = pLocToAdd[i];
706 }
707 /* -----------------------------27.11.00 16:48--------------------------------
708 
709  ---------------------------------------------------------------------------*/
710 void lcl_MergeDisplayArray(
711         SvxLinguData_Impl &rData,
712         const ServiceInfo_Impl &rToAdd )
713 {
714     sal_uLong nCnt = 0;
715 
716     ServiceInfoArr &rSvcInfoArr = rData.GetDisplayServiceArray();
717     sal_uLong nEntries = rData.GetDisplayServiceCount();
718 
719     ServiceInfo_Impl* pEntry;
720     for (sal_uLong i = 0;  i < nEntries;  ++i)
721 	{
722         pEntry = &rSvcInfoArr[i];
723         if (pEntry  &&  pEntry->sDisplayName == rToAdd.sDisplayName)
724 		{
725             if(rToAdd.xSpell.is())
726 			{
727                 DBG_ASSERT( !pEntry->xSpell.is() &&
728                             pEntry->sSpellImplName.getLength() == 0,
729                             "merge conflict" );
730                 pEntry->sSpellImplName = rToAdd.sSpellImplName;
731                 pEntry->xSpell = rToAdd.xSpell;
732 			}
733             if(rToAdd.xGrammar.is())
734             {
735                 DBG_ASSERT( !pEntry->xGrammar.is() &&
736                             pEntry->sGrammarImplName.getLength() == 0,
737                             "merge conflict" );
738                 pEntry->sGrammarImplName = rToAdd.sGrammarImplName;
739                 pEntry->xGrammar = rToAdd.xGrammar;
740             }
741             if(rToAdd.xHyph.is())
742 			{
743                 DBG_ASSERT( !pEntry->xHyph.is() &&
744                             pEntry->sHyphImplName.getLength() == 0,
745                             "merge conflict" );
746                 pEntry->sHyphImplName = rToAdd.sHyphImplName;
747                 pEntry->xHyph = rToAdd.xHyph;
748 			}
749             if(rToAdd.xThes.is())
750 			{
751                 DBG_ASSERT( !pEntry->xThes.is() &&
752                             pEntry->sThesImplName.getLength() == 0,
753                             "merge conflict" );
754                 pEntry->sThesImplName = rToAdd.sThesImplName;
755                 pEntry->xThes = rToAdd.xThes;
756 			}
757 			return ;
758 		}
759         ++nCnt;
760 	}
761     rData.GetDisplayServiceArray().push_back( rToAdd );
762     rData.SetDisplayServiceCount( nCnt + 1 );
763 }
764 /* -----------------------------26.11.00 18:07--------------------------------
765 
766  ---------------------------------------------------------------------------*/
767 SvxLinguData_Impl::SvxLinguData_Impl() :
768     nDisplayServices    (0)
769 {
770 	xMSF = ::comphelper::getProcessServiceFactory();
771 	uno::Reference < XInterface > xI = xMSF->createInstance(
772 		C2U( "com.sun.star.linguistic2.LinguServiceManager" ) );
773 	xLinguSrvcMgr = uno::Reference<XLinguServiceManager>(xI, UNO_QUERY);
774 	DBG_ASSERT(xLinguSrvcMgr.is(), "No linguistic service available!");
775 	if(xLinguSrvcMgr.is())
776 	{
777 		Locale aCurrentLocale;
778 	    LanguageType eLang = Application::GetSettings().GetLanguage();
779 		SvxLanguageToLocale(aCurrentLocale, eLang);
780 		Sequence<Any> aArgs(2);//second arguments has to be empty!
781 		aArgs.getArray()[0] <<= SvxGetLinguPropertySet();
782 
783 		//read spell checker
784 		Sequence< OUString > aSpellNames = xLinguSrvcMgr->getAvailableServices(
785 						C2U(cSpell),	Locale() );
786 		const OUString* pSpellNames = aSpellNames.getConstArray();
787 
788 		sal_Int32 nIdx;
789 		for(nIdx = 0; nIdx < aSpellNames.getLength(); nIdx++)
790 		{
791             ServiceInfo_Impl aInfo;
792             aInfo.sSpellImplName = pSpellNames[nIdx];
793             aInfo.xSpell = uno::Reference<XSpellChecker>(
794                             xMSF->createInstanceWithArguments(aInfo.sSpellImplName, aArgs), UNO_QUERY);
795 
796             uno::Reference<XServiceDisplayName> xDispName(aInfo.xSpell, UNO_QUERY);
797             if(xDispName.is())
798                 aInfo.sDisplayName = xDispName->getServiceDisplayName( aCurrentLocale );
799 
800             const Sequence< Locale > aLocales( aInfo.xSpell->getLocales() );
801             //! suppress display of entries with no supported languages (see feature 110994)
802             if (aLocales.getLength())
803             {
804                 lcl_MergeLocales( aAllServiceLocales, aLocales );
805                 lcl_MergeDisplayArray( *this, aInfo );
806             }
807         }
808 
809         //read grammar checker
810         Sequence< OUString > aGrammarNames = xLinguSrvcMgr->getAvailableServices(
811                         C2U(cGrammar), Locale() );
812         const OUString* pGrammarNames = aGrammarNames.getConstArray();
813         for(nIdx = 0; nIdx < aGrammarNames.getLength(); nIdx++)
814         {
815             ServiceInfo_Impl aInfo;
816             aInfo.sGrammarImplName = pGrammarNames[nIdx];
817             aInfo.xGrammar = uno::Reference<XProofreader>(
818                             xMSF->createInstanceWithArguments(aInfo.sGrammarImplName, aArgs), UNO_QUERY);
819 
820             uno::Reference<XServiceDisplayName> xDispName(aInfo.xGrammar, UNO_QUERY);
821             if(xDispName.is())
822                 aInfo.sDisplayName = xDispName->getServiceDisplayName( aCurrentLocale );
823 
824             const Sequence< Locale > aLocales( aInfo.xGrammar->getLocales() );
825             //! suppress display of entries with no supported languages (see feature 110994)
826             if (aLocales.getLength())
827             {
828                 lcl_MergeLocales( aAllServiceLocales, aLocales );
829                 lcl_MergeDisplayArray( *this, aInfo );
830             }
831         }
832 
833 		//read hyphenator
834 		Sequence< OUString > aHyphNames = xLinguSrvcMgr->getAvailableServices(
835 						C2U(cHyph),	Locale() );
836 		const OUString* pHyphNames = aHyphNames.getConstArray();
837 		for(nIdx = 0; nIdx < aHyphNames.getLength(); nIdx++)
838 		{
839             ServiceInfo_Impl aInfo;
840             aInfo.sHyphImplName = pHyphNames[nIdx];
841             aInfo.xHyph = uno::Reference<XHyphenator>(
842                             xMSF->createInstanceWithArguments(aInfo.sHyphImplName, aArgs), UNO_QUERY);
843 
844             uno::Reference<XServiceDisplayName> xDispName(aInfo.xHyph, UNO_QUERY);
845             if(xDispName.is())
846                 aInfo.sDisplayName = xDispName->getServiceDisplayName( aCurrentLocale );
847 
848             const Sequence< Locale > aLocales( aInfo.xHyph->getLocales() );
849             //! suppress display of entries with no supported languages (see feature 110994)
850             if (aLocales.getLength())
851             {
852                 lcl_MergeLocales( aAllServiceLocales, aLocales );
853                 lcl_MergeDisplayArray( *this, aInfo );
854             }
855 		}
856 
857 		//read thesauri
858 		Sequence< OUString > aThesNames = xLinguSrvcMgr->getAvailableServices(
859 						C2U(cThes),		Locale() );
860 		const OUString* pThesNames = aThesNames.getConstArray();
861 		for(nIdx = 0; nIdx < aThesNames.getLength(); nIdx++)
862 		{
863             ServiceInfo_Impl aInfo;
864             aInfo.sThesImplName = pThesNames[nIdx];
865             aInfo.xThes = uno::Reference<XThesaurus>(
866                             xMSF->createInstanceWithArguments(aInfo.sThesImplName, aArgs), UNO_QUERY);
867 
868             uno::Reference<XServiceDisplayName> xDispName(aInfo.xThes, UNO_QUERY);
869             if(xDispName.is())
870                 aInfo.sDisplayName = xDispName->getServiceDisplayName( aCurrentLocale );
871 
872             const Sequence< Locale > aLocales( aInfo.xThes->getLocales() );
873             //! suppress display of entries with no supported languages (see feature 110994)
874             if (aLocales.getLength())
875             {
876                 lcl_MergeLocales( aAllServiceLocales, aLocales );
877                 lcl_MergeDisplayArray( *this, aInfo );
878             }
879 		}
880 
881         Sequence< OUString > aCfgSvcs;
882 		const Locale* pAllLocales = aAllServiceLocales.getConstArray();
883 		for(sal_Int32 nLocale = 0; nLocale < aAllServiceLocales.getLength(); nLocale++)
884 		{
885             sal_Int16 nLang = SvxLocaleToLanguage( pAllLocales[nLocale] );
886 
887             aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(C2U(cSpell), pAllLocales[nLocale]);
888             SetChecked( aCfgSvcs );
889             if (aCfgSvcs.getLength())
890                 aCfgSpellTable[ nLang ] = aCfgSvcs;
891 
892             aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(C2U(cGrammar), pAllLocales[nLocale]);
893             SetChecked( aCfgSvcs );
894             if (aCfgSvcs.getLength())
895                 aCfgGrammarTable[ nLang ] = aCfgSvcs;
896 
897             aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(C2U(cHyph), pAllLocales[nLocale]);
898             SetChecked( aCfgSvcs );
899             if (aCfgSvcs.getLength())
900                 aCfgHyphTable[ nLang ] = aCfgSvcs;
901 
902             aCfgSvcs = xLinguSrvcMgr->getConfiguredServices(C2U(cThes), pAllLocales[nLocale]);
903             SetChecked( aCfgSvcs );
904             if (aCfgSvcs.getLength())
905                 aCfgThesTable[ nLang ] = aCfgSvcs;
906 		}
907 	}
908 }
909 /* -----------------------------22.05.01 10:43--------------------------------
910 
911 ---------------------------------------------------------------------------*/
912 SvxLinguData_Impl::SvxLinguData_Impl( const SvxLinguData_Impl &rData ) :
913     aDisplayServiceArr  (rData.aDisplayServiceArr),
914     nDisplayServices    (rData.nDisplayServices),
915     aAllServiceLocales  (rData.aAllServiceLocales),
916     aCfgSpellTable      (rData.aCfgSpellTable),
917     aCfgHyphTable       (rData.aCfgHyphTable),
918     aCfgThesTable       (rData.aCfgThesTable),
919     aCfgGrammarTable    (rData.aCfgGrammarTable),
920     xMSF                (rData.xMSF),
921     xLinguSrvcMgr       (rData.xLinguSrvcMgr)
922 {
923 }
924 /* -----------------------------22.05.01 10:43--------------------------------
925 
926  ---------------------------------------------------------------------------*/
927 SvxLinguData_Impl & SvxLinguData_Impl::operator = (const SvxLinguData_Impl &rData)
928 {
929     xMSF                = rData.xMSF;
930     xLinguSrvcMgr       = rData.xLinguSrvcMgr;
931     aAllServiceLocales  = rData.aAllServiceLocales;
932     aCfgSpellTable      = rData.aCfgSpellTable;
933     aCfgHyphTable       = rData.aCfgHyphTable;
934     aCfgThesTable       = rData.aCfgThesTable;
935     aCfgGrammarTable    = rData.aCfgGrammarTable;
936     aDisplayServiceArr  = rData.aDisplayServiceArr;
937     nDisplayServices    = rData.nDisplayServices;
938     return *this;
939 }
940 /* -----------------------------26.11.00 18:08--------------------------------
941 
942  ---------------------------------------------------------------------------*/
943 SvxLinguData_Impl::~SvxLinguData_Impl()
944 {
945 }
946 /* -----------------------------26.11.00 19:42--------------------------------
947 
948  ---------------------------------------------------------------------------*/
949 void SvxLinguData_Impl::SetChecked(const Sequence<OUString>& rConfiguredServices)
950 {
951 	const OUString* pConfiguredServices = rConfiguredServices.getConstArray();
952 	for(sal_Int32 n = 0; n < rConfiguredServices.getLength(); n++)
953 	{
954         ServiceInfo_Impl* pEntry;
955         for (sal_uLong i = 0;  i < nDisplayServices;  ++i)
956 		{
957             pEntry = &aDisplayServiceArr[i];
958             if (pEntry  &&  !pEntry->bConfigured)
959             {
960                 const OUString &rSrvcImplName = pConfiguredServices[n];
961                 if (rSrvcImplName.getLength()  &&
962                     (pEntry->sSpellImplName == rSrvcImplName  ||
963                         pEntry->sGrammarImplName  == rSrvcImplName  ||
964                         pEntry->sHyphImplName  == rSrvcImplName  ||
965                         pEntry->sThesImplName  == rSrvcImplName))
966                 {
967                     pEntry->bConfigured = sal_True;
968                     break;
969                 }
970             }
971 		}
972 	}
973 }
974 /* -----------------------------26.11.00 20:43--------------------------------
975 
976  ---------------------------------------------------------------------------*/
977 
978 sal_Bool SvxLinguData_Impl::AddRemove(
979             Sequence< OUString > &rConfigured,
980             const OUString &rImplName, sal_Bool bAdd )
981 {
982     sal_Bool bRet = sal_False;  // modified?
983 
984     sal_Int32 nEntries = rConfigured.getLength();
985     sal_Int32 nPos = lcl_SeqGetEntryPos(rConfigured, rImplName);
986     if (bAdd  &&  nPos < 0)         // add new entry
987     {
988         rConfigured.realloc( ++nEntries );
989         OUString *pConfigured = rConfigured.getArray();
990         pConfigured = rConfigured.getArray();
991         pConfigured[nEntries - 1] = rImplName;
992         bRet = sal_True;
993     }
994     else if (!bAdd  &&  nPos >= 0)  // remove existing entry
995     {
996         OUString *pConfigured = rConfigured.getArray();
997         for (sal_Int32 i = nPos;  i < nEntries - 1;  ++i)
998             pConfigured[i] = pConfigured[i + 1];
999         rConfigured.realloc(--nEntries);
1000         bRet = sal_True;
1001     }
1002 
1003 	return bRet;
1004 }
1005 
1006 
1007 void SvxLinguData_Impl::Reconfigure( const OUString &rDisplayName, sal_Bool bEnable )
1008 {
1009     DBG_ASSERT( rDisplayName.getLength(), "empty DisplayName" );
1010 
1011     ServiceInfo_Impl *pInfo = 0;
1012     ServiceInfo_Impl *pTmp  = 0;
1013     for (sal_uLong i = 0;  i < nDisplayServices;  ++i)
1014     {
1015         pTmp = &aDisplayServiceArr[i];
1016         if (pTmp  &&  pTmp->sDisplayName == rDisplayName)
1017         {
1018             pInfo = pTmp;
1019             break;
1020         }
1021     }
1022     DBG_ASSERT( pInfo, "DisplayName entry not found" );
1023     if (pInfo)
1024     {
1025         pInfo->bConfigured = bEnable;
1026 
1027         Sequence< Locale > aLocales;
1028         const Locale *pLocale = 0;
1029         sal_Int32 nLocales = 0;
1030         sal_Int32 i;
1031 
1032         // update configured spellchecker entries
1033         if (pInfo->xSpell.is())
1034         {
1035             aLocales = pInfo->xSpell->getLocales();
1036             pLocale = aLocales.getConstArray();
1037             nLocales = aLocales.getLength();
1038             for (i = 0;  i < nLocales;  ++i)
1039             {
1040                 sal_Int16 nLang = SvxLocaleToLanguage( pLocale[i] );
1041                 if (!aCfgSpellTable.count( nLang ) && bEnable)
1042                     aCfgSpellTable[ nLang ] = Sequence< OUString >();
1043                 if (aCfgSpellTable.count( nLang ))
1044                     AddRemove( aCfgSpellTable[ nLang ], pInfo->sSpellImplName, bEnable );
1045             }
1046         }
1047 
1048         // update configured grammar checker entries
1049         if (pInfo->xGrammar.is())
1050         {
1051             aLocales = pInfo->xGrammar->getLocales();
1052             pLocale = aLocales.getConstArray();
1053             nLocales = aLocales.getLength();
1054             for (i = 0;  i < nLocales;  ++i)
1055             {
1056                 sal_Int16 nLang = SvxLocaleToLanguage( pLocale[i] );
1057                 if (!aCfgGrammarTable.count( nLang ) && bEnable)
1058                     aCfgGrammarTable[ nLang ] = Sequence< OUString >();
1059                 if (aCfgGrammarTable.count( nLang ))
1060                     AddRemove( aCfgGrammarTable[ nLang ], pInfo->sGrammarImplName, bEnable );
1061             }
1062         }
1063 
1064         // update configured hyphenator entries
1065         if (pInfo->xHyph.is())
1066         {
1067             aLocales = pInfo->xHyph->getLocales();
1068             pLocale = aLocales.getConstArray();
1069             nLocales = aLocales.getLength();
1070             for (i = 0;  i < nLocales;  ++i)
1071             {
1072                 sal_Int16 nLang = SvxLocaleToLanguage( pLocale[i] );
1073                 if (!aCfgHyphTable.count( nLang ) && bEnable)
1074                     aCfgHyphTable[ nLang ] = Sequence< OUString >();
1075                 if (aCfgHyphTable.count( nLang ))
1076                     AddRemove( aCfgHyphTable[ nLang ], pInfo->sHyphImplName, bEnable );
1077             }
1078         }
1079 
1080         // update configured spellchecker entries
1081         if (pInfo->xThes.is())
1082         {
1083             aLocales = pInfo->xThes->getLocales();
1084             pLocale = aLocales.getConstArray();
1085             nLocales = aLocales.getLength();
1086             for (i = 0;  i < nLocales;  ++i)
1087             {
1088                 sal_Int16 nLang = SvxLocaleToLanguage( pLocale[i] );
1089                 if (!aCfgThesTable.count( nLang ) && bEnable)
1090                     aCfgThesTable[ nLang ] = Sequence< OUString >();
1091                 if (aCfgThesTable.count( nLang ))
1092                     AddRemove( aCfgThesTable[ nLang ], pInfo->sThesImplName, bEnable );
1093             }
1094         }
1095     }
1096 }
1097 
1098 
1099 // class SvxLinguTabPage -------------------------------------------------
1100 
1101 #define CBCOL_FIRST		0
1102 #define CBCOL_SECOND	1
1103 #define CBCOL_BOTH		2
1104 
1105 SvxLinguTabPage::SvxLinguTabPage( Window* pParent,
1106 								  const SfxItemSet& rSet ):
1107 
1108 	SfxTabPage( pParent, CUI_RES( RID_SFXPAGE_LINGU ), rSet ),
1109 
1110     aLinguisticFL       ( this, CUI_RES( FL_LINGUISTIC ) ),
1111 	aLinguModulesFT		( this, CUI_RES( FT_LINGU_MODULES ) ),
1112 	aLinguModulesCLB	( this, CUI_RES( CLB_LINGU_MODULES ) ),
1113 	aLinguModulesEditPB	( this, CUI_RES( PB_LINGU_MODULES_EDIT ) ),
1114     aLinguDicsFT        ( this, CUI_RES( FT_LINGU_DICS ) ),
1115     aLinguDicsCLB       ( this, CUI_RES( CLB_LINGU_DICS ) ),
1116     aLinguDicsNewPB     ( this, CUI_RES( PB_LINGU_DICS_NEW_DIC ) ),
1117     aLinguDicsEditPB    ( this, CUI_RES( PB_LINGU_DICS_EDIT_DIC ) ),
1118     aLinguDicsDelPB     ( this, CUI_RES( PB_LINGU_DICS_DEL_DIC ) ),
1119 	aLinguOptionsFT		( this, CUI_RES( FT_LINGU_OPTIONS ) ),
1120 	aLinguOptionsCLB	( this, CUI_RES( CLB_LINGU_OPTIONS ) ),
1121     aLinguOptionsEditPB ( this, CUI_RES( PB_LINGU_OPTIONS_EDIT ) ),
1122     aMoreDictsLink      ( this, CUI_RES( FT_LINGU_OPTIONS_MOREDICTS ) ),
1123 	sCapitalWords		( CUI_RES( STR_CAPITAL_WORDS ) ),
1124 	sWordsWithDigits	( CUI_RES( STR_WORDS_WITH_DIGITS ) ),
1125 	sCapitalization		( CUI_RES( STR_CAPITALIZATION ) ),
1126 	sSpellSpecial		( CUI_RES( STR_SPELL_SPECIAL ) ),
1127 	sSpellAuto			( CUI_RES( STR_SPELL_AUTO ) ),
1128     sGrammarAuto        ( CUI_RES( STR_GRAMMAR_AUTO ) ),
1129 	sNumMinWordlen  	( CUI_RES( STR_NUM_MIN_WORDLEN ) ),
1130 	sNumPreBreak		( CUI_RES( STR_NUM_PRE_BREAK ) ),
1131 	sNumPostBreak		( CUI_RES( STR_NUM_POST_BREAK ) ),
1132 	sHyphAuto			( CUI_RES( STR_HYPH_AUTO ) ),
1133 	sHyphSpecial		( CUI_RES( STR_HYPH_SPECIAL ) ),
1134 
1135 	pLinguData			( NULL )
1136 {
1137 	pCheckButtonData = NULL;
1138 
1139     aLinguModulesCLB.SetStyle( aLinguModulesCLB.GetStyle()|WB_CLIPCHILDREN|WB_HSCROLL|WB_FORCE_MAKEVISIBLE );
1140 	aLinguModulesCLB.SetHelpId(HID_CLB_LINGU_MODULES );
1141 	aLinguModulesCLB.SetHighlightRange();
1142 	aLinguModulesCLB.SetSelectHdl( LINK( this, SvxLinguTabPage, SelectHdl_Impl ));
1143     aLinguModulesCLB.SetDoubleClickHdl(LINK(this, SvxLinguTabPage, BoxDoubleClickHdl_Impl));
1144     aLinguModulesCLB.SetCheckButtonHdl(LINK(this, SvxLinguTabPage, BoxCheckButtonHdl_Impl));
1145 
1146 	aLinguModulesEditPB.SetClickHdl( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
1147 	aLinguOptionsEditPB.SetClickHdl( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
1148 
1149     aLinguDicsCLB.SetStyle( aLinguDicsCLB.GetStyle()|WB_CLIPCHILDREN|WB_HSCROLL|WB_FORCE_MAKEVISIBLE );
1150     aLinguDicsCLB.SetHelpId(HID_CLB_EDIT_MODULES_DICS );
1151     aLinguDicsCLB.SetHighlightRange();
1152     aLinguDicsCLB.SetSelectHdl( LINK( this, SvxLinguTabPage, SelectHdl_Impl ));
1153     aLinguDicsCLB.SetCheckButtonHdl(LINK(this, SvxLinguTabPage, BoxCheckButtonHdl_Impl));
1154 
1155     aLinguDicsNewPB.SetClickHdl( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
1156     aLinguDicsEditPB.SetClickHdl( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
1157     aLinguDicsDelPB.SetClickHdl( LINK( this, SvxLinguTabPage, ClickHdl_Impl ));
1158 
1159     aLinguOptionsCLB.SetStyle( aLinguOptionsCLB.GetStyle()|WB_CLIPCHILDREN|WB_HSCROLL|WB_FORCE_MAKEVISIBLE );
1160 	aLinguOptionsCLB.SetHelpId(HID_CLB_LINGU_OPTIONS );
1161 	aLinguOptionsCLB.SetHighlightRange();
1162 	aLinguOptionsCLB.SetSelectHdl( LINK( this, SvxLinguTabPage, SelectHdl_Impl ));
1163     aLinguOptionsCLB.SetDoubleClickHdl(LINK(this, SvxLinguTabPage, BoxDoubleClickHdl_Impl));
1164 
1165     if ( SvtExtendedSecurityOptions().GetOpenHyperlinkMode()
1166             != SvtExtendedSecurityOptions::OPEN_NEVER )
1167     {
1168         aMoreDictsLink.SetURL( String(
1169             RTL_CONSTASCII_STRINGPARAM( "http://extensions.services.openoffice.org/dictionary?cid=926386" ) ) );
1170         aMoreDictsLink.SetClickHdl( LINK( this, SvxLinguTabPage, OpenURLHdl_Impl ) );
1171     }
1172     else
1173         aMoreDictsLink.Hide();
1174 
1175 	String sAccessibleNameModuleEdit( CUI_RES( STR_LINGU_MODULES_EDIT ) );
1176 	String sAccessibleNameDicsEdit	( CUI_RES( STR_LINGU_DICS_EDIT_DIC ) );
1177 	String sAccessibleNameOptionEdit( CUI_RES( STR_LINGU_OPTIONS_EDIT ) );
1178 
1179 	aLinguModulesEditPB.SetAccessibleName(sAccessibleNameModuleEdit);
1180 	aLinguDicsEditPB.SetAccessibleName(sAccessibleNameDicsEdit);
1181 	aLinguOptionsEditPB.SetAccessibleName(sAccessibleNameOptionEdit);
1182 
1183     // force recalculation of hash value used for checking the need of updating
1184     // because new dictionaries might be installed / downloaded.
1185     //! Thus it needs to be called now since it may infuence the supported languages
1186     //! to be reported AND the found user-dictionaries(!) as well.
1187     SvxLinguConfigUpdate::UpdateAll( sal_True );
1188 
1189     xProp = uno::Reference< XPropertySet >( SvxGetLinguPropertySet(), UNO_QUERY );
1190 	xDicList = uno::Reference< XDictionaryList >( SvxGetDictionaryList(), UNO_QUERY );
1191 	if (xDicList.is())
1192 	{
1193         // keep references to all **currently** available dictionaries,
1194         // since the diclist may get changed meanwhile (e.g. through the API).
1195         // We want the dialog to operate on the same set of dictionaries it
1196         // was started with.
1197         // Also we have to take care to not loose the last reference when
1198         // someone else removes a dictionary from the list.
1199         // removed dics will be replaced by NULL new entries be added to the end
1200         // Thus we may use indizes as consistent references.
1201         aDics = xDicList->getDictionaries();
1202 
1203         UpdateDicBox_Impl();
1204 	}
1205 	else
1206 	{
1207         aLinguDicsFT.Disable();
1208         aLinguDicsCLB.Disable();
1209         aLinguDicsNewPB.Disable();
1210         aLinguDicsEditPB.Disable();
1211         aLinguDicsDelPB.Disable();
1212 	}
1213 
1214 	const SfxSpellCheckItem* pItem = 0;
1215 	SfxItemState eItemState = SFX_ITEM_UNKNOWN;
1216 
1217 	eItemState = rSet.GetItemState( GetWhich( SID_ATTR_SPELL ),
1218 									sal_False, (const SfxPoolItem**)&pItem );
1219 
1220 	// handelt es sich um ein Default-Item?
1221 	if ( eItemState == SFX_ITEM_DEFAULT )
1222 		pItem = (const SfxSpellCheckItem*)&(rSet.Get( GetWhich( SID_ATTR_SPELL ) ) );
1223 	else if ( eItemState == SFX_ITEM_DONTCARE )
1224 		pItem = NULL;
1225 
1226 	FreeResource();
1227 }
1228 
1229 // -----------------------------------------------------------------------
1230 
1231 SvxLinguTabPage::~SvxLinguTabPage()
1232 {
1233 	if (pLinguData)
1234 		delete pLinguData;
1235 }
1236 
1237 //------------------------------------------------------------------------
1238 
1239 //nicht �berladen wegschmeissen
1240 sal_uInt16* SvxLinguTabPage::GetRanges()
1241 {
1242 	//TL???
1243 	return pRanges;
1244 }
1245 
1246 //------------------------------------------------------------------------
1247 
1248 SfxTabPage* SvxLinguTabPage::Create( Window* pParent,
1249 									 const SfxItemSet& rAttrSet )
1250 {
1251 	return ( new SvxLinguTabPage( pParent, rAttrSet ) );
1252 }
1253 
1254 //------------------------------------------------------------------------
1255 
1256 Any lcl_Bool2Any(sal_Bool bVal)
1257 {
1258 	Any aRet(&bVal, ::getBooleanCppuType());
1259 	return aRet;
1260 }
1261 
1262 
1263 sal_Bool lcl_Bool2Any(Any& rVal)
1264 {
1265 	return *(sal_Bool*)rVal.getValue();
1266 }
1267 
1268 
1269 sal_Bool SvxLinguTabPage::FillItemSet( SfxItemSet& rCoreSet )
1270 {
1271 	sal_Bool bModified = sal_True; // !!!!
1272 
1273 	// if not HideGroups was called with GROUP_MODULES...
1274 	if (aLinguModulesCLB.IsVisible())
1275 	{
1276         DBG_ASSERT( pLinguData, "pLinguData not yet initialized" );
1277         if (!pLinguData)
1278             pLinguData = new SvxLinguData_Impl;
1279 
1280         LangImplNameTable::const_iterator aIt;
1281 
1282         // update spellchecker configuration entries
1283         const LangImplNameTable *pTable = &pLinguData->GetSpellTable();
1284         for (aIt = pTable->begin();  aIt != pTable->end();  ++aIt)
1285         {
1286             sal_Int16 nLang = aIt->first;
1287             const Sequence< OUString > aImplNames( aIt->second );
1288 #if OSL_DEBUG_LEVEL > 1
1289             const OUString *pTmpStr;
1290             pTmpStr = aImplNames.getConstArray();
1291 #endif
1292             uno::Reference< XLinguServiceManager > xMgr( pLinguData->GetManager() );
1293             Locale aLocale( SvxCreateLocale(nLang) );
1294             if (xMgr.is())
1295                 xMgr->setConfiguredServices( C2U(cSpell), aLocale, aImplNames );
1296         }
1297 
1298         // update grammar checker configuration entries
1299         pTable = &pLinguData->GetGrammarTable();
1300         for (aIt = pTable->begin();  aIt != pTable->end();  ++aIt)
1301         {
1302             sal_Int16 nLang = aIt->first;
1303             const Sequence< OUString > aImplNames( aIt->second );
1304 #if OSL_DEBUG_LEVEL > 1
1305             const OUString *pTmpStr;
1306             pTmpStr = aImplNames.getConstArray();
1307 #endif
1308             uno::Reference< XLinguServiceManager > xMgr( pLinguData->GetManager() );
1309             Locale aLocale( SvxCreateLocale(nLang) );
1310             if (xMgr.is())
1311                 xMgr->setConfiguredServices( C2U(cGrammar), aLocale, aImplNames );
1312         }
1313 
1314         // update hyphenator configuration entries
1315         pTable = &pLinguData->GetHyphTable();
1316         for (aIt = pTable->begin();  aIt != pTable->end();  ++aIt)
1317         {
1318             sal_Int16 nLang = aIt->first;
1319             const Sequence< OUString > aImplNames( aIt->second );
1320 #if OSL_DEBUG_LEVEL > 1
1321             const OUString *pTmpStr;
1322             pTmpStr = aImplNames.getConstArray();
1323 #endif
1324             uno::Reference< XLinguServiceManager > xMgr( pLinguData->GetManager() );
1325             Locale aLocale( SvxCreateLocale(nLang) );
1326             if (xMgr.is())
1327                 xMgr->setConfiguredServices( C2U(cHyph), aLocale, aImplNames );
1328         }
1329 
1330         // update thesaurus configuration entries
1331         pTable = &pLinguData->GetThesTable();
1332         for (aIt = pTable->begin();  aIt != pTable->end();  ++aIt)
1333         {
1334             sal_Int16 nLang = aIt->first;
1335             const Sequence< OUString > aImplNames( aIt->second );
1336 #if OSL_DEBUG_LEVEL > 1
1337             const OUString *pTmpStr;
1338             pTmpStr = aImplNames.getConstArray();
1339 #endif
1340             uno::Reference< XLinguServiceManager > xMgr( pLinguData->GetManager() );
1341             Locale aLocale( SvxCreateLocale(nLang) );
1342             if (xMgr.is())
1343                 xMgr->setConfiguredServices( C2U(cThes), aLocale, aImplNames );
1344         }
1345 	}
1346 
1347 
1348     //
1349     // activate dictionaries according to checkbox state
1350     //
1351     Sequence< OUString > aActiveDics;
1352     sal_Int32 nActiveDics = 0;
1353     sal_uLong nEntries = aLinguDicsCLB.GetEntryCount();
1354     for (sal_uLong i = 0;  i < nEntries;  ++i)
1355     {
1356         sal_Int32 nDics = aDics.getLength();
1357 //        const uno::Reference< XDictionary > *pDic = aDics.getConstArray();
1358 
1359         aActiveDics.realloc( nDics );
1360         OUString *pActiveDic = aActiveDics.getArray();
1361 
1362         SvLBoxEntry *pEntry = aLinguDicsCLB.GetEntry( i );
1363         if (pEntry)
1364         {
1365             DicUserData aData( (sal_uLong)pEntry->GetUserData() );
1366             if (aData.GetEntryId() < nDics)
1367             {
1368                 sal_Bool bChecked = aLinguDicsCLB.IsChecked( (sal_uInt16) i );
1369                 uno::Reference< XDictionary > xDic( aDics.getConstArray()[ i ] );
1370                 if (xDic.is())
1371                 {
1372                     if (SvxGetIgnoreAllList() == xDic)
1373                         bChecked = sal_True;
1374                     xDic->setActive( bChecked );
1375 
1376                     if (bChecked)
1377                     {
1378                         String aDicName( xDic->getName() );
1379                         pActiveDic[ nActiveDics++ ] = aDicName;
1380                     }
1381                 }
1382             }
1383         }
1384     }
1385     //
1386     aActiveDics.realloc( nActiveDics );
1387     Any aTmp;
1388     aTmp <<= aActiveDics;
1389     SvtLinguConfig aLngCfg;
1390     aLngCfg.SetProperty( UPH_ACTIVE_DICTIONARIES, aTmp );
1391 
1392 
1393     nEntries = aLinguOptionsCLB.GetEntryCount();
1394     for (sal_uInt16 j = 0;  j < nEntries;  ++j)
1395 	{
1396 		SvLBoxEntry *pEntry = aLinguOptionsCLB.GetEntry( j );
1397 
1398 		OptionsUserData aData( (sal_uLong)pEntry->GetUserData() );
1399 		String aPropName( lcl_GetPropertyName( (EID_OPTIONS) aData.GetEntryId() ) );
1400 
1401 		Any aAny;
1402 		if (aData.IsCheckable())
1403 		{
1404 			sal_Bool bChecked = aLinguOptionsCLB.IsChecked( j );
1405 			aAny <<= bChecked;
1406 		}
1407 		else if (aData.HasNumericValue())
1408 		{
1409 			sal_Int16 nVal = aData.GetNumericValue();
1410 			aAny <<= nVal;
1411 		}
1412 
1413 		if (xProp.is())
1414 			xProp->setPropertyValue( aPropName, aAny );
1415 		aLngCfg.SetProperty( aPropName, aAny );
1416 	}
1417 
1418 	SvLBoxEntry *pPreBreakEntry  = aLinguOptionsCLB.GetEntry( (sal_uInt16) EID_NUM_PRE_BREAK );
1419 	SvLBoxEntry *pPostBreakEntry = aLinguOptionsCLB.GetEntry( (sal_uInt16) EID_NUM_POST_BREAK );
1420 	DBG_ASSERT( pPreBreakEntry, "NULL Pointer" );
1421 	DBG_ASSERT( pPostBreakEntry, "NULL Pointer" );
1422 	if (pPreBreakEntry && pPostBreakEntry)
1423 	{
1424 		OptionsUserData aPreBreakData( (sal_uLong)pPreBreakEntry->GetUserData() );
1425 		OptionsUserData aPostBreakData( (sal_uLong)pPostBreakEntry->GetUserData() );
1426 		if ( aPreBreakData.IsModified() || aPostBreakData.IsModified() )
1427 		{
1428 			SfxHyphenRegionItem aHyp( GetWhich( SID_ATTR_HYPHENREGION ) );
1429 			aHyp.GetMinLead()  = (sal_uInt8) aPreBreakData.GetNumericValue();
1430 			aHyp.GetMinTrail() = (sal_uInt8) aPostBreakData.GetNumericValue();
1431 			rCoreSet.Put( aHyp );
1432 		}
1433 	}
1434 
1435 
1436     // automatic spell checking
1437 	sal_Bool bNewAutoCheck = aLinguOptionsCLB.IsChecked( (sal_uInt16) EID_SPELL_AUTO );
1438 	const SfxPoolItem* pOld = GetOldItem( rCoreSet, SID_AUTOSPELL_CHECK );
1439 	if ( !pOld || ( (SfxBoolItem*)pOld )->GetValue() != bNewAutoCheck )
1440 	{
1441 		rCoreSet.Put( SfxBoolItem( GetWhich( SID_AUTOSPELL_CHECK ),
1442 								bNewAutoCheck ) );
1443 		bModified |= sal_True;
1444 	}
1445 
1446 	return bModified;
1447 }
1448 
1449 // ----------------------------------------------------------------------
1450 
1451 sal_uLong SvxLinguTabPage::GetDicUserData( const uno::Reference< XDictionary > &rxDic, sal_uInt16 nIdx )
1452 {
1453     sal_uLong nRes = 0;
1454     DBG_ASSERT( rxDic.is(), "dictionary not supplied" );
1455     if (rxDic.is())
1456     {
1457         uno::Reference< frame::XStorable > xStor( rxDic, UNO_QUERY );
1458 
1459 //        sal_uLong nUserData = 0;
1460         sal_Bool bChecked = rxDic->isActive();
1461         sal_Bool bEditable = !xStor.is() || !xStor->isReadonly();
1462         sal_Bool bDeletable = bEditable;
1463 //        sal_Bool bNegativ = rxDic->getDictionaryType() == DictionaryType_NEGATIVE;
1464 
1465         nRes = DicUserData( nIdx,
1466                 bChecked, bEditable, bDeletable ).GetUserData();
1467     }
1468     return nRes;
1469 }
1470 
1471 
1472 void SvxLinguTabPage::AddDicBoxEntry(
1473         const uno::Reference< XDictionary > &rxDic,
1474         sal_uInt16 nIdx )
1475 {
1476     aLinguDicsCLB.SetUpdateMode(sal_False);
1477 
1478     String aTxt( ::GetDicInfoStr( rxDic->getName(),
1479                         SvxLocaleToLanguage( rxDic->getLocale() ),
1480                         DictionaryType_NEGATIVE == rxDic->getDictionaryType() ) );
1481     aLinguDicsCLB.InsertEntry( aTxt, (sal_uInt16)LISTBOX_APPEND );  // append at end
1482     SvLBoxEntry* pEntry = aLinguDicsCLB.GetEntry( aLinguDicsCLB.GetEntryCount() - 1 );
1483     DBG_ASSERT( pEntry, "failed to add entry" );
1484     if (pEntry)
1485     {
1486         DicUserData aData( GetDicUserData( rxDic, nIdx ) );
1487         pEntry->SetUserData( (void *) aData.GetUserData() );
1488         lcl_SetCheckButton( pEntry, aData.IsChecked() );
1489     }
1490 
1491     aLinguDicsCLB.SetUpdateMode(sal_True);
1492 }
1493 
1494 // ----------------------------------------------------------------------
1495 
1496 void SvxLinguTabPage::UpdateDicBox_Impl()
1497 {
1498     aLinguDicsCLB.SetUpdateMode(sal_False);
1499     aLinguDicsCLB.Clear();
1500 
1501 	sal_Int32 nDics	 = aDics.getLength();
1502 	const uno::Reference< XDictionary > *pDic = aDics.getConstArray();
1503 	for (sal_Int32 i = 0;  i < nDics;  ++i)
1504 	{
1505 		const uno::Reference< XDictionary > &rDic = pDic[i];
1506 		if (rDic.is())
1507             AddDicBoxEntry( rDic, (sal_uInt16)i );
1508 	}
1509 
1510     aLinguDicsCLB.SetUpdateMode(sal_True);
1511 }
1512 
1513 // ----------------------------------------------------------------------
1514 
1515 void SvxLinguTabPage::UpdateModulesBox_Impl()
1516 {
1517     if (pLinguData)
1518     {
1519         const ServiceInfoArr &rAllDispSrvcArr = pLinguData->GetDisplayServiceArray();
1520         const sal_uLong nDispSrvcCount = pLinguData->GetDisplayServiceCount();
1521 
1522         aLinguModulesCLB.Clear();
1523 
1524         for (sal_uInt16 i = 0;  i < nDispSrvcCount;  ++i)
1525         {
1526             const ServiceInfo_Impl &rInfo = rAllDispSrvcArr[i];
1527             aLinguModulesCLB.InsertEntry( rInfo.sDisplayName, (sal_uInt16)LISTBOX_APPEND );
1528             SvLBoxEntry* pEntry = aLinguModulesCLB.GetEntry(i);
1529             pEntry->SetUserData( (void *) &rInfo );
1530             aLinguModulesCLB.CheckEntryPos( i, rInfo.bConfigured );
1531         }
1532         aLinguModulesEditPB.Enable( nDispSrvcCount > 0 );
1533     }
1534 }
1535 
1536 //------------------------------------------------------------------------
1537 
1538 void SvxLinguTabPage::Reset( const SfxItemSet& rSet )
1539 {
1540 	// if not HideGroups was called with GROUP_MODULES...
1541 	if (aLinguModulesCLB.IsVisible())
1542 	{
1543 		if (!pLinguData)
1544 			pLinguData = new SvxLinguData_Impl;
1545         UpdateModulesBox_Impl();
1546 	}
1547 
1548 
1549 	//
1550 	//	get data from configuration
1551 	//
1552 
1553 	SvtLinguConfig aLngCfg;
1554 
1555 	aLinguOptionsCLB.SetUpdateMode(sal_False);
1556 	aLinguOptionsCLB.Clear();
1557 
1558 	SvLBoxTreeList *pModel = aLinguOptionsCLB.GetModel();
1559 	SvLBoxEntry* pEntry = NULL;
1560 
1561 	sal_Int16 nVal = 0;
1562 	sal_Bool  bVal  = sal_False;
1563 	sal_uLong nUserData = 0;
1564 
1565     pEntry = CreateEntry( sSpellAuto,		CBCOL_FIRST );
1566 	aLngCfg.GetProperty( C2U(UPN_IS_SPELL_AUTO) ) >>= bVal;
1567 	const SfxPoolItem* pItem = GetItem( rSet, SID_AUTOSPELL_CHECK );
1568 	if (pItem)
1569 		bVal = ((SfxBoolItem *) pItem)->GetValue();
1570 	nUserData = OptionsUserData( EID_SPELL_AUTO, sal_False, 0, sal_True, bVal).GetUserData();
1571 	pEntry->SetUserData( (void *)nUserData );
1572 	pModel->Insert( pEntry );
1573 	lcl_SetCheckButton( pEntry, bVal );
1574 
1575     pEntry = CreateEntry( sGrammarAuto,       CBCOL_FIRST );
1576     aLngCfg.GetProperty( C2U(UPN_IS_GRAMMAR_AUTO) ) >>= bVal;
1577 //    const SfxPoolItem* pItem = GetItem( rSet, SID_AUTOSPELL_CHECK );
1578 //    if (pItem)
1579 //        bVal = ((SfxBoolItem *) pItem)->GetValue();
1580     nUserData = OptionsUserData( EID_GRAMMAR_AUTO, sal_False, 0, sal_True, bVal).GetUserData();
1581     pEntry->SetUserData( (void *)nUserData );
1582     pModel->Insert( pEntry );
1583     lcl_SetCheckButton( pEntry, bVal );
1584 
1585 	pEntry = CreateEntry( sCapitalWords,	CBCOL_FIRST );
1586 	aLngCfg.GetProperty( C2U(UPN_IS_SPELL_UPPER_CASE) ) >>= bVal;
1587 	nUserData = OptionsUserData( EID_CAPITAL_WORDS, sal_False, 0, sal_True, bVal).GetUserData();
1588 	pEntry->SetUserData( (void *)nUserData );
1589 	pModel->Insert( pEntry );
1590 	lcl_SetCheckButton( pEntry, bVal );
1591 
1592 	pEntry = CreateEntry( sWordsWithDigits,	CBCOL_FIRST );
1593 	aLngCfg.GetProperty( C2U(UPN_IS_SPELL_WITH_DIGITS) ) >>= bVal;
1594 	nUserData = OptionsUserData( EID_WORDS_WITH_DIGITS, sal_False, 0, sal_True, bVal).GetUserData();
1595 	pEntry->SetUserData( (void *)nUserData );
1596 	pModel->Insert( pEntry );
1597 	lcl_SetCheckButton( pEntry, bVal );
1598 
1599 	pEntry = CreateEntry( sCapitalization,	CBCOL_FIRST );
1600 	aLngCfg.GetProperty( C2U(UPN_IS_SPELL_CAPITALIZATION) ) >>= bVal;
1601 	nUserData = OptionsUserData( EID_CAPITALIZATION, sal_False, 0, sal_True, bVal).GetUserData();
1602 	pEntry->SetUserData( (void *)nUserData );
1603 	pModel->Insert( pEntry );
1604 	lcl_SetCheckButton( pEntry, bVal );
1605 
1606 	pEntry = CreateEntry( sSpellSpecial,	CBCOL_FIRST );
1607 	aLngCfg.GetProperty( C2U(UPN_IS_SPELL_SPECIAL) ) >>= bVal;
1608 	nUserData = OptionsUserData( EID_SPELL_SPECIAL, sal_False, 0, sal_True, bVal).GetUserData();
1609 	pEntry->SetUserData( (void *)nUserData );
1610 	pModel->Insert( pEntry );
1611 	lcl_SetCheckButton( pEntry, bVal );
1612 
1613 	pEntry = CreateEntry( sNumMinWordlen,	CBCOL_SECOND );
1614 	aLngCfg.GetProperty( C2U(UPN_HYPH_MIN_WORD_LENGTH) ) >>= nVal;
1615 	nUserData = OptionsUserData( EID_NUM_MIN_WORDLEN, sal_True, (sal_uInt16)nVal, sal_False, sal_False).GetUserData();
1616 	pEntry->SetUserData( (void *)nUserData );
1617 	pModel->Insert( pEntry );
1618 
1619 	const SfxHyphenRegionItem *pHyp = NULL;
1620 	sal_uInt16 nWhich = GetWhich( SID_ATTR_HYPHENREGION );
1621     if ( rSet.GetItemState( nWhich, sal_False ) == SFX_ITEM_SET )
1622 		pHyp = &( (const SfxHyphenRegionItem &) rSet.Get( nWhich ) );
1623 
1624 	pEntry = CreateEntry( sNumPreBreak,		CBCOL_SECOND );
1625 	aLngCfg.GetProperty( C2U(UPN_HYPH_MIN_LEADING) ) >>= nVal;
1626 	if (pHyp)
1627 		nVal = (sal_Int16) pHyp->GetMinLead();
1628 	nUserData = OptionsUserData( EID_NUM_PRE_BREAK, sal_True, (sal_uInt16)nVal, sal_False, sal_False).GetUserData();
1629 	pEntry->SetUserData( (void *)nUserData );
1630 	pModel->Insert( pEntry );
1631 
1632 	pEntry = CreateEntry( sNumPostBreak,	CBCOL_SECOND );
1633 	aLngCfg.GetProperty( C2U(UPN_HYPH_MIN_TRAILING) ) >>= nVal;
1634 	if (pHyp)
1635 		nVal = (sal_Int16) pHyp->GetMinTrail();
1636 	nUserData = OptionsUserData( EID_NUM_POST_BREAK, sal_True, (sal_uInt16)nVal, sal_False, sal_False).GetUserData();
1637 	pEntry->SetUserData( (void *)nUserData );
1638 	pModel->Insert( pEntry );
1639 
1640 	pEntry = CreateEntry( sHyphAuto,		CBCOL_FIRST );
1641 	aLngCfg.GetProperty( C2U(UPN_IS_HYPH_AUTO) ) >>= bVal;
1642 	nUserData = OptionsUserData( EID_HYPH_AUTO, sal_False, 0, sal_True, bVal).GetUserData();
1643 	pEntry->SetUserData( (void *)nUserData );
1644 	pModel->Insert( pEntry );
1645 	lcl_SetCheckButton( pEntry, bVal );
1646 
1647 	pEntry = CreateEntry( sHyphSpecial,		CBCOL_FIRST );
1648 	aLngCfg.GetProperty( C2U(UPN_IS_HYPH_SPECIAL) ) >>= bVal;
1649 	nUserData = OptionsUserData( EID_HYPH_SPECIAL, sal_False, 0, sal_True, bVal).GetUserData();
1650 	pEntry->SetUserData( (void *)nUserData );
1651 	pModel->Insert( pEntry );
1652 	lcl_SetCheckButton( pEntry, bVal );
1653 
1654 	aLinguOptionsCLB.SetUpdateMode(sal_True);
1655 }
1656 
1657 // -----------------------------------------------------------------------
1658 
1659 IMPL_LINK( SvxLinguTabPage, BoxDoubleClickHdl_Impl, SvTreeListBox *, pBox )
1660 {
1661     if (pBox == &aLinguModulesCLB)
1662     {
1663         //! in order to avoid a bug causing a GPF when double clicking
1664         //! on a module entry and exiting the "Edit Modules" dialog
1665         //! after that.
1666         Application::PostUserEvent( LINK(
1667                     this, SvxLinguTabPage, PostDblClickHdl_Impl ) );
1668     }
1669     else if (pBox == &aLinguOptionsCLB)
1670     {
1671         ClickHdl_Impl(&aLinguOptionsEditPB);
1672     }
1673     return 0;
1674 }
1675 
1676 // -----------------------------------------------------------------------
1677 
1678 IMPL_LINK( SvxLinguTabPage, PostDblClickHdl_Impl, SvTreeListBox *, EMPTYARG )
1679 {
1680     ClickHdl_Impl(&aLinguModulesEditPB);
1681 	return 0;
1682 }
1683 
1684 // -----------------------------------------------------------------------
1685 
1686 IMPL_LINK( SvxLinguTabPage, OpenURLHdl_Impl, svt::FixedHyperlink *, EMPTYARG )
1687 {
1688     ::rtl::OUString sURL( aMoreDictsLink.GetURL() );
1689     lcl_OpenURL( sURL );
1690     return 0;
1691 }
1692 
1693 // -----------------------------------------------------------------------
1694 
1695 IMPL_LINK( SvxLinguTabPage, BoxCheckButtonHdl_Impl, SvTreeListBox *, pBox )
1696 {
1697     if (pBox == &aLinguModulesCLB)
1698     {
1699         DBG_ASSERT( pLinguData, "NULL pointer, LinguData missing" );
1700         sal_uInt16 nPos = aLinguModulesCLB.GetSelectEntryPos();
1701         if (nPos != LISTBOX_ENTRY_NOTFOUND  &&  pLinguData)
1702         {
1703             pLinguData->Reconfigure( aLinguModulesCLB.GetText( nPos ),
1704                                      aLinguModulesCLB.IsChecked( nPos ) );
1705         }
1706     }
1707     else if (pBox == &aLinguDicsCLB)
1708     {
1709         sal_uInt16 nPos = aLinguDicsCLB.GetSelectEntryPos();
1710         if (nPos != LISTBOX_ENTRY_NOTFOUND)
1711         {
1712             const uno::Reference< XDictionary > &rDic = aDics.getConstArray()[ nPos ];
1713             if (SvxGetIgnoreAllList() == rDic)
1714             {
1715                 SvLBoxEntry* pEntry = aLinguDicsCLB.GetEntry( nPos );
1716                 if (pEntry)
1717                     lcl_SetCheckButton( pEntry, sal_True );
1718             }
1719         }
1720     }
1721 	return 0;
1722 }
1723 
1724 // -----------------------------------------------------------------------
1725 
1726 IMPL_LINK( SvxLinguTabPage, ClickHdl_Impl, PushButton *, pBtn )
1727 {
1728 	if (&aLinguModulesEditPB == pBtn)
1729 	{
1730 		if (!pLinguData)
1731 			pLinguData = new SvxLinguData_Impl;
1732 
1733         SvxLinguData_Impl   aOldLinguData( *pLinguData );
1734         SvxEditModulesDlg   aDlg( this, *pLinguData );
1735         if (aDlg.Execute() != RET_OK)
1736             *pLinguData = aOldLinguData;
1737 
1738         // evaluate new status of 'bConfigured' flag
1739         sal_uLong nLen = pLinguData->GetDisplayServiceCount();
1740         for (sal_uLong i = 0;  i < nLen;  ++i)
1741             pLinguData->GetDisplayServiceArray()[i].bConfigured = sal_False;
1742         const Locale* pAllLocales = pLinguData->GetAllSupportedLocales().getConstArray();
1743         sal_Int32 nLocales = pLinguData->GetAllSupportedLocales().getLength();
1744         for (sal_Int32 k = 0;  k < nLocales;  ++k)
1745 		{
1746             sal_Int16 nLang = SvxLocaleToLanguage( pAllLocales[k] );
1747             if (pLinguData->GetSpellTable().count( nLang ))
1748                 pLinguData->SetChecked( pLinguData->GetSpellTable()[ nLang ] );
1749             if (pLinguData->GetGrammarTable().count( nLang ))
1750                 pLinguData->SetChecked( pLinguData->GetGrammarTable()[ nLang ] );
1751             if (pLinguData->GetHyphTable().count( nLang ))
1752                 pLinguData->SetChecked( pLinguData->GetHyphTable()[ nLang ] );
1753             if (pLinguData->GetThesTable().count( nLang ))
1754                 pLinguData->SetChecked( pLinguData->GetThesTable()[ nLang ] );
1755 		}
1756 
1757         // show new status of modules
1758         UpdateModulesBox_Impl();
1759 	}
1760     else if (&aLinguDicsNewPB == pBtn)
1761 	{
1762         uno::Reference< XSpellChecker1 > xSpellChecker1;
1763 		SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
1764 		if(pFact)
1765 		{
1766 			AbstractSvxNewDictionaryDialog* aDlg = pFact->CreateSvxNewDictionaryDialog( this, xSpellChecker1, RID_SFXDLG_NEWDICT );
1767             DBG_ASSERT(aDlg, "Dialogdiet fail!");
1768 			uno::Reference< XDictionary >  xNewDic;
1769             if ( aDlg->Execute() == RET_OK )
1770                 xNewDic = uno::Reference< XDictionary >( aDlg->GetNewDictionary(), UNO_QUERY );
1771 			if ( xNewDic.is() )
1772 			{
1773 				// add new dics to the end
1774 				sal_Int32 nLen = aDics.getLength();
1775 				aDics.realloc( nLen + 1 );
1776 
1777 				aDics.getArray()[ nLen ] = xNewDic;
1778 
1779 				AddDicBoxEntry( xNewDic, (sal_uInt16) nLen );
1780 			}
1781 			delete aDlg; //add by CHINA001
1782 		}
1783 	}
1784     else if (&aLinguDicsEditPB == pBtn)
1785 	{
1786         SvLBoxEntry *pEntry = aLinguDicsCLB.GetCurEntry();
1787 		if (pEntry)
1788 		{
1789 			DicUserData aData( (sal_uLong) pEntry->GetUserData() );
1790 			sal_uInt16 nDicPos = aData.GetEntryId();
1791 			sal_Int32 nDics = aDics.getLength();
1792 			if (nDicPos < nDics)
1793 			{
1794 				uno::Reference< XDictionary > xDic;
1795 				xDic = aDics.getConstArray()[ nDicPos ];
1796 				if (xDic.is())
1797 				{
1798                     uno::Reference< XSpellChecker1 > xSpellChecker1;
1799 					SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
1800 					if(pFact)
1801 					{
1802 						VclAbstractDialog* aDlg = pFact->CreateSvxEditDictionaryDialog( this, xDic->getName(), xSpellChecker1, RID_SFXDLG_EDITDICT );
1803                         DBG_ASSERT(aDlg, "Dialogdiet fail!");
1804                         aDlg->Execute();
1805                         delete aDlg;
1806 					}
1807 				}
1808 			}
1809 		}
1810 	}
1811     else if (&aLinguDicsDelPB == pBtn)
1812 	{
1813 		if ( RET_NO ==
1814 		 	QueryBox( this, CUI_RES( RID_SFXQB_DELDICT ) ).Execute() )
1815 			return 0;
1816 
1817         SvLBoxEntry *pEntry = aLinguDicsCLB.GetCurEntry();
1818 		if (pEntry)
1819 		{
1820 			DicUserData aData( (sal_uLong) pEntry->GetUserData() );
1821 			sal_uInt16 nDicPos = aData.GetEntryId();
1822 			sal_Int32 nDics = aDics.getLength();
1823 			if (nDicPos < nDics)
1824 			{
1825 				uno::Reference< XDictionary > xDic;
1826 				xDic = aDics.getConstArray()[ nDicPos ];
1827 				if (xDic.is())
1828 				{
1829 					if (SvxGetIgnoreAllList() == xDic)
1830 						xDic->clear();
1831 					else
1832 					{
1833 						if (xDicList.is())
1834 							xDicList->removeDictionary( xDic );
1835 
1836 						uno::Reference< frame::XStorable > xStor( xDic, UNO_QUERY );
1837 						if ( xStor->hasLocation() && !xStor->isReadonly() )
1838 						{
1839 							String sURL = xStor->getLocation();
1840 							INetURLObject aObj(sURL);
1841 							DBG_ASSERT( aObj.GetProtocol() == INET_PROT_FILE,
1842 									"non-file URLs cannot be deleted" );
1843 							if ( aObj.GetProtocol() == INET_PROT_FILE )
1844 							{
1845 								KillFile_Impl( aObj.GetMainURL( INetURLObject::NO_DECODE ) );
1846 							}
1847 						}
1848 
1849                         aDics.getArray()[ nDicPos ] = 0;
1850 
1851                         // remove entry from checklistbox
1852                         sal_uLong nCnt = aLinguDicsCLB.GetEntryCount();
1853                         for (sal_uLong i = 0;  i < nCnt;  ++i)
1854                         {
1855                             SvLBoxEntry *pDicEntry = aLinguDicsCLB.GetEntry( i );
1856                             DBG_ASSERT( pDicEntry, "missing entry" );
1857                             if (pDicEntry)
1858                             {
1859                                 DicUserData aDicData( (sal_uLong) pDicEntry->GetUserData() );
1860                                 if (aDicData.GetEntryId() == nDicPos )
1861                                 {
1862                                     aLinguDicsCLB.RemoveEntry( (sal_uInt16) i );
1863                                     break;
1864                                 }
1865                             }
1866                         }
1867                         DBG_ASSERT( nCnt > aLinguDicsCLB.GetEntryCount(),
1868                                 "remove failed ?");
1869 					}
1870 				}
1871 			}
1872 		}
1873 	}
1874 	else if (&aLinguOptionsEditPB == pBtn)
1875 	{
1876 		SvLBoxEntry *pEntry = aLinguOptionsCLB.GetCurEntry();
1877 		DBG_ASSERT( pEntry, "no entry selected" );
1878 		if (pEntry)
1879 		{
1880 			long nVal = -1;
1881 			OptionsUserData aData( (sal_uLong)pEntry->GetUserData() );
1882 			if(aData.HasNumericValue())
1883 			{
1884 				int nRID = -1;
1885 				switch (aData.GetEntryId())
1886 				{
1887 					case EID_NUM_PRE_BREAK	: nRID = STR_NUM_PRE_BREAK_DLG; break;
1888 					case EID_NUM_POST_BREAK	: nRID = STR_NUM_POST_BREAK_DLG; break;
1889 					case EID_NUM_MIN_WORDLEN: nRID = STR_NUM_MIN_WORDLEN_DLG; break;
1890 					default:
1891 						DBG_ERROR( "unexpected case" );
1892 				}
1893 
1894 				OptionsBreakSet aDlg( this, nRID );
1895                 aDlg.GetNumericFld().SetValue( aData.GetNumericValue() );
1896 				if (RET_OK == aDlg.Execute() )
1897 				{
1898 					nVal = static_cast<long>(aDlg.GetNumericFld().GetValue());
1899 					if (-1 != nVal && aData.GetNumericValue() != nVal)
1900 					{
1901 						aData.SetNumericValue( (sal_uInt8)nVal ); //! sets IsModified !
1902 						pEntry->SetUserData( (void *) aData.GetUserData() );
1903 						aLinguOptionsCLB.Invalidate();
1904 					}
1905 				}
1906 			}
1907 		}
1908 	}
1909 	else
1910 	{
1911 		DBG_ERROR( "pBtn unexpected value" );
1912 	}
1913 
1914 	return 0;
1915 }
1916 
1917 // -----------------------------------------------------------------------
1918 
1919 IMPL_LINK( SvxLinguTabPage, SelectHdl_Impl, SvxCheckListBox *, pBox )
1920 {
1921 	if (&aLinguModulesCLB == pBox)
1922 	{
1923 	}
1924     else if (&aLinguDicsCLB == pBox)
1925 	{
1926 		SvLBoxEntry *pEntry = pBox->GetCurEntry();
1927 		if (pEntry)
1928 		{
1929 			DicUserData aData( (sal_uLong) pEntry->GetUserData() );
1930 
1931 			// always allow to edit (i.e. at least view the content of the dictionary)
1932             aLinguDicsEditPB.Enable( true/*aData.IsEditable()*/ );
1933             aLinguDicsDelPB .Enable( aData.IsDeletable() );
1934 		}
1935 	}
1936 	else if (&aLinguOptionsCLB == pBox)
1937 	{
1938 		SvLBoxEntry *pEntry = pBox->GetCurEntry();
1939 		if (pEntry)
1940 		{
1941 			OptionsUserData aData( (sal_uLong) pEntry->GetUserData() );
1942 			aLinguOptionsEditPB.Enable( aData.HasNumericValue() );
1943 		}
1944 	}
1945 	else
1946 	{
1947 		DBG_ERROR( "pBox unexpected value" );
1948 	}
1949 
1950 	return 0;
1951 }
1952 
1953 // -----------------------------------------------------------------------
1954 
1955 SvLBoxEntry* SvxLinguTabPage::CreateEntry( String& rTxt, sal_uInt16 nCol )
1956 {
1957 	SvLBoxEntry* pEntry = new SvLBoxEntry;
1958 
1959 	if( !pCheckButtonData )
1960 		pCheckButtonData = new SvLBoxButtonData( &aLinguOptionsCLB );
1961 
1962 	String sEmpty;
1963 	if (CBCOL_FIRST == nCol)
1964 		pEntry->AddItem( new SvLBoxButton( pEntry, SvLBoxButtonKind_enabledCheckbox, 0, pCheckButtonData ) );
1965 	if (CBCOL_SECOND == nCol)
1966 		pEntry->AddItem( new SvLBoxString( pEntry, 0, sEmpty) );	// Leerspalte
1967 	pEntry->AddItem( new SvLBoxContextBmp( pEntry, 0, Image(), Image(), 0));	// Sonst Puff!
1968 	pEntry->AddItem( new BrwString_Impl( pEntry, 0, rTxt ) );
1969 
1970 	return pEntry;
1971 }
1972 
1973 // -----------------------------------------------------------------------
1974 
1975 void SvxLinguTabPage::HideGroups( sal_uInt16 nGrp )
1976 {
1977 	if ( 0 != ( GROUP_MODULES & nGrp ) )
1978 	{
1979 		aLinguModulesFT.Hide();
1980 		aLinguModulesCLB.Hide();
1981 		aLinguModulesEditPB.Hide();
1982 
1983         // reposition / resize remaining controls
1984         long nDeltaY = aLinguDicsFT.GetPosPixel().Y() -
1985                        aLinguModulesFT.GetPosPixel().Y();
1986         DBG_ASSERT( nDeltaY >= 0, "move/resize value is negative" );
1987         Point   aPos;
1988         //
1989         aPos = aLinguDicsFT.GetPosPixel();
1990         aPos.Y() -= nDeltaY;
1991         aLinguDicsFT.SetPosPixel( aPos );
1992         aPos = aLinguDicsCLB.GetPosPixel();
1993         aPos.Y() -= nDeltaY;
1994         aLinguDicsCLB.SetPosPixel( aPos );
1995         aPos = aLinguDicsNewPB.GetPosPixel();
1996         aPos.Y() -= nDeltaY;
1997         aLinguDicsNewPB.SetPosPixel( aPos );
1998         aPos = aLinguDicsEditPB.GetPosPixel();
1999         aPos.Y() -= nDeltaY;
2000         aLinguDicsEditPB.SetPosPixel( aPos );
2001         aPos = aLinguDicsDelPB.GetPosPixel();
2002         aPos.Y() -= nDeltaY;
2003         aLinguDicsDelPB.SetPosPixel( aPos );
2004         //
2005         aPos = aLinguOptionsFT.GetPosPixel();
2006         aPos.Y() -= nDeltaY;
2007         aLinguOptionsFT.SetPosPixel( aPos );
2008         aPos = aLinguOptionsCLB.GetPosPixel();
2009         aPos.Y() -= nDeltaY;
2010         aLinguOptionsCLB.SetPosPixel( aPos );
2011         aPos = aLinguOptionsEditPB.GetPosPixel();
2012         aPos.Y() -= nDeltaY;
2013         aLinguOptionsEditPB.SetPosPixel( aPos );
2014         //
2015         Size aSize( aLinguOptionsCLB.GetSizePixel() );
2016         aSize.Height() += nDeltaY;
2017         aLinguOptionsCLB.SetSizePixel( aSize );
2018 
2019         if ( SvtExtendedSecurityOptions().GetOpenHyperlinkMode()
2020                 != SvtExtendedSecurityOptions::OPEN_NEVER )
2021         {
2022             aSize = GetOutputSizePixel();
2023             aSize.Height() += ( aMoreDictsLink.GetSizePixel().Height() * 11 / 8 );
2024             SetSizePixel( aSize );
2025             aMoreDictsLink.Show();
2026         }
2027 	}
2028 }
2029 /*--------------------------------------------------
2030 --------------------------------------------------*/
2031 
2032 SvxEditModulesDlg::SvxEditModulesDlg(Window* pParent, SvxLinguData_Impl& rData) :
2033     ModalDialog( pParent, CUI_RES(RID_SVXDLG_EDIT_MODULES ) ),
2034     aModulesFL      ( this, CUI_RES( FL_EDIT_MODULES_OPTIONS ) ),
2035     aLanguageFT     ( this, CUI_RES( FT_EDIT_MODULES_LANGUAGE ) ),
2036     aLanguageLB     ( this, CUI_RES( LB_EDIT_MODULES_LANGUAGE ), sal_False ),
2037     aModulesCLB     ( this, CUI_RES( CLB_EDIT_MODULES_MODULES ) ),
2038     aPrioUpPB       ( this, CUI_RES( PB_EDIT_MODULES_PRIO_UP ) ),
2039     aPrioDownPB     ( this, CUI_RES( PB_EDIT_MODULES_PRIO_DOWN ) ),
2040     aBackPB         ( this, CUI_RES( PB_EDIT_MODULES_PRIO_BACK ) ),
2041     aMoreDictsLink  ( this, CUI_RES( FT_EDIT_MODULES_NEWDICTSLINK ) ),
2042     aButtonsFL      ( this, CUI_RES( FL_EDIT_MODULES_BUTTONS ) ),
2043     aHelpPB         ( this, CUI_RES( PB_HELP ) ),
2044     aClosePB        ( this, CUI_RES( PB_OK ) ),
2045     sSpell          (       CUI_RES( ST_SPELL ) ),
2046     sHyph           (       CUI_RES( ST_HYPH ) ),
2047     sThes           (       CUI_RES( ST_THES ) ),
2048     sGrammar        (       CUI_RES( ST_GRAMMAR ) ),
2049     rLinguData      ( rData )
2050 {
2051 	pCheckButtonData = NULL;
2052 	FreeResource();
2053 
2054     pDefaultLinguData = new SvxLinguData_Impl( rLinguData );
2055 
2056 	aModulesCLB.SetStyle( aModulesCLB.GetStyle()|WB_CLIPCHILDREN|WB_HSCROLL|WB_FORCE_MAKEVISIBLE );
2057 	aModulesCLB.SetHighlightRange();
2058 	aModulesCLB.SetHelpId(HID_CLB_EDIT_MODULES_MODULES );
2059 	aModulesCLB.SetSelectHdl( LINK( this, SvxEditModulesDlg, SelectHdl_Impl ));
2060     aModulesCLB.SetCheckButtonHdl( LINK( this, SvxEditModulesDlg, BoxCheckButtonHdl_Impl) );
2061 
2062     aClosePB   .SetClickHdl( LINK( this, SvxEditModulesDlg, ClickHdl_Impl ));
2063     aPrioUpPB  .SetClickHdl( LINK( this, SvxEditModulesDlg, UpDownHdl_Impl ));
2064 	aPrioDownPB.SetClickHdl( LINK( this, SvxEditModulesDlg, UpDownHdl_Impl ));
2065     aBackPB    .SetClickHdl( LINK( this, SvxEditModulesDlg, BackHdl_Impl ));
2066     // in case of not installed language modules
2067     aPrioUpPB  .Enable( sal_False );
2068     aPrioDownPB.Enable( sal_False );
2069 
2070     if ( SvtExtendedSecurityOptions().GetOpenHyperlinkMode()
2071             != SvtExtendedSecurityOptions::OPEN_NEVER )
2072     {
2073         aMoreDictsLink.SetURL( String(
2074             RTL_CONSTASCII_STRINGPARAM( "http://extensions.services.openoffice.org/dictionary?cid=926386" ) ) );
2075         aMoreDictsLink.SetClickHdl( LINK( this, SvxEditModulesDlg, OpenURLHdl_Impl ) );
2076     }
2077     else
2078     {
2079         aMoreDictsLink.Hide();
2080         long nPos = aMoreDictsLink.GetPosPixel().Y() + aMoreDictsLink.GetSizePixel().Height();
2081         Size aSize = aModulesCLB.GetSizePixel();
2082         aSize.Height() += ( nPos - ( aModulesCLB.GetPosPixel().Y() + aSize.Height() ) );
2083         aModulesCLB.SetSizePixel( aSize );
2084     }
2085 
2086     //
2087     //fill language box
2088     //
2089     Sequence< sal_Int16 > aAvailLang;
2090     uno::Reference< XAvailableLocales > xAvail( rLinguData.GetManager(), UNO_QUERY );
2091     if (xAvail.is())
2092     {
2093         aAvailLang = lcl_LocaleSeqToLangSeq(
2094                         xAvail->getAvailableLocales( C2U(cSpell) ) );
2095     }
2096     const Sequence< Locale >& rLoc = rLinguData.GetAllSupportedLocales();
2097 	const Locale* pLocales = rLoc.getConstArray();
2098 	aLanguageLB.Clear();
2099 	for(long i = 0; i < rLoc.getLength(); i++)
2100 	{
2101         sal_Int16 nLang = SvxLocaleToLanguage( pLocales[i] );
2102         aLanguageLB.InsertLanguage( nLang, lcl_SeqHasLang( aAvailLang, nLang ) );
2103 	}
2104 	LanguageType eSysLang = MsLangId::getSystemLanguage();
2105 	aLanguageLB.SelectLanguage( eSysLang );
2106 	if(!aLanguageLB.IsLanguageSelected( eSysLang ) )
2107 		aLanguageLB.SelectEntryPos(0);
2108 
2109 	aLanguageLB.SetSelectHdl( LINK( this, SvxEditModulesDlg, LangSelectHdl_Impl ));
2110 	LangSelectHdl_Impl(&aLanguageLB);
2111 }
2112 
2113 
2114 SvxEditModulesDlg::~SvxEditModulesDlg()
2115 {
2116     delete pDefaultLinguData;
2117 }
2118 
2119 
2120 SvLBoxEntry* SvxEditModulesDlg::CreateEntry( String& rTxt, sal_uInt16 nCol )
2121 {
2122 	SvLBoxEntry* pEntry = new SvLBoxEntry;
2123 	if( !pCheckButtonData )
2124 	{
2125 		pCheckButtonData = new SvLBoxButtonData( &aModulesCLB );
2126         pCheckButtonData->SetLink( aModulesCLB.GetCheckButtonHdl() );
2127 	}
2128 
2129 	String sEmpty;
2130 	if (CBCOL_FIRST == nCol)
2131 		pEntry->AddItem( new SvLBoxButton( pEntry, SvLBoxButtonKind_enabledCheckbox, 0, pCheckButtonData ) );
2132 	if (CBCOL_SECOND == nCol)
2133 		pEntry->AddItem( new SvLBoxString( pEntry, 0, sEmpty) );	// Leerspalte
2134 	pEntry->AddItem( new SvLBoxContextBmp( pEntry, 0, Image(), Image(), 0));	// Sonst Puff!
2135 	pEntry->AddItem( new BrwStringDic_Impl( pEntry, 0, rTxt ) );
2136 
2137 	return pEntry;
2138 }
2139 
2140 /* ---------------------------------------------------------------------------
2141 
2142  ---------------------------------------------------------------------------*/
2143 IMPL_LINK( SvxEditModulesDlg, SelectHdl_Impl, SvxCheckListBox *, pBox )
2144 {
2145 	if (&aModulesCLB == pBox)
2146 	{
2147 		sal_Bool bDisableUp = sal_True;
2148 		sal_Bool bDisableDown = sal_True;
2149 		SvLBoxEntry *pEntry = pBox->GetCurEntry();
2150 		if (pEntry)
2151 		{
2152 			ModuleUserData_Impl* pData = (ModuleUserData_Impl*)pEntry->GetUserData();
2153 			if(!pData->IsParent() && pData->GetType() != TYPE_HYPH)
2154 			{
2155 				sal_uInt16	nCurPos = pBox->GetSelectEntryPos();
2156 				if(nCurPos < pBox->GetEntryCount() - 1)
2157 				{
2158 					bDisableDown = ((ModuleUserData_Impl*)pBox->
2159 							GetEntry(nCurPos + 1)->GetUserData())->IsParent();
2160 				}
2161 				if(nCurPos > 1)
2162 				{
2163             					bDisableUp = ((ModuleUserData_Impl*)pBox->
2164 							GetEntry(nCurPos - 1)->GetUserData())->IsParent();
2165 				}
2166 			}
2167 			aPrioUpPB.Enable(!bDisableUp);
2168 			aPrioDownPB.Enable(!bDisableDown);
2169 		}
2170 	}
2171 	else
2172 	{
2173 		DBG_ERROR( "pBox unexpected value" );
2174 	}
2175 
2176 	return 0;
2177 }
2178 /* -----------------------------28.05.01 11:00--------------------------------
2179 
2180  ---------------------------------------------------------------------------*/
2181 IMPL_LINK( SvxEditModulesDlg, BoxCheckButtonHdl_Impl, SvTreeListBox *, pBox )
2182 {
2183 //    if (pBox == (SvTreeListBox *) &aModulesCLB)
2184 //    {
2185         pBox = &aModulesCLB;
2186 		SvLBoxEntry *pCurEntry = pBox->GetCurEntry();
2187 		if (pCurEntry)
2188 		{
2189 			ModuleUserData_Impl* pData = (ModuleUserData_Impl *)
2190 												pCurEntry->GetUserData();
2191 			if (!pData->IsParent()  &&  pData->GetType() == TYPE_HYPH)
2192 			{
2193 				// make hyphenator checkboxes function as radio-buttons
2194 				// (at most one box may be checked)
2195 				SvLBoxEntry *pEntry = pBox->First();
2196 				while (pEntry)
2197 				{
2198 					pData = (ModuleUserData_Impl *) pEntry->GetUserData();
2199 					if (!pData->IsParent()  &&
2200 						 pData->GetType() == TYPE_HYPH  &&
2201 						 pEntry != pCurEntry)
2202 					{
2203 						lcl_SetCheckButton( pEntry, sal_False );
2204 						pBox->InvalidateEntry( pEntry );
2205 					}
2206 					pEntry = pBox->Next( pEntry );
2207 				}
2208 			}
2209 		}
2210 //    }
2211 	return 0;
2212 }
2213 /* -----------------------------27.11.00 14:00--------------------------------
2214 
2215  ---------------------------------------------------------------------------*/
2216 OUString lcl_GetServiceName(sal_uInt8 nType)
2217 {
2218 	switch(nType)
2219 	{
2220         case  TYPE_SPELL    : return C2U(cSpell);
2221         case  TYPE_GRAMMAR  : return C2U(cGrammar);
2222         case  TYPE_HYPH     : return C2U(cHyph);
2223         case  TYPE_THES     : return C2U(cThes);
2224 	}
2225 	return OUString();
2226 }
2227 
2228 
2229 IMPL_LINK( SvxEditModulesDlg, LangSelectHdl_Impl, ListBox *, pBox )
2230 {
2231 	LanguageType  eCurLanguage = aLanguageLB.GetSelectLanguage();
2232 	static Locale aLastLocale;
2233 	Locale aCurLocale;
2234 	SvxLanguageToLocale(aCurLocale, eCurLanguage);
2235 	SvLBoxTreeList *pModel = aModulesCLB.GetModel();
2236 //	uno::Reference<XLinguServiceManager>&   xMgr = rLinguData.GetManager();
2237 
2238     if (pBox)
2239 	{
2240         // save old probably changed settings
2241         // before switching to new language entries
2242 
2243         sal_Int16 nLang = SvxLocaleToLanguage( aLastLocale );
2244 
2245 		sal_Int32 nStart = 0, nLocalIndex = 0;
2246         Sequence< OUString > aChange;
2247 		sal_Bool bChanged = sal_False;
2248 		for(sal_uInt16 i = 0; i < aModulesCLB.GetEntryCount(); i++)
2249 		{
2250 			SvLBoxEntry *pEntry = aModulesCLB.GetEntry(i);
2251 			ModuleUserData_Impl* pData = (ModuleUserData_Impl*)pEntry->GetUserData();
2252 			if(pData->IsParent())
2253 			{
2254 				if(bChanged)
2255 				{
2256                     LangImplNameTable *pTable = 0;
2257                     sal_uInt8 nType = pData->GetType();
2258                     switch (nType - 1)
2259                     {
2260                         case  TYPE_SPELL    : pTable = &rLinguData.GetSpellTable(); break;
2261                         case  TYPE_GRAMMAR  : pTable = &rLinguData.GetGrammarTable();  break;
2262                         case  TYPE_HYPH     : pTable = &rLinguData.GetHyphTable();  break;
2263                         case  TYPE_THES     : pTable = &rLinguData.GetThesTable();  break;
2264                     }
2265                     if (pTable)
2266                     {
2267                         aChange.realloc(nStart);
2268                         (*pTable)[ nLang ] = aChange;
2269                     }
2270 				}
2271 				nLocalIndex = nStart = 0;
2272 				aChange.realloc(aModulesCLB.GetEntryCount());
2273 				bChanged = sal_False;
2274 			}
2275 			else
2276 			{
2277 				OUString* pChange = aChange.getArray();
2278 				pChange[nStart] = pData->GetImplName();
2279 				bChanged |= pData->GetIndex() != nLocalIndex ||
2280 					pData->IsChecked() != aModulesCLB.IsChecked(i);
2281 				if(aModulesCLB.IsChecked(i))
2282 					nStart++;
2283 				++nLocalIndex;
2284 			}
2285 		}
2286 		if(bChanged)
2287 		{
2288 			aChange.realloc(nStart);
2289             rLinguData.GetThesTable()[ nLang ] = aChange;
2290 		}
2291 	}
2292 
2293 	for(sal_uLong i = 0; i < aModulesCLB.GetEntryCount(); i++)
2294 		delete (ModuleUserData_Impl*)aModulesCLB.GetEntry(i)->GetUserData();
2295 
2296     //
2297     // display entries for new selected language
2298     //
2299 	aModulesCLB.Clear();
2300 	if(LANGUAGE_DONTKNOW != eCurLanguage)
2301 	{
2302 //		sal_Int32 nEntryPos = 1;
2303 
2304         sal_uLong n;
2305         ServiceInfo_Impl* pInfo;
2306 
2307         //
2308         // spellchecker entries
2309         //
2310 		SvLBoxEntry* pEntry = CreateEntry( sSpell,	CBCOL_SECOND );
2311         ModuleUserData_Impl* pUserData = new ModuleUserData_Impl(
2312                                          String(), sal_True, sal_False, TYPE_SPELL, 0 );
2313 		pEntry->SetUserData( (void *)pUserData );
2314 		pModel->Insert( pEntry );
2315         //
2316         Sequence< OUString > aNames( rLinguData.GetSortedImplNames( eCurLanguage, TYPE_SPELL ) );
2317         const OUString *pName = aNames.getConstArray();
2318         sal_uLong nNames = (sal_uLong) aNames.getLength();
2319 		sal_Int32 nLocalIndex = 0;	// index relative to parent
2320         for (n = 0;  n < nNames;  ++n)
2321 		{
2322 			OUString aImplName;
2323 			sal_Bool	 bIsSuppLang = sal_False;
2324 
2325             pInfo = rLinguData.GetInfoByImplName( pName[n] );
2326 			if (pInfo)
2327 			{
2328 				bIsSuppLang = pInfo->xSpell.is()  &&
2329 							  pInfo->xSpell->hasLocale( aCurLocale );
2330 				aImplName = pInfo->sSpellImplName;
2331 			}
2332             if (aImplName.getLength() && bIsSuppLang)
2333 			{
2334                 String aTxt( pInfo->sDisplayName );
2335                 SvLBoxEntry* pNewEntry = CreateEntry( aTxt, CBCOL_FIRST );
2336 
2337                 LangImplNameTable &rTable = rLinguData.GetSpellTable();
2338                 const bool bHasLang = rTable.count( eCurLanguage );
2339 				if (!bHasLang)
2340 				{
2341 					DBG_WARNING( "language entry missing" );	// only relevant if all languages found should be supported
2342 				}
2343                 const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0;
2344                 lcl_SetCheckButton( pNewEntry, bCheck );
2345                 pUserData = new ModuleUserData_Impl( aImplName, sal_False,
2346                                         bCheck, TYPE_SPELL, (sal_uInt8)nLocalIndex++ );
2347                 pNewEntry->SetUserData( (void *)pUserData );
2348                 pModel->Insert( pNewEntry );
2349 			}
2350 		}
2351 
2352         //
2353         // grammar checker entries
2354         //
2355         pEntry = CreateEntry( sGrammar,    CBCOL_SECOND );
2356         pUserData = new ModuleUserData_Impl( String(), sal_True, sal_False, TYPE_GRAMMAR, 0 );
2357         pEntry->SetUserData( (void *)pUserData );
2358         pModel->Insert( pEntry );
2359         //
2360         aNames = rLinguData.GetSortedImplNames( eCurLanguage, TYPE_GRAMMAR );
2361         pName = aNames.getConstArray();
2362         nNames = (sal_uLong) aNames.getLength();
2363         nLocalIndex = 0;
2364         for (n = 0;  n < nNames;  ++n)
2365         {
2366             OUString aImplName;
2367             sal_Bool     bIsSuppLang = sal_False;
2368 
2369             pInfo = rLinguData.GetInfoByImplName( pName[n] );
2370             if (pInfo)
2371             {
2372                 bIsSuppLang = pInfo->xGrammar.is()  &&
2373                               pInfo->xGrammar->hasLocale( aCurLocale );
2374                 aImplName = pInfo->sGrammarImplName;
2375             }
2376             if (aImplName.getLength() && bIsSuppLang)
2377             {
2378                 String aTxt( pInfo->sDisplayName );
2379                 SvLBoxEntry* pNewEntry = CreateEntry( aTxt, CBCOL_FIRST );
2380 
2381                 LangImplNameTable &rTable = rLinguData.GetGrammarTable();
2382                 const bool bHasLang = rTable.count( eCurLanguage );
2383                 if (!bHasLang)
2384                 {
2385                     DBG_WARNING( "language entry missing" );    // only relevant if all languages found should be supported
2386                 }
2387                 const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0;
2388                 lcl_SetCheckButton( pNewEntry, bCheck );
2389                 pUserData = new ModuleUserData_Impl( aImplName, sal_False,
2390                                         bCheck, TYPE_GRAMMAR, (sal_uInt8)nLocalIndex++ );
2391                 pNewEntry->SetUserData( (void *)pUserData );
2392                 pModel->Insert( pNewEntry );
2393             }
2394         }
2395 
2396         //
2397         // hyphenator entries
2398         //
2399 		pEntry = CreateEntry( sHyph,	CBCOL_SECOND );
2400 		pUserData = new ModuleUserData_Impl( String(), sal_True, sal_False, TYPE_HYPH, 0 );
2401 		pEntry->SetUserData( (void *)pUserData );
2402 		pModel->Insert( pEntry );
2403         //
2404         aNames = rLinguData.GetSortedImplNames( eCurLanguage, TYPE_HYPH );
2405         pName = aNames.getConstArray();
2406         nNames = (sal_uLong) aNames.getLength();
2407 		nLocalIndex = 0;
2408         for (n = 0;  n < nNames;  ++n)
2409 		{
2410 			OUString aImplName;
2411 			sal_Bool	 bIsSuppLang = sal_False;
2412 
2413             pInfo = rLinguData.GetInfoByImplName( pName[n] );
2414 			if (pInfo)
2415 			{
2416 				bIsSuppLang = pInfo->xHyph.is()  &&
2417 							  pInfo->xHyph->hasLocale( aCurLocale );
2418 				aImplName = pInfo->sHyphImplName;
2419 			}
2420             if (aImplName.getLength() && bIsSuppLang)
2421 			{
2422                 String aTxt( pInfo->sDisplayName );
2423                 SvLBoxEntry* pNewEntry = CreateEntry( aTxt, CBCOL_FIRST );
2424 
2425                 LangImplNameTable &rTable = rLinguData.GetHyphTable();
2426                 const bool bHasLang = rTable.count( eCurLanguage );
2427 				if (!bHasLang)
2428 				{
2429 					DBG_WARNING( "language entry missing" );	// only relevant if all languages found should be supported
2430 				}
2431                 const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0;
2432                 lcl_SetCheckButton( pNewEntry, bCheck );
2433                 pUserData = new ModuleUserData_Impl( aImplName, sal_False,
2434                                         bCheck, TYPE_HYPH, (sal_uInt8)nLocalIndex++ );
2435                 pNewEntry->SetUserData( (void *)pUserData );
2436                 pModel->Insert( pNewEntry );
2437 			}
2438 		}
2439 
2440         //
2441         // thesaurus entries
2442         //
2443 		pEntry = CreateEntry( sThes,	CBCOL_SECOND );
2444 		pUserData = new ModuleUserData_Impl( String(), sal_True, sal_False, TYPE_THES, 0 );
2445 		pEntry->SetUserData( (void *)pUserData );
2446 		pModel->Insert( pEntry );
2447         //
2448         aNames = rLinguData.GetSortedImplNames( eCurLanguage, TYPE_THES );
2449         pName = aNames.getConstArray();
2450         nNames = (sal_uLong) aNames.getLength();
2451 		nLocalIndex = 0;
2452         for (n = 0;  n < nNames;  ++n)
2453 		{
2454 			OUString aImplName;
2455 			sal_Bool	 bIsSuppLang = sal_False;
2456 
2457             pInfo = rLinguData.GetInfoByImplName( pName[n] );
2458 			if (pInfo)
2459 			{
2460 				bIsSuppLang = pInfo->xThes.is()  &&
2461 							  pInfo->xThes->hasLocale( aCurLocale );
2462 				aImplName = pInfo->sThesImplName;
2463 			}
2464             if (aImplName.getLength() && bIsSuppLang)
2465 			{
2466                 String aTxt( pInfo->sDisplayName );
2467                 SvLBoxEntry* pNewEntry = CreateEntry( aTxt, CBCOL_FIRST );
2468 
2469                 LangImplNameTable &rTable = rLinguData.GetThesTable();
2470                 const bool bHasLang = rTable.count( eCurLanguage );
2471 				if (!bHasLang)
2472 				{
2473 					DBG_WARNING( "language entry missing" );	// only relevant if all languages found should be supported
2474 				}
2475                 const bool bCheck = bHasLang && lcl_SeqGetEntryPos( rTable[ eCurLanguage ], aImplName ) >= 0;
2476                 lcl_SetCheckButton( pNewEntry, bCheck );
2477                 pUserData = new ModuleUserData_Impl( aImplName, sal_False,
2478                                         bCheck, TYPE_THES, (sal_uInt8)nLocalIndex++ );
2479                 pNewEntry->SetUserData( (void *)pUserData );
2480                 pModel->Insert( pNewEntry );
2481 			}
2482 		}
2483 	}
2484 	aLastLocale.Language = aCurLocale.Language;
2485 	aLastLocale.Country = aCurLocale.Country;
2486 	return 0;
2487 }
2488 /* -----------------------------27.11.00 19:50--------------------------------
2489 
2490  ---------------------------------------------------------------------------*/
2491 IMPL_LINK( SvxEditModulesDlg, UpDownHdl_Impl, PushButton *, pBtn )
2492 {
2493 	sal_Bool bUp = &aPrioUpPB == pBtn;
2494 	sal_uInt16	nCurPos = aModulesCLB.GetSelectEntryPos();
2495     SvLBoxEntry* pEntry;
2496     if (nCurPos != LISTBOX_ENTRY_NOTFOUND  &&
2497         0 != (pEntry = aModulesCLB.GetEntry(nCurPos)))
2498     {
2499         aModulesCLB.SetUpdateMode(sal_False);
2500         SvLBoxTreeList *pModel = aModulesCLB.GetModel();
2501 
2502         ModuleUserData_Impl* pData = (ModuleUserData_Impl*)pEntry->GetUserData();
2503         String aStr(aModulesCLB.GetEntryText(pEntry));
2504         SvLBoxEntry* pToInsert = CreateEntry( aStr, CBCOL_FIRST );
2505         pToInsert->SetUserData( (void *)pData);
2506         sal_Bool bIsChecked = aModulesCLB.IsChecked(nCurPos);
2507 
2508         pModel->Remove(pEntry);
2509 
2510         sal_uInt16 nDestPos = bUp ? nCurPos - 1 : nCurPos + 1;
2511         pModel->Insert(pToInsert, nDestPos);
2512         aModulesCLB.CheckEntryPos(nDestPos, bIsChecked );
2513         aModulesCLB.SelectEntryPos(nDestPos );
2514         SelectHdl_Impl(&aModulesCLB);
2515         aModulesCLB.SetUpdateMode(sal_True);
2516     }
2517 	return 0;
2518 }
2519 /* ---------------------------------------------------------------------------
2520 
2521  ---------------------------------------------------------------------------*/
2522 IMPL_LINK( SvxEditModulesDlg, ClickHdl_Impl, PushButton *, pBtn )
2523 {
2524 	if (&aClosePB == pBtn)
2525 	{
2526 		// store language config
2527 		LangSelectHdl_Impl(&aLanguageLB);
2528 		EndDialog( RET_OK );
2529 	}
2530 	else
2531 	{
2532 		DBG_ERROR( "pBtn unexpected value" );
2533 	}
2534 
2535 	return 0;
2536 }
2537 /* -----------------------------27.11.00 20:31--------------------------------
2538 
2539  ---------------------------------------------------------------------------*/
2540 IMPL_LINK( SvxEditModulesDlg, BackHdl_Impl, PushButton *, EMPTYARG )
2541 {
2542     rLinguData = *pDefaultLinguData;
2543 	LangSelectHdl_Impl(0);
2544 	return 0;
2545 }
2546 
2547 // -----------------------------------------------------------------------
2548 
2549 IMPL_LINK( SvxEditModulesDlg, OpenURLHdl_Impl, svt::FixedHyperlink *, EMPTYARG )
2550 {
2551     ::rtl::OUString sURL( aMoreDictsLink.GetURL() );
2552     lcl_OpenURL( sURL );
2553     return 0;
2554 }
2555 
2556