Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
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>
28 :
29 : #define SVX_OPTGENRL_CXX
30 :
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
38 :
39 : #include <boost/ref.hpp>
40 : #include <boost/make_shared.hpp>
41 :
42 : namespace
43 : {
44 :
45 : // rows
46 : enum RowType
47 : {
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,
60 :
61 : nRowCount
62 : };
63 :
64 : // language flags
65 : namespace Lang
66 : {
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;
72 : }
73 :
74 : //
75 : // vRowInfo[] -- rows (text + one or more edit boxes)
76 : // The order is the same as in RowType above, which is up to down.
77 : //
78 : struct
79 : {
80 : // id of the text
81 : int nTextId;
82 : // language flags (see Lang above):
83 : // which language is this row for?
84 : unsigned nLangFlags;
85 : }
86 : const vRowInfo[] =
87 : {
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 },
100 : };
101 :
102 : //
103 : // vFieldInfo[] -- edit boxes
104 : // The order is up to down, and then left to right.
105 : //
106 : struct
107 : {
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;
120 : }
121 : const vFieldInfo[] =
122 : {
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 },
161 : };
162 :
163 :
164 : } // namespace
165 :
166 : // -----------------------------------------------------------------------
167 :
168 : //
169 : // Row
170 : //
171 0 : struct SvxGeneralTabPage::Row
172 : {
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;
179 :
180 : public:
181 0 : Row (Window& rParent, int nResId, RowType eRow_) :
182 : eRow(eRow_),
183 0 : aLabel(&rParent, CUI_RES(nResId), true),
184 0 : nFirstField(0), nLastField(0)
185 0 : { }
186 : };
187 :
188 : // -----------------------------------------------------------------------
189 :
190 : //
191 : // Field
192 : //
193 0 : struct SvxGeneralTabPage::Field
194 : {
195 : // which field is this? (in vFieldInfo[] above)
196 : unsigned iField;
197 : // edit box
198 : Edit aEdit;
199 :
200 : public:
201 0 : Field (Window& rParent, int nResId, unsigned iField_) :
202 : iField(iField_),
203 0 : aEdit(&rParent, CUI_RES(nResId), true)
204 0 : { }
205 : };
206 :
207 : // -----------------------------------------------------------------------
208 :
209 0 : SvxGeneralTabPage::SvxGeneralTabPage( Window* pParent, const SfxItemSet& rCoreSet ) :
210 :
211 0 : SfxTabPage( pParent, CUI_RES(RID_SFXPAGE_GENERAL), rCoreSet ),
212 :
213 0 : aAddrFrm ( this, CUI_RES( GB_ADDRESS ) ),
214 0 : aUseDataCB ( this, CUI_RES( CB_USEDATA ) )
215 : {
216 0 : CreateControls();
217 0 : PositionControls();
218 0 : SetExchangeSupport(); // this page needs ExchangeSupport
219 0 : SetLinks();
220 0 : SetAccessibleNames();
221 0 : }
222 :
223 : //------------------------------------------------------------------------
224 :
225 0 : SvxGeneralTabPage::~SvxGeneralTabPage ()
226 0 : { }
227 :
228 : //------------------------------------------------------------------------
229 :
230 : // Creates and initializes the titles and the edit boxes,
231 : // according to vRowInfo[] and vFieldInfo[] above.
232 0 : void SvxGeneralTabPage::CreateControls ()
233 : {
234 : // which language bit do we use? (see Lang and vRowInfo[] above)
235 : unsigned LangBit;
236 0 : switch (LanguageType const eLang = Application::GetSettings().GetUILanguageTag().getLanguageType())
237 : {
238 : case LANGUAGE_ENGLISH_US:
239 0 : LangBit = Lang::US;
240 0 : break;
241 : case LANGUAGE_RUSSIAN:
242 0 : LangBit = Lang::Russian;
243 0 : break;
244 : default:
245 0 : if (MsLangId::isFamilyNameFirst(eLang))
246 0 : LangBit = Lang::Eastern;
247 : else
248 0 : LangBit = Lang::Others;
249 0 : break;
250 : }
251 :
252 : // creating rows
253 0 : unsigned iField = 0;
254 0 : for (unsigned iRow = 0; iRow != nRowCount; ++iRow)
255 : {
256 0 : RowType const eRow = static_cast<RowType>(iRow);
257 : // is the row visible?
258 0 : if (!(vRowInfo[iRow].nLangFlags & LangBit))
259 0 : continue;
260 : // creating row
261 : vRows.push_back(boost::make_shared<Row>(
262 : boost::ref(*this), vRowInfo[iRow].nTextId, eRow
263 0 : ));
264 0 : Row& rRow = *vRows.back();
265 : // fields in the row
266 : static unsigned const nFieldCount = SAL_N_ELEMENTS(vFieldInfo);
267 : // skipping other (invisible) rows
268 0 : while (iField != nFieldCount && vFieldInfo[iField].eRow != eRow)
269 0 : ++iField;
270 : // fields in the row
271 0 : rRow.nFirstField = vFields.size();
272 0 : for ( ; iField != nFieldCount && vFieldInfo[iField].eRow == eRow; ++iField)
273 : {
274 : // creating edit field
275 : vFields.push_back(boost::make_shared<Field>(
276 : boost::ref(*this), vFieldInfo[iField].nEditId, iField
277 0 : ));
278 : // "short name" field?
279 0 : if (vFieldInfo[iField].nEditId == ED_SHORTNAME)
280 : {
281 0 : nNameRow = vRows.size() - 1;
282 0 : nShortNameField = vFields.size() - 1;
283 : }
284 : }
285 0 : rRow.nLastField = vFields.size();
286 : }
287 :
288 0 : FreeResource();
289 0 : }
290 :
291 : //------------------------------------------------------------------------
292 :
293 : // sets the size and the position of the controls
294 0 : void SvxGeneralTabPage::PositionControls ()
295 : {
296 : // sizes and locations
297 0 : int const nLeft = 12, nMid = 100, nRight = 250;
298 0 : int const nTop = 14;
299 0 : unsigned const nHSpace = 2, nVSpace = 3;
300 0 : unsigned const nRowHeight = 15, nTextVMargin = 2;
301 :
302 0 : Point aLabelPos(nLeft, nTop + nTextVMargin);
303 0 : Size aLabelSize(nMid - nLeft - nHSpace, nRowHeight - nVSpace - 2*nTextVMargin);
304 0 : for (unsigned iRow = 0; iRow != vRows.size(); ++iRow, aLabelPos.Y() += nRowHeight)
305 : {
306 0 : Row& rRow = *vRows[iRow];
307 : // label
308 : rRow.aLabel.SetPosSizePixel(
309 0 : LogicToPixel(aLabelPos, MAP_APPFONT),
310 0 : LogicToPixel(aLabelSize, MAP_APPFONT)
311 0 : );
312 : // field position
313 0 : Point aFieldPos(nMid, aLabelPos.Y() - nTextVMargin);
314 0 : Size aFieldSize(0, nRowHeight - nVSpace);
315 : // sum of the relative widths
316 0 : float fRelWidthSum = 0;
317 0 : for (unsigned iField = rRow.nFirstField; iField != rRow.nLastField; ++iField)
318 0 : fRelWidthSum += vFieldInfo[vFields[iField]->iField].fRelativeWidth;
319 : // sum of the actual widths (total width - spaces)
320 : unsigned const nActWidthSum =
321 0 : (nRight - nMid) - nHSpace*(rRow.nLastField - rRow.nFirstField);
322 : // calculating the actual widths
323 0 : float X = nMid; // starting position
324 0 : for (unsigned iField = rRow.nFirstField; iField != rRow.nLastField; ++iField)
325 : {
326 : // calculating position and size
327 0 : Field& rField = *vFields[iField];
328 0 : aFieldPos.X() = X;
329 0 : X += vFieldInfo[rField.iField].fRelativeWidth * nActWidthSum / fRelWidthSum;
330 0 : aFieldSize.Width() = X - aFieldPos.X();
331 0 : X += 2;
332 : // setting size
333 : rField.aEdit.SetPosSizePixel(
334 0 : LogicToPixel(aFieldPos, MAP_APPFONT),
335 0 : LogicToPixel(aFieldSize, MAP_APPFONT)
336 0 : );
337 : }
338 : }
339 0 : }
340 :
341 : //------------------------------------------------------------------------
342 :
343 0 : void SvxGeneralTabPage::SetLinks ()
344 : {
345 : // link for updating the initials
346 0 : Link aLink = LINK( this, SvxGeneralTabPage, ModifyHdl_Impl );
347 0 : Row& rNameRow = *vRows[nNameRow];
348 0 : for (unsigned i = rNameRow.nFirstField; i != rNameRow.nLastField - 1; ++i)
349 0 : vFields[i]->aEdit.SetModifyHdl(aLink);
350 0 : }
351 :
352 : //------------------------------------------------------------------------
353 :
354 0 : void SvxGeneralTabPage::SetAccessibleNames ()
355 : {
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 0 : for (unsigned i = 0; i != vRows.size(); ++i)
362 : {
363 0 : Row& rRow = *vRows[i];
364 0 : rtl::OUString const sLabel = rRow.aLabel.GetDisplayText();
365 0 : rtl::OUString sList = sLabel; // between brackets or the whole label
366 : // brackets?
367 0 : int iBracket = sLabel.indexOf('(');
368 0 : if (iBracket != -1)
369 0 : sList = sList.copy(iBracket + 1, sLabel.lastIndexOf(')') - iBracket - 1);
370 : // cutting at '/'s
371 0 : sal_Int32 nIndex = 0;
372 0 : for (unsigned iField = rRow.nFirstField; iField != rRow.nLastField; ++iField)
373 : {
374 : // the token
375 0 : rtl::OUString sPart = sList.getToken(0, static_cast<sal_Unicode>('/'), nIndex).trim();
376 0 : Edit& rEdit = vFields[iField]->aEdit;
377 : // creating the accessible name
378 0 : if (iBracket != -1)
379 0 : rEdit.SetAccessibleName(sLabel.copy(0, iBracket) + "(" + sPart + ")");
380 : else
381 0 : rEdit.SetAccessibleName(sPart);
382 0 : }
383 0 : }
384 0 : }
385 :
386 : //------------------------------------------------------------------------
387 :
388 0 : SfxTabPage* SvxGeneralTabPage::Create( Window* pParent, const SfxItemSet& rAttrSet )
389 : {
390 0 : return ( new SvxGeneralTabPage( pParent, rAttrSet ) );
391 : }
392 :
393 : //------------------------------------------------------------------------
394 :
395 0 : sal_Bool SvxGeneralTabPage::FillItemSet( SfxItemSet& )
396 : {
397 : // remove leading and trailing whitespaces
398 0 : for (unsigned i = 0; i != vFields.size(); ++i)
399 0 : vFields[i]->aEdit.SetText( comphelper::string::strip(vFields[i]->aEdit.GetText(), ' ') );
400 :
401 0 : sal_Bool bModified = sal_False;
402 0 : bModified |= GetAddress_Impl();
403 0 : SvtSaveOptions aSaveOpt;
404 0 : if ( aUseDataCB.IsChecked() != aSaveOpt.IsUseUserData() )
405 : {
406 0 : aSaveOpt.SetUseUserData( aUseDataCB.IsChecked() );
407 0 : bModified |= sal_True;
408 : }
409 0 : return bModified;
410 : }
411 :
412 : //------------------------------------------------------------------------
413 :
414 0 : void SvxGeneralTabPage::Reset( const SfxItemSet& rSet )
415 : {
416 0 : SetAddress_Impl();
417 :
418 0 : sal_uInt16 const nWhich = GetWhich(SID_FIELD_GRABFOCUS);
419 :
420 0 : if (rSet.GetItemState(nWhich) == SFX_ITEM_SET)
421 : {
422 0 : if (sal_uInt16 const nField = ((SfxUInt16Item&)rSet.Get(nWhich)).GetValue())
423 : {
424 0 : for (unsigned i = 0; i != vFields.size(); ++i)
425 0 : if (nField == vFieldInfo[vFields[i]->iField].nGrabFocusId)
426 0 : vFields[i]->aEdit.GrabFocus();
427 : }
428 : else
429 0 : vFields.front()->aEdit.GrabFocus();
430 : }
431 :
432 0 : aUseDataCB.Check( SvtSaveOptions().IsUseUserData() );
433 0 : }
434 :
435 : //------------------------------------------------------------------------
436 :
437 : // ModifyHdl_Impl()
438 : // This handler updates the initials (short name)
439 : // when one of the name fields was updated.
440 0 : IMPL_LINK( SvxGeneralTabPage, ModifyHdl_Impl, Edit *, pEdit )
441 : {
442 : // short name field and row
443 0 : Field& rShortName = *vFields[nShortNameField];
444 0 : Row& rNameRow = *vRows[nNameRow];
445 : // number of initials
446 0 : unsigned const nInits = rNameRow.nLastField - rNameRow.nFirstField - 1;
447 : // which field was updated? (in rNameRow)
448 0 : unsigned nField = nInits;
449 0 : for (unsigned i = 0; i != nInits; ++i)
450 0 : if (&vFields[rNameRow.nFirstField + i]->aEdit == pEdit)
451 0 : nField = i;
452 : // Since middle names are not supported, clear shortname if it
453 : // contains a middle initial
454 0 : if (rtl::OUString(rShortName.aEdit.GetText()).getLength() > 2)
455 : {
456 0 : rtl::OUString sEmptyString;
457 0 : rShortName.aEdit.SetText(sEmptyString);
458 : }
459 : // updating the initial
460 0 : if (nField < nInits && rShortName.aEdit.IsEnabled())
461 : {
462 0 : rtl::OUString sShortName = rShortName.aEdit.GetText();
463 0 : while ((unsigned)sShortName.getLength() < nInits)
464 0 : sShortName += rtl::OUString(' ');
465 0 : rtl::OUString sName = pEdit->GetText();
466 0 : rtl::OUString sLetter = rtl::OUString(sName.getLength() ? sName.toChar() : ' ');
467 0 : rShortName.aEdit.SetText(sShortName.replaceAt(nField, 1, sLetter).trim());
468 : }
469 0 : return 0;
470 : }
471 :
472 : //------------------------------------------------------------------------
473 :
474 0 : sal_Bool SvxGeneralTabPage::GetAddress_Impl()
475 : {
476 : // updating
477 0 : SvtUserOptions aUserOpt;
478 0 : for (unsigned i = 0; i != vFields.size(); ++i)
479 : aUserOpt.SetToken(
480 0 : vFieldInfo[vFields[i]->iField].nUserOptionsId,
481 0 : vFields[i]->aEdit.GetText()
482 0 : );
483 :
484 : // modified?
485 0 : for (unsigned i = 0; i != vFields.size(); ++i)
486 0 : if (vFields[i]->aEdit.GetSavedValue() != vFields[i]->aEdit.GetText())
487 0 : return true;
488 0 : return false;
489 : }
490 :
491 : //------------------------------------------------------------------------
492 :
493 0 : void SvxGeneralTabPage::SetAddress_Impl()
494 : {
495 : // updating and disabling edit boxes
496 0 : SvtUserOptions aUserOpt;
497 0 : for (unsigned iRow = 0; iRow != vRows.size(); ++iRow)
498 : {
499 0 : Row& rRow = *vRows[iRow];
500 : // the label is enabled if any of its edit fields are enabled
501 0 : bool bEnableLabel = false;
502 0 : for (unsigned iField = rRow.nFirstField; iField != rRow.nLastField; ++iField)
503 : {
504 0 : Field& rField = *vFields[iField];
505 : // updating content
506 0 : unsigned const nToken = vFieldInfo[rField.iField].nUserOptionsId;
507 0 : rField.aEdit.SetText(aUserOpt.GetToken(nToken));
508 : // is enabled?
509 0 : bool const bEnableEdit = !aUserOpt.IsTokenReadonly(nToken);
510 0 : rField.aEdit.Enable(bEnableEdit);
511 0 : bEnableLabel = bEnableLabel || bEnableEdit;
512 : }
513 0 : rRow.aLabel.Enable(bEnableLabel);
514 : }
515 :
516 : // saving
517 0 : for (unsigned i = 0; i != vFields.size(); ++i)
518 0 : vFields[i]->aEdit.SaveValue();
519 0 : }
520 :
521 : // -----------------------------------------------------------------------
522 :
523 0 : int SvxGeneralTabPage::DeactivatePage( SfxItemSet* pSet_ )
524 : {
525 0 : if ( pSet_ )
526 0 : FillItemSet( *pSet_ );
527 0 : return LEAVE_PAGE;
528 3 : }
529 :
530 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|