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 .
20 #include <comphelper/string.hxx>
21 #include <i18npool/mslangid.hxx>
22 #include <tools/shl.hxx>
23 #include <vcl/svapp.hxx>
24 #include <vcl/msgbox.hxx>
25 #include <unotools/saveopt.hxx>
26 #include <svl/intitem.hxx>
27 #include <vcl/edit.hxx>
29 #define SVX_OPTGENRL_CXX
32 #include "optgenrl.hrc"
33 #include <unotools/useroptions.hxx>
34 #include "cuioptgenrl.hxx"
35 #include <dialmgr.hxx>
36 #include <svx/dlgutil.hxx>
37 #include <svx/svxids.hrc> // SID_FIELD_GRABFOCUS
39 #include <boost/ref.hpp>
40 #include <boost/make_shared.hpp>
67 unsigned const Others
= 1;
68 unsigned const Russian
= 2;
69 unsigned const Eastern
= 4;
70 unsigned const US
= 8;
71 unsigned const All
= -1;
75 // vRowInfo[] -- rows (text + one or more edit boxes)
76 // The order is the same as in RowType above, which is up to down.
82 // language flags (see Lang above):
83 // which language is this row for?
88 { FT_COMPANY
, Lang::All
},
89 { FT_NAME
, Lang::All
& ~Lang::Russian
& ~Lang::Eastern
},
90 { FT_NAME_RUSS
, Lang::Russian
},
91 { FT_NAME_EASTERN
, Lang::Eastern
},
92 { FT_STREET
, Lang::All
& ~Lang::Russian
},
93 { FT_STREET_RUSS
, Lang::Russian
},
94 { FT_CITY
, Lang::All
& ~Lang::US
},
95 { FT_CITY_US
, Lang::US
},
96 { FT_COUNTRY
, Lang::All
},
97 { FT_TITLEPOS
, Lang::All
},
98 { FT_PHONE
, Lang::All
},
99 { FT_FAXMAIL
, Lang::All
},
103 // vFieldInfo[] -- edit boxes
104 // The order is up to down, and then left to right.
110 // id of the edit box
113 // The actual width is calculated from the relative width to fill
114 // the entire row. See PositionControls() below.
115 float fRelativeWidth
;
116 // id for SvtUserOptions in unotools/useroptions.hxx
118 // id for settings the focus (defined in svx/optgenrl.hxx)
124 { Row_Company
, ED_COMPANY
, 1, USER_OPT_COMPANY
, COMPANY_EDIT
},
126 { Row_Name
, ED_FIRSTNAME
, 5, USER_OPT_FIRSTNAME
, FIRSTNAME_EDIT
},
127 { Row_Name
, ED_NAME
, 5, USER_OPT_LASTNAME
, LASTNAME_EDIT
},
128 { Row_Name
, ED_SHORTNAME
, 2, USER_OPT_ID
, SHORTNAME_EDIT
},
130 { Row_Name_Russian
, ED_NAME
, 5, USER_OPT_LASTNAME
, LASTNAME_EDIT
},
131 { Row_Name_Russian
, ED_FIRSTNAME
, 5, USER_OPT_FIRSTNAME
, FIRSTNAME_EDIT
},
132 { Row_Name_Russian
, ED_FATHERNAME
, 5, USER_OPT_FATHERSNAME
, 0 },
133 { Row_Name_Russian
, ED_SHORTNAME
, 2, USER_OPT_ID
, SHORTNAME_EDIT
},
134 // Name (eastern: reversed name order)
135 { Row_Name_Eastern
, ED_NAME
, 5, USER_OPT_LASTNAME
, LASTNAME_EDIT
},
136 { Row_Name_Eastern
, ED_FIRSTNAME
, 5, USER_OPT_FIRSTNAME
, FIRSTNAME_EDIT
},
137 { Row_Name_Eastern
, ED_SHORTNAME
, 2, USER_OPT_ID
, SHORTNAME_EDIT
},
139 { Row_Street
, ED_STREET
, 1, USER_OPT_STREET
, STREET_EDIT
},
141 { Row_Street_Russian
, ED_STREET
, 8, USER_OPT_STREET
, STREET_EDIT
},
142 { Row_Street_Russian
, ED_APARTMENTNR
, 1, USER_OPT_APARTMENT
, 0 },
144 { Row_City
, ED_PLZ
, 1, USER_OPT_ZIP
, PLZ_EDIT
},
145 { Row_City
, ED_CITY
, 5, USER_OPT_CITY
, CITY_EDIT
},
147 { Row_City_US
, ED_US_CITY
, 15, USER_OPT_CITY
, CITY_EDIT
},
148 { Row_City_US
, ED_US_STATE
, 5, USER_OPT_STATE
, STATE_EDIT
},
149 { Row_City_US
, ED_US_ZIPCODE
, 4, USER_OPT_ZIP
, PLZ_EDIT
},
151 { Row_Country
, ED_COUNTRY
, 1, USER_OPT_COUNTRY
, COUNTRY_EDIT
},
153 { Row_TitlePos
, ED_TITLE
, 1, USER_OPT_TITLE
, TITLE_EDIT
},
154 { Row_TitlePos
, ED_POSITION
, 1, USER_OPT_POSITION
, POSITION_EDIT
},
156 { Row_Phone
, ED_TELPRIVAT
, 1, USER_OPT_TELEPHONEHOME
, TELPRIV_EDIT
},
157 { Row_Phone
, ED_TELCOMPANY
, 1, USER_OPT_TELEPHONEWORK
, TELCOMPANY_EDIT
},
159 { Row_FaxMail
, ED_FAX
, 1, USER_OPT_FAX
, FAX_EDIT
},
160 { Row_FaxMail
, ED_EMAIL
, 1, USER_OPT_EMAIL
, EMAIL_EDIT
},
166 // -----------------------------------------------------------------------
171 struct SvxGeneralTabPage::Row
177 // first and last field in the row (last is exclusive)
178 unsigned nFirstField
, nLastField
;
181 Row (Window
& rParent
, int nResId
, RowType eRow_
) :
183 aLabel(&rParent
, CUI_RES(nResId
), true),
184 nFirstField(0), nLastField(0)
188 // -----------------------------------------------------------------------
193 struct SvxGeneralTabPage::Field
195 // which field is this? (in vFieldInfo[] above)
201 Field (Window
& rParent
, int nResId
, unsigned iField_
) :
203 aEdit(&rParent
, CUI_RES(nResId
), true)
207 // -----------------------------------------------------------------------
209 SvxGeneralTabPage::SvxGeneralTabPage( Window
* pParent
, const SfxItemSet
& rCoreSet
) :
211 SfxTabPage( pParent
, CUI_RES(RID_SFXPAGE_GENERAL
), rCoreSet
),
213 aAddrFrm ( this, CUI_RES( GB_ADDRESS
) ),
214 aUseDataCB ( this, CUI_RES( CB_USEDATA
) )
218 SetExchangeSupport(); // this page needs ExchangeSupport
220 SetAccessibleNames();
223 //------------------------------------------------------------------------
225 SvxGeneralTabPage::~SvxGeneralTabPage ()
228 //------------------------------------------------------------------------
230 // Creates and initializes the titles and the edit boxes,
231 // according to vRowInfo[] and vFieldInfo[] above.
232 void SvxGeneralTabPage::CreateControls ()
234 // which language bit do we use? (see Lang and vRowInfo[] above)
236 switch (LanguageType
const eLang
= Application::GetSettings().GetUILanguageTag().getLanguageType())
238 case LANGUAGE_ENGLISH_US
:
241 case LANGUAGE_RUSSIAN
:
242 LangBit
= Lang::Russian
;
245 if (MsLangId::isFamilyNameFirst(eLang
))
246 LangBit
= Lang::Eastern
;
248 LangBit
= Lang::Others
;
254 for (unsigned iRow
= 0; iRow
!= nRowCount
; ++iRow
)
256 RowType
const eRow
= static_cast<RowType
>(iRow
);
257 // is the row visible?
258 if (!(vRowInfo
[iRow
].nLangFlags
& LangBit
))
261 vRows
.push_back(boost::make_shared
<Row
>(
262 boost::ref(*this), vRowInfo
[iRow
].nTextId
, eRow
264 Row
& rRow
= *vRows
.back();
266 static unsigned const nFieldCount
= SAL_N_ELEMENTS(vFieldInfo
);
267 // skipping other (invisible) rows
268 while (iField
!= nFieldCount
&& vFieldInfo
[iField
].eRow
!= eRow
)
271 rRow
.nFirstField
= vFields
.size();
272 for ( ; iField
!= nFieldCount
&& vFieldInfo
[iField
].eRow
== eRow
; ++iField
)
274 // creating edit field
275 vFields
.push_back(boost::make_shared
<Field
>(
276 boost::ref(*this), vFieldInfo
[iField
].nEditId
, iField
278 // "short name" field?
279 if (vFieldInfo
[iField
].nEditId
== ED_SHORTNAME
)
281 nNameRow
= vRows
.size() - 1;
282 nShortNameField
= vFields
.size() - 1;
285 rRow
.nLastField
= vFields
.size();
291 //------------------------------------------------------------------------
293 // sets the size and the position of the controls
294 void SvxGeneralTabPage::PositionControls ()
296 // sizes and locations
297 int const nLeft
= 12, nMid
= 100, nRight
= 250;
299 unsigned const nHSpace
= 2, nVSpace
= 3;
300 unsigned const nRowHeight
= 15, nTextVMargin
= 2;
302 Point
aLabelPos(nLeft
, nTop
+ nTextVMargin
);
303 Size
aLabelSize(nMid
- nLeft
- nHSpace
, nRowHeight
- nVSpace
- 2*nTextVMargin
);
304 for (unsigned iRow
= 0; iRow
!= vRows
.size(); ++iRow
, aLabelPos
.Y() += nRowHeight
)
306 Row
& rRow
= *vRows
[iRow
];
308 rRow
.aLabel
.SetPosSizePixel(
309 LogicToPixel(aLabelPos
, MAP_APPFONT
),
310 LogicToPixel(aLabelSize
, MAP_APPFONT
)
313 Point
aFieldPos(nMid
, aLabelPos
.Y() - nTextVMargin
);
314 Size
aFieldSize(0, nRowHeight
- nVSpace
);
315 // sum of the relative widths
316 float fRelWidthSum
= 0;
317 for (unsigned iField
= rRow
.nFirstField
; iField
!= rRow
.nLastField
; ++iField
)
318 fRelWidthSum
+= vFieldInfo
[vFields
[iField
]->iField
].fRelativeWidth
;
319 // sum of the actual widths (total width - spaces)
320 unsigned const nActWidthSum
=
321 (nRight
- nMid
) - nHSpace
*(rRow
.nLastField
- rRow
.nFirstField
);
322 // calculating the actual widths
323 float X
= nMid
; // starting position
324 for (unsigned iField
= rRow
.nFirstField
; iField
!= rRow
.nLastField
; ++iField
)
326 // calculating position and size
327 Field
& rField
= *vFields
[iField
];
329 X
+= vFieldInfo
[rField
.iField
].fRelativeWidth
* nActWidthSum
/ fRelWidthSum
;
330 aFieldSize
.Width() = X
- aFieldPos
.X();
333 rField
.aEdit
.SetPosSizePixel(
334 LogicToPixel(aFieldPos
, MAP_APPFONT
),
335 LogicToPixel(aFieldSize
, MAP_APPFONT
)
341 //------------------------------------------------------------------------
343 void SvxGeneralTabPage::SetLinks ()
345 // link for updating the initials
346 Link aLink
= LINK( this, SvxGeneralTabPage
, ModifyHdl_Impl
);
347 Row
& rNameRow
= *vRows
[nNameRow
];
348 for (unsigned i
= rNameRow
.nFirstField
; i
!= rNameRow
.nLastField
- 1; ++i
)
349 vFields
[i
]->aEdit
.SetModifyHdl(aLink
);
352 //------------------------------------------------------------------------
354 void SvxGeneralTabPage::SetAccessibleNames ()
356 // Because some labels have text for more than one edit field we have to
357 // split these texts and set these texts as accessible name
358 // of the corresponding edit fields.
359 // E.g. "City/State/Zip" -> "City", "State", "Zip" or
360 // "Tel. (Home/Work)" -> "Tel. (Home)", "Tel. (Work)"
361 for (unsigned i
= 0; i
!= vRows
.size(); ++i
)
363 Row
& rRow
= *vRows
[i
];
364 rtl::OUString
const sLabel
= rRow
.aLabel
.GetDisplayText();
365 rtl::OUString sList
= sLabel
; // between brackets or the whole label
367 int iBracket
= sLabel
.indexOf('(');
369 sList
= sList
.copy(iBracket
+ 1, sLabel
.lastIndexOf(')') - iBracket
- 1);
371 sal_Int32 nIndex
= 0;
372 for (unsigned iField
= rRow
.nFirstField
; iField
!= rRow
.nLastField
; ++iField
)
375 rtl::OUString sPart
= sList
.getToken(0, static_cast<sal_Unicode
>('/'), nIndex
).trim();
376 Edit
& rEdit
= vFields
[iField
]->aEdit
;
377 // creating the accessible name
379 rEdit
.SetAccessibleName(sLabel
.copy(0, iBracket
) + "(" + sPart
+ ")");
381 rEdit
.SetAccessibleName(sPart
);
386 //------------------------------------------------------------------------
388 SfxTabPage
* SvxGeneralTabPage::Create( Window
* pParent
, const SfxItemSet
& rAttrSet
)
390 return ( new SvxGeneralTabPage( pParent
, rAttrSet
) );
393 //------------------------------------------------------------------------
395 sal_Bool
SvxGeneralTabPage::FillItemSet( SfxItemSet
& )
397 // remove leading and trailing whitespaces
398 for (unsigned i
= 0; i
!= vFields
.size(); ++i
)
399 vFields
[i
]->aEdit
.SetText( comphelper::string::strip(vFields
[i
]->aEdit
.GetText(), ' ') );
401 sal_Bool bModified
= sal_False
;
402 bModified
|= GetAddress_Impl();
403 SvtSaveOptions aSaveOpt
;
404 if ( aUseDataCB
.IsChecked() != aSaveOpt
.IsUseUserData() )
406 aSaveOpt
.SetUseUserData( aUseDataCB
.IsChecked() );
407 bModified
|= sal_True
;
412 //------------------------------------------------------------------------
414 void SvxGeneralTabPage::Reset( const SfxItemSet
& rSet
)
418 sal_uInt16
const nWhich
= GetWhich(SID_FIELD_GRABFOCUS
);
420 if (rSet
.GetItemState(nWhich
) == SFX_ITEM_SET
)
422 if (sal_uInt16
const nField
= ((SfxUInt16Item
&)rSet
.Get(nWhich
)).GetValue())
424 for (unsigned i
= 0; i
!= vFields
.size(); ++i
)
425 if (nField
== vFieldInfo
[vFields
[i
]->iField
].nGrabFocusId
)
426 vFields
[i
]->aEdit
.GrabFocus();
429 vFields
.front()->aEdit
.GrabFocus();
432 aUseDataCB
.Check( SvtSaveOptions().IsUseUserData() );
435 //------------------------------------------------------------------------
438 // This handler updates the initials (short name)
439 // when one of the name fields was updated.
440 IMPL_LINK( SvxGeneralTabPage
, ModifyHdl_Impl
, Edit
*, pEdit
)
442 // short name field and row
443 Field
& rShortName
= *vFields
[nShortNameField
];
444 Row
& rNameRow
= *vRows
[nNameRow
];
445 // number of initials
446 unsigned const nInits
= rNameRow
.nLastField
- rNameRow
.nFirstField
- 1;
447 // which field was updated? (in rNameRow)
448 unsigned nField
= nInits
;
449 for (unsigned i
= 0; i
!= nInits
; ++i
)
450 if (&vFields
[rNameRow
.nFirstField
+ i
]->aEdit
== pEdit
)
452 // Since middle names are not supported, clear shortname if it
453 // contains a middle initial
454 if (rtl::OUString(rShortName
.aEdit
.GetText()).getLength() > 2)
456 rtl::OUString sEmptyString
;
457 rShortName
.aEdit
.SetText(sEmptyString
);
459 // updating the initial
460 if (nField
< nInits
&& rShortName
.aEdit
.IsEnabled())
462 rtl::OUString sShortName
= rShortName
.aEdit
.GetText();
463 while ((unsigned)sShortName
.getLength() < nInits
)
464 sShortName
+= rtl::OUString(' ');
465 rtl::OUString sName
= pEdit
->GetText();
466 rtl::OUString sLetter
= rtl::OUString(sName
.getLength() ? sName
.toChar() : ' ');
467 rShortName
.aEdit
.SetText(sShortName
.replaceAt(nField
, 1, sLetter
).trim());
472 //------------------------------------------------------------------------
474 sal_Bool
SvxGeneralTabPage::GetAddress_Impl()
477 SvtUserOptions aUserOpt
;
478 for (unsigned i
= 0; i
!= vFields
.size(); ++i
)
480 vFieldInfo
[vFields
[i
]->iField
].nUserOptionsId
,
481 vFields
[i
]->aEdit
.GetText()
485 for (unsigned i
= 0; i
!= vFields
.size(); ++i
)
486 if (vFields
[i
]->aEdit
.GetSavedValue() != vFields
[i
]->aEdit
.GetText())
491 //------------------------------------------------------------------------
493 void SvxGeneralTabPage::SetAddress_Impl()
495 // updating and disabling edit boxes
496 SvtUserOptions aUserOpt
;
497 for (unsigned iRow
= 0; iRow
!= vRows
.size(); ++iRow
)
499 Row
& rRow
= *vRows
[iRow
];
500 // the label is enabled if any of its edit fields are enabled
501 bool bEnableLabel
= false;
502 for (unsigned iField
= rRow
.nFirstField
; iField
!= rRow
.nLastField
; ++iField
)
504 Field
& rField
= *vFields
[iField
];
506 unsigned const nToken
= vFieldInfo
[rField
.iField
].nUserOptionsId
;
507 rField
.aEdit
.SetText(aUserOpt
.GetToken(nToken
));
509 bool const bEnableEdit
= !aUserOpt
.IsTokenReadonly(nToken
);
510 rField
.aEdit
.Enable(bEnableEdit
);
511 bEnableLabel
= bEnableLabel
|| bEnableEdit
;
513 rRow
.aLabel
.Enable(bEnableLabel
);
517 for (unsigned i
= 0; i
!= vFields
.size(); ++i
)
518 vFields
[i
]->aEdit
.SaveValue();
521 // -----------------------------------------------------------------------
523 int SvxGeneralTabPage::DeactivatePage( SfxItemSet
* pSet_
)
526 FillItemSet( *pSet_
);
530 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */