1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_dbmm.hxx" 26 27 #include "progressmixer.hxx" 28 29 /** === begin UNO includes === **/ 30 /** === end UNO includes === **/ 31 32 #include <osl/diagnose.h> 33 34 #include <map> 35 36 //........................................................................ 37 namespace dbmm 38 { 39 //........................................................................ 40 41 /** === begin UNO using === **/ 42 /** === end UNO using === **/ 43 44 #define OVERALL_RANGE 100000 45 46 //==================================================================== 47 //= misc types 48 //==================================================================== 49 struct PhaseData 50 { 51 // the weight of the phase, relative to all other phases 52 PhaseWeight nWeight; 53 // the "local" range of the phase 54 sal_uInt32 nRange; 55 // this is the point in the "overall range" at which this phase starts 56 sal_uInt32 nGlobalStart; 57 /** the "global" range of the phase, i.e. its range after weighting with all other 58 phases 59 */ 60 sal_uInt32 nGlobalRange; 61 PhaseDatadbmm::PhaseData62 PhaseData() 63 :nWeight(1) 64 ,nRange(100) 65 ,nGlobalStart(0) 66 ,nGlobalRange(100) 67 { 68 } 69 PhaseDatadbmm::PhaseData70 PhaseData( const PhaseWeight _nWeight ) 71 :nWeight( _nWeight ) 72 ,nRange(100) 73 ,nGlobalStart(0) 74 ,nGlobalRange(100) 75 { 76 } 77 }; 78 79 typedef ::std::map< PhaseID, PhaseData > Phases; 80 81 //==================================================================== 82 //= ProgressMixer_Data 83 //==================================================================== 84 struct ProgressMixer_Data 85 { 86 Phases aPhases; 87 Phases::iterator pCurrentPhase; 88 sal_uInt32 nWeightSum; /// the cached sum of the weights 89 double nOverallStretch; 90 IProgressConsumer& rConsumer; 91 ProgressMixer_Datadbmm::ProgressMixer_Data92 ProgressMixer_Data( IProgressConsumer& _rConsumer ) 93 :aPhases() 94 ,pCurrentPhase( aPhases.end() ) 95 ,nWeightSum( 0 ) 96 ,nOverallStretch( 0 ) 97 ,rConsumer( _rConsumer ) 98 { 99 } 100 }; 101 102 //-------------------------------------------------------------------- 103 namespace 104 { 105 #if OSL_DEBUG_LEVEL > 0 106 //---------------------------------------------------------------- lcl_isRunning(const ProgressMixer_Data & _rData)107 bool lcl_isRunning( const ProgressMixer_Data& _rData ) 108 { 109 return _rData.pCurrentPhase != _rData.aPhases.end(); 110 } 111 #endif 112 //---------------------------------------------------------------- lcl_ensureInitialized(ProgressMixer_Data & _rData)113 void lcl_ensureInitialized( ProgressMixer_Data& _rData ) 114 { 115 OSL_PRECOND( _rData.nWeightSum, "lcl_ensureInitialized: we have no phases, this will crash!" ); 116 117 if ( _rData.nOverallStretch ) 118 return; 119 120 _rData.nOverallStretch = 1.0 * OVERALL_RANGE / _rData.nWeightSum; 121 122 // tell the single phases their "overall starting point" 123 PhaseWeight nRunningWeight( 0 ); 124 for ( Phases::iterator phase = _rData.aPhases.begin(); 125 phase != _rData.aPhases.end(); 126 ++phase 127 ) 128 { 129 phase->second.nGlobalStart = (sal_uInt32)( nRunningWeight * _rData.nOverallStretch ); 130 nRunningWeight += phase->second.nWeight; 131 132 sal_uInt32 nNextPhaseStart = (sal_uInt32)( nRunningWeight * _rData.nOverallStretch ); 133 phase->second.nGlobalRange = nNextPhaseStart - phase->second.nGlobalStart; 134 } 135 136 _rData.rConsumer.start( OVERALL_RANGE ); 137 } 138 } 139 140 //==================================================================== 141 //= ProgressMixer 142 //==================================================================== 143 //-------------------------------------------------------------------- ProgressMixer(IProgressConsumer & _rConsumer)144 ProgressMixer::ProgressMixer( IProgressConsumer& _rConsumer ) 145 :m_pData( new ProgressMixer_Data( _rConsumer ) ) 146 { 147 } 148 149 //-------------------------------------------------------------------- ~ProgressMixer()150 ProgressMixer::~ProgressMixer() 151 { 152 } 153 154 //-------------------------------------------------------------------- registerPhase(const PhaseID _nID,const PhaseWeight _nWeight)155 void ProgressMixer::registerPhase( const PhaseID _nID, const PhaseWeight _nWeight ) 156 { 157 OSL_PRECOND( !lcl_isRunning( *m_pData ), "ProgressMixer::registerPhase: already running!" ); 158 OSL_ENSURE( m_pData->aPhases.find( _nID ) == m_pData->aPhases.end(), 159 "ProgressMixer::registerPhase: ID already used!" ); 160 m_pData->aPhases[ _nID ] = PhaseData( _nWeight ); 161 m_pData->nWeightSum += _nWeight; 162 } 163 164 //-------------------------------------------------------------------- startPhase(const PhaseID _nID,const sal_uInt32 _nPhaseRange)165 void ProgressMixer::startPhase( const PhaseID _nID, const sal_uInt32 _nPhaseRange ) 166 { 167 OSL_ENSURE( m_pData->aPhases.find( _nID ) != m_pData->aPhases.end(), 168 "ProgresMixer::startPhase: unknown phase!" ); 169 170 m_pData->aPhases[ _nID ].nRange = _nPhaseRange; 171 m_pData->pCurrentPhase = m_pData->aPhases.find( _nID ); 172 } 173 174 //-------------------------------------------------------------------- advancePhase(const sal_uInt32 _nPhaseProgress)175 void ProgressMixer::advancePhase( const sal_uInt32 _nPhaseProgress ) 176 { 177 OSL_PRECOND( lcl_isRunning( *m_pData ), "ProgresMixer::advancePhase: not running!" ); 178 179 // in case this is the first call, ensure all the ranges/weights are calculated 180 // correctly 181 lcl_ensureInitialized( *m_pData ); 182 183 const PhaseData& rPhase( m_pData->pCurrentPhase->second ); 184 185 double nLocalProgress = 1.0 * _nPhaseProgress / rPhase.nRange; 186 sal_uInt32 nOverallProgress = (sal_uInt32) 187 ( rPhase.nGlobalStart + nLocalProgress * rPhase.nGlobalRange ); 188 189 m_pData->rConsumer.advance( nOverallProgress ); 190 } 191 192 //-------------------------------------------------------------------- endPhase()193 void ProgressMixer::endPhase() 194 { 195 OSL_PRECOND( lcl_isRunning( *m_pData ), "ProgresMixer::endPhase: not running!" ); 196 197 // in case this is the first call, ensure all the ranges/weights are calculated 198 // correctly 199 lcl_ensureInitialized( *m_pData ); 200 201 // simply assume the phase's complete range is over 202 advancePhase( m_pData->pCurrentPhase->second.nRange ); 203 204 // if that's the last phase, this is the "global end", too 205 Phases::const_iterator pNextPhase( m_pData->pCurrentPhase ); 206 ++pNextPhase; 207 if ( pNextPhase == m_pData->aPhases.end() ) 208 m_pData->rConsumer.end(); 209 } 210 211 //........................................................................ 212 } // namespace dbmm 213 //........................................................................ 214