masterfix: #10000# fix ambigous String
[LibreOffice.git] / cui / source / dialogs / hyphen.cxx
blob16026aaff6d1c30f1c94e25e791208a1bdcb0935
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_cui.hxx"
31 #include "hyphen.hxx"
32 #include "hyphen.hrc"
33 #include "cuires.hrc"
34 #include "dialmgr.hxx"
36 #include <editeng/splwrap.hxx>
37 #include <editeng/svxenum.hxx>
38 #include <editeng/unolingu.hxx>
39 #include <svtools/langtab.hxx>
40 #include <svx/dialmgr.hxx>
41 #include <svx/dlgutil.hxx>
42 #include <tools/list.hxx>
43 #include <tools/shl.hxx>
44 #include <vcl/msgbox.hxx>
46 #include <com/sun/star/linguistic2/XPossibleHyphens.hpp>
48 using namespace ::com::sun::star;
51 #define HYPH_POS_CHAR '='
52 #define CONTINUE_HYPH USHRT_MAX
54 #define CUR_HYPH_POS_CHAR '-'
57 // class HyphenEdit_Impl -------------------------------------------------------
59 class HyphenEdit_Impl : public Edit
61 public:
62 HyphenEdit_Impl( Window* pParent, const ResId& rResId );
64 protected:
65 virtual void KeyInput( const KeyEvent &rKEvt );
69 HyphenEdit_Impl::HyphenEdit_Impl( Window* pParent, const ResId& rResId ) :
70 Edit( pParent, rResId )
75 void HyphenEdit_Impl::KeyInput( const KeyEvent& rKEvt )
77 // sal_uInt16 nMod = rKEvt.GetKeyCode().GetModifier();
78 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
80 switch ( nCode )
82 case KEY_LEFT:
83 ( (SvxHyphenWordDialog*)GetParent() )->SelLeft();
84 break;
86 case KEY_RIGHT:
87 ( (SvxHyphenWordDialog*)GetParent() )->SelRight();
88 break;
90 case KEY_TAB:
91 case KEY_ESCAPE:
92 case KEY_RETURN:
93 Edit::KeyInput(rKEvt);
94 break;
95 default:
96 Control::KeyInput( rKEvt ); // An den Dialog weiterleiten
97 break;
102 // struct SvxHyphenWordDialog_Impl ---------------------------------------------
104 struct SvxHyphenWordDialog_Impl
106 SvxHyphenWordDialog * m_pDialog;
107 // Window * m_pParent;
109 FixedText aWordFT;
110 HyphenEdit_Impl aWordEdit;
111 ImageButton aLeftBtn;
112 ImageButton aRightBtn;
113 OKButton aOkBtn;
114 PushButton aContBtn;
115 PushButton aDelBtn;
116 FixedLine aFLBottom;
117 HelpButton aHelpBtn;
118 PushButton aHyphAll;
119 CancelButton aCancelBtn;
120 String aLabel;
121 SvxSpellWrapper* pHyphWrapper;
122 uno::Reference< linguistic2::XHyphenator > xHyphenator;
123 uno::Reference< linguistic2::XPossibleHyphens > xPossHyph;
124 String aEditWord; // aEditWord and aWordEdit.GetText() differ only by the character for the current selected hyphenation position
125 String aActWord; // actual word to be hyphenated
126 LanguageType nActLanguage; // and its language
127 sal_uInt16 nMaxHyphenationPos; // right most valid hyphenation pos
128 sal_uInt16 nHyphPos;
129 sal_uInt16 nOldPos;
130 sal_Int32 nHyphenationPositionsOffset;
131 sal_Bool bBusy;
134 void EnableLRBtn_Impl();
135 String EraseUnusableHyphens_Impl( ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XPossibleHyphens > &rxPossHyph, sal_uInt16 nMaxHyphenationPos );
137 void InitControls_Impl();
138 void ContinueHyph_Impl( sal_uInt16 nInsPos = 0 );
139 sal_uInt16 GetHyphIndex_Impl();
140 void SelLeft_Impl();
141 void SelRight_Impl();
143 DECL_LINK( Left_Impl, Button* );
144 DECL_LINK( Right_Impl, Button* );
145 DECL_LINK( CutHdl_Impl, Button* );
146 DECL_LINK( ContinueHdl_Impl, Button* );
147 DECL_LINK( DeleteHdl_Impl, Button* );
148 DECL_LINK( HyphenateAllHdl_Impl, Button* );
149 DECL_LINK( CancelHdl_Impl, Button* );
150 DECL_LINK( GetFocusHdl_Impl, Edit* );
153 SvxHyphenWordDialog_Impl(
154 SvxHyphenWordDialog * pDialog,
155 const String &rWord,
156 LanguageType nLang,
157 uno::Reference< linguistic2::XHyphenator > &xHyphen,
158 SvxSpellWrapper* pWrapper );
159 ~SvxHyphenWordDialog_Impl();
163 SvxHyphenWordDialog_Impl::SvxHyphenWordDialog_Impl(
164 SvxHyphenWordDialog * pDialog,
165 const String &rWord,
166 LanguageType nLang,
167 uno::Reference< linguistic2::XHyphenator > &xHyphen,
168 SvxSpellWrapper* pWrapper ) :
170 m_pDialog ( pDialog ),
171 aWordFT ( pDialog, CUI_RES( FT_WORD ) ),
172 aWordEdit ( pDialog, CUI_RES( ED_WORD ) ),
173 aLeftBtn ( pDialog, CUI_RES( BTN_LEFT ) ),
174 aRightBtn ( pDialog, CUI_RES( BTN_RIGHT ) ),
175 aOkBtn ( pDialog, CUI_RES( BTN_HYPH_CUT ) ),
176 aContBtn ( pDialog, CUI_RES( BTN_HYPH_CONTINUE ) ),
177 aDelBtn ( pDialog, CUI_RES( BTN_HYPH_DELETE ) ),
178 aFLBottom ( pDialog, CUI_RES( FL_BOTTOM ) ),
179 aHelpBtn ( pDialog, CUI_RES( BTN_HYPH_HELP ) ),
180 aHyphAll ( pDialog, CUI_RES( BTN_HYPH_ALL ) ),
181 aCancelBtn ( pDialog, CUI_RES( BTN_HYPH_CANCEL ) ),
182 aLabel ( pDialog->GetText() ),
183 pHyphWrapper ( NULL ),
184 xHyphenator ( NULL ),
185 xPossHyph ( NULL ),
186 aActWord ( ),
187 nActLanguage ( LANGUAGE_NONE ),
188 nMaxHyphenationPos ( 0 ),
189 nHyphPos ( 0 ),
190 nOldPos ( 0 ),
191 nHyphenationPositionsOffset( 0 ),
192 bBusy ( sal_False )
194 aActWord = rWord;
195 nActLanguage = nLang;
196 xHyphenator = xHyphen;
197 pHyphWrapper = pWrapper;
199 uno::Reference< linguistic2::XHyphenatedWord > xHyphWord( pHyphWrapper ?
200 pHyphWrapper->GetLast() : NULL, uno::UNO_QUERY );
201 DBG_ASSERT( xHyphWord.is(), "hyphenation result missing" );
202 if (xHyphWord.is())
204 DBG_ASSERT( aActWord == String( xHyphWord->getWord() ), "word mismatch" );
205 DBG_ASSERT( nActLanguage == SvxLocaleToLanguage( xHyphWord->getLocale() ), "language mismatch" );
206 nMaxHyphenationPos = xHyphWord->getHyphenationPos();
209 InitControls_Impl();
210 aWordEdit.GrabFocus();
212 aLeftBtn.SetClickHdl( LINK( this, SvxHyphenWordDialog_Impl, Left_Impl ) );
213 aRightBtn.SetClickHdl( LINK( this, SvxHyphenWordDialog_Impl, Right_Impl ) );
214 aOkBtn.SetClickHdl( LINK( this, SvxHyphenWordDialog_Impl, CutHdl_Impl ) );
215 aContBtn.SetClickHdl( LINK( this, SvxHyphenWordDialog_Impl, ContinueHdl_Impl ) );
216 aDelBtn.SetClickHdl( LINK( this, SvxHyphenWordDialog_Impl, DeleteHdl_Impl ) );
217 aHyphAll.SetClickHdl( LINK( this, SvxHyphenWordDialog_Impl, HyphenateAllHdl_Impl ) );
218 aCancelBtn.SetClickHdl( LINK( this, SvxHyphenWordDialog_Impl, CancelHdl_Impl ) );
219 aWordEdit.SetGetFocusHdl( LINK( this, SvxHyphenWordDialog_Impl, GetFocusHdl_Impl ) );
223 SvxHyphenWordDialog_Impl::~SvxHyphenWordDialog_Impl()
228 void SvxHyphenWordDialog_Impl::EnableLRBtn_Impl()
230 String aTxt( aEditWord );
231 xub_StrLen nLen = aTxt.Len();
232 xub_StrLen i;
234 aRightBtn.Disable();
235 for ( i = nOldPos + 2; i < nLen; ++i )
237 if ( aTxt.GetChar( i ) == sal_Unicode( HYPH_POS_CHAR ) )
239 aRightBtn.Enable();
240 break;
244 DBG_ASSERT(nOldPos < aTxt.Len(), "nOldPos out of range");
245 if (nOldPos >= aTxt.Len())
246 nOldPos = aTxt.Len() - 1;
247 aLeftBtn.Disable();
248 for ( i = nOldPos; i-- > 0; )
250 if ( aTxt.GetChar( i ) == sal_Unicode( HYPH_POS_CHAR ) )
252 aLeftBtn.Enable();
253 break;
259 String SvxHyphenWordDialog_Impl::EraseUnusableHyphens_Impl(
260 uno::Reference< linguistic2::XPossibleHyphens > &rxPossHyph,
261 sal_uInt16 _nMaxHyphenationPos )
263 // returns a String showing only those hyphen positions which will result
264 // in a line break if hyphenation is done there
265 // 1) we will need to discard all hyphenation positions at th end that
266 // will not result in a line break where the text to the left still fits
267 // on the line.
268 // 2) since as from OOo 3.2 '-' are part of a word an thus text like
269 // 'multi-line-editor' is regarded as single word we also need to discard those
270 // hyphenation positions to the left of the rightmost '-' that is still left of
271 // the rightmost valid hyphenation position according to 1)
273 // Example:
274 // If the possible hyphenation position in 'multi-line-editor' are to eb marked
275 // by '=' then the text will look like this 'mul=ti-line-ed=it=or'.
276 // If now the first line is only large enough for 'multi-line-edi' we need to discard
277 // the last possible hyphnation point because of 1). The the right most valid
278 // hyphenation position is "ed=itor". The first '-' left of this position is
279 // "line-ed", thus because of 2) we now need to discard all possible hyphneation
280 // positions to the left of that as well. Thus in the end leaving us with just
281 // 'multi-line-ed=itor' as return value for this function. (Just one valid hyphenation
282 // position for the user too choose from. However ALL the '-' characters in the word
283 // will ALWAYS be valid implicit hyphenation positions for the core to choose from!
284 // And thus even if this word is skipped in the hyphenation dialog it will still be broken
285 // right after 'multi-line-' (actually it might already be broken up that way before
286 // the hyphenation dialog is called!).
287 // Thus rule 2) just eliminates those positions which will not be used by the core at all
288 // even if the user were to select one of them.
290 String aTxt;
291 DBG_ASSERT(rxPossHyph.is(), "missing possible hyphens");
292 if (rxPossHyph.is())
294 DBG_ASSERT( aActWord == String( rxPossHyph->getWord() ), "word mismatch" );
296 aTxt = String( rxPossHyph->getPossibleHyphens() );
298 nHyphenationPositionsOffset = 0;
299 uno::Sequence< sal_Int16 > aHyphenationPositions(
300 rxPossHyph->getHyphenationPositions() );
301 sal_Int32 nLen = aHyphenationPositions.getLength();
302 const sal_Int16 *pHyphenationPos = aHyphenationPositions.getConstArray();
304 // find position nIdx after which all hyphen positions are unusable
305 xub_StrLen nIdx = STRING_NOTFOUND;
306 xub_StrLen nPos = 0, nPos1 = 0, nPos2 = 0;
307 if (nLen)
309 xub_StrLen nStart = 0;
310 for (sal_Int32 i = 0; i < nLen; ++i)
312 if (pHyphenationPos[i] > _nMaxHyphenationPos)
313 break;
314 else
316 // find corresponding hyphen pos in string
317 nPos = aTxt.Search( sal_Unicode( HYPH_POS_CHAR ), nStart );
319 if (nStart == STRING_NOTFOUND)
320 break;
321 else
323 nIdx = nPos;
324 nStart = nPos + 1;
329 DBG_ASSERT(nIdx != STRING_NOTFOUND, "no usable hyphenation position");
331 // 1) remove all not usable hyphenation positions from the end of the string
332 nPos = nIdx == STRING_NOTFOUND ? 0 : nIdx + 1;
333 nPos1 = nPos; //save for later use in 2) below
334 const String aTmp( sal_Unicode( HYPH_POS_CHAR ) );
335 const String aEmpty;
336 while (nPos != STRING_NOTFOUND)
337 nPos = aTxt.SearchAndReplace( aTmp, aEmpty, nPos + 1 );
339 // 2) remove all hyphenation positions from the start that are not considered by the core
340 const String aSearchRange( aTxt.Copy( 0, nPos1 ) );
341 nPos2 = aSearchRange.SearchBackward( '-' ); // the '-' position the core will use by default
342 if (nPos2 != STRING_NOTFOUND)
344 String aLeft( aSearchRange.Copy( 0, nPos2 ) );
345 nPos = 0;
346 while (nPos != STRING_NOTFOUND)
348 nPos = aLeft.SearchAndReplace( aTmp, aEmpty, nPos + 1 );
349 if (nPos != STRING_NOTFOUND)
350 ++nHyphenationPositionsOffset;
352 aTxt.Replace( 0, nPos2, aLeft );
355 return aTxt;
359 void SvxHyphenWordDialog_Impl::InitControls_Impl()
361 xPossHyph = NULL;
362 if (xHyphenator.is())
364 lang::Locale aLocale( SvxCreateLocale(nActLanguage) );
365 xPossHyph = xHyphenator->createPossibleHyphens( aActWord, aLocale,
366 uno::Sequence< beans::PropertyValue >() );
367 if (xPossHyph.is())
368 aEditWord = EraseUnusableHyphens_Impl( xPossHyph, nMaxHyphenationPos );
370 aWordEdit.SetText( aEditWord );
372 nOldPos = aEditWord.Len();
373 SelLeft_Impl();
374 EnableLRBtn_Impl();
378 void SvxHyphenWordDialog_Impl::ContinueHyph_Impl( sal_uInt16 nInsPos )
380 if ( nInsPos != CONTINUE_HYPH && xPossHyph.is())
382 if (nInsPos)
384 String aTmp( aEditWord );
385 DBG_ASSERT(nInsPos <= aTmp.Len() - 2, "wrong hyphen position");
387 sal_Int16 nIdxPos = -1;
388 for (sal_uInt16 i = 0; i <= nInsPos; ++i)
390 if (HYPH_POS_CHAR == aTmp.GetChar( i ))
391 nIdxPos++;
393 // take the possible hyphenation positions that got removed from the
394 // start of the wor dinot account:
395 nIdxPos += nHyphenationPositionsOffset;
397 uno::Sequence< sal_Int16 > aSeq = xPossHyph->getHyphenationPositions();
398 sal_Int32 nLen = aSeq.getLength();
399 DBG_ASSERT(nLen, "empty sequence");
400 DBG_ASSERT(0 <= nIdxPos && nIdxPos < nLen, "index out of range");
401 if (nLen && 0 <= nIdxPos && nIdxPos < nLen)
403 nInsPos = aSeq.getConstArray()[ nIdxPos ];
404 pHyphWrapper->InsertHyphen( nInsPos );
407 else
409 //! calling with 0 as argument will remove hyphens!
410 pHyphWrapper->InsertHyphen( nInsPos );
414 if ( pHyphWrapper->FindSpellError() )
416 uno::Reference< linguistic2::XHyphenatedWord > xHyphWord( pHyphWrapper->GetLast(), uno::UNO_QUERY );
418 // adapt actual word and language to new found hyphenation result
419 if(xHyphWord.is())
421 aActWord = String( xHyphWord->getWord() );
422 nActLanguage = SvxLocaleToLanguage( xHyphWord->getLocale() );
423 nMaxHyphenationPos = xHyphWord->getHyphenationPos();
424 InitControls_Impl();
425 m_pDialog->SetWindowTitle( nActLanguage );
428 else
429 m_pDialog->EndDialog( RET_OK );
433 sal_uInt16 SvxHyphenWordDialog_Impl::GetHyphIndex_Impl()
435 sal_uInt16 nPos = 0;
436 String aTxt( aWordEdit.GetText() );
438 for ( sal_uInt16 i=0 ; i < aTxt.Len(); ++i )
440 sal_Unicode cChar = aTxt.GetChar( i );
441 if ( cChar == CUR_HYPH_POS_CHAR )
442 break;
443 if ( cChar != HYPH_POS_CHAR )
444 nPos++;
446 return nPos;
450 void SvxHyphenWordDialog_Impl::SelLeft_Impl()
452 DBG_ASSERT( nOldPos > 0, "invalid hyphenation position" );
453 if (nOldPos > 0)
455 String aTxt( aEditWord );
456 for ( xub_StrLen i = nOldPos - 1; i > 0; --i)
458 DBG_ASSERT(i <= aTxt.Len(), "index out of range");
459 if (aTxt.GetChar( i ) == sal_Unicode( HYPH_POS_CHAR ))
461 aTxt.SetChar( i, sal_Unicode( CUR_HYPH_POS_CHAR ) );
463 nOldPos = i;
464 aWordEdit.SetText( aTxt );
465 aWordEdit.GrabFocus();
466 aWordEdit.SetSelection( Selection( i, i + 1 ) );
467 break;
470 nHyphPos = GetHyphIndex_Impl();
471 EnableLRBtn_Impl();
476 void SvxHyphenWordDialog_Impl::SelRight_Impl()
478 String aTxt( aEditWord );
479 for ( xub_StrLen i = nOldPos + 1; i < aTxt.Len(); ++i )
481 if (aTxt.GetChar( i ) == sal_Unicode( HYPH_POS_CHAR ))
483 aTxt.SetChar( i, sal_Unicode( CUR_HYPH_POS_CHAR ) );
485 nOldPos = i;
486 aWordEdit.SetText( aTxt );
487 aWordEdit.GrabFocus();
488 aWordEdit.SetSelection( Selection( i, i + 1 ) );
489 break;
492 nHyphPos = GetHyphIndex_Impl();
493 EnableLRBtn_Impl();
497 IMPL_LINK( SvxHyphenWordDialog_Impl, CutHdl_Impl, Button *, EMPTYARG )
499 if( !bBusy )
501 bBusy = sal_True;
502 ContinueHyph_Impl( /*nHyphPos*/nOldPos );
503 bBusy = sal_False;
505 return 0;
509 IMPL_LINK( SvxHyphenWordDialog_Impl, HyphenateAllHdl_Impl, Button *, EMPTYARG /*pButton*/ )
511 if( !bBusy )
515 uno::Reference< beans::XPropertySet > xProp( SvxGetLinguPropertySet() );
516 const rtl::OUString aName( rtl::OUString::createFromAscii( "IsHyphAuto" ) );
517 uno::Any aAny;
519 aAny <<= sal_True;
520 xProp->setPropertyValue( aName, aAny );
522 bBusy = sal_True;
523 ContinueHyph_Impl( /*nHyphPos*/nOldPos );
524 bBusy = sal_False;
526 aAny <<= sal_False;
527 xProp->setPropertyValue( aName, aAny );
529 catch (uno::Exception &e)
531 (void) e;
532 DBG_ASSERT( 0, "Hyphenate All failed" );
535 return 0;
539 IMPL_LINK( SvxHyphenWordDialog_Impl, DeleteHdl_Impl, Button *, EMPTYARG )
541 if( !bBusy )
543 bBusy = sal_True;
544 ContinueHyph_Impl();
545 bBusy = sal_False;
547 return 0;
551 IMPL_LINK( SvxHyphenWordDialog_Impl, ContinueHdl_Impl, Button *, EMPTYARG )
553 if( !bBusy )
555 bBusy = sal_True;
556 ContinueHyph_Impl( CONTINUE_HYPH );
557 bBusy = sal_False;
559 return 0;
563 IMPL_LINK( SvxHyphenWordDialog_Impl, CancelHdl_Impl, Button *, EMPTYARG )
565 if( !bBusy )
567 bBusy = sal_True;
568 pHyphWrapper->SpellEnd();
569 m_pDialog->EndDialog( RET_CANCEL );
570 bBusy = sal_False;
572 return 0;
576 IMPL_LINK( SvxHyphenWordDialog_Impl, Left_Impl, Button *, EMPTYARG )
578 if( !bBusy )
580 bBusy = sal_True;
581 SelLeft_Impl();
582 bBusy = sal_False;
584 return 0;
588 IMPL_LINK( SvxHyphenWordDialog_Impl, Right_Impl, Button *, EMPTYARG )
590 if( !bBusy )
592 bBusy = sal_True;
593 SelRight_Impl();
594 bBusy = sal_False;
596 return 0;
600 IMPL_LINK( SvxHyphenWordDialog_Impl, GetFocusHdl_Impl, Edit *, EMPTYARG )
602 aWordEdit.SetSelection( Selection( nOldPos, nOldPos + 1 ) );
603 return 0;
607 // class SvxHyphenWordDialog ---------------------------------------------
609 SvxHyphenWordDialog::SvxHyphenWordDialog(
610 const String &rWord, LanguageType nLang,
611 Window* pParent,
612 uno::Reference< linguistic2::XHyphenator > &xHyphen,
613 SvxSpellWrapper* pWrapper ) :
615 SfxModalDialog( pParent, CUI_RES( RID_SVXDLG_HYPHENATE ) )
617 m_pImpl = std::auto_ptr< SvxHyphenWordDialog_Impl >(
618 new SvxHyphenWordDialog_Impl( this, rWord, nLang, xHyphen, pWrapper ) );
620 FreeResource();
622 SetWindowTitle( nLang );
624 // disable controls if service is not available
625 if (!m_pImpl->xHyphenator.is())
626 Enable( sal_False );
630 SvxHyphenWordDialog::~SvxHyphenWordDialog()
635 void SvxHyphenWordDialog::SetWindowTitle( LanguageType nLang )
637 String aLangStr( SvtLanguageTable::GetLanguageString( nLang ) );
638 String aTmp( m_pImpl->aLabel );
639 aTmp.AppendAscii( RTL_CONSTASCII_STRINGPARAM( " (" ) );
640 aTmp.Append( aLangStr );
641 aTmp.Append( sal_Unicode( ')' ) );
642 SetText( aTmp );
646 void SvxHyphenWordDialog::SelLeft()
648 m_pImpl->SelRight_Impl();
652 void SvxHyphenWordDialog::SelRight()
654 m_pImpl->SelLeft_Impl();