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 <vcl/msgbox.hxx>
22 : #include <vcl/field.hxx>
23 : #include <svl/eitem.hxx>
24 : #include <svl/intitem.hxx>
25 : #include <svl/style.hxx>
26 :
27 : #include <sfx2/styfitem.hxx>
28 : #include <sfx2/styledlg.hxx>
29 : #include <sfx2/app.hxx>
30 : #include <sfx2/mgetempl.hxx>
31 : #include <sfx2/objsh.hxx>
32 : #include "sfxtypes.hxx"
33 : #include "sfx2/sfxresid.hxx"
34 : #include <sfx2/module.hxx>
35 :
36 : #include <sfx2/sfx.hrc>
37 : #include "dialog.hrc"
38 : #include "mgetempl.hrc"
39 :
40 : #include <svl/style.hrc>
41 :
42 : // SfxManageStyleSheetPage -----------------------------------------------
43 :
44 0 : SfxManageStyleSheetPage::SfxManageStyleSheetPage( Window* pParent, const SfxItemSet& rAttrSet ) :
45 :
46 : SfxTabPage( pParent, SfxResId( TP_MANAGE_STYLES ), rAttrSet ),
47 :
48 : aNameFt ( this, SfxResId( FT_NAME ) ),
49 : aNameEd ( this, SfxResId( ED_NAME ) ),
50 : aNameMLE ( this, SfxResId( MLE_NAME ) ),
51 : aAutoCB ( this, SfxResId( CB_AUTO ) ),
52 :
53 : aFollowFt ( this, SfxResId( FT_NEXT ) ),
54 : aFollowLb ( this, SfxResId( LB_NEXT ) ),
55 :
56 : aBaseFt ( this, SfxResId( FT_BASE ) ),
57 : aBaseLb ( this, SfxResId( LB_BASE ) ),
58 :
59 : aFilterFt ( this, SfxResId( FT_REGION ) ),
60 : aFilterLb ( this, SfxResId( LB_REGION ) ),
61 :
62 : aDescGb ( this, SfxResId( GB_DESC ) ),
63 : aDescFt ( this, SfxResId( FT_DESC ) ),
64 : aDescED ( this, SfxResId( ED_DESC ) ),
65 :
66 0 : pStyle( &( (SfxStyleDialog*)GetParentDialog() )->GetStyleSheet() ),
67 :
68 : pItem ( 0 ),
69 : bModified ( sal_False ),
70 0 : aName ( pStyle->GetName() ),
71 0 : aFollow ( pStyle->GetFollow() ),
72 0 : aParent ( pStyle->GetParent() ),
73 0 : nFlags ( pStyle->GetMask() )
74 :
75 : /* [Description]
76 :
77 : Constructor, initializes the list box with the templates
78 : */
79 :
80 : {
81 0 : FreeResource();
82 :
83 0 : if ( IsBackground() )
84 0 : aDescED.SetBackground( GetBackground() );
85 0 : FixedInfo* pInfo = new FixedInfo( this );
86 0 : aDescED.SetFont( pInfo->GetFont() );
87 0 : delete pInfo;
88 :
89 0 : aDescED.Hide();
90 0 : aDescFt.Show();
91 :
92 : // this Page needs ExchangeSupport
93 0 : SetExchangeSupport();
94 :
95 0 : ResMgr* pResMgr = SFX_APP()->GetModule_Impl()->GetResMgr();
96 : OSL_ENSURE( pResMgr, "No ResMgr in Module" );
97 0 : pFamilies = new SfxStyleFamilies( ResId( DLG_STYLE_DESIGNER, *pResMgr ) );
98 :
99 0 : SfxStyleSheetBasePool* pPool = 0;
100 0 : SfxObjectShell* pDocShell = SfxObjectShell::Current();
101 :
102 0 : if ( pDocShell )
103 0 : pPool = pDocShell->GetStyleSheetPool();
104 : OSL_ENSURE( pPool, "no Pool or no DocShell" );
105 :
106 0 : if ( pPool )
107 : {
108 0 : pPool->SetSearchMask( pStyle->GetFamily() );
109 0 : pPool->First(); // for SW - update internal list
110 : }
111 :
112 0 : if ( !pStyle->GetName().Len() && pPool )
113 : {
114 : // NullString as Name -> generate Name
115 0 : String aNoName( SfxResId(STR_NONAME).toString() );
116 0 : sal_uInt16 nNo = 1;
117 0 : String aNo( aNoName );
118 0 : aNoName += String::CreateFromInt32( nNo );
119 0 : while ( pPool->Find( aNoName ) )
120 : {
121 0 : ++nNo;
122 0 : aNoName = aNo;
123 0 : aNoName += String::CreateFromInt32( nNo );
124 : }
125 0 : pStyle->SetName( aNoName );
126 0 : aName = aNoName;
127 0 : aFollow = pStyle->GetFollow();
128 0 : aParent = pStyle->GetParent();
129 : }
130 0 : aNameEd.SetText(pStyle->GetName());
131 :
132 : // Set the field read-only if it is NOT an user-defined style
133 : // but allow selecting and copying
134 0 : if ( !pStyle->IsUserDefined() ) {
135 0 : aNameEd.SetReadOnly();
136 0 : aNameEd.Hide();
137 :
138 0 : aNameMLE.SetControlBackground( GetSettings().GetStyleSettings().GetDialogColor() );
139 0 : aNameMLE.SetText( pStyle->GetName() );
140 0 : aNameMLE.EnableCursor( sal_False );
141 0 : aNameMLE.Show();
142 : }
143 :
144 0 : if ( pStyle->HasFollowSupport() && pPool )
145 : {
146 0 : SfxStyleSheetBase* pPoolStyle = pPool->First();
147 :
148 0 : while ( pPoolStyle )
149 : {
150 0 : aFollowLb.InsertEntry( pPoolStyle->GetName() );
151 0 : pPoolStyle = pPool->Next();
152 : }
153 :
154 : // A new Template is not jet in the Pool
155 0 : if ( LISTBOX_ENTRY_NOTFOUND == aFollowLb.GetEntryPos( pStyle->GetName() ) )
156 0 : aFollowLb.InsertEntry( pStyle->GetName() );
157 : }
158 : else
159 : {
160 0 : aFollowFt.Hide();
161 0 : aFollowLb.Hide();
162 :
163 0 : aFilterFt.SetPosPixel( aBaseFt.GetPosPixel() );
164 0 : aFilterLb.SetPosPixel( aBaseLb.GetPosPixel() );
165 :
166 0 : aBaseFt.SetPosPixel( aFollowFt.GetPosPixel() );
167 0 : aBaseLb.SetPosPixel( aFollowLb.GetPosPixel() );
168 : }
169 :
170 0 : if ( pStyle->HasParentSupport() && pPool )
171 : {
172 0 : if ( pStyle->HasClearParentSupport() )
173 : // the base template can be set to NULL
174 0 : aBaseLb.InsertEntry( SfxResId(STR_NONE).toString() );
175 :
176 0 : SfxStyleSheetBase* pPoolStyle = pPool->First();
177 :
178 0 : while ( pPoolStyle )
179 : {
180 0 : const String aStr( pPoolStyle->GetName() );
181 : // own name as base template
182 0 : if ( aStr != aName )
183 0 : aBaseLb.InsertEntry( aStr );
184 0 : pPoolStyle = pPool->Next();
185 0 : }
186 : }
187 : else
188 : {
189 0 : aBaseFt.Disable();
190 0 : aBaseLb.Disable();
191 : }
192 :
193 0 : size_t nCount = pFamilies->size();
194 : size_t i;
195 0 : for ( i = 0; i < nCount; ++i )
196 : {
197 0 : pItem = pFamilies->at( i );
198 :
199 0 : if ( pItem->GetFamily() == pStyle->GetFamily() )
200 0 : break;
201 : }
202 :
203 0 : if ( i < nCount )
204 : {
205 0 : sal_uInt16 nStyleFilterIdx = 0xffff;
206 : // Filter flags
207 0 : const SfxStyleFilter& rList = pItem->GetFilterList();
208 0 : nCount = rList.size();
209 0 : sal_uInt16 nIdx = 0;
210 0 : sal_uInt16 nMask = pStyle->GetMask() & ~SFXSTYLEBIT_USERDEF;
211 :
212 0 : if ( !nMask ) // User Template?
213 0 : nMask = pStyle->GetMask();
214 :
215 0 : for ( i = 0; i < nCount; ++i )
216 : {
217 0 : SfxFilterTupel* pTupel = rList[ i ];
218 :
219 0 : if ( pTupel->nFlags != SFXSTYLEBIT_AUTO &&
220 : pTupel->nFlags != SFXSTYLEBIT_USED &&
221 : pTupel->nFlags != SFXSTYLEBIT_ALL )
222 : {
223 0 : aFilterLb.InsertEntry( pTupel->aName, nIdx );
224 0 : aFilterLb.SetEntryData(nIdx, (void*)(long)i);
225 :
226 0 : if ( ( pTupel->nFlags & nMask ) == nMask )
227 0 : nStyleFilterIdx = nIdx;
228 0 : ++nIdx;
229 : }
230 : }
231 :
232 0 : if ( nStyleFilterIdx != 0xFFFF )
233 0 : aFilterLb.SelectEntryPos( nStyleFilterIdx );
234 : }
235 :
236 0 : if ( !aFilterLb.GetEntryCount() || !pStyle->IsUserDefined() )
237 : {
238 0 : pItem = 0;
239 0 : aFilterFt.Disable();
240 0 : aFilterLb.Disable();
241 : }
242 : else
243 0 : aFilterLb.SaveValue();
244 0 : SetDescriptionText_Impl();
245 :
246 0 : if ( aFollowLb.IsEnabled() || aBaseLb.IsEnabled() )
247 : {
248 : aNameEd.SetGetFocusHdl(
249 0 : LINK( this, SfxManageStyleSheetPage, GetFocusHdl ) );
250 : aNameEd.SetLoseFocusHdl(
251 0 : LINK( this, SfxManageStyleSheetPage, LoseFocusHdl ) );
252 : }
253 : // It is a style with auto update? (SW only)
254 0 : if(SFX_ITEM_SET == rAttrSet.GetItemState(SID_ATTR_AUTO_STYLE_UPDATE))
255 : {
256 0 : Size aSize = aNameEd.GetSizePixel();
257 0 : aSize.Width() /= 2;
258 0 : aNameEd.SetSizePixel(aSize);
259 0 : aAutoCB.Show();
260 : }
261 0 : }
262 :
263 : //-------------------------------------------------------------------------
264 :
265 0 : SfxManageStyleSheetPage::~SfxManageStyleSheetPage()
266 :
267 : /* [Description]
268 :
269 : Destructor, release of the data
270 : */
271 :
272 : {
273 0 : aNameEd.SetGetFocusHdl( Link() );
274 0 : aNameEd.SetLoseFocusHdl( Link() );
275 0 : delete pFamilies;
276 0 : pItem = 0;
277 0 : pStyle = 0;
278 :
279 0 : }
280 :
281 : //-------------------------------------------------------------------------
282 :
283 0 : void SfxManageStyleSheetPage::UpdateName_Impl( ListBox* pBox,
284 : const String& rNew )
285 :
286 : /* [Description]
287 :
288 : After the change of a template name update the ListBox pBox
289 :
290 : [Parameter]
291 :
292 : ListBox* pBox ListBox, whose entries are to be updated
293 : const String& rNew the new Name
294 : */
295 :
296 : {
297 0 : if ( pBox->IsEnabled() )
298 : {
299 : // it is the current entry, which name was modified
300 0 : const sal_Bool bSelect = pBox->GetSelectEntry() == aBuf;
301 0 : pBox->RemoveEntry( aBuf );
302 0 : pBox->InsertEntry( rNew );
303 :
304 0 : if ( bSelect )
305 0 : pBox->SelectEntry( rNew );
306 : }
307 0 : }
308 :
309 : //-------------------------------------------------------------------------
310 :
311 0 : void SfxManageStyleSheetPage::SetDescriptionText_Impl()
312 :
313 : /* [Description]
314 :
315 : Set attribute description. Get the set metric for this.
316 : */
317 :
318 : {
319 0 : SfxMapUnit eUnit = SFX_MAPUNIT_CM;
320 0 : FieldUnit eFieldUnit( FUNIT_CM );
321 0 : SfxModule* pModule = SfxModule::GetActiveModule();
322 0 : if ( pModule )
323 : {
324 0 : const SfxPoolItem* pPoolItem = pModule->GetItem( SID_ATTR_METRIC );
325 0 : if ( pPoolItem )
326 0 : eFieldUnit = (FieldUnit)( (SfxUInt16Item*)pPoolItem )->GetValue();
327 : }
328 :
329 0 : switch ( eFieldUnit )
330 : {
331 0 : case FUNIT_MM: eUnit = SFX_MAPUNIT_MM; break;
332 : case FUNIT_CM:
333 : case FUNIT_M:
334 0 : case FUNIT_KM: eUnit = SFX_MAPUNIT_CM; break;
335 : case FUNIT_POINT:
336 0 : case FUNIT_PICA: eUnit = SFX_MAPUNIT_POINT; break;
337 : case FUNIT_INCH:
338 : case FUNIT_FOOT:
339 0 : case FUNIT_MILE: eUnit = SFX_MAPUNIT_INCH; break;
340 :
341 : default:
342 : OSL_FAIL( "non supported field unit" );
343 : }
344 0 : aDescFt.SetText( pStyle->GetDescription( eUnit ) );
345 0 : }
346 :
347 : //-------------------------------------------------------------------------
348 :
349 0 : IMPL_LINK_INLINE_START( SfxManageStyleSheetPage, GetFocusHdl, Edit *, pEdit )
350 :
351 : /* [Description]
352 :
353 : StarView Handler; GetFocus-Handler of the Edits with the template name.
354 : */
355 :
356 : {
357 0 : aBuf = comphelper::string::stripStart(pEdit->GetText(), ' ');
358 0 : return 0;
359 : }
360 0 : IMPL_LINK_INLINE_END( SfxManageStyleSheetPage, GetFocusHdl, Edit *, pEdit )
361 :
362 : //-------------------------------------------------------------------------
363 :
364 0 : IMPL_LINK_INLINE_START( SfxManageStyleSheetPage, LoseFocusHdl, Edit *, pEdit )
365 :
366 : /* [Description]
367 :
368 : StarView Handler; loose-focus-handler of the edits of the template name.
369 : This will update the listbox with the subsequent templates. The current
370 : template itself is not returned in the listbox of the base templates.
371 : */
372 :
373 : {
374 0 : const String aStr(comphelper::string::stripStart(pEdit->GetText(), ' '));
375 0 : pEdit->SetText( aStr );
376 : // Update the Listbox of the base template if possible
377 0 : if ( aStr != aBuf )
378 0 : UpdateName_Impl( &aFollowLb, aStr );
379 0 : return 0;
380 : }
381 0 : IMPL_LINK_INLINE_END( SfxManageStyleSheetPage, LoseFocusHdl, Edit *, pEdit )
382 :
383 : //-------------------------------------------------------------------------
384 :
385 0 : sal_Bool SfxManageStyleSheetPage::FillItemSet( SfxItemSet& rSet )
386 :
387 : /* [Description]
388 :
389 : Handler for setting the (modified) data. I called from the OK of the
390 : SfxTabDialog.
391 :
392 : [Parameter]
393 :
394 : SfxItemSet &rAttrSet The set, which receives the data.
395 :
396 : [Return value]
397 :
398 : sal_Bool sal_True: The data had been changed
399 : sal_False: The data had not been changed
400 :
401 : [Cross-reference]
402 :
403 : <class SfxTabDialog>
404 : */
405 :
406 : {
407 0 : const sal_uInt16 nFilterIdx = aFilterLb.GetSelectEntryPos();
408 :
409 : // Set Filter
410 :
411 0 : if ( LISTBOX_ENTRY_NOTFOUND != nFilterIdx &&
412 0 : nFilterIdx != aFilterLb.GetSavedValue() &&
413 0 : aFilterLb.IsEnabled() )
414 : {
415 0 : bModified = sal_True;
416 : OSL_ENSURE( pItem, "No Item" );
417 : // is only possibly for user templates
418 0 : sal_uInt16 nMask = pItem->GetFilterList()[ (size_t)aFilterLb.GetEntryData( nFilterIdx ) ]->nFlags | SFXSTYLEBIT_USERDEF;
419 0 : pStyle->SetMask( nMask );
420 : }
421 0 : if(aAutoCB.IsVisible() &&
422 0 : aAutoCB.IsChecked() != aAutoCB.GetSavedValue())
423 : {
424 0 : rSet.Put(SfxBoolItem(SID_ATTR_AUTO_STYLE_UPDATE, aAutoCB.IsChecked()));
425 : }
426 :
427 0 : return bModified;
428 : }
429 :
430 : //-------------------------------------------------------------------------
431 :
432 0 : void SfxManageStyleSheetPage::Reset( const SfxItemSet& /*rAttrSet*/ )
433 :
434 : /* [Description]
435 :
436 : Handler to initialize the page with the initial data.
437 :
438 : [Parameter]
439 :
440 : const SfxItemSet &rAttrSet The data set
441 :
442 : [Cross-reference]
443 :
444 : <class SfxTabDialog>
445 : */
446 :
447 : {
448 0 : bModified = sal_False;
449 0 : String sCmp( pStyle->GetName() );
450 :
451 0 : if ( sCmp != aName )
452 0 : pStyle->SetName( aName );
453 0 : aNameEd.SetText( aName );
454 :
455 0 : if ( aFollowLb.IsEnabled() )
456 : {
457 0 : sCmp = pStyle->GetFollow();
458 :
459 0 : if ( sCmp != aFollow )
460 0 : pStyle->SetFollow( aFollow );
461 :
462 0 : if ( !aFollow.Len() )
463 0 : aFollowLb.SelectEntry( aName );
464 : else
465 0 : aFollowLb.SelectEntry( aFollow );
466 : }
467 :
468 0 : if ( aBaseLb.IsEnabled() )
469 : {
470 0 : sCmp = pStyle->GetParent();
471 :
472 0 : if ( sCmp != aParent )
473 0 : pStyle->SetParent( aParent );
474 :
475 0 : if ( !aParent.Len() )
476 0 : aBaseLb.SelectEntry( SfxResId(STR_NONE).toString() );
477 : else
478 0 : aBaseLb.SelectEntry( aParent );
479 :
480 0 : if ( SfxResId(STR_STANDARD).toString().equals(aName) )
481 : {
482 : // the default template can not be linked
483 0 : aBaseFt.Disable();
484 0 : aBaseLb.Disable();
485 : }
486 : }
487 :
488 0 : if ( aFilterLb.IsEnabled() )
489 : {
490 0 : sal_uInt16 nCmp = pStyle->GetMask();
491 :
492 0 : if ( nCmp != nFlags )
493 0 : pStyle->SetMask( nFlags );
494 0 : aFilterLb.SelectEntryPos( aFilterLb.GetSavedValue() );
495 0 : }
496 0 : }
497 :
498 : //-------------------------------------------------------------------------
499 :
500 0 : SfxTabPage* SfxManageStyleSheetPage::Create( Window* pParent,
501 : const SfxItemSet &rAttrSet )
502 :
503 : /* [Description]
504 :
505 : Factory for the creation of the page.
506 :
507 : [Cross-reference]
508 :
509 : <class SfxTabDialog>
510 : */
511 :
512 : {
513 0 : return new SfxManageStyleSheetPage( pParent, rAttrSet );
514 : }
515 :
516 : //-------------------------------------------------------------------------
517 :
518 0 : void SfxManageStyleSheetPage::ActivatePage( const SfxItemSet& rSet)
519 :
520 : /* [Description]
521 :
522 : ActivatePage handler of SfxTabDialog, is used for the the update of the
523 : descriptive text, since this might have changed through changes of data on
524 : other pages.
525 :
526 : [Parameter]
527 :
528 : const SfxItemSet& the set for the exchange of data; is not used here.
529 :
530 : [Cross-reference]
531 :
532 : <SfxTabDialog::ActivatePage(const SfxItemSet &)>
533 : */
534 :
535 : {
536 0 : SetDescriptionText_Impl();
537 :
538 : // It is a style with auto update? (SW only)
539 : const SfxPoolItem* pPoolItem;
540 :
541 0 : if ( SFX_ITEM_SET ==
542 0 : rSet.GetItemState( SID_ATTR_AUTO_STYLE_UPDATE, sal_False, &pPoolItem ) )
543 0 : aAutoCB.Check( ( (const SfxBoolItem*)pPoolItem )->GetValue() );
544 0 : aAutoCB.SaveValue();
545 0 : }
546 :
547 : //-------------------------------------------------------------------------
548 :
549 0 : int SfxManageStyleSheetPage::DeactivatePage( SfxItemSet* pItemSet )
550 :
551 : /* [Description]
552 :
553 : DeactivatePage-handler of SfxTabDialog; data is set on the template, so
554 : that the correct inheritance on the other pages of the dialog is made.
555 : If an error occurs, leaving the page is prevented.
556 : [Parameter]
557 :
558 : SfxItemSet* the set for the exchange of data; is not used here.
559 :
560 : [Cross-reference]
561 :
562 : <SfxTabDialog::DeactivatePage(SfxItemSet*)>
563 : */
564 :
565 : {
566 0 : int nRet = SfxTabPage::LEAVE_PAGE;
567 :
568 0 : if ( aNameEd.IsModified() )
569 : {
570 : // By pressing <Enter> LoseFocus() is not trigged through StarView
571 0 : if ( aNameEd.HasFocus() )
572 0 : LoseFocusHdl( &aNameEd );
573 :
574 0 : if (!pStyle->SetName(comphelper::string::stripStart(aNameEd.GetText(), ' ')))
575 : {
576 0 : InfoBox aBox( this, SfxResId( MSG_TABPAGE_INVALIDNAME ) );
577 0 : aBox.Execute();
578 0 : aNameEd.GrabFocus();
579 0 : aNameEd.SetSelection( Selection( SELECTION_MIN, SELECTION_MAX ) );
580 0 : return SfxTabPage::KEEP_PAGE;
581 : }
582 0 : bModified = sal_True;
583 : }
584 :
585 0 : if ( pStyle->HasFollowSupport() && aFollowLb.IsEnabled() )
586 : {
587 0 : const String aFollowEntry( aFollowLb.GetSelectEntry() );
588 :
589 0 : if ( pStyle->GetFollow() != aFollowEntry )
590 : {
591 0 : if ( !pStyle->SetFollow( aFollowEntry ) )
592 : {
593 0 : InfoBox aBox( this, SfxResId( MSG_TABPAGE_INVALIDSTYLE ) );
594 0 : aBox.Execute();
595 0 : aFollowLb.GrabFocus();
596 0 : return SfxTabPage::KEEP_PAGE;
597 : }
598 0 : bModified = sal_True;
599 0 : }
600 : }
601 :
602 0 : if ( aBaseLb.IsEnabled() )
603 : {
604 0 : String aParentEntry( aBaseLb.GetSelectEntry() );
605 :
606 0 : if ( SfxResId(STR_NONE).toString().equals(aParentEntry) || aParentEntry == pStyle->GetName() )
607 0 : aParentEntry.Erase();
608 :
609 0 : if ( pStyle->GetParent() != aParentEntry )
610 : {
611 0 : if ( !pStyle->SetParent( aParentEntry ) )
612 : {
613 0 : InfoBox aBox( this, SfxResId( MSG_TABPAGE_INVALIDPARENT ) );
614 0 : aBox.Execute();
615 0 : aBaseLb.GrabFocus();
616 0 : return SfxTabPage::KEEP_PAGE;
617 : }
618 0 : bModified = sal_True;
619 0 : nRet |= (int)SfxTabPage::REFRESH_SET;
620 0 : }
621 : }
622 :
623 0 : if ( pItemSet )
624 0 : FillItemSet( *pItemSet );
625 :
626 0 : return nRet;
627 66 : }
628 :
629 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|