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