LCOV - code coverage report
Current view: top level - extensions/source/abpilot - fieldmappingimpl.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 97 0.0 %
Date: 2012-08-25 Functions: 0 7 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 :            : /*************************************************************************
       3                 :            :  *
       4                 :            :  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       5                 :            :  *
       6                 :            :  * Copyright 2000, 2010 Oracle and/or its affiliates.
       7                 :            :  *
       8                 :            :  * OpenOffice.org - a multi-platform office productivity suite
       9                 :            :  *
      10                 :            :  * This file is part of OpenOffice.org.
      11                 :            :  *
      12                 :            :  * OpenOffice.org is free software: you can redistribute it and/or modify
      13                 :            :  * it under the terms of the GNU Lesser General Public License version 3
      14                 :            :  * only, as published by the Free Software Foundation.
      15                 :            :  *
      16                 :            :  * OpenOffice.org is distributed in the hope that it will be useful,
      17                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      18                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19                 :            :  * GNU Lesser General Public License version 3 for more details
      20                 :            :  * (a copy is included in the LICENSE file that accompanied this code).
      21                 :            :  *
      22                 :            :  * You should have received a copy of the GNU Lesser General Public License
      23                 :            :  * version 3 along with OpenOffice.org.  If not, see
      24                 :            :  * <http://www.openoffice.org/license.html>
      25                 :            :  * for a copy of the LGPLv3 License.
      26                 :            :  *
      27                 :            :  ************************************************************************/
      28                 :            : 
      29                 :            : #include "fieldmappingimpl.hxx"
      30                 :            : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
      31                 :            : #include <com/sun/star/beans/PropertyValue.hpp>
      32                 :            : #include <com/sun/star/beans/XPropertySet.hpp>
      33                 :            : #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
      34                 :            : #include <com/sun/star/awt/XWindow.hpp>
      35                 :            : #include <com/sun/star/sdb/CommandType.hpp>
      36                 :            : #include <tools/debug.hxx>
      37                 :            : #include <toolkit/unohlp.hxx>
      38                 :            : #include <vcl/stdtext.hxx>
      39                 :            : #include <com/sun/star/util/AliasProgrammaticPair.hpp>
      40                 :            : #include "abpresid.hrc"
      41                 :            : #include "componentmodule.hxx"
      42                 :            : #include <unotools/confignode.hxx>
      43                 :            : #include "sal/macros.h"
      44                 :            : 
      45                 :            : //.........................................................................
      46                 :            : namespace abp
      47                 :            : {
      48                 :            : //.........................................................................
      49                 :            : 
      50                 :            :     using namespace ::utl;
      51                 :            :     using namespace ::com::sun::star::uno;
      52                 :            :     using namespace ::com::sun::star::awt;
      53                 :            :     using namespace ::com::sun::star::util;
      54                 :            :     using namespace ::com::sun::star::lang;
      55                 :            :     using namespace ::com::sun::star::beans;
      56                 :            :     using namespace ::com::sun::star::sdb;
      57                 :            :     using namespace ::com::sun::star::ui::dialogs;
      58                 :            : 
      59                 :            :     //---------------------------------------------------------------------
      60                 :          0 :     static const ::rtl::OUString& lcl_getDriverSettingsNodeName()
      61                 :            :     {
      62                 :          0 :         static const ::rtl::OUString s_sDriverSettingsNodeName(RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.DataAccess/DriverSettings/com.sun.star.comp.sdbc.MozabDriver" ));
      63                 :          0 :         return s_sDriverSettingsNodeName;
      64                 :            :     }
      65                 :            : 
      66                 :            :     //---------------------------------------------------------------------
      67                 :          0 :     static const ::rtl::OUString& lcl_getAddressBookNodeName()
      68                 :            :     {
      69                 :          0 :         static const ::rtl::OUString s_sAddressBookNodeName(RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.DataAccess/AddressBook" ));
      70                 :          0 :         return s_sAddressBookNodeName;
      71                 :            :     }
      72                 :            : 
      73                 :            :     //.....................................................................
      74                 :            :     namespace fieldmapping
      75                 :            :     {
      76                 :            :     //.....................................................................
      77                 :            : 
      78                 :            :         //-----------------------------------------------------------------
      79                 :          0 :         sal_Bool invokeDialog( const Reference< XMultiServiceFactory >& _rxORB, class Window* _pParent,
      80                 :            :             const Reference< XPropertySet >& _rxDataSource, AddressSettings& _rSettings ) SAL_THROW ( ( ) )
      81                 :            :         {
      82                 :          0 :             _rSettings.aFieldMapping.clear();
      83                 :            : 
      84                 :            :             DBG_ASSERT( _rxORB.is(), "fieldmapping::invokeDialog: invalid service factory!" );
      85                 :            :             DBG_ASSERT( _rxDataSource.is(), "fieldmapping::invokeDialog: invalid data source!" );
      86                 :          0 :             if ( !_rxORB.is() || !_rxDataSource.is() )
      87                 :          0 :                 return sal_False;
      88                 :            : 
      89                 :            :             try
      90                 :            :             {
      91                 :            :                 // ........................................................
      92                 :            :                 // the parameters for creating the dialog
      93                 :          0 :                 Sequence< Any > aArguments(5);
      94                 :          0 :                 Any* pArguments = aArguments.getArray();
      95                 :            : 
      96                 :            :                 // the parent window
      97                 :          0 :                 Reference< XWindow > xDialogParent = VCLUnoHelper::GetInterface( _pParent );
      98                 :          0 :                 *pArguments++ <<= PropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "ParentWindow" )), -1, makeAny( xDialogParent ), PropertyState_DIRECT_VALUE);
      99                 :            : 
     100                 :            :                 // the data source to use
     101                 :          0 :                 *pArguments++ <<= PropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "DataSource" )), -1, makeAny( _rxDataSource ), PropertyState_DIRECT_VALUE);
     102                 :          0 :                 *pArguments++ <<= PropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "DataSourceName" )), -1, makeAny( (sal_Bool)_rSettings.bRegisterDataSource ? _rSettings.sRegisteredDataSourceName : _rSettings.sDataSourceName ), PropertyState_DIRECT_VALUE);
     103                 :            : 
     104                 :            :                 // the table to use
     105                 :          0 :                 *pArguments++ <<= PropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Command" )), -1, makeAny( _rSettings.sSelectedTable ), PropertyState_DIRECT_VALUE);
     106                 :            : 
     107                 :            :                 // the title
     108                 :          0 :                 ::rtl::OUString sTitle = String( ModuleRes( RID_STR_FIELDDIALOGTITLE ) );
     109                 :          0 :                 *pArguments++ <<= PropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Title" )), -1, makeAny( sTitle ), PropertyState_DIRECT_VALUE);
     110                 :            : 
     111                 :            :                 // ........................................................
     112                 :            :                 // create an instance of the dialog service
     113                 :          0 :                 static ::rtl::OUString s_sAdressBookFieldAssignmentServiceName(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ui.AddressBookSourceDialog" ));
     114                 :            :                 Reference< XExecutableDialog > xDialog(
     115                 :          0 :                     _rxORB->createInstanceWithArguments( s_sAdressBookFieldAssignmentServiceName, aArguments ),
     116                 :            :                     UNO_QUERY
     117                 :          0 :                 );
     118                 :          0 :                 if ( !xDialog.is( ) )
     119                 :            :                 {
     120                 :          0 :                     ShowServiceNotAvailableError( _pParent, s_sAdressBookFieldAssignmentServiceName, sal_True );
     121                 :          0 :                     return sal_False;
     122                 :            :                 }
     123                 :            : 
     124                 :            :                 // execute the dialog
     125                 :          0 :                 if ( xDialog->execute() )
     126                 :            :                 {
     127                 :            :                     // retrieve the field mapping as set by he user
     128                 :          0 :                     Reference< XPropertySet > xDialogProps( xDialog, UNO_QUERY );
     129                 :            : 
     130                 :          0 :                     Sequence< AliasProgrammaticPair > aMapping;
     131                 :            : #ifdef DBG_UTIL
     132                 :            :                     sal_Bool bSuccess =
     133                 :            : #endif
     134                 :          0 :                     xDialogProps->getPropertyValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "FieldMapping" )) ) >>= aMapping;
     135                 :            :                     DBG_ASSERT( bSuccess, "fieldmapping::invokeDialog: invalid property type for FieldMapping!" );
     136                 :            : 
     137                 :            :                     // and copy it into the map
     138                 :          0 :                     const AliasProgrammaticPair* pMapping = aMapping.getConstArray();
     139                 :          0 :                     const AliasProgrammaticPair* pMappingEnd = pMapping + aMapping.getLength();
     140                 :          0 :                     for (;pMapping != pMappingEnd; ++pMapping)
     141                 :          0 :                         _rSettings.aFieldMapping[ pMapping->ProgrammaticName ] = pMapping->Alias;
     142                 :            : 
     143                 :          0 :                     return sal_True;
     144                 :          0 :                 }
     145                 :            : 
     146                 :            :             }
     147                 :          0 :             catch(const Exception&)
     148                 :            :             {
     149                 :            :                 OSL_FAIL("fieldmapping::invokeDialog: caught an exception while executing the dialog!");
     150                 :            :             }
     151                 :          0 :             return sal_False;
     152                 :            :         }
     153                 :            : 
     154                 :            :         //-----------------------------------------------------------------
     155                 :          0 :         void defaultMapping(  const Reference< XMultiServiceFactory >& _rxORB, MapString2String& _rFieldAssignment ) SAL_THROW ( ( ) )
     156                 :            :         {
     157                 :          0 :             _rFieldAssignment.clear();
     158                 :            : 
     159                 :            :             try
     160                 :            :             {
     161                 :            :                 // what we have:
     162                 :            :                 // a) For the address data source, we need a mapping from programmatic names (1) to real column names
     163                 :            :                 // b) The SDBC driver has a fixed set of columns, which, when returned, are named according to
     164                 :            :                 //    some configuration entries. E.g., the driver displays the field which it knows contains
     165                 :            :                 //    the first name as "First Name" - the latter string is stored in the config.
     166                 :            :                 //    For this, the driver uses programmatic names, too, but they differ from the programmatic names the
     167                 :            :                 //    template documents have.
     168                 :            :                 // So what we need first is a mapping from programmatic names (1) to programmatic names (2)
     169                 :            :                 const sal_Char* pMappingProgrammatics[] =
     170                 :            :                 {
     171                 :            :                     "FirstName",            "FirstName",
     172                 :            :                     "LastName",             "LastName",
     173                 :            :                     "Street",               "HomeAddress",
     174                 :            :                     "Zip",                  "HomeZipCode",
     175                 :            :                     "City",                 "HomeCity",
     176                 :            :                     "State",                "HomeState",
     177                 :            :                     "Country",              "HomeCountry",
     178                 :            :                     "PhonePriv",            "HomePhone",
     179                 :            :                     "PhoneComp",            "WorkPhone",
     180                 :            :                     "PhoneCell",            "CellularNumber",
     181                 :            :                     "Pager",                "PagerNumber",
     182                 :            :                     "Fax",                  "FaxNumber",
     183                 :            :                     "EMail",                "PrimaryEmail",
     184                 :            :                     "URL",                  "WebPage1",
     185                 :            :                     "Note",                 "Notes",
     186                 :            :                     "Altfield1",            "Custom1",
     187                 :            :                     "Altfield2",            "Custom2",
     188                 :            :                     "Altfield3",            "Custom3",
     189                 :            :                     "Altfield4",            "Custom4",
     190                 :            :                     "Title",                "JobTitle",
     191                 :            :                     "Company",              "Company",
     192                 :            :                     "Department",           "Department"
     193                 :          0 :                 };
     194                 :            :                     // (this list is not complete: both lists of programmatic names are larger in real,
     195                 :            :                     // but this list above is the intersection)
     196                 :            : 
     197                 :            : 
     198                 :            :                 // access the configuration information which the driver uses for determining it's column names
     199                 :          0 :                 ::rtl::OUString sDriverAliasesNodeName = lcl_getDriverSettingsNodeName();
     200                 :          0 :                 sDriverAliasesNodeName += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "/ColumnAliases" ));
     201                 :            : 
     202                 :            :                 // create a config node for this
     203                 :            :                 OConfigurationTreeRoot aDriverFieldAliasing = OConfigurationTreeRoot::createWithServiceFactory(
     204                 :          0 :                     _rxORB, sDriverAliasesNodeName, -1, OConfigurationTreeRoot::CM_READONLY);
     205                 :            : 
     206                 :            :                 // loop through all programmatic pairs
     207                 :            :                 DBG_ASSERT( 0 == SAL_N_ELEMENTS( pMappingProgrammatics ) % 2,
     208                 :            :                     "fieldmapping::defaultMapping: invalid programmatic map!" );
     209                 :            :                 // number of pairs
     210                 :          0 :                 sal_Int32 nIntersectedProgrammatics = SAL_N_ELEMENTS( pMappingProgrammatics ) / 2;
     211                 :            : 
     212                 :          0 :                 const sal_Char** pProgrammatic = pMappingProgrammatics;
     213                 :          0 :                 ::rtl::OUString sAddressProgrammatic;
     214                 :          0 :                 ::rtl::OUString sDriverProgrammatic;
     215                 :          0 :                 ::rtl::OUString sDriverUI;
     216                 :          0 :                 for (   sal_Int32 i=0;
     217                 :            :                         i < nIntersectedProgrammatics;
     218                 :            :                         ++i
     219                 :            :                     )
     220                 :            :                 {
     221                 :          0 :                     sAddressProgrammatic = ::rtl::OUString::createFromAscii( *pProgrammatic++ );
     222                 :          0 :                     sDriverProgrammatic = ::rtl::OUString::createFromAscii( *pProgrammatic++ );
     223                 :            : 
     224                 :          0 :                     if ( aDriverFieldAliasing.hasByName( sDriverProgrammatic ) )
     225                 :            :                     {
     226                 :          0 :                         aDriverFieldAliasing.getNodeValue( sDriverProgrammatic ) >>= sDriverUI;
     227                 :          0 :                         if ( 0 == sDriverUI.getLength() )
     228                 :            :                         {
     229                 :            :                             OSL_FAIL( "fieldmapping::defaultMapping: invalid driver UI column name!");
     230                 :            :                         }
     231                 :            :                         else
     232                 :          0 :                             _rFieldAssignment[ sAddressProgrammatic ] = sDriverUI;
     233                 :            :                     }
     234                 :            :                     else
     235                 :            :                     {
     236                 :            :                         OSL_FAIL( "fieldmapping::defaultMapping: invalid driver programmatic name!" );
     237                 :            :                     }
     238                 :          0 :                 }
     239                 :            :             }
     240                 :          0 :             catch( const Exception& )
     241                 :            :             {
     242                 :            :                 OSL_FAIL("fieldmapping::defaultMapping: code is assumed to throw no exceptions!");
     243                 :            :                     // the config nodes we're using herein should not do this ....
     244                 :            :             }
     245                 :          0 :         }
     246                 :            : 
     247                 :            :         //-----------------------------------------------------------------
     248                 :          0 :         void writeTemplateAddressFieldMapping( const Reference< XMultiServiceFactory >& _rxORB, const MapString2String& _rFieldAssignment ) SAL_THROW ( ( ) )
     249                 :            :         {
     250                 :            :             // want to have a non-const map for easier handling
     251                 :          0 :             MapString2String aFieldAssignment( _rFieldAssignment );
     252                 :            : 
     253                 :            :             // access the configuration information which the driver uses for determining it's column names
     254                 :          0 :             const ::rtl::OUString& sAddressBookNodeName = lcl_getAddressBookNodeName();
     255                 :            : 
     256                 :            :             // create a config node for this
     257                 :            :             OConfigurationTreeRoot aAddressBookSettings = OConfigurationTreeRoot::createWithServiceFactory(
     258                 :          0 :                 _rxORB, sAddressBookNodeName, -1, OConfigurationTreeRoot::CM_UPDATABLE);
     259                 :            : 
     260                 :          0 :             OConfigurationNode aFields = aAddressBookSettings.openNode( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Fields" )) );
     261                 :            : 
     262                 :            :             // loop through all existent fields
     263                 :          0 :             Sequence< ::rtl::OUString > aExistentFields = aFields.getNodeNames();
     264                 :          0 :             const ::rtl::OUString* pExistentFields = aExistentFields.getConstArray();
     265                 :          0 :             const ::rtl::OUString* pExistentFieldsEnd = pExistentFields + aExistentFields.getLength();
     266                 :            : 
     267                 :          0 :             const ::rtl::OUString sProgrammaticNodeName(RTL_CONSTASCII_USTRINGPARAM( "ProgrammaticFieldName" ));
     268                 :          0 :             const ::rtl::OUString sAssignedNodeName(RTL_CONSTASCII_USTRINGPARAM( "AssignedFieldName" ));
     269                 :            : 
     270                 :          0 :             for ( ; pExistentFields != pExistentFieldsEnd; ++pExistentFields )
     271                 :            :             {
     272                 :            : #ifdef DBG_UTIL
     273                 :            :                 ::rtl::OUString sRedundantProgrammaticName;
     274                 :            :                 aFields.openNode( *pExistentFields ).getNodeValue( sProgrammaticNodeName ) >>= sRedundantProgrammaticName;
     275                 :            : #endif
     276                 :            :                 DBG_ASSERT( sRedundantProgrammaticName == *pExistentFields,
     277                 :            :                     "fieldmapping::writeTemplateAddressFieldMapping: inconsistent config data!" );
     278                 :            :                     // there should be a redundancy in the config data .... if this asserts, there isn't anymore!
     279                 :            : 
     280                 :            :                 // do we have a new alias for the programmatic?
     281                 :          0 :                 MapString2StringIterator aPos = aFieldAssignment.find( *pExistentFields );
     282                 :          0 :                 if ( aFieldAssignment.end() != aPos )
     283                 :            :                 {   // yes
     284                 :            :                     // -> set a new value
     285                 :          0 :                     OConfigurationNode aExistentField = aFields.openNode( *pExistentFields );
     286                 :          0 :                     aExistentField.setNodeValue( sAssignedNodeName, makeAny( aPos->second ) );
     287                 :            :                     // and remove the mapping entry
     288                 :          0 :                     aFieldAssignment.erase( *pExistentFields );
     289                 :            :                 }
     290                 :            :                 else
     291                 :            :                 {   // no
     292                 :            :                     // -> remove it
     293                 :          0 :                     aFields.removeNode( *pExistentFields );
     294                 :            :                 }
     295                 :            :             }
     296                 :            : 
     297                 :            :             // now everything remaining in aFieldAssignment marks a mapping entry which was not present
     298                 :            :             // in the config before
     299                 :          0 :             for (   ConstMapString2StringIterator aNewMapping = aFieldAssignment.begin();
     300                 :          0 :                     aNewMapping != aFieldAssignment.end();
     301                 :            :                     ++aNewMapping
     302                 :            :                 )
     303                 :            :             {
     304                 :            :                 DBG_ASSERT( !aFields.hasByName( aNewMapping->first ),
     305                 :            :                     "fieldmapping::writeTemplateAddressFieldMapping: inconsistence!" );
     306                 :            :                     // in case the config node for the fields already has the node named <aNewMapping->first>,
     307                 :            :                     // the entry should have been removed from aNewMapping (in the above loop)
     308                 :          0 :                 OConfigurationNode aNewField =  aFields.createNode( aNewMapping->first );
     309                 :          0 :                 aNewField.setNodeValue( sProgrammaticNodeName, makeAny( aNewMapping->first ) );
     310                 :          0 :                 aNewField.setNodeValue( sAssignedNodeName, makeAny( aNewMapping->second ) );
     311                 :          0 :             }
     312                 :            : 
     313                 :            :             // commit the changes done
     314                 :          0 :             aAddressBookSettings.commit();
     315                 :          0 :         }
     316                 :            : 
     317                 :            :     //.....................................................................
     318                 :            :     }   // namespace fieldmapping
     319                 :            :     //.....................................................................
     320                 :            : 
     321                 :            :     //.....................................................................
     322                 :            :     namespace addressconfig
     323                 :            :     {
     324                 :            :     //.....................................................................
     325                 :            : 
     326                 :            :         //-----------------------------------------------------------------
     327                 :          0 :         void writeTemplateAddressSource( const Reference< XMultiServiceFactory >& _rxORB,
     328                 :            :             const ::rtl::OUString& _rDataSourceName, const ::rtl::OUString& _rTableName ) SAL_THROW ( ( ) )
     329                 :            :         {
     330                 :            :             // access the configuration information which the driver uses for determining it's column names
     331                 :          0 :             const ::rtl::OUString& sAddressBookNodeName = lcl_getAddressBookNodeName();
     332                 :            : 
     333                 :            :             // create a config node for this
     334                 :            :             OConfigurationTreeRoot aAddressBookSettings = OConfigurationTreeRoot::createWithServiceFactory(
     335                 :          0 :                 _rxORB, sAddressBookNodeName, -1, OConfigurationTreeRoot::CM_UPDATABLE);
     336                 :            : 
     337                 :          0 :             aAddressBookSettings.setNodeValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "DataSourceName" )), makeAny( _rDataSourceName ) );
     338                 :          0 :             aAddressBookSettings.setNodeValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Command" )), makeAny( _rTableName ) );
     339                 :          0 :             aAddressBookSettings.setNodeValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "CommandType" )), makeAny( (sal_Int32)CommandType::TABLE ) );
     340                 :            : 
     341                 :            :             // commit the changes done
     342                 :          0 :             aAddressBookSettings.commit();
     343                 :          0 :         }
     344                 :            : 
     345                 :            :         //-----------------------------------------------------------------
     346                 :          0 :         void markPilotSuccess( const Reference< XMultiServiceFactory >& _rxORB ) SAL_THROW ( ( ) )
     347                 :            :         {
     348                 :            :             // access the configuration information which the driver uses for determining it's column names
     349                 :          0 :             const ::rtl::OUString& sAddressBookNodeName = lcl_getAddressBookNodeName();
     350                 :            : 
     351                 :            :             // create a config node for this
     352                 :            :             OConfigurationTreeRoot aAddressBookSettings = OConfigurationTreeRoot::createWithServiceFactory(
     353                 :          0 :                 _rxORB, sAddressBookNodeName, -1, OConfigurationTreeRoot::CM_UPDATABLE);
     354                 :            : 
     355                 :            :             // set the flag
     356                 :          0 :             aAddressBookSettings.setNodeValue( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "AutoPilotCompleted" )), makeAny( (sal_Bool)sal_True ) );
     357                 :            : 
     358                 :            :             // commit the changes done
     359                 :          0 :             aAddressBookSettings.commit();
     360                 :          0 :         }
     361                 :            : 
     362                 :            :     //.....................................................................
     363                 :            :     }   // namespace addressconfig
     364                 :            :     //.....................................................................
     365                 :            : 
     366                 :            : //.........................................................................
     367                 :            : }   // namespace abp
     368                 :            : //.........................................................................
     369                 :            : 
     370                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10