Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 : #include "conditionalexpression.hxx"
20 :
21 : //........................................................................
22 : namespace rptui
23 : {
24 : //........................................................................
25 :
26 : /** === begin UNO using === **/
27 : /** === end UNO using === **/
28 :
29 : // =============================================================================
30 : // = ConditionalExpression
31 : // =============================================================================
32 : // -----------------------------------------------------------------------------
33 0 : ConditionalExpression::ConditionalExpression( const sal_Char* _pAsciiPattern )
34 0 : :m_sPattern( ::rtl::OUString::createFromAscii( _pAsciiPattern ) )
35 : {
36 0 : }
37 :
38 : // -----------------------------------------------------------------------------
39 0 : ::rtl::OUString ConditionalExpression::assembleExpression( const ::rtl::OUString& _rFieldDataSource, const ::rtl::OUString& _rLHS, const ::rtl::OUString& _rRHS ) const
40 : {
41 0 : ::rtl::OUString sExpression( m_sPattern );
42 :
43 0 : sal_Int32 nPatternIndex = sExpression.indexOf( '$' );
44 0 : while ( nPatternIndex > -1 )
45 : {
46 0 : const ::rtl::OUString* pReplace = NULL;
47 0 : switch ( sExpression.getStr()[ nPatternIndex + 1 ] )
48 : {
49 0 : case '$': pReplace = &_rFieldDataSource; break;
50 0 : case '1': pReplace = &_rLHS; break;
51 0 : case '2': pReplace = &_rRHS; break;
52 0 : default: break;
53 : }
54 :
55 0 : if ( pReplace == NULL )
56 : {
57 : OSL_FAIL( "ConditionalExpression::assembleExpression: illegal pattern!" );
58 0 : break;
59 : }
60 :
61 0 : sExpression = sExpression.replaceAt( nPatternIndex, 2, *pReplace );
62 0 : nPatternIndex = sExpression.indexOf( '$', nPatternIndex + pReplace->getLength() + 1 );
63 : }
64 0 : return sExpression;
65 : }
66 :
67 : // -----------------------------------------------------------------------------
68 0 : bool ConditionalExpression::matchExpression( const ::rtl::OUString& _rExpression, const ::rtl::OUString& _rFieldDataSource, ::rtl::OUString& _out_rLHS, ::rtl::OUString& _out_rRHS ) const
69 : {
70 : (void)_rExpression;
71 : (void)_rFieldDataSource;
72 : (void)_out_rLHS;
73 : (void)_out_rRHS;
74 :
75 : // if we had regular expression, the matching would be pretty easy ...
76 : // just replace $1 and $2 in the pattern with (.*), and then get them with \1 resp. \2.
77 : // Unfortunately, we don't have such a regexp engine ...
78 :
79 : // Okay, let's start with replacing all $$ in our pattern with the actual field data source
80 0 : ::rtl::OUString sMatchExpression( m_sPattern );
81 0 : const ::rtl::OUString sFieldDataPattern( RTL_CONSTASCII_USTRINGPARAM( "$$" ) );
82 0 : sal_Int32 nIndex( sMatchExpression.indexOf( sFieldDataPattern ) );
83 0 : while ( nIndex != -1 )
84 : {
85 0 : sMatchExpression = sMatchExpression.replaceAt( nIndex, sFieldDataPattern.getLength(), _rFieldDataSource );
86 0 : nIndex = sMatchExpression.indexOf( sFieldDataPattern, nIndex + _rFieldDataSource.getLength() );
87 : }
88 :
89 0 : const ::rtl::OUString sLHSPattern( RTL_CONSTASCII_USTRINGPARAM( "$1" ) );
90 0 : const ::rtl::OUString sRHSPattern( RTL_CONSTASCII_USTRINGPARAM( "$2" ) );
91 0 : sal_Int32 nLHSIndex( sMatchExpression.indexOf( sLHSPattern ) );
92 0 : sal_Int32 nRHSIndex( sMatchExpression.indexOf( sRHSPattern ) );
93 :
94 : // now we should have at most one occurrence of $1 and $2, resp.
95 : OSL_ENSURE( sMatchExpression.indexOf( sLHSPattern, nLHSIndex + 1 ) == -1,
96 : "ConditionalExpression::matchExpression: unsupported pattern (more than one LHS occurrence)!" );
97 : OSL_ENSURE( sMatchExpression.indexOf( sRHSPattern, nRHSIndex + 1 ) == -1,
98 : "ConditionalExpression::matchExpression: unsupported pattern (more than one RHS occurrence)!" );
99 : // Also, an LHS must be present, and precede the RHS (if present)
100 : OSL_ENSURE( ( nLHSIndex != -1 ) && ( ( nLHSIndex < nRHSIndex ) || ( nRHSIndex == -1 ) ),
101 : "ConditionalExpression::matchExpression: no LHS, or an RHS preceeding the LHS - this is not supported!" );
102 :
103 : // up to the occurrence of the LHS (which must exist, see above), the two expressions
104 : // must be identical
105 0 : if ( _rExpression.getLength() < nLHSIndex )
106 0 : return false;
107 0 : const ::rtl::OUString sExprPart1( _rExpression.copy( 0, nLHSIndex ) );
108 0 : const ::rtl::OUString sMatchExprPart1( sMatchExpression.copy( 0, nLHSIndex ) );
109 0 : if ( sExprPart1 != sMatchExprPart1 )
110 : // the left-most expression parts do not match
111 0 : return false;
112 :
113 : // after the occurrence of the RHS (or the LHS, if there is no RHS), the two expressions
114 : // must be identical, too
115 0 : bool bHaveRHS( nRHSIndex != -1 );
116 0 : sal_Int32 nRightMostIndex( bHaveRHS ? nRHSIndex : nLHSIndex );
117 0 : const ::rtl::OUString sMatchExprPart3( sMatchExpression.copy( nRightMostIndex + 2 ) );
118 0 : if ( _rExpression.getLength() < sMatchExprPart3.getLength() )
119 : // the expression is not even long enough to hold the right-most part of the match expression
120 0 : return false;
121 0 : const ::rtl::OUString sExprPart3( _rExpression.copy( _rExpression.getLength() - sMatchExprPart3.getLength() ) );
122 0 : if ( sExprPart3 != sMatchExprPart3 )
123 : // the right-most expression parts do not match
124 0 : return false;
125 :
126 : // if we don't have an RHS, we're done
127 0 : if ( !bHaveRHS )
128 : {
129 0 : _out_rLHS = _rExpression.copy( sExprPart1.getLength(), _rExpression.getLength() - sExprPart1.getLength() - sExprPart3.getLength() );
130 0 : return true;
131 : }
132 :
133 : // strip the match expression by its right-most and left-most part, and by the placeholders $1 and $2
134 0 : sal_Int32 nMatchExprPart2Start( nLHSIndex + sLHSPattern.getLength() );
135 : ::rtl::OUString sMatchExprPart2 = sMatchExpression.copy(
136 : nMatchExprPart2Start,
137 0 : sMatchExpression.getLength() - nMatchExprPart2Start - sMatchExprPart3.getLength() - 2
138 0 : );
139 : // strip the expression by its left-most and right-most part
140 : const ::rtl::OUString sExpression( _rExpression.copy(
141 : sExprPart1.getLength(),
142 0 : _rExpression.getLength() - sExprPart1.getLength() - sExprPart3.getLength()
143 0 : ) );
144 :
145 0 : sal_Int32 nPart2Index = sExpression.indexOf( sMatchExprPart2 );
146 0 : if ( nPart2Index == -1 )
147 : // the "middle" part of the match expression does not exist in the expression at all
148 0 : return false;
149 :
150 : OSL_ENSURE( sExpression.indexOf( sMatchExprPart2, nPart2Index + 1 ) == -1,
151 : "ConditionalExpression::matchExpression: ambiguous matching!" );
152 : // if this fires, then we're lost: The middle part exists two times in the expression,
153 : // so we cannot reliably determine what's the LHS and what's the RHS.
154 : // Well, the whole mechanism is flawed, anyway:
155 : // Encoding the field content in the conditional expression will break as soon
156 : // as somebody
157 : // - assigns a Data Field to a control
158 : // - creates a conditional format expression for the control
159 : // - assigns another Data Field to the control
160 : // - opens the Conditional Format Dialog, again
161 : // Here, at the latest, you can see that we need another mechanism, anyway, which does not
162 : // rely on those strange expression building/matching
163 :
164 0 : _out_rLHS = sExpression.copy( 0, nPart2Index );
165 0 : _out_rRHS = sExpression.copy( nPart2Index + sMatchExprPart2.getLength() );
166 :
167 0 : return true;
168 : }
169 :
170 : // =============================================================================
171 : // = ConditionalExpressionFactory
172 : // =============================================================================
173 : // -----------------------------------------------------------------------------
174 0 : size_t ConditionalExpressionFactory::getKnownConditionalExpressions( ConditionalExpressions& _out_rCondExp )
175 : {
176 0 : ConditionalExpressions aEmpty;
177 0 : _out_rCondExp.swap( aEmpty );
178 :
179 0 : _out_rCondExp[ eBetween ] = PConditionalExpression( new ConditionalExpression( "AND( ( $$ ) >= ( $1 ); ( $$ ) <= ( $2 ) )" ) );
180 0 : _out_rCondExp[ eNotBetween ] = PConditionalExpression( new ConditionalExpression( "NOT( AND( ( $$ ) >= ( $1 ); ( $$ ) <= ( $2 ) ) )" ) );
181 0 : _out_rCondExp[ eEqualTo ] = PConditionalExpression( new ConditionalExpression( "( $$ ) = ( $1 )" ) );
182 0 : _out_rCondExp[ eNotEqualTo ] = PConditionalExpression( new ConditionalExpression( "( $$ ) <> ( $1 )" ) );
183 0 : _out_rCondExp[ eGreaterThan ] = PConditionalExpression( new ConditionalExpression( "( $$ ) > ( $1 )" ) );
184 0 : _out_rCondExp[ eLessThan ] = PConditionalExpression( new ConditionalExpression( "( $$ ) < ( $1 )" ) );
185 0 : _out_rCondExp[ eGreaterOrEqual ] = PConditionalExpression( new ConditionalExpression( "( $$ ) >= ( $1 )" ) );
186 0 : _out_rCondExp[ eLessOrEqual ] = PConditionalExpression( new ConditionalExpression( "( $$ ) <= ( $1 )" ) );
187 :
188 0 : return _out_rCondExp.size();
189 : }
190 : //........................................................................
191 : } // namespace rptui
192 : //........................................................................
193 :
194 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|