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