Version 4.0.0.1, tag libreoffice-4.0.0.1
[LibreOffice.git] / cui / source / options / optgenrl.cxx
blob5a1438b2073d15152afdc9b0002c427ac1b0c29a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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
31 #include <cuires.hrc>
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>
42 namespace
45 // rows
46 enum RowType
48 Row_Company,
49 Row_Name,
50 Row_Name_Russian,
51 Row_Name_Eastern,
52 Row_Street,
53 Row_Street_Russian,
54 Row_City,
55 Row_City_US,
56 Row_Country,
57 Row_TitlePos,
58 Row_Phone,
59 Row_FaxMail,
61 nRowCount
64 // language flags
65 namespace Lang
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.
78 struct
80 // id of the text
81 int nTextId;
82 // language flags (see Lang above):
83 // which language is this row for?
84 unsigned nLangFlags;
86 const vRowInfo[] =
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.
106 struct
108 // in which row?
109 RowType eRow;
110 // id of the edit box
111 int nEditId;
112 // relative width
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
117 int nUserOptionsId;
118 // id for settings the focus (defined in svx/optgenrl.hxx)
119 int nGrabFocusId;
121 const vFieldInfo[] =
123 // Company
124 { Row_Company, ED_COMPANY, 1, USER_OPT_COMPANY, COMPANY_EDIT },
125 // Name
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 },
129 // Name (russian)
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 },
138 // Street
139 { Row_Street, ED_STREET, 1, USER_OPT_STREET, STREET_EDIT },
140 // Street (russian)
141 { Row_Street_Russian, ED_STREET, 8, USER_OPT_STREET, STREET_EDIT },
142 { Row_Street_Russian, ED_APARTMENTNR, 1, USER_OPT_APARTMENT, 0 },
143 // City
144 { Row_City, ED_PLZ, 1, USER_OPT_ZIP, PLZ_EDIT },
145 { Row_City, ED_CITY, 5, USER_OPT_CITY, CITY_EDIT },
146 // City (US)
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 },
150 // Country
151 { Row_Country, ED_COUNTRY, 1, USER_OPT_COUNTRY, COUNTRY_EDIT },
152 // Title/Position
153 { Row_TitlePos, ED_TITLE, 1, USER_OPT_TITLE, TITLE_EDIT },
154 { Row_TitlePos, ED_POSITION, 1, USER_OPT_POSITION, POSITION_EDIT },
155 // Phone
156 { Row_Phone, ED_TELPRIVAT, 1, USER_OPT_TELEPHONEHOME, TELPRIV_EDIT },
157 { Row_Phone, ED_TELCOMPANY, 1, USER_OPT_TELEPHONEWORK, TELCOMPANY_EDIT },
158 // Fax/Mail
159 { Row_FaxMail, ED_FAX, 1, USER_OPT_FAX, FAX_EDIT },
160 { Row_FaxMail, ED_EMAIL, 1, USER_OPT_EMAIL, EMAIL_EDIT },
164 } // namespace
166 // -----------------------------------------------------------------------
169 // Row
171 struct SvxGeneralTabPage::Row
173 // which row is it?
174 RowType eRow;
175 // row label
176 FixedText aLabel;
177 // first and last field in the row (last is exclusive)
178 unsigned nFirstField, nLastField;
180 public:
181 Row (Window& rParent, int nResId, RowType eRow_) :
182 eRow(eRow_),
183 aLabel(&rParent, CUI_RES(nResId), true),
184 nFirstField(0), nLastField(0)
188 // -----------------------------------------------------------------------
191 // Field
193 struct SvxGeneralTabPage::Field
195 // which field is this? (in vFieldInfo[] above)
196 unsigned iField;
197 // edit box
198 Edit aEdit;
200 public:
201 Field (Window& rParent, int nResId, unsigned iField_) :
202 iField(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 ) )
216 CreateControls();
217 PositionControls();
218 SetExchangeSupport(); // this page needs ExchangeSupport
219 SetLinks();
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)
235 unsigned LangBit;
236 switch (LanguageType const eLang = Application::GetSettings().GetUILanguageTag().getLanguageType())
238 case LANGUAGE_ENGLISH_US:
239 LangBit = Lang::US;
240 break;
241 case LANGUAGE_RUSSIAN:
242 LangBit = Lang::Russian;
243 break;
244 default:
245 if (MsLangId::isFamilyNameFirst(eLang))
246 LangBit = Lang::Eastern;
247 else
248 LangBit = Lang::Others;
249 break;
252 // creating rows
253 unsigned iField = 0;
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))
259 continue;
260 // creating row
261 vRows.push_back(boost::make_shared<Row>(
262 boost::ref(*this), vRowInfo[iRow].nTextId, eRow
264 Row& rRow = *vRows.back();
265 // fields in the row
266 static unsigned const nFieldCount = SAL_N_ELEMENTS(vFieldInfo);
267 // skipping other (invisible) rows
268 while (iField != nFieldCount && vFieldInfo[iField].eRow != eRow)
269 ++iField;
270 // fields in the row
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();
288 FreeResource();
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;
298 int const nTop = 14;
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];
307 // label
308 rRow.aLabel.SetPosSizePixel(
309 LogicToPixel(aLabelPos, MAP_APPFONT),
310 LogicToPixel(aLabelSize, MAP_APPFONT)
312 // field position
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];
328 aFieldPos.X() = X;
329 X += vFieldInfo[rField.iField].fRelativeWidth * nActWidthSum / fRelWidthSum;
330 aFieldSize.Width() = X - aFieldPos.X();
331 X += 2;
332 // setting size
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
366 // brackets?
367 int iBracket = sLabel.indexOf('(');
368 if (iBracket != -1)
369 sList = sList.copy(iBracket + 1, sLabel.lastIndexOf(')') - iBracket - 1);
370 // cutting at '/'s
371 sal_Int32 nIndex = 0;
372 for (unsigned iField = rRow.nFirstField; iField != rRow.nLastField; ++iField)
374 // the token
375 rtl::OUString sPart = sList.getToken(0, static_cast<sal_Unicode>('/'), nIndex).trim();
376 Edit& rEdit = vFields[iField]->aEdit;
377 // creating the accessible name
378 if (iBracket != -1)
379 rEdit.SetAccessibleName(sLabel.copy(0, iBracket) + "(" + sPart + ")");
380 else
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;
409 return bModified;
412 //------------------------------------------------------------------------
414 void SvxGeneralTabPage::Reset( const SfxItemSet& rSet )
416 SetAddress_Impl();
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();
428 else
429 vFields.front()->aEdit.GrabFocus();
432 aUseDataCB.Check( SvtSaveOptions().IsUseUserData() );
435 //------------------------------------------------------------------------
437 // ModifyHdl_Impl()
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)
451 nField = i;
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());
469 return 0;
472 //------------------------------------------------------------------------
474 sal_Bool SvxGeneralTabPage::GetAddress_Impl()
476 // updating
477 SvtUserOptions aUserOpt;
478 for (unsigned i = 0; i != vFields.size(); ++i)
479 aUserOpt.SetToken(
480 vFieldInfo[vFields[i]->iField].nUserOptionsId,
481 vFields[i]->aEdit.GetText()
484 // modified?
485 for (unsigned i = 0; i != vFields.size(); ++i)
486 if (vFields[i]->aEdit.GetSavedValue() != vFields[i]->aEdit.GetText())
487 return true;
488 return false;
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];
505 // updating content
506 unsigned const nToken = vFieldInfo[rField.iField].nUserOptionsId;
507 rField.aEdit.SetText(aUserOpt.GetToken(nToken));
508 // is enabled?
509 bool const bEnableEdit = !aUserOpt.IsTokenReadonly(nToken);
510 rField.aEdit.Enable(bEnableEdit);
511 bEnableLabel = bEnableLabel || bEnableEdit;
513 rRow.aLabel.Enable(bEnableLabel);
516 // saving
517 for (unsigned i = 0; i != vFields.size(); ++i)
518 vFields[i]->aEdit.SaveValue();
521 // -----------------------------------------------------------------------
523 int SvxGeneralTabPage::DeactivatePage( SfxItemSet* pSet_ )
525 if ( pSet_ )
526 FillItemSet( *pSet_ );
527 return LEAVE_PAGE;
530 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */