radioapp/radiouiengine/src/radiostation.cpp
changeset 32 189d20c34778
parent 28 075425b8d9a4
child 33 11b6825f0862
equal deleted inserted replaced
28:075425b8d9a4 32:189d20c34778
    62 
    62 
    63 const uint DISABLE_LOCAL_AREA_COVERAGE_MASK = 0x0800;
    63 const uint DISABLE_LOCAL_AREA_COVERAGE_MASK = 0x0800;
    64 
    64 
    65 const int PS_NAME_CHANGE_THRESHOLD_SECONDS = 10;
    65 const int PS_NAME_CHANGE_THRESHOLD_SECONDS = 10;
    66 
    66 
       
    67 // Macros to help protect shared null and manual station instances to help debugging
       
    68 // Enabled in emulator or win32 builds by default
       
    69 #if defined __WINS__ || defined BUILD_WIN32
       
    70 #   define PROTECT_SHAREDNULL_AND_MANUALSTATION
       
    71 #endif
       
    72 
       
    73 #ifdef PROTECT_SHAREDNULL_AND_MANUALSTATION
       
    74 #   define ASSERT_SHARED_NULL_IS_INTACT \
       
    75         Q_ASSERT_X( mData->mPresetIndex != SharedNull, "RadioStation", "Shared null modified illegally!" );
       
    76 #   define ASSERT_MANUAL_STATION \
       
    77         Q_ASSERT_X( mData->mPresetIndex != ManualStation, "RadioStation", "Illegally modifying manual station" );
       
    78 #else
       
    79 #   define ASSERT_SHARED_NULL_IS_INTACT
       
    80 #   define ASSERT_MANUAL_STATION
       
    81 #endif // PROTECT_SHAREDNULL_AND_MANUALSTATION
       
    82 
    67 /**
    83 /**
    68  * Static shared data instance that is used by all default-constructed RadioStation instances
    84  * Static shared data instance that is used by all default-constructed RadioStation instances
    69  */
    85  */
    70 Q_GLOBAL_STATIC_WITH_ARGS( RadioStationPrivate, shared_null, ( RadioStation::SharedNull ) )
    86 static RadioStationPrivate shared_null( RadioStation::SharedNull, 0 );
    71 
    87 
    72 /*!
    88 /*!
    73  *
    89  *
    74  */
    90  */
    75 QString RadioStation::parseFrequency( uint frequency )
    91 QString RadioStation::parseFrequency( uint frequency )
    81 
    97 
    82 /*!
    98 /*!
    83  *
    99  *
    84  */
   100  */
    85 RadioStation::RadioStation() :
   101 RadioStation::RadioStation() :
    86     QObject( 0 )
   102     mData( &shared_null )
    87 {
   103 {
    88     mData = shared_null();
       
    89     mData->ref.ref();
       
    90 }
   104 }
    91 
   105 
    92 /*!
   106 /*!
    93  *
   107  *
    94  */
   108  */
    95 RadioStation::RadioStation( const RadioStation& other ) :
   109 RadioStation::RadioStation( const RadioStation& other ) :
    96     QObject( 0 )
   110     mData( other.mData )
       
   111 {
       
   112 }
       
   113 
       
   114 /*!
       
   115  *
       
   116  */
       
   117 RadioStation::RadioStation( int presetIndex, uint frequency ) :
       
   118     mData( new RadioStationPrivate( presetIndex, frequency ) )
       
   119 {
       
   120 }
       
   121 
       
   122 /*!
       
   123  *
       
   124  */
       
   125 RadioStation::~RadioStation()
       
   126 {
       
   127 }
       
   128 
       
   129 /*!
       
   130  *
       
   131  */
       
   132 RadioStation& RadioStation::operator=( const RadioStation& other )
    97 {
   133 {
    98     mData = other.mData;
   134     mData = other.mData;
    99     mData->ref.ref();
       
   100 }
       
   101 
       
   102 /*!
       
   103  *
       
   104  */
       
   105 RadioStation::RadioStation( int presetIndex, uint frequency ) :
       
   106     QObject( 0 )
       
   107 {
       
   108     mData = new RadioStationPrivate( presetIndex, frequency );
       
   109 }
       
   110 
       
   111 /*!
       
   112  *
       
   113  */
       
   114 RadioStation::~RadioStation()
       
   115 {
       
   116     decrementReferenceCount();
       
   117 }
       
   118 
       
   119 /*!
       
   120  *
       
   121  */
       
   122 RadioStation& RadioStation::operator=( const RadioStation& other )
       
   123 {
       
   124     qAtomicAssign( mData, other.mData );
       
   125     return *this;
   135     return *this;
   126 }
   136 }
   127 
   137 
   128 /*!
   138 /*!
   129  *
   139  *
   130  */
   140  */
   131 void RadioStation::reset()
   141 void RadioStation::reset()
   132 {
   142 {
   133     decrementReferenceCount();
   143     mData = &shared_null;
   134     mData = shared_null();
   144     ASSERT_SHARED_NULL_IS_INTACT
   135     mData->ref.ref();
       
   136 }
   145 }
   137 
   146 
   138 /*!
   147 /*!
   139  *
   148  *
   140  */
   149  */
   141 void RadioStation::setChangeFlags( RadioStation::Change flags )
   150 void RadioStation::setChangeFlags( RadioStation::Change flags )
   142 {
   151 {
   143     if ( mData->mChangeFlags != flags ) {
   152     if ( mData->mChangeFlags != flags ) {
   144         detach();
       
   145         mData->mChangeFlags = flags;
   153         mData->mChangeFlags = flags;
   146     }
   154     }
   147 }
   155 }
   148 
   156 
   149 /*!
   157 /*!
   150  *
   158  *
   151  */
   159  */
   152 void RadioStation::setPresetIndex( int presetIndex )
   160 void RadioStation::setPresetIndex( int presetIndex )
   153 {
   161 {
   154     if ( mData->mPresetIndex != presetIndex ) {
   162     if ( mData->mPresetIndex != presetIndex ) {
   155         detach();
   163         ASSERT_MANUAL_STATION
   156         mData->mPresetIndex = presetIndex;
   164         mData->mPresetIndex = presetIndex;
   157         mData->mChangeFlags |= RadioStation::PersistentDataChanged;
   165         mData->mChangeFlags |= RadioStation::PersistentDataChanged;
   158     }
   166     }
   159 }
   167 }
   160 
   168 
   162  *
   170  *
   163  */
   171  */
   164 void RadioStation::setFrequency( uint frequency )
   172 void RadioStation::setFrequency( uint frequency )
   165 {
   173 {
   166     if ( mData->mFrequency != frequency ) {
   174     if ( mData->mFrequency != frequency ) {
   167         detach();
       
   168         mData->mFrequency = frequency;
   175         mData->mFrequency = frequency;
   169         mData->mChangeFlags |= RadioStation::PersistentDataChanged;
   176         mData->mChangeFlags |= RadioStation::PersistentDataChanged;
       
   177         ASSERT_SHARED_NULL_IS_INTACT
   170     }
   178     }
   171 }
   179 }
   172 
   180 
   173 /*!
   181 /*!
   174  * Sets the preset name
   182  * Sets the preset name
   176 void RadioStation::setName( const QString& name )
   184 void RadioStation::setName( const QString& name )
   177 {
   185 {
   178     // Name emptiness is checked because this name setter is used by incoming RDS PS name
   186     // Name emptiness is checked because this name setter is used by incoming RDS PS name
   179     // and empty names should be ignored
   187     // and empty names should be ignored
   180     if ( !name.isEmpty() && !mData->mRenamedByUser && mData->mName.compare( name ) != 0 ) {
   188     if ( !name.isEmpty() && !mData->mRenamedByUser && mData->mName.compare( name ) != 0 ) {
   181         detach();
       
   182         mData->mName = name.trimmed();
   189         mData->mName = name.trimmed();
   183         mData->mChangeFlags |= RadioStation::PersistentDataChanged | RadioStation::NameChanged;
   190         mData->mChangeFlags |= RadioStation::PersistentDataChanged | RadioStation::NameChanged;
   184 
   191 
   185         // Save the time when PS name changed and if the last change was too close to the current time
   192         // Save the time when PS name changed and if the last change was too close to the current time
   186         // change the PS type to dynamic if it has already been incorrectly determined to be static.
   193         // change the PS type to dynamic if it has already been incorrectly determined to be static.
   201             mData->mUrl = "<a href=\"buu\">www." + mData->mName.toLower() + ".fi</a>";
   208             mData->mUrl = "<a href=\"buu\">www." + mData->mName.toLower() + ".fi</a>";
   202         } else {
   209         } else {
   203             mData->mUrl = "";
   210             mData->mUrl = "";
   204         }
   211         }
   205         mData->mChangeFlags |= RadioStation::UrlChanged;
   212         mData->mChangeFlags |= RadioStation::UrlChanged;
       
   213         ASSERT_SHARED_NULL_IS_INTACT
   206     }
   214     }
   207 }
   215 }
   208 
   216 
   209 /*!
   217 /*!
   210  *
   218  *
   211  */
   219  */
   212 void RadioStation::setGenre( const int genre )
   220 void RadioStation::setGenre( const int genre )
   213 {
   221 {
   214     if ( mData->mGenre != genre ) {
   222     if ( mData->mGenre != genre ) {
   215         detach();
       
   216         mData->mGenre = genre;
   223         mData->mGenre = genre;
   217         mData->mChangeFlags |= RadioStation::PersistentDataChanged | RadioStation::GenreChanged;
   224         mData->mChangeFlags |= RadioStation::PersistentDataChanged | RadioStation::GenreChanged;
       
   225         ASSERT_SHARED_NULL_IS_INTACT
   218     }
   226     }
   219 }
   227 }
   220 
   228 
   221 /*!
   229 /*!
   222  *
   230  *
   223  */
   231  */
   224 void RadioStation::setUrl( const QString& url )
   232 void RadioStation::setUrl( const QString& url )
   225 {
   233 {
   226     if ( mData->mUrl.compare( url ) != 0 ) {
   234     if ( mData->mUrl.compare( url ) != 0 ) {
   227         detach();
       
   228         mData->mUrl = url;
   235         mData->mUrl = url;
   229         mData->mChangeFlags |= RadioStation::PersistentDataChanged | RadioStation::UrlChanged;
   236         mData->mChangeFlags |= RadioStation::PersistentDataChanged | RadioStation::UrlChanged;
       
   237         ASSERT_SHARED_NULL_IS_INTACT
   230     }
   238     }
   231 }
   239 }
   232 
   240 
   233 /*!
   241 /*!
   234  * Sets the PI code
   242  * Sets the PI code
   236  */
   244  */
   237 bool RadioStation::setPiCode( int piCode, RadioRegion::Region region )
   245 bool RadioStation::setPiCode( int piCode, RadioRegion::Region region )
   238 {
   246 {
   239     LOG_FORMAT( "RadioStation::setPiCode new PI: %d", piCode );
   247     LOG_FORMAT( "RadioStation::setPiCode new PI: %d", piCode );
   240     // toggling local area coverage bit code must not be interpreted as new PI code
   248     // toggling local area coverage bit code must not be interpreted as new PI code
   241     if( region != RadioRegion::America )
   249     if ( region != RadioRegion::America ) {
   242     {
       
   243         piCode &= ~DISABLE_LOCAL_AREA_COVERAGE_MASK;
   250         piCode &= ~DISABLE_LOCAL_AREA_COVERAGE_MASK;
   244     }
   251     }
   245 
   252 
   246     LOG_FORMAT( "stored PI: %d", mData->mPiCode );
   253     LOG_FORMAT( "stored PI: %d", mData->mPiCode );
   247     LOG_FORMAT( "call sign check done: %d", mData->mCallSignCheckDone );
   254     LOG_FORMAT( "call sign check done: %d", mData->mCallSignCheckDone );
   248     //prevent executing the below code when unnessesary
   255     //prevent executing the below code when unnessesary
   249     if ( mData->mPiCode != piCode || !mData->mCallSignCheckDone )
   256     if ( mData->mPiCode != piCode || !mData->mCallSignCheckDone ) {
   250 	{
       
   251         detach();
       
   252         mData->mPiCode = piCode;
   257         mData->mPiCode = piCode;
   253         mData->mChangeFlags |= RadioStation::PersistentDataChanged | RadioStation::PiCodeChanged;
   258         mData->mChangeFlags |= RadioStation::PersistentDataChanged | RadioStation::PiCodeChanged;
   254         // call sign not calculated for clear channel stations
   259         // call sign not calculated for clear channel stations
   255 		//TODO: Remove magic numbers
   260 		//TODO: Remove magic numbers
   256         if( ( (mData->mPiCode & 0xF000 ) >> 12 ) == 0x1 )
   261         if ( ( (mData->mPiCode & 0xF000 ) >> 12 ) == 0x1 ) {
   257         {
       
   258             LOG( "Clear channel station" );
   262             LOG( "Clear channel station" );
   259             mData->mCallSignCheckDone = true;
   263             mData->mCallSignCheckDone = true;
   260         }
   264         } else if ( region == RadioRegion::America && mData->mName.isEmpty() && !isRenamed() ) {
   261 		// if America region, not PS name received and not user renamed station
       
   262         else if ( region == RadioRegion::America && mData->mName.isEmpty() && !isRenamed() )
       
   263         {
       
   264             LOG( "Calculate call sign" );
   265             LOG( "Calculate call sign" );
   265             mData->mName = piCodeToCallSign( mData->mPiCode );
   266             mData->mName = piCodeToCallSign( mData->mPiCode );
   266             mData->mChangeFlags |= RadioStation::NameChanged;
   267             mData->mChangeFlags |= RadioStation::NameChanged;
   267         }
   268         }
   268 
   269 
   269         if ( mData->mChangeFlags.testFlag( RadioStation::PsTypeChanged ) )
   270         if ( mData->mChangeFlags.testFlag( RadioStation::PsTypeChanged ) ) {
   270 		{
       
   271             LOG( "Call sign check done" );
   271             LOG( "Call sign check done" );
   272             mData->mCallSignCheckDone = true;
   272             mData->mCallSignCheckDone = true;
   273         }
   273         }
   274 
   274 
       
   275         ASSERT_SHARED_NULL_IS_INTACT
   275         return true;
   276         return true;
   276     }
   277     }
   277     return false;
   278     return false;
   278 }
   279 }
   279 
   280 
   281  *
   282  *
   282  */
   283  */
   283 void RadioStation::setPsType( PsType psType )
   284 void RadioStation::setPsType( PsType psType )
   284 {
   285 {
   285     if ( mData->mPsType != psType ) {
   286     if ( mData->mPsType != psType ) {
   286         detach();
       
   287         mData->mPsType = psType;
   287         mData->mPsType = psType;
   288         mData->mChangeFlags |= RadioStation::PsTypeChanged;
   288         mData->mChangeFlags |= RadioStation::PsTypeChanged;
       
   289         ASSERT_SHARED_NULL_IS_INTACT
   289     }
   290     }
   290 }
   291 }
   291 
   292 
   292 /*!
   293 /*!
   293  *
   294  *
   294  */
   295  */
   295 void RadioStation::setRadioText( const QString& radioText )
   296 void RadioStation::setRadioText( const QString& radioText )
   296 {
   297 {
   297     if ( mData->mRadioText.compare( radioText ) != 0 ) {
   298     if ( mData->mRadioText.compare( radioText ) != 0 ) {
   298         detach();
       
   299         mData->mRadioText = radioText.isEmpty() ? "" : radioText.trimmed();
   299         mData->mRadioText = radioText.isEmpty() ? "" : radioText.trimmed();
   300         mData->mChangeFlags |= RadioStation::RadioTextChanged;
   300         mData->mChangeFlags |= RadioStation::RadioTextChanged;
       
   301         ASSERT_SHARED_NULL_IS_INTACT
   301     }
   302     }
   302 }
   303 }
   303 
   304 
   304 /*!
   305 /*!
   305  *
   306  *
   314         if ( rtPlusClass == RtPlus::Homepage ) {
   315         if ( rtPlusClass == RtPlus::Homepage ) {
   315             setUrl( rtPlusItem );
   316             setUrl( rtPlusItem );
   316             return;
   317             return;
   317         }
   318         }
   318 
   319 
   319         detach();
       
   320         QString replacement = "";
   320         QString replacement = "";
   321         if ( rtPlusClass == RtPlus::Artist ) {
   321         if ( rtPlusClass == RtPlus::Artist ) {
   322             replacement = HTML_ARTIST;
   322             replacement = HTML_ARTIST;
   323         } else if ( rtPlusClass == RtPlus::Title ) {
   323         } else if ( rtPlusClass == RtPlus::Title ) {
   324             replacement = HTML_TITLE;
   324             replacement = HTML_TITLE;
   334  *
   334  *
   335  */
   335  */
   336 void RadioStation::setDynamicPsText( const QString& dynamicPsText )
   336 void RadioStation::setDynamicPsText( const QString& dynamicPsText )
   337 {
   337 {
   338     if ( mData->mDynamicPsText.compare( dynamicPsText ) != 0 ) {
   338     if ( mData->mDynamicPsText.compare( dynamicPsText ) != 0 ) {
   339         detach();
       
   340         mData->mDynamicPsText = dynamicPsText;
   339         mData->mDynamicPsText = dynamicPsText;
   341         mData->mChangeFlags |= RadioStation::DynamicPsChanged;
   340         mData->mChangeFlags |= RadioStation::DynamicPsChanged;
       
   341         ASSERT_SHARED_NULL_IS_INTACT
   342     }
   342     }
   343 }
   343 }
   344 
   344 
   345 /*!
   345 /*!
   346  *
   346  *
   347  */
   347  */
   348 bool RadioStation::isValid() const
   348 bool RadioStation::isValid() const
   349 {
   349 {
   350     return mData->mPresetIndex >= 0 && mData->mFrequency > 0;
   350     return mData->mFrequency > 0 && ( isType( ManualStation ) || mData->mPresetIndex >= 0 );
   351 }
   351 }
   352 
   352 
   353 /*!
   353 /*!
   354  *
   354  *
   355  */
   355  */
   364 void RadioStation::setUserDefinedName( const QString& name )
   364 void RadioStation::setUserDefinedName( const QString& name )
   365 {
   365 {
   366     // We don't check for name emptiness because this setter is used also to remove the renaming
   366     // We don't check for name emptiness because this setter is used also to remove the renaming
   367     // of a station by setting an empty name
   367     // of a station by setting an empty name
   368     if ( mData->mName.compare( name ) != 0 ) {
   368     if ( mData->mName.compare( name ) != 0 ) {
   369         detach();
       
   370         mData->mName = name;
   369         mData->mName = name;
   371         mData->mRenamedByUser = !name.isEmpty();
   370         mData->mRenamedByUser = !name.isEmpty();
   372         mData->mChangeFlags |= RadioStation::PersistentDataChanged | RadioStation::NameChanged;
   371         mData->mChangeFlags |= RadioStation::PersistentDataChanged | RadioStation::NameChanged;
   373     }
   372     }
   374 }
   373 }
   390 }
   389 }
   391 
   390 
   392 /*!
   391 /*!
   393  *
   392  *
   394  */
   393  */
   395 QString RadioStation::frequencyMhz() const
   394 QString RadioStation::frequencyString() const
   396 {
   395 {
   397     return qtTrId( "txt_rad_list_l1_mhz_big" ).arg( parseFrequency( mData->mFrequency ) );
   396     return parseFrequency( mData->mFrequency );
   398 }
       
   399 
       
   400 /*!
       
   401  *
       
   402  */
       
   403 QString RadioStation::nameOrFrequencyMhz() const
       
   404 {
       
   405     if ( !mData->mName.isEmpty() ) {
       
   406         return mData->mName;
       
   407     }
       
   408     return frequencyMhz();
       
   409 }
   397 }
   410 
   398 
   411 /*!
   399 /*!
   412  *
   400  *
   413  */
   401  */
   428  *
   416  *
   429  */
   417  */
   430 void RadioStation::setFavorite( bool favorite )
   418 void RadioStation::setFavorite( bool favorite )
   431 {
   419 {
   432     if ( isFavorite() != favorite ) {
   420     if ( isFavorite() != favorite ) {
   433         detach();
       
   434         favorite ? setType( RadioStation::Favorite ) : unsetType( RadioStation::Favorite );
   421         favorite ? setType( RadioStation::Favorite ) : unsetType( RadioStation::Favorite );
   435         mData->mChangeFlags |= RadioStation::PersistentDataChanged | RadioStation::FavoriteChanged;
   422         mData->mChangeFlags |= RadioStation::PersistentDataChanged | RadioStation::FavoriteChanged;
       
   423         ASSERT_SHARED_NULL_IS_INTACT
   436     }
   424     }
   437 }
   425 }
   438 
   426 
   439 /*!
   427 /*!
   440  *
   428  *
   464  *
   452  *
   465  */
   453  */
   466 bool RadioStation::hasRds() const
   454 bool RadioStation::hasRds() const
   467 {
   455 {
   468     return hasPiCode() ||
   456     return hasPiCode() ||
   469             mData->mGenre != -1 ||
   457         mData->mGenre != -1 ||
   470             !mData->mDynamicPsText.isEmpty() ||
   458         !mData->mDynamicPsText.isEmpty() ||
   471             !mData->mRadioText.isEmpty() ||
   459         !mData->mRadioText.isEmpty() ||
   472             ( !mData->mName.isEmpty() && !isRenamed() );
   460         ( !mData->mName.isEmpty() && !isRenamed() );
   473 }
   461 }
   474 
   462 
   475 /*!
   463 /*!
   476  *
   464  *
   477  */
   465  */
   478 void RadioStation::setType( RadioStation::Type type )
   466 void RadioStation::setType( RadioStation::Type type )
   479 {
   467 {
   480     if ( !isType( type ) ) {
   468     if ( !isType( type ) ) {
   481         detach();
       
   482 
   469 
   483         // Check if favorite-status changed
   470         // Check if favorite-status changed
   484         if ( mData->mType.testFlag( RadioStation::Favorite ) != type.testFlag( RadioStation::Favorite ) ) {
   471         if ( mData->mType.testFlag( RadioStation::Favorite ) != type.testFlag( RadioStation::Favorite ) ) {
   485             mData->mChangeFlags |= RadioStation::FavoriteChanged;
   472             mData->mChangeFlags |= RadioStation::FavoriteChanged;
   486         }
   473         }
   487 
   474 
   488         mData->mType |= type;
   475         mData->mType |= type;
   489         mData->mChangeFlags |= RadioStation::PersistentDataChanged | RadioStation::TypeChanged;
   476         mData->mChangeFlags |= RadioStation::PersistentDataChanged | RadioStation::TypeChanged;
       
   477         ASSERT_SHARED_NULL_IS_INTACT
   490     }
   478     }
   491 }
   479 }
   492 
   480 
   493 /*!
   481 /*!
   494  *
   482  *
   495  */
   483  */
   496 void RadioStation::unsetType( RadioStation::Type type )
   484 void RadioStation::unsetType( RadioStation::Type type )
   497 {
   485 {
   498     if ( isType( type ) ) {
   486     if ( isType( type ) ) {
   499         detach();
       
   500 
   487 
   501         // Check if favorite-status changed
   488         // Check if favorite-status changed
   502         if ( mData->mType.testFlag( RadioStation::Favorite ) != type.testFlag( RadioStation::Favorite ) ) {
   489         if ( mData->mType.testFlag( RadioStation::Favorite ) != type.testFlag( RadioStation::Favorite ) ) {
   503             mData->mChangeFlags |= RadioStation::FavoriteChanged;
   490             mData->mChangeFlags |= RadioStation::FavoriteChanged;
   504         }
   491         }
   505 
   492 
   506         mData->mType &= ~type;
   493         mData->mType &= ~type;
   507         mData->mChangeFlags |= RadioStation::PersistentDataChanged | RadioStation::TypeChanged;
   494         mData->mChangeFlags |= RadioStation::PersistentDataChanged | RadioStation::TypeChanged;
       
   495         ASSERT_SHARED_NULL_IS_INTACT
   508     }
   496     }
   509 }
   497 }
   510 
   498 
   511 /*!
   499 /*!
   512  *
   500  *
   568  *
   556  *
   569  */
   557  */
   570 void RadioStation::resetChangeFlags()
   558 void RadioStation::resetChangeFlags()
   571 {
   559 {
   572     if ( mData->mChangeFlags != RadioStation::NoChange ) {
   560     if ( mData->mChangeFlags != RadioStation::NoChange ) {
   573         detach();
       
   574         mData->mChangeFlags = RadioStation::NoChange;
   561         mData->mChangeFlags = RadioStation::NoChange;
   575     }
       
   576 }
       
   577 
       
   578 /**
       
   579  * Decrements the reference count of the implicitly shared data.
       
   580  */
       
   581 void RadioStation::decrementReferenceCount()
       
   582 {
       
   583     if ( !mData->ref.deref() ) {
       
   584         delete mData;
       
   585         mData = 0;
       
   586     }
   562     }
   587 }
   563 }
   588 
   564 
   589 /*!
   565 /*!
   590  *
   566  *
   593  {
   569  {
   594     QString callSign;
   570     QString callSign;
   595 
   571 
   596     LOG_FORMAT( "RadioStation::piCodeToCallSign PI: %d", programmeIdentification );
   572     LOG_FORMAT( "RadioStation::piCodeToCallSign PI: %d", programmeIdentification );
   597     // call signs beginning with 'K'
   573     // call signs beginning with 'K'
   598     if( ( programmeIdentification>=KXXX_CALLSIGN_PI_FIRST ) && ( programmeIdentification < WXXX_CALLSIGN_PI_FIRST ) ) {
   574     if ( ( programmeIdentification>=KXXX_CALLSIGN_PI_FIRST ) && ( programmeIdentification < WXXX_CALLSIGN_PI_FIRST ) ) {
   599         callSign += "K";
   575         callSign += "K";
   600         callSign += iterateCallSign( KXXX_CALLSIGN_PI_FIRST, programmeIdentification );
   576         callSign += iterateCallSign( KXXX_CALLSIGN_PI_FIRST, programmeIdentification );
   601     }
   577     }
   602     // call signs beginning with 'W'
   578     // call signs beginning with 'W'
   603     else if (( programmeIdentification >= WXXX_CALLSIGN_PI_FIRST ) && ( programmeIdentification <= WXXX_CALLSIGN_PI_LAST )) {
   579     else if ( ( programmeIdentification >= WXXX_CALLSIGN_PI_FIRST ) && ( programmeIdentification <= WXXX_CALLSIGN_PI_LAST ) ) {
   604         callSign += "W";
   580         callSign += "W";
   605         callSign += iterateCallSign( WXXX_CALLSIGN_PI_FIRST, programmeIdentification );
   581         callSign += iterateCallSign( WXXX_CALLSIGN_PI_FIRST, programmeIdentification );
   606     }
   582     }
   607     // 3 letter only call signs
   583     // 3 letter only call signs
   608     else if(( programmeIdentification >= XXX_CALLSIGN_PI_FIRST ) && ( programmeIdentification <= XXX_CALLSIGN_PI_LAST)) {
   584     else if ( ( programmeIdentification >= XXX_CALLSIGN_PI_FIRST ) && ( programmeIdentification <= XXX_CALLSIGN_PI_LAST ) ) {
   609         callSign += callSignString( programmeIdentification );
   585         callSign += callSignString( programmeIdentification );
   610     }
   586     } else {
   611     else
       
   612     {
       
   613         LOG( "RadioStation::piCodeToCallSign - Unhandled else" );
   587         LOG( "RadioStation::piCodeToCallSign - Unhandled else" );
   614     }
   588     }
   615 
   589 
   616     LOG_FORMAT( "RadioStation::piCodeToCallSign, call sign: %s", GETSTRING(callSign) );
   590     LOG_FORMAT( "RadioStation::piCodeToCallSign, call sign: %s", GETSTRING(callSign) );
   617 
   591 
   624 QString RadioStation::iterateCallSign( int piBase, int programmeIdentification )
   598 QString RadioStation::iterateCallSign( int piBase, int programmeIdentification )
   625 {
   599 {
   626     QString callSign;
   600     QString callSign;
   627     LOG_FORMAT( "RadioStation::iterateCallSign base: %d", piBase );
   601     LOG_FORMAT( "RadioStation::iterateCallSign base: %d", piBase );
   628 
   602 
   629     int sum(0), i(0);
   603     int sum = 0;
   630 
   604     int i = 0;
   631     while( sum < programmeIdentification ) {
   605     while( sum < programmeIdentification ) {
   632         i++;
   606         ++i;
   633         sum = piBase + i * 676 + 0 + 0;
   607         sum = piBase + i * 676 + 0 + 0;
   634     }
   608     }
   635     callSign += callSignChar( i - 1 );
   609     callSign += callSignChar( i - 1 );
   636 
   610 
   637     int tmpSum( sum - 676 );
   611     int tmpSum( sum - 676 );
   638     sum -= 676;
   612     sum -= 676;
   639     i = 0;
   613     i = 0;
   640     while( sum <= programmeIdentification ) {
   614     while( sum <= programmeIdentification ) {
   641         i++;
   615         ++i;
   642         sum = tmpSum + 0 + i * 26 + 0;
   616         sum = tmpSum + 0 + i * 26 + 0;
   643     }
   617     }
   644     callSign += callSignChar( i - 1 );
   618     callSign += callSignChar( i - 1 );
   645 
   619 
   646     tmpSum = sum - 26;
   620     tmpSum = sum - 26;
   647     sum -= 26;
   621     sum -= 26;
   648     i = 0;
   622     i = 0;
   649     while( sum <= programmeIdentification ) {
   623     while( sum <= programmeIdentification ) {
   650         i++;
   624         ++i;
   651         sum = tmpSum + 0 + 0 + i;
   625         sum = tmpSum + 0 + 0 + i;
   652     }
   626     }
   653     callSign += callSignChar( i - 1 );
   627     callSign += callSignChar( i - 1 );
   654 
   628 
   655     return callSign;
   629     return callSign;
   666         }
   640         }
   667     }
   641     }
   668 
   642 
   669     LOG_FORMAT( "RadioStation::callSignString, Not found PI: %d", programmeIdentification );
   643     LOG_FORMAT( "RadioStation::callSignString, Not found PI: %d", programmeIdentification );
   670 
   644 
   671     return QString("????");
   645     return QString( "????" );
   672 }
   646 }
   673 
   647 
   674 /*!
   648 /*!
   675  *
   649  *
   676  */
   650  */
   682     }
   656     }
   683     return '?';
   657     return '?';
   684 }
   658 }
   685 
   659 
   686 /**
   660 /**
   687  * Detach from the implicitly shared data
       
   688  */
       
   689 void RadioStation::detach()
       
   690 {
       
   691     if ( !isDetached() ) {
       
   692         RadioStationPrivate* newData = new RadioStationPrivate( *mData );
       
   693 
       
   694         decrementReferenceCount();
       
   695 
       
   696         newData->ref = 1;
       
   697         mData = newData;
       
   698 
       
   699         // The shared null instance of the data has its preset index set to -200 (RadioStation::SharedNull).
       
   700         // We change the preset index of the detached data to -100 (RadioStation::Invalid) just to ease
       
   701         // debugging. This guarantees that the only instance that has value -200 is the actual shared null.
       
   702         #ifdef _DEBUG
       
   703         if ( mData->mPresetIndex == RadioStation::SharedNull ) {
       
   704             mData->mPresetIndex = RadioStation::Invalid;
       
   705         }
       
   706         #endif
       
   707     }
       
   708 }
       
   709 
       
   710 /**
       
   711  * Checks if the class is detached from implicitly shared data
   661  * Checks if the class is detached from implicitly shared data
   712  */
   662  */
   713 bool RadioStation::isDetached() const
   663 bool RadioStation::isDetached() const
   714 {
   664 {
   715     return mData->ref == 1;
   665     return mData->ref == 1;