Index: sc/inc/global.hxx =================================================================== RCS file: /cvs/sc/sc/inc/global.hxx,v retrieving revision 1.49 diff -u -p -r1.49 global.hxx --- sc/inc/global.hxx 6 Jul 2007 12:30:02 -0000 1.49 +++ sc/inc/global.hxx 9 Aug 2007 18:29:24 -0000 @@ -817,7 +817,11 @@ enum ScQueryOp SC_TOPVAL, SC_BOTVAL, SC_TOPPERC, - SC_BOTPERC + SC_BOTPERC, + SC_CONTAINS, + SC_DOES_NOT_CONTAIN, + SC_BEGINS_WITH, + SC_ENDS_WITH }; // ----------------------------------------------------------------------- Index: sc/source/core/data/table3.cxx =================================================================== RCS file: /cvs/sc/sc/source/core/data/table3.cxx,v retrieving revision 1.28 diff -u -p -r1.28 table3.cxx --- sc/source/core/data/table3.cxx 5 Mar 2007 14:40:30 -0000 1.28 +++ sc/source/core/data/table3.cxx 9 Aug 2007 18:29:24 -0000 @@ -40,6 +40,7 @@ // INCLUDE --------------------------------------------------------------- +#include #include #include #include @@ -925,6 +926,28 @@ BOOL ScTable::DoSubTotals( ScSubTotalPar return bSpaceLeft; } +static BOOL HasNonWSInRange (const String& s, int start, int end) +{ + for (int i = start; i < end; ++i) { + if (!unicode::isSpace(s.GetChar(i))) + return TRUE; + } + return FALSE; +} + +static BOOL IsMatch (BOOL bMatchWholeCell, ScQueryOp eOp, const String& s, int nMatchStart, int nMatchEnd) +{ + BOOL bBegin = HasNonWSInRange(s, 0, nMatchStart); + BOOL bEnd = HasNonWSInRange(s, nMatchEnd, s.Len()); + + if (bMatchWholeCell && (bBegin || bEnd)) + return FALSE; + else if (eOp == SC_BEGINS_WITH && bBegin) + return FALSE; + else if (eOp == SC_ENDS_WITH && bEnd) + return FALSE; + return TRUE; +} BOOL ScTable::ValidQuery(SCROW nRow, const ScQueryParam& rParam, BOOL* pSpecial /* =NULL */ , ScBaseCell* pCell /* =NULL */ , @@ -1018,13 +1041,22 @@ BOOL ScTable::ValidQuery(SCROW nRow, con } } } - else if ( (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL) || + else if ( (rEntry.eOp == SC_CONTAINS || rEntry.eOp == SC_DOES_NOT_CONTAIN || + rEntry.eOp == SC_BEGINS_WITH || rEntry.eOp == SC_ENDS_WITH || + rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL) || (rEntry.bQueryByString && (pCell ? pCell->HasStringData() : HasStringData( static_cast(rEntry.nField), nRow)))) { // by String String aCellStr; + + // Contains and Does not contain is similar to EQUAL and NOT EQUAL + // but with bMatchWholeCell set to false + if( rEntry.eOp == SC_CONTAINS || rEntry.eOp == SC_DOES_NOT_CONTAIN || + rEntry.eOp == SC_BEGINS_WITH || rEntry.eOp == SC_ENDS_WITH ) + bMatchWholeCell = FALSE; + if ( pCell ) { if (pCell->GetCellType() != CELLTYPE_NOTE) @@ -1037,7 +1069,9 @@ BOOL ScTable::ValidQuery(SCROW nRow, con GetInputString( static_cast(rEntry.nField), nRow, aCellStr ); BOOL bRealRegExp = (rParam.bRegExp && ((rEntry.eOp == SC_EQUAL) - || (rEntry.eOp == SC_NOT_EQUAL))); + || (rEntry.eOp == SC_NOT_EQUAL) || (rEntry.eOp == SC_CONTAINS) + || (rEntry.eOp == SC_DOES_NOT_CONTAIN) || (rEntry.eOp == SC_BEGINS_WITH) + || (rEntry.eOp == SC_ENDS_WITH))); BOOL bTestRegExp = (pbTestEqualCondition && rParam.bRegExp && ((rEntry.eOp == SC_LESS_EQUAL) || (rEntry.eOp == SC_GREATER_EQUAL))); @@ -1048,17 +1082,21 @@ BOOL ScTable::ValidQuery(SCROW nRow, con BOOL bMatch = (BOOL) rEntry.GetSearchTextPtr( rParam.bCaseSens ) ->SearchFrwrd( aCellStr, &nStart, &nEnd ); // from 614 on, nEnd is behind the found text - if ( bMatch && bMatchWholeCell - && (nStart != 0 || nEnd != aCellStr.Len()) ) - bMatch = FALSE; // RegExp must match entire cell string + if ( bMatch ) + { + bMatch = IsMatch(bMatchWholeCell, rEntry.eOp, aCellStr, nStart, nEnd); + } if ( bRealRegExp ) - bOk = ((rEntry.eOp == SC_NOT_EQUAL) ? !bMatch : bMatch); + bOk = ( ( rEntry.eOp == SC_NOT_EQUAL || + rEntry.eOp == SC_DOES_NOT_CONTAIN ) ? !bMatch : bMatch ); else bTestEqual = bMatch; } if ( !bRealRegExp ) { - if ( rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL ) + if ( rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL || + rEntry.eOp == SC_CONTAINS || rEntry.eOp == SC_DOES_NOT_CONTAIN || + rEntry.eOp == SC_BEGINS_WITH || rEntry.eOp == SC_ENDS_WITH ) { if ( !rEntry.bQueryByString && rEntry.pStr->Len() == 0 ) { @@ -1067,8 +1105,6 @@ BOOL ScTable::ValidQuery(SCROW nRow, con // don't find any string (isEqual would find empty string results in formula cells). bOk = FALSE; } - else if ( bMatchWholeCell ) - bOk = pTransliteration->isEqual( aCellStr, *rEntry.pStr ); else { ::com::sun::star::uno::Sequence< sal_Int32 > xOff; @@ -1078,9 +1114,14 @@ BOOL ScTable::ValidQuery(SCROW nRow, con String aQuer( pTransliteration->transliterate( *rEntry.pStr, ScGlobal::eLnge, 0, rEntry.pStr->Len(), &xOff ) ); - bOk = (aCell.Search( aQuer ) != STRING_NOTFOUND); + xub_StrLen nPos = aCell.Search( aQuer ); + bOk = ( nPos != STRING_NOTFOUND ); + if ( bOk ) { + bOk = IsMatch(bMatchWholeCell, rEntry.eOp, aCell, nPos, nPos+aQuer.Len()); + } } - if ( rEntry.eOp == SC_NOT_EQUAL ) + if ( rEntry.eOp == SC_NOT_EQUAL || + rEntry.eOp == SC_DOES_NOT_CONTAIN ) bOk = !bOk; } else Index: sc/source/filter/excel/excimp8.cxx =================================================================== RCS file: /cvs/sc/sc/source/filter/excel/excimp8.cxx,v retrieving revision 1.120 diff -u -p -r1.120 excimp8.cxx --- sc/source/filter/excel/excimp8.cxx 17 Jul 2007 13:33:21 -0000 1.120 +++ sc/source/filter/excel/excimp8.cxx 9 Aug 2007 18:29:24 -0000 @@ -454,6 +454,126 @@ void XclImpAutoFilterData::InsertQueryPa } } +static void ExcelQueryToOooQuery( ScQueryEntry& rEntry, ScQueryParam& rParam ) +{ + if( rEntry.pStr == NULL ) + return; + if( rEntry.eOp != SC_EQUAL && rEntry.eOp != SC_NOT_EQUAL ) + return; + xub_StrLen nLen = rEntry.pStr->Len(); + if( nLen == 0 ) + return; + BOOL bRegExp = FALSE; + for( int i = 0; i < nLen; ++i ) { + sal_Unicode c = rEntry.pStr->GetChar( i ); + if( c == '*' ) { + if( rEntry.eOp == SC_NOT_EQUAL ) { + bRegExp = TRUE; + rEntry.eOp = SC_DOES_NOT_CONTAIN; + } + else if( rEntry.eOp == SC_DOES_NOT_CONTAIN ) + ; // ignore + else if( i == 0 ) + rEntry.eOp = SC_ENDS_WITH; + else if( i == nLen-1 ) + rEntry.eOp = rEntry.eOp == SC_ENDS_WITH ? SC_CONTAINS : SC_BEGINS_WITH; + else + bRegExp = TRUE; + } + else if( c == '?' ) + bRegExp = TRUE; + } + if( rEntry.pStr->GetChar( 0 ) == '*' ) + rEntry.pStr->Erase( 0, 1 ); + nLen = rEntry.pStr->Len(); + if( nLen > 0 && rEntry.pStr->GetChar( nLen-1 ) == '*' ) { + rEntry.pStr->Erase( nLen-1, 1 ); + --nLen; + } + if( bRegExp ) { + rParam.bRegExp = TRUE; + for( int i = 0; i < nLen; ++i ) { + sal_Unicode c = rEntry.pStr->GetChar( i ); + switch( c ) { + case '*': + rEntry.pStr->ReplaceAscii( i, 1, ".*" ); + ++i; + ++nLen; + break; + case '.': + rEntry.pStr->InsertAscii( "\\", i ); + ++i; + ++nLen; + break; + case '?': + rEntry.pStr->ReplaceAscii( i, 1, "." ); + break; + default: break; + } + } + } +} + +static void ExcelQueryToOooQuery( ScQueryEntry& rEntry, ScQueryParam& rParam ) +{ + if( rEntry.pStr == NULL ) + return; + if( rEntry.eOp != SC_EQUAL && rEntry.eOp != SC_NOT_EQUAL ) + return; + xub_StrLen nLen = rEntry.pStr->Len(); + if( nLen == 0 ) + return; + BOOL bRegExp = FALSE; + for( int i = 0; i < nLen; ++i ) { + sal_Unicode c = rEntry.pStr->GetChar( i ); + if( c == '*' ) { + if( rEntry.eOp == SC_NOT_EQUAL ) { + bRegExp = TRUE; + rEntry.eOp = SC_DOES_NOT_CONTAIN; + } + else if( rEntry.eOp == SC_DOES_NOT_CONTAIN ) + ; // ignore + else if( i == 0 ) + rEntry.eOp = SC_ENDS_WITH; + else if( i == nLen-1 ) + rEntry.eOp = rEntry.eOp == SC_ENDS_WITH ? SC_CONTAINS : SC_BEGINS_WITH; + else + bRegExp = TRUE; + } + else if( c == '?' ) + bRegExp = TRUE; + } + if( rEntry.pStr->GetChar( 0 ) == '*' ) + rEntry.pStr->Erase( 0, 1 ); + nLen = rEntry.pStr->Len(); + if( nLen > 0 && rEntry.pStr->GetChar( nLen-1 ) == '*' ) { + rEntry.pStr->Erase( nLen-1, 1 ); + --nLen; + } + if( bRegExp ) { + rParam.bRegExp = TRUE; + for( int i = 0; i < nLen; ++i ) { + sal_Unicode c = rEntry.pStr->GetChar( i ); + switch( c ) { + case '*': + rEntry.pStr->ReplaceAscii( i, 1, ".*" ); + ++i; + ++nLen; + break; + case '.': + rEntry.pStr->InsertAscii( "\\", i ); + ++i; + ++nLen; + break; + case '?': + rEntry.pStr->ReplaceAscii( i, 1, "." ); + break; + default: break; + } + } + } +} + void XclImpAutoFilterData::ReadAutoFilter( XclImpStream& rStrm ) { UINT16 nCol, nFlags; @@ -491,14 +611,14 @@ void XclImpAutoFilterData::ReadAutoFilte BOOL bIgnore; UINT8 nStrLen[ 2 ] = { 0, 0 }; - String* pEntryStr[ 2 ] = { NULL, NULL }; + ScQueryEntry *pQueryEntries[ 2 ] = { NULL, NULL }; for( nE = 0; nE < 2; nE++ ) { if( nFirstEmpty < nCount ) { ScQueryEntry& aEntry = aParam.GetEntry( nFirstEmpty ); - pEntryStr[ nE ] = aEntry.pStr; + pQueryEntries[ nE ] = &aEntry; bIgnore = FALSE; rStrm >> nType >> nOper; @@ -586,8 +706,10 @@ void XclImpAutoFilterData::ReadAutoFilte } for( nE = 0; nE < 2; nE++ ) - if( nStrLen[ nE ] && pEntryStr[ nE ] ) - pEntryStr[ nE ]->Assign( rStrm.ReadUniString( nStrLen[ nE ] ) ); + if( nStrLen[ nE ] && pQueryEntries[ nE ] ) { + pQueryEntries[ nE ]->pStr->Assign ( rStrm.ReadUniString( nStrLen[ nE ] ) ); + ExcelQueryToOooQuery( *pQueryEntries[ nE ], aParam ); + } } } Index: sc/source/filter/excel/excrecds.cxx =================================================================== RCS file: /cvs/sc/sc/source/filter/excel/excrecds.cxx,v retrieving revision 1.87 diff -u -p -r1.87 excrecds.cxx --- sc/source/filter/excel/excrecds.cxx 22 May 2007 19:45:31 -0000 1.87 +++ sc/source/filter/excel/excrecds.cxx 9 Aug 2007 18:29:24 -0000 @@ -630,13 +630,50 @@ BOOL XclExpAutofilter::AddCondition( ScQ return TRUE; } -BOOL XclExpAutofilter::AddEntry( const ScQueryEntry& rEntry ) +static String OooQueryToExcelQuery( const ScQueryEntry& rEntry, const ScQueryParam& rParam ) +{ + String aStr (*rEntry.pStr); + BOOL bHaveRegex = rParam.bRegExp; + if( bHaveRegex ) { + xub_StrLen nLen = aStr.Len(); + for( int i = 0; i < nLen; ++i ) { + sal_Unicode c = aStr.GetChar( i ); + if( c == '.' ) { + if( i+1 < nLen && aStr.GetChar( i+1 ) == '*' ) { + aStr.ReplaceAscii( i, 2, "*" ); + --nLen; + } + else + aStr.ReplaceAscii( i, 1, "?" ); + } + else if( c == '\\' ) { + aStr.Erase( i, 1 ); + --nLen; + } + } + } + if( rEntry.eOp == SC_ENDS_WITH || rEntry.eOp == SC_CONTAINS || rEntry.eOp == SC_DOES_NOT_CONTAIN ) + aStr.InsertAscii( "*" , 0 ); + if( rEntry.eOp == SC_BEGINS_WITH || rEntry.eOp == SC_CONTAINS || rEntry.eOp == SC_DOES_NOT_CONTAIN ) + aStr.AppendAscii( "*" ); + return aStr; +} + +BOOL XclExpAutofilter::AddEntry( const ScQueryEntry& rEntry, const ScQueryParam& rParam ) { BOOL bConflict = FALSE; String sText; - if( rEntry.pStr ) - sText.Assign( *rEntry.pStr ); + ScQueryOp eOp = rEntry.eOp; + if( rEntry.pStr ) { + if (eOp != SC_BEGINS_WITH && eOp != SC_ENDS_WITH && + eOp != SC_CONTAINS && eOp != SC_DOES_NOT_CONTAIN) + sText.Assign( *rEntry.pStr ); + else { + sText.Assign( OooQueryToExcelQuery( rEntry, rParam ) ); + eOp = eOp == SC_DOES_NOT_CONTAIN ? SC_NOT_EQUAL : SC_EQUAL; + } + } BOOL bLen = sText.Len() > 0; @@ -655,7 +692,7 @@ BOOL XclExpAutofilter::AddEntry( const S // top10 flags UINT16 nNewFlags = 0x0000; - switch( rEntry.eOp ) + switch( eOp ) { case SC_TOPVAL: nNewFlags = (EXC_AFFLAG_TOP10 | EXC_AFFLAG_TOP10TOP); @@ -688,7 +725,7 @@ BOOL XclExpAutofilter::AddEntry( const S UINT8 nType = bIsNum ? EXC_AFTYPE_DOUBLE : EXC_AFTYPE_STRING; UINT8 nOper = EXC_AFOPER_NONE; - switch( rEntry.eOp ) + switch( eOp ) { case SC_EQUAL: nOper = EXC_AFOPER_EQUAL; break; case SC_LESS: nOper = EXC_AFOPER_LESS; break; @@ -801,7 +838,7 @@ ExcAutoFilterRecs::ExcAutoFilterRecs( co bConflict = (nEntry == 1) && (rEntry.eConnect == SC_OR) && (nFirstField != rEntry.nField); if( !bConflict ) - bConflict = pFilter->AddEntry( rEntry ); + bConflict = pFilter->AddEntry( rEntry, aParam ); } } Index: sc/source/filter/inc/excrecds.hxx =================================================================== RCS file: /cvs/sc/sc/source/filter/inc/excrecds.hxx,v retrieving revision 1.49 diff -u -p -r1.49 excrecds.hxx --- sc/source/filter/inc/excrecds.hxx 27 Feb 2007 12:32:42 -0000 1.49 +++ sc/source/filter/inc/excrecds.hxx 9 Aug 2007 18:29:25 -0000 @@ -469,7 +469,7 @@ public: inline BOOL HasCondition() const { return !aCond[ 0 ].IsEmpty(); } inline BOOL HasTop10() const { return ::get_flag( nFlags, EXC_AFFLAG_TOP10 ); } - BOOL AddEntry( const ScQueryEntry& rEntry ); + BOOL AddEntry( const ScQueryEntry& rEntry, const ScQueryParam& rParam ); }; // ---------------------------------------------------------------------------- Index: sc/source/ui/src/filter.src =================================================================== RCS file: /cvs/sc/sc/source/ui/src/filter.src,v retrieving revision 1.57 diff -u -p -r1.57 filter.src --- sc/source/ui/src/filter.src 19 Apr 2007 16:37:30 -0000 1.57 +++ sc/source/ui/src/filter.src 9 Aug 2007 18:29:26 -0000 @@ -126,16 +126,20 @@ ModelessDialog RID_SCDLG_FILTER DropDown = TRUE ; stringlist [ en-US ] = { - < "=" ; Default ; > ; + < "Equals" ; Default ; > ; < "<" ; Default ; > ; < ">" ; Default ; > ; < "<=" ; Default ; > ; < ">=" ; Default ; > ; - < "<>" ; Default ; > ; + < "Not equals" ; Default ; > ; < "Largest" ; Default ; > ; < "Smallest" ; Default ; > ; < "Largest %" ; Default ; > ; < "Smallest %" ; Default ; > ; + < "Contains" ; Default ; > ; + < "Does not Contain" ; Default ; > ; + < "Begins with" ; Default ; > ; + < "Ends with" ; Default ; > ; }; }; ListBox LB_COND2 @@ -147,16 +151,20 @@ ModelessDialog RID_SCDLG_FILTER DropDown = TRUE ; stringlist [ en-US ] = { - < "=" ; Default ; > ; + < "Equals" ; Default ; > ; < "<" ; Default ; > ; < ">" ; Default ; > ; < "<=" ; Default ; > ; < ">=" ; Default ; > ; - < "<>" ; Default ; > ; + < "Not equals" ; Default ; > ; < "Largest" ; Default ; > ; < "Smallest" ; Default ; > ; < "Largest %" ; Default ; > ; < "Smallest %" ; Default ; > ; + < "Contains" ; Default ; > ; + < "Does not Contain" ; Default ; > ; + < "Begins with" ; Default ; > ; + < "Ends with" ; Default ; > ; }; }; ListBox LB_COND3 @@ -168,16 +176,20 @@ ModelessDialog RID_SCDLG_FILTER DropDown = TRUE ; stringlist [ en-US ] = { - < "=" ; Default ; > ; + < "Equals" ; Default ; > ; < "<" ; Default ; > ; < ">" ; Default ; > ; < "<=" ; Default ; > ; < ">=" ; Default ; > ; - < "<>" ; Default ; > ; + < "Not equals" ; Default ; > ; < "Largest" ; Default ; > ; < "Smallest" ; Default ; > ; < "Largest %" ; Default ; > ; < "Smallest %" ; Default ; > ; + < "Contains" ; Default ; > ; + < "Does not Contain" ; Default ; > ; + < "Begins with" ; Default ; > ; + < "Ends with" ; Default ; > ; }; }; ComboBox ED_VAL1 Index: sc/util/makefile.mk =================================================================== RCS file: /cvs/sc/sc/util/makefile.mk,v retrieving revision 1.41 diff -u -p -r1.41 makefile.mk --- sc/util/makefile.mk 22 May 2007 20:15:40 -0000 1.41 +++ sc/util/makefile.mk 9 Aug 2007 18:29:27 -0000 @@ -98,6 +98,7 @@ SHL1STDLIBS= \ $(VOSLIB) \ $(SALLIB) \ $(TOOLSLIB) \ + $(I18NUTILLIB) \ $(I18NISOLANGLIB) \ $(UNOTOOLSLIB) \ $(SOTLIB) \