1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include "dialmgr.hxx"
24 #include <editeng/splwrap.hxx>
25 #include <editeng/svxenum.hxx>
26 #include <editeng/unolingu.hxx>
27 #include <svtools/langtab.hxx>
28 #include <svx/dialmgr.hxx>
29 #include <svx/dlgutil.hxx>
30 #include <tools/shl.hxx>
31 #include <vcl/msgbox.hxx>
33 #define HYPH_POS_CHAR '='
34 #define CONTINUE_HYPH USHRT_MAX
36 #define CUR_HYPH_POS_CHAR '-'
40 HyphenEdit::HyphenEdit(Window
* pParent
)
41 : Edit(pParent
, WB_LEFT
|WB_VCENTER
|WB_BORDER
|WB_3DLOOK
|WB_TABSTOP
)
45 extern "C" SAL_DLLPUBLIC_EXPORT Window
* SAL_CALL
makeHyphenEdit(Window
*pParent
, VclBuilder::stringmap
&)
47 return new HyphenEdit(pParent
);
50 void HyphenEdit::KeyInput( const KeyEvent
& rKEvt
)
52 sal_uInt16 nCode
= rKEvt
.GetKeyCode().GetCode();
57 ( (SvxHyphenWordDialog
*)GetParentDialog() )->SelLeft();
61 ( (SvxHyphenWordDialog
*)GetParentDialog() )->SelRight();
67 Edit::KeyInput(rKEvt
);
70 Control::KeyInput( rKEvt
); // pass on to the dialog
76 void SvxHyphenWordDialog::EnableLRBtn_Impl()
78 String
aTxt( aEditWord
);
79 xub_StrLen nLen
= aTxt
.Len();
82 m_pRightBtn
->Disable();
83 for ( i
= nOldPos
+ 2; i
< nLen
; ++i
)
85 if ( aTxt
.GetChar( i
) == sal_Unicode( HYPH_POS_CHAR
) )
87 m_pRightBtn
->Enable();
92 DBG_ASSERT(nOldPos
< aTxt
.Len(), "nOldPos out of range");
93 if (nOldPos
>= aTxt
.Len())
94 nOldPos
= aTxt
.Len() - 1;
95 m_pLeftBtn
->Disable();
96 for ( i
= nOldPos
; i
-- > 0; )
98 if ( aTxt
.GetChar( i
) == sal_Unicode( HYPH_POS_CHAR
) )
100 m_pLeftBtn
->Enable();
107 String
SvxHyphenWordDialog::EraseUnusableHyphens_Impl(
108 uno::Reference
< linguistic2::XPossibleHyphens
> &rxPossHyph
,
109 sal_uInt16 _nMaxHyphenationPos
)
111 // returns a String showing only those hyphen positions which will result
112 // in a line break if hyphenation is done there
113 // 1) we will need to discard all hyphenation positions at th end that
114 // will not result in a line break where the text to the left still fits
116 // 2) since as from OOo 3.2 '-' are part of a word an thus text like
117 // 'multi-line-editor' is regarded as single word we also need to discard those
118 // hyphenation positions to the left of the rightmost '-' that is still left of
119 // the rightmost valid hyphenation position according to 1)
122 // If the possible hyphenation position in 'multi-line-editor' are to eb marked
123 // by '=' then the text will look like this 'mul=ti-line-ed=it=or'.
124 // If now the first line is only large enough for 'multi-line-edi' we need to discard
125 // the last possible hyphnation point because of 1). The right most valid
126 // hyphenation position is "ed=itor". The first '-' left of this position is
127 // "line-ed", thus because of 2) we now need to discard all possible hyphneation
128 // positions to the left of that as well. Thus in the end leaving us with just
129 // 'multi-line-ed=itor' as return value for this function. (Just one valid hyphenation
130 // position for the user too choose from. However ALL the '-' characters in the word
131 // will ALWAYS be valid implicit hyphenation positions for the core to choose from!
132 // And thus even if this word is skipped in the hyphenation dialog it will still be broken
133 // right after 'multi-line-' (actually it might already be broken up that way before
134 // the hyphenation dialog is called!).
135 // Thus rule 2) just eliminates those positions which will not be used by the core at all
136 // even if the user were to select one of them.
139 DBG_ASSERT(rxPossHyph
.is(), "missing possible hyphens");
142 DBG_ASSERT( aActWord
== String( rxPossHyph
->getWord() ), "word mismatch" );
144 aTxt
= String( rxPossHyph
->getPossibleHyphens() );
146 nHyphenationPositionsOffset
= 0;
147 uno::Sequence
< sal_Int16
> aHyphenationPositions(
148 rxPossHyph
->getHyphenationPositions() );
149 sal_Int32 nLen
= aHyphenationPositions
.getLength();
150 const sal_Int16
*pHyphenationPos
= aHyphenationPositions
.getConstArray();
152 // find position nIdx after which all hyphen positions are unusable
153 xub_StrLen nIdx
= STRING_NOTFOUND
;
154 xub_StrLen nPos
= 0, nPos1
= 0, nPos2
= 0;
157 xub_StrLen nStart
= 0;
158 for (sal_Int32 i
= 0; i
< nLen
; ++i
)
160 if (pHyphenationPos
[i
] > _nMaxHyphenationPos
)
164 // find corresponding hyphen pos in string
165 nPos
= aTxt
.Search( sal_Unicode( HYPH_POS_CHAR
), nStart
);
167 if (nStart
== STRING_NOTFOUND
)
177 DBG_ASSERT(nIdx
!= STRING_NOTFOUND
, "no usable hyphenation position");
179 // 1) remove all not usable hyphenation positions from the end of the string
180 nPos
= nIdx
== STRING_NOTFOUND
? 0 : nIdx
+ 1;
181 nPos1
= nPos
; //save for later use in 2) below
182 const OUString
aTmp( sal_Unicode( HYPH_POS_CHAR
) );
183 const OUString aEmpty
;
184 while (nPos
!= STRING_NOTFOUND
)
185 nPos
= aTxt
.SearchAndReplace( aTmp
, aEmpty
, nPos
+ 1 );
187 // 2) remove all hyphenation positions from the start that are not considered by the core
188 const String
aSearchRange( aTxt
.Copy( 0, nPos1
) );
189 nPos2
= aSearchRange
.SearchBackward( '-' ); // the '-' position the core will use by default
190 if (nPos2
!= STRING_NOTFOUND
)
192 String
aLeft( aSearchRange
.Copy( 0, nPos2
) );
194 while (nPos
!= STRING_NOTFOUND
)
196 nPos
= aLeft
.SearchAndReplace( aTmp
, aEmpty
, nPos
+ 1 );
197 if (nPos
!= STRING_NOTFOUND
)
198 ++nHyphenationPositionsOffset
;
200 aTxt
.Replace( 0, nPos2
, aLeft
);
207 void SvxHyphenWordDialog::InitControls_Impl()
210 if (xHyphenator
.is())
212 lang::Locale
aLocale( LanguageTag(nActLanguage
).getLocale() );
213 xPossHyph
= xHyphenator
->createPossibleHyphens( aActWord
, aLocale
,
214 uno::Sequence
< beans::PropertyValue
>() );
216 aEditWord
= EraseUnusableHyphens_Impl( xPossHyph
, nMaxHyphenationPos
);
218 m_pWordEdit
->SetText( aEditWord
);
220 nOldPos
= aEditWord
.Len();
226 void SvxHyphenWordDialog::ContinueHyph_Impl( sal_uInt16 nInsPos
)
228 if ( nInsPos
!= CONTINUE_HYPH
&& xPossHyph
.is())
232 String
aTmp( aEditWord
);
233 DBG_ASSERT(nInsPos
<= aTmp
.Len() - 2, "wrong hyphen position");
235 sal_Int16 nIdxPos
= -1;
236 for (sal_uInt16 i
= 0; i
<= nInsPos
; ++i
)
238 if (HYPH_POS_CHAR
== aTmp
.GetChar( i
))
241 // take the possible hyphenation positions that got removed from the
242 // start of the wor dinot account:
243 nIdxPos
+= nHyphenationPositionsOffset
;
245 uno::Sequence
< sal_Int16
> aSeq
= xPossHyph
->getHyphenationPositions();
246 sal_Int32 nLen
= aSeq
.getLength();
247 DBG_ASSERT(nLen
, "empty sequence");
248 DBG_ASSERT(0 <= nIdxPos
&& nIdxPos
< nLen
, "index out of range");
249 if (nLen
&& 0 <= nIdxPos
&& nIdxPos
< nLen
)
251 nInsPos
= aSeq
.getConstArray()[ nIdxPos
];
252 pHyphWrapper
->InsertHyphen( nInsPos
);
257 //! calling with 0 as argument will remove hyphens!
258 pHyphWrapper
->InsertHyphen( nInsPos
);
262 if ( pHyphWrapper
->FindSpellError() )
264 uno::Reference
< linguistic2::XHyphenatedWord
> xHyphWord( pHyphWrapper
->GetLast(), uno::UNO_QUERY
);
266 // adapt actual word and language to new found hyphenation result
269 aActWord
= String( xHyphWord
->getWord() );
270 nActLanguage
= LanguageTag( xHyphWord
->getLocale() ).getLanguageType();
271 nMaxHyphenationPos
= xHyphWord
->getHyphenationPos();
273 SetWindowTitle( nActLanguage
);
281 sal_uInt16
SvxHyphenWordDialog::GetHyphIndex_Impl()
284 String
aTxt( m_pWordEdit
->GetText() );
286 for ( sal_uInt16 i
=0 ; i
< aTxt
.Len(); ++i
)
288 sal_Unicode cChar
= aTxt
.GetChar( i
);
289 if ( cChar
== CUR_HYPH_POS_CHAR
)
291 if ( cChar
!= HYPH_POS_CHAR
)
298 void SvxHyphenWordDialog::SelLeft()
300 DBG_ASSERT( nOldPos
> 0, "invalid hyphenation position" );
303 String
aTxt( aEditWord
);
304 for ( xub_StrLen i
= nOldPos
- 1; i
> 0; --i
)
306 DBG_ASSERT(i
<= aTxt
.Len(), "index out of range");
307 if (aTxt
.GetChar( i
) == sal_Unicode( HYPH_POS_CHAR
))
309 aTxt
.SetChar( i
, sal_Unicode( CUR_HYPH_POS_CHAR
) );
312 m_pWordEdit
->SetText( aTxt
);
313 m_pWordEdit
->GrabFocus();
314 m_pWordEdit
->SetSelection( Selection( i
, i
+ 1 ) );
318 nHyphPos
= GetHyphIndex_Impl();
324 void SvxHyphenWordDialog::SelRight()
326 String
aTxt( aEditWord
);
327 for ( xub_StrLen i
= nOldPos
+ 1; i
< aTxt
.Len(); ++i
)
329 if (aTxt
.GetChar( i
) == sal_Unicode( HYPH_POS_CHAR
))
331 aTxt
.SetChar( i
, sal_Unicode( CUR_HYPH_POS_CHAR
) );
334 m_pWordEdit
->SetText( aTxt
);
335 m_pWordEdit
->GrabFocus();
336 m_pWordEdit
->SetSelection( Selection( i
, i
+ 1 ) );
340 nHyphPos
= GetHyphIndex_Impl();
345 IMPL_LINK_NOARG(SvxHyphenWordDialog
, CutHdl_Impl
)
350 ContinueHyph_Impl( /*nHyphPos*/nOldPos
);
357 IMPL_LINK( SvxHyphenWordDialog
, HyphenateAllHdl_Impl
, Button
*, EMPTYARG
/*pButton*/ )
363 uno::Reference
< linguistic2::XLinguProperties
> xProp( SvxGetLinguPropertySet() );
365 xProp
->setIsHyphAuto( sal_True
);
368 ContinueHyph_Impl( /*nHyphPos*/nOldPos
);
371 xProp
->setIsHyphAuto( sal_False
);
373 catch (uno::Exception
&e
)
376 DBG_ASSERT( 0, "Hyphenate All failed" );
383 IMPL_LINK_NOARG(SvxHyphenWordDialog
, DeleteHdl_Impl
)
395 IMPL_LINK_NOARG(SvxHyphenWordDialog
, ContinueHdl_Impl
)
400 ContinueHyph_Impl( CONTINUE_HYPH
);
407 IMPL_LINK_NOARG(SvxHyphenWordDialog
, CancelHdl_Impl
)
412 pHyphWrapper
->SpellEnd();
413 EndDialog( RET_CANCEL
);
420 IMPL_LINK_NOARG(SvxHyphenWordDialog
, Left_Impl
)
432 IMPL_LINK_NOARG(SvxHyphenWordDialog
, Right_Impl
)
444 IMPL_LINK_NOARG(SvxHyphenWordDialog
, GetFocusHdl_Impl
)
446 m_pWordEdit
->SetSelection( Selection( nOldPos
, nOldPos
+ 1 ) );
451 // class SvxHyphenWordDialog ---------------------------------------------
453 SvxHyphenWordDialog::SvxHyphenWordDialog(
454 const String
&rWord
, LanguageType nLang
,
456 uno::Reference
< linguistic2::XHyphenator
> &xHyphen
,
457 SvxSpellWrapper
* pWrapper
)
458 : SfxModalDialog(pParent
, "HyphenateDialog", "cui/ui/hyphenate.ui")
462 , nActLanguage(LANGUAGE_NONE
)
463 , nMaxHyphenationPos(0)
466 , nHyphenationPositionsOffset(0)
469 get(m_pWordEdit
, "worded");
470 get(m_pLeftBtn
, "left");
471 get(m_pRightBtn
, "right");
473 get(m_pContBtn
, "continue");
474 get(m_pDelBtn
, "delete");
475 get(m_pHyphAll
, "hyphall");
476 get(m_pCloseBtn
, "close");
480 nActLanguage
= nLang
;
481 xHyphenator
= xHyphen
;
482 pHyphWrapper
= pWrapper
;
484 uno::Reference
< linguistic2::XHyphenatedWord
> xHyphWord( pHyphWrapper
?
485 pHyphWrapper
->GetLast() : NULL
, uno::UNO_QUERY
);
486 DBG_ASSERT( xHyphWord
.is(), "hyphenation result missing" );
489 DBG_ASSERT( aActWord
== String( xHyphWord
->getWord() ), "word mismatch" );
490 DBG_ASSERT( nActLanguage
== LanguageTag( xHyphWord
->getLocale() ).getLanguageType(), "language mismatch" );
491 nMaxHyphenationPos
= xHyphWord
->getHyphenationPos();
495 m_pWordEdit
->GrabFocus();
497 m_pLeftBtn
->SetClickHdl( LINK( this, SvxHyphenWordDialog
, Left_Impl
) );
498 m_pRightBtn
->SetClickHdl( LINK( this, SvxHyphenWordDialog
, Right_Impl
) );
499 m_pOkBtn
->SetClickHdl( LINK( this, SvxHyphenWordDialog
, CutHdl_Impl
) );
500 m_pContBtn
->SetClickHdl( LINK( this, SvxHyphenWordDialog
, ContinueHdl_Impl
) );
501 m_pDelBtn
->SetClickHdl( LINK( this, SvxHyphenWordDialog
, DeleteHdl_Impl
) );
502 m_pHyphAll
->SetClickHdl( LINK( this, SvxHyphenWordDialog
, HyphenateAllHdl_Impl
) );
503 m_pCloseBtn
->SetClickHdl( LINK( this, SvxHyphenWordDialog
, CancelHdl_Impl
) );
504 m_pWordEdit
->SetGetFocusHdl( LINK( this, SvxHyphenWordDialog
, GetFocusHdl_Impl
) );
506 SetWindowTitle( nLang
);
508 // disable controls if service is not available
509 if (!xHyphenator
.is())
514 SvxHyphenWordDialog::~SvxHyphenWordDialog()
519 void SvxHyphenWordDialog::SetWindowTitle( LanguageType nLang
)
521 String
aLangStr( SvtLanguageTable::GetLanguageString( nLang
) );
522 OUString
aTmp( aLabel
);
529 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */