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 #include "conditionalexpression.hxx" 25 26 /** === begin UNO includes === **/ 27 /** === end UNO includes === **/ 28 29 //........................................................................ 30 namespace rptui 31 { 32 //........................................................................ 33 34 /** === begin UNO using === **/ 35 /** === end UNO using === **/ 36 37 // ============================================================================= 38 // = ConditionalExpression 39 // ============================================================================= 40 // ----------------------------------------------------------------------------- ConditionalExpression(const sal_Char * _pAsciiPattern)41 ConditionalExpression::ConditionalExpression( const sal_Char* _pAsciiPattern ) 42 :m_sPattern( ::rtl::OUString::createFromAscii( _pAsciiPattern ) ) 43 { 44 } 45 46 // ----------------------------------------------------------------------------- assembleExpression(const::rtl::OUString & _rFieldDataSource,const::rtl::OUString & _rLHS,const::rtl::OUString & _rRHS) const47 ::rtl::OUString ConditionalExpression::assembleExpression( const ::rtl::OUString& _rFieldDataSource, const ::rtl::OUString& _rLHS, const ::rtl::OUString& _rRHS ) const 48 { 49 ::rtl::OUString sExpression( m_sPattern ); 50 51 sal_Int32 nPatternIndex = sExpression.indexOf( '$' ); 52 while ( nPatternIndex > -1 ) 53 { 54 const ::rtl::OUString* pReplace = NULL; 55 switch ( sExpression.getStr()[ nPatternIndex + 1 ] ) 56 { 57 case '$': pReplace = &_rFieldDataSource; break; 58 case '1': pReplace = &_rLHS; break; 59 case '2': pReplace = &_rRHS; break; 60 default: break; 61 } 62 63 if ( pReplace == NULL ) 64 { 65 OSL_ENSURE( false, "ConditionalExpression::assembleExpression: illegal pattern!" ); 66 break; 67 } 68 69 sExpression = sExpression.replaceAt( nPatternIndex, 2, *pReplace ); 70 nPatternIndex = sExpression.indexOf( '$', nPatternIndex + pReplace->getLength() + 1 ); 71 } 72 return sExpression; 73 } 74 75 // ----------------------------------------------------------------------------- matchExpression(const::rtl::OUString & _rExpression,const::rtl::OUString & _rFieldDataSource,::rtl::OUString & _out_rLHS,::rtl::OUString & _out_rRHS) const76 bool ConditionalExpression::matchExpression( const ::rtl::OUString& _rExpression, const ::rtl::OUString& _rFieldDataSource, ::rtl::OUString& _out_rLHS, ::rtl::OUString& _out_rRHS ) const 77 { 78 (void)_rExpression; 79 (void)_rFieldDataSource; 80 (void)_out_rLHS; 81 (void)_out_rRHS; 82 83 // if we had regular expression, the matching would be pretty easy ... 84 // just replace $1 and $2 in the pattern with (.*), and then get them with \1 resp. \2. 85 // Unfortunately, we don't have such a regexp engine ... 86 87 // Okay, let's start with replacing all $$ in our pattern with the actual field data source 88 ::rtl::OUString sMatchExpression( m_sPattern ); 89 const ::rtl::OUString sFieldDataPattern( RTL_CONSTASCII_USTRINGPARAM( "$$" ) ); 90 sal_Int32 nIndex( sMatchExpression.indexOf( sFieldDataPattern ) ); 91 while ( nIndex != -1 ) 92 { 93 sMatchExpression = sMatchExpression.replaceAt( nIndex, sFieldDataPattern.getLength(), _rFieldDataSource ); 94 nIndex = sMatchExpression.indexOf( sFieldDataPattern, nIndex + _rFieldDataSource.getLength() ); 95 } 96 97 const ::rtl::OUString sLHSPattern( RTL_CONSTASCII_USTRINGPARAM( "$1" ) ); 98 const ::rtl::OUString sRHSPattern( RTL_CONSTASCII_USTRINGPARAM( "$2" ) ); 99 sal_Int32 nLHSIndex( sMatchExpression.indexOf( sLHSPattern ) ); 100 sal_Int32 nRHSIndex( sMatchExpression.indexOf( sRHSPattern ) ); 101 102 // now we should have at most one occurance of $1 and $2, resp. 103 OSL_ENSURE( sMatchExpression.indexOf( sLHSPattern, nLHSIndex + 1 ) == -1, 104 "ConditionalExpression::matchExpression: unsupported pattern (more than one LHS occurance)!" ); 105 OSL_ENSURE( sMatchExpression.indexOf( sRHSPattern, nRHSIndex + 1 ) == -1, 106 "ConditionalExpression::matchExpression: unsupported pattern (more than one RHS occurance)!" ); 107 // Also, an LHS must be present, and precede the RHS (if present) 108 OSL_ENSURE( ( nLHSIndex != -1 ) && ( ( nLHSIndex < nRHSIndex ) || ( nRHSIndex == -1 ) ), 109 "ConditionalExpression::matchExpression: no LHS, or an RHS preceeding the LHS - this is not supported!" ); 110 111 // up to the occurance of the LHS (which must exist, see above), the two expressions 112 // must be identical 113 if ( _rExpression.getLength() < nLHSIndex ) 114 return false; 115 const ::rtl::OUString sExprPart1( _rExpression.copy( 0, nLHSIndex ) ); 116 const ::rtl::OUString sMatchExprPart1( sMatchExpression.copy( 0, nLHSIndex ) ); 117 if ( sExprPart1 != sMatchExprPart1 ) 118 // the left-most expression parts do not match 119 return false; 120 121 // after the occurance of the RHS (or the LHS, if there is no RHS), the two expressions 122 // must be identical, too 123 bool bHaveRHS( nRHSIndex != -1 ); 124 sal_Int32 nRightMostIndex( bHaveRHS ? nRHSIndex : nLHSIndex ); 125 const ::rtl::OUString sMatchExprPart3( sMatchExpression.copy( nRightMostIndex + 2 ) ); 126 if ( _rExpression.getLength() < sMatchExprPart3.getLength() ) 127 // the expression is not even long enough to hold the right-most part of the match expression 128 return false; 129 const ::rtl::OUString sExprPart3( _rExpression.copy( _rExpression.getLength() - sMatchExprPart3.getLength() ) ); 130 if ( sExprPart3 != sMatchExprPart3 ) 131 // the right-most expression parts do not match 132 return false; 133 134 // if we don't have an RHS, we're done 135 if ( !bHaveRHS ) 136 { 137 _out_rLHS = _rExpression.copy( sExprPart1.getLength(), _rExpression.getLength() - sExprPart1.getLength() - sExprPart3.getLength() ); 138 return true; 139 } 140 141 // strip the match expression by its right-most and left-most part, and by the placeholders $1 and $2 142 sal_Int32 nMatchExprPart2Start( nLHSIndex + sLHSPattern.getLength() ); 143 ::rtl::OUString sMatchExprPart2 = sMatchExpression.copy( 144 nMatchExprPart2Start, 145 sMatchExpression.getLength() - nMatchExprPart2Start - sMatchExprPart3.getLength() - 2 146 ); 147 // strip the expression by its left-most and right-most part 148 const ::rtl::OUString sExpression( _rExpression.copy( 149 sExprPart1.getLength(), 150 _rExpression.getLength() - sExprPart1.getLength() - sExprPart3.getLength() 151 ) ); 152 153 sal_Int32 nPart2Index = sExpression.indexOf( sMatchExprPart2 ); 154 if ( nPart2Index == -1 ) 155 // the "middle" part of the match expression does not exist in the expression at all 156 return false; 157 158 OSL_ENSURE( sExpression.indexOf( sMatchExprPart2, nPart2Index + 1 ) == -1, 159 "ConditionalExpression::matchExpression: ambiguous matching!" ); 160 // if this fires, then we're lost: The middle part exists two times in the expression, 161 // so we cannot reliably determine what's the LHS and what's the RHS. 162 // Well, the whole mechanism is flawed, anyway: 163 // Encoding the field content in the conditional expression will break as soon 164 // as somebody 165 // - assigns a Data Field to a control 166 // - creates a conditional format expression for the control 167 // - assigns another Data Field to the control 168 // - opens the Conditional Format Dialog, again 169 // Here, at the latest, you can see that we need another mechanism, anyway, which does not 170 // rely on those strange expression building/matching 171 172 _out_rLHS = sExpression.copy( 0, nPart2Index ); 173 _out_rRHS = sExpression.copy( nPart2Index + sMatchExprPart2.getLength() ); 174 175 return true; 176 } 177 178 // ============================================================================= 179 // = ConditionalExpressionFactory 180 // ============================================================================= 181 // ----------------------------------------------------------------------------- getKnownConditionalExpressions(ConditionalExpressions & _out_rCondExp)182 size_t ConditionalExpressionFactory::getKnownConditionalExpressions( ConditionalExpressions& _out_rCondExp ) 183 { 184 ConditionalExpressions aEmpty; 185 _out_rCondExp.swap( aEmpty ); 186 187 _out_rCondExp[ eBetween ] = PConditionalExpression( new ConditionalExpression( "AND( ( $$ ) >= ( $1 ); ( $$ ) <= ( $2 ) )" ) ); 188 _out_rCondExp[ eNotBetween ] = PConditionalExpression( new ConditionalExpression( "NOT( AND( ( $$ ) >= ( $1 ); ( $$ ) <= ( $2 ) ) )" ) ); 189 _out_rCondExp[ eEqualTo ] = PConditionalExpression( new ConditionalExpression( "( $$ ) = ( $1 )" ) ); 190 _out_rCondExp[ eNotEqualTo ] = PConditionalExpression( new ConditionalExpression( "( $$ ) <> ( $1 )" ) ); 191 _out_rCondExp[ eGreaterThan ] = PConditionalExpression( new ConditionalExpression( "( $$ ) > ( $1 )" ) ); 192 _out_rCondExp[ eLessThan ] = PConditionalExpression( new ConditionalExpression( "( $$ ) < ( $1 )" ) ); 193 _out_rCondExp[ eGreaterOrEqual ] = PConditionalExpression( new ConditionalExpression( "( $$ ) >= ( $1 )" ) ); 194 _out_rCondExp[ eLessOrEqual ] = PConditionalExpression( new ConditionalExpression( "( $$ ) <= ( $1 )" ) ); 195 196 return _out_rCondExp.size(); 197 } 198 //........................................................................ 199 } // namespace rptui 200 //........................................................................ 201