xref: /AOO41X/main/reportdesign/source/core/misc/conditionalexpression.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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