View | Details | Raw Unified | Return to issue 77677
Collapse All | Expand All

(-)sc/inc/dbcolect.hxx (+2 lines)
Lines 113-118 Link Here
113
	String*			pQueryStr[MAXQUERY];
113
	String*			pQueryStr[MAXQUERY];
114
	double			nQueryVal[MAXQUERY];
114
	double			nQueryVal[MAXQUERY];
115
	ScQueryConnect  eQueryConnect[MAXQUERY];
115
	ScQueryConnect  eQueryConnect[MAXQUERY];
116
    BOOL            bMatchMultiStrValues[MAXQUERY];
117
    ScHashOUStringSet aStrValues[MAXQUERY];
116
	BOOL			bIsAdvanced;		// TRUE if created by advanced filter
118
	BOOL			bIsAdvanced;		// TRUE if created by advanced filter
117
	ScRange			aAdvSource;			// source range
119
	ScRange			aAdvSource;			// source range
118
	// SubTotalParam
120
	// SubTotalParam
(-)sc/inc/global.hxx (+15 lines)
Lines 58-63 Link Here
58
#include "scdllapi.h"
58
#include "scdllapi.h"
59
#endif
59
#endif
60
60
61
#include <hash_set>
62
61
class ImageList;
63
class ImageList;
62
class Bitmap;
64
class Bitmap;
63
class SfxItemSet;
65
class SfxItemSet;
Lines 887-892 Link Here
887
	class TextSearch;
889
	class TextSearch;
888
}
890
}
889
891
892
struct ScHashOUString
893
{
894
    size_t operator()( const ::rtl::OUString& str ) const
895
    {
896
        return str.hashCode();
897
    }
898
};
899
900
typedef ::std::hash_set< ::rtl::OUString, ScHashOUString, ::std::equal_to<rtl::OUString> > ScHashOUStringSet;
901
890
struct ScQueryEntry
902
struct ScQueryEntry
891
{
903
{
892
	BOOL			bDoQuery;
904
	BOOL			bDoQuery;
Lines 899-904 Link Here
899
	utl::SearchParam*	pSearchParam;		// falls RegExp, nicht gespeichert
911
	utl::SearchParam*	pSearchParam;		// falls RegExp, nicht gespeichert
900
	utl::TextSearch*	pSearchText;		// falls RegExp, nicht gespeichert
912
	utl::TextSearch*	pSearchText;		// falls RegExp, nicht gespeichert
901
913
914
    ScHashOUStringSet aStrValues;
915
    BOOL            bMatchMultiStrValues;        // match individual string values.
916
902
	ScQueryEntry();
917
	ScQueryEntry();
903
	ScQueryEntry(const ScQueryEntry& r);
918
	ScQueryEntry(const ScQueryEntry& r);
904
	~ScQueryEntry();
919
	~ScQueryEntry();
(-)sc/source/core/data/dpsave.cxx (-1 / +2 lines)
Lines 619-625 Link Here
619
		{
619
		{
620
			// single filter field: first field equal to selected string
620
			// single filter field: first field equal to selected string
621
			sheet::TableFilterField aField( sheet::FilterConnection_AND, 0,
621
			sheet::TableFilterField aField( sheet::FilterConnection_AND, 0,
622
					sheet::FilterOperator_EQUAL, sal_False, 0.0, *pSelectedPage );
622
					sheet::FilterOperator_EQUAL, sal_False, 0.0, *pSelectedPage,
623
                    uno::Sequence<rtl::OUString>(), sal_False );
623
			aFilter = uno::Sequence<sheet::TableFilterField>( &aField, 1 );
624
			aFilter = uno::Sequence<sheet::TableFilterField>( &aField, 1 );
624
		}
625
		}
625
		// else keep empty sequence
626
		// else keep empty sequence
(-)sc/source/core/data/dptabsrc.cxx (-1 / +2 lines)
Lines 1529-1535 Link Here
1529
		{
1529
		{
1530
			// single filter field: first field equal to selected string
1530
			// single filter field: first field equal to selected string
1531
			sheet::TableFilterField aField( sheet::FilterConnection_AND, 0,
1531
			sheet::TableFilterField aField( sheet::FilterConnection_AND, 0,
1532
					sheet::FilterOperator_EQUAL, sal_False, 0.0, aSelectedPage );
1532
					sheet::FilterOperator_EQUAL, sal_False, 0.0, aSelectedPage,
1533
                    uno::Sequence<rtl::OUString>(), sal_False );
1533
			aRet <<= uno::Sequence<sheet::TableFilterField>( &aField, 1 );
1534
			aRet <<= uno::Sequence<sheet::TableFilterField>( &aField, 1 );
1534
		}
1535
		}
1535
		else
1536
		else
(-)sc/source/core/data/global2.cxx (-1 / +11 lines)
Lines 163-168 Link Here
163
	pStr			= new String;
163
	pStr			= new String;
164
	pSearchParam	= NULL;
164
	pSearchParam	= NULL;
165
	pSearchText		= NULL;
165
	pSearchText		= NULL;
166
    bMatchMultiStrValues = FALSE;
166
}
167
}
167
168
168
ScQueryEntry::ScQueryEntry(const ScQueryEntry& r)
169
ScQueryEntry::ScQueryEntry(const ScQueryEntry& r)
Lines 176-181 Link Here
176
	pStr			= new String(*r.pStr);
177
	pStr			= new String(*r.pStr);
177
	pSearchParam	= NULL;
178
	pSearchParam	= NULL;
178
	pSearchText		= NULL;
179
	pSearchText		= NULL;
180
    bMatchMultiStrValues = r.bMatchMultiStrValues;
181
    aStrValues = r.aStrValues;
179
}
182
}
180
183
181
ScQueryEntry::~ScQueryEntry()
184
ScQueryEntry::~ScQueryEntry()
Lines 205-210 Link Here
205
	pSearchParam	= NULL;
208
	pSearchParam	= NULL;
206
	pSearchText		= NULL;
209
	pSearchText		= NULL;
207
210
211
    bMatchMultiStrValues = r.bMatchMultiStrValues;
212
    aStrValues = r.aStrValues;
213
208
	return *this;
214
	return *this;
209
}
215
}
210
216
Lines 224-229 Link Here
224
	}
230
	}
225
	pSearchParam	= NULL;
231
	pSearchParam	= NULL;
226
	pSearchText		= NULL;
232
	pSearchText		= NULL;
233
    bMatchMultiStrValues = FALSE;
234
    aStrValues.clear();
227
}
235
}
228
236
229
BOOL ScQueryEntry::operator==( const ScQueryEntry& r ) const
237
BOOL ScQueryEntry::operator==( const ScQueryEntry& r ) const
Lines 234-240 Link Here
234
		&& eConnect			== r.eConnect
242
		&& eConnect			== r.eConnect
235
		&& nField			== r.nField
243
		&& nField			== r.nField
236
		&& nVal				== r.nVal
244
		&& nVal				== r.nVal
237
		&& *pStr			== *r.pStr;
245
		&& *pStr			== *r.pStr
246
        && bMatchMultiStrValues == r.bMatchMultiStrValues
247
        && aStrValues == r.aStrValues;
238
	//! pSearchParam und pSearchText nicht vergleichen
248
	//! pSearchParam und pSearchText nicht vergleichen
239
}
249
}
240
250
(-)sc/source/core/data/table3.cxx (-69 / +83 lines)
Lines 1036-1117 Link Here
1036
            else
1036
            else
1037
                GetInputString( static_cast<SCCOL>(rEntry.nField), nRow, aCellStr );
1037
                GetInputString( static_cast<SCCOL>(rEntry.nField), nRow, aCellStr );
1038
1038
1039
            BOOL bRealRegExp = (rParam.bRegExp && ((rEntry.eOp == SC_EQUAL)
1039
            if (rEntry.bMatchMultiStrValues)
1040
                || (rEntry.eOp == SC_NOT_EQUAL)));
1041
            BOOL bTestRegExp = (pbTestEqualCondition && rParam.bRegExp
1042
                && ((rEntry.eOp == SC_LESS_EQUAL)
1043
                    || (rEntry.eOp == SC_GREATER_EQUAL)));
1044
            if ( bRealRegExp || bTestRegExp )
1045
            {
1040
            {
1046
				xub_StrLen nStart = 0;
1041
                // Filter by individual string values.
1047
				xub_StrLen nEnd   = aCellStr.Len();
1042
1048
                BOOL bMatch = (BOOL) rEntry.GetSearchTextPtr( rParam.bCaseSens )
1043
                rtl::OUString aCellStr2(aCellStr);
1049
					->SearchFrwrd( aCellStr, &nStart, &nEnd );
1044
                ScHashOUStringSet::const_iterator pos = rEntry.aStrValues.find(aCellStr2);
1050
				// from 614 on, nEnd is behind the found text
1045
                if (pos == rEntry.aStrValues.end())
1051
                if ( bMatch && bMatchWholeCell
1046
                    bOk = FALSE;
1052
						&& (nStart != 0 || nEnd != aCellStr.Len()) )
1053
                    bMatch = FALSE;    // RegExp must match entire cell string
1054
                if ( bRealRegExp )
1055
                    bOk = ((rEntry.eOp == SC_NOT_EQUAL) ? !bMatch : bMatch);
1056
                else
1047
                else
1057
                    bTestEqual = bMatch;
1048
                    bOk = TRUE;
1058
            }
1049
            }
1059
            if ( !bRealRegExp )
1050
            else
1060
			{
1051
            {    
1061
				if ( rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL )
1052
                BOOL bRealRegExp = (rParam.bRegExp && ((rEntry.eOp == SC_EQUAL)
1062
				{
1053
                    || (rEntry.eOp == SC_NOT_EQUAL)));
1063
                    if ( !rEntry.bQueryByString && rEntry.pStr->Len() == 0 )
1054
                BOOL bTestRegExp = (pbTestEqualCondition && rParam.bRegExp
1055
                    && ((rEntry.eOp == SC_LESS_EQUAL)
1056
                        || (rEntry.eOp == SC_GREATER_EQUAL)));
1057
                if ( bRealRegExp || bTestRegExp )
1058
                {
1059
                    xub_StrLen nStart = 0;
1060
                    xub_StrLen nEnd   = aCellStr.Len();
1061
                    BOOL bMatch = (BOOL) rEntry.GetSearchTextPtr( rParam.bCaseSens )
1062
                        ->SearchFrwrd( aCellStr, &nStart, &nEnd );
1063
                        // from 614 on, nEnd is behind the found text
1064
                    if ( bMatch && bMatchWholeCell
1065
                            && (nStart != 0 || nEnd != aCellStr.Len()) )
1066
                        bMatch = FALSE;    // RegExp must match entire cell string
1067
                    if ( bRealRegExp )
1068
                        bOk = ((rEntry.eOp == SC_NOT_EQUAL) ? !bMatch : bMatch);
1069
                    else
1070
                        bTestEqual = bMatch;
1071
                }
1072
                if ( !bRealRegExp )
1073
                {
1074
                    if ( rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL )
1064
                    {
1075
                    {
1065
                        // #i18374# When used from functions (match, countif, sumif, vlookup, hlookup, lookup),
1076
                        if ( !rEntry.bQueryByString && rEntry.pStr->Len() == 0 )
1066
                        // the query value is assigned directly, and the string is empty. In that case,
1077
                        {
1067
                        // don't find any string (isEqual would find empty string results in formula cells).
1078
                                // #i18374# When used from functions (match, countif, sumif, vlookup, hlookup, lookup),
1068
                        bOk = FALSE;
1079
                                // the query value is assigned directly, and the string is empty. In that case,
1080
                                // don't find any string (isEqual would find empty string results in formula cells).
1081
                            bOk = FALSE;
1082
                        }
1083
                        else if ( bMatchWholeCell )
1084
                            bOk = pTransliteration->isEqual( aCellStr, *rEntry.pStr );
1085
                        else
1086
                        {
1087
                            ::com::sun::star::uno::Sequence< sal_Int32 > xOff;
1088
                            String aCell( pTransliteration->transliterate(
1089
                                aCellStr, ScGlobal::eLnge, 0, aCellStr.Len(),
1090
                                &xOff ) );
1091
                            String aQuer( pTransliteration->transliterate(
1092
                                *rEntry.pStr, ScGlobal::eLnge, 0, rEntry.pStr->Len(),
1093
                                &xOff ) );
1094
                            bOk = (aCell.Search( aQuer ) != STRING_NOTFOUND);
1095
                        }
1096
                        if ( rEntry.eOp == SC_NOT_EQUAL )
1097
                            bOk = !bOk;
1069
                    }
1098
                    }
1070
                    else if ( bMatchWholeCell )
1099
                    else
1071
                        bOk = pTransliteration->isEqual( aCellStr, *rEntry.pStr );
1100
                    {   // use collator here because data was probably sorted
1072
					else
1101
                        sal_Int32 nCompare = pCollator->compareString(
1073
					{
1102
                            aCellStr, *rEntry.pStr );
1074
                        ::com::sun::star::uno::Sequence< sal_Int32 > xOff;
1103
                        switch (rEntry.eOp)
1075
                        String aCell( pTransliteration->transliterate(
1076
                            aCellStr, ScGlobal::eLnge, 0, aCellStr.Len(),
1077
                            &xOff ) );
1078
                        String aQuer( pTransliteration->transliterate(
1079
                            *rEntry.pStr, ScGlobal::eLnge, 0, rEntry.pStr->Len(),
1080
                            &xOff ) );
1081
                        bOk = (aCell.Search( aQuer ) != STRING_NOTFOUND);
1082
					}
1083
					if ( rEntry.eOp == SC_NOT_EQUAL )
1084
						bOk = !bOk;
1085
				}
1086
				else
1087
                {   // use collator here because data was probably sorted
1088
					sal_Int32 nCompare = pCollator->compareString(
1089
						aCellStr, *rEntry.pStr );
1090
					switch (rEntry.eOp)
1091
					{
1092
						case SC_LESS :
1093
                            bOk = (nCompare < 0);
1094
							break;
1095
						case SC_GREATER :
1096
                            bOk = (nCompare > 0);
1097
							break;
1098
						case SC_LESS_EQUAL :
1099
                            bOk = (nCompare <= 0);
1100
                            if ( bOk && pbTestEqualCondition && !bTestEqual )
1101
                                bTestEqual = (nCompare == 0);
1102
							break;
1103
						case SC_GREATER_EQUAL :
1104
                            bOk = (nCompare >= 0);
1105
                            if ( bOk && pbTestEqualCondition && !bTestEqual )
1106
                                bTestEqual = (nCompare == 0);
1107
							break;
1108
                        default:
1109
                        {
1104
                        {
1110
                            // added to avoid warnings
1105
                            case SC_LESS :
1106
                                bOk = (nCompare < 0);
1107
                                break;
1108
                            case SC_GREATER :
1109
                                bOk = (nCompare > 0);
1110
                                break;
1111
                            case SC_LESS_EQUAL :
1112
                                bOk = (nCompare <= 0);
1113
                                if ( bOk && pbTestEqualCondition && !bTestEqual )
1114
                                    bTestEqual = (nCompare == 0);
1115
                                break;
1116
                            case SC_GREATER_EQUAL :
1117
                                bOk = (nCompare >= 0);
1118
                                if ( bOk && pbTestEqualCondition && !bTestEqual )
1119
                                    bTestEqual = (nCompare == 0);
1120
                                break;
1121
                            default:
1122
                            {
1123
                                    // added to avoid warnings
1124
                            }
1111
                        }
1125
                        }
1112
					}
1126
                    }
1113
				}
1127
                } // if ( !bRealRegExp )
1114
			}
1128
            }
1115
		}
1129
		}
1116
        else if (rParam.bMixedComparison)
1130
        else if (rParam.bMixedComparison)
1117
        {
1131
        {
(-)sc/source/core/tool/dbcolect.cxx (+6 lines)
Lines 544-549 Link Here
544
		*pQueryStr[i]		= *rData.pQueryStr[i];
544
		*pQueryStr[i]		= *rData.pQueryStr[i];
545
		nQueryVal[i]		= rData.nQueryVal[i];
545
		nQueryVal[i]		= rData.nQueryVal[i];
546
		eQueryConnect[i]	= rData.eQueryConnect[i];
546
		eQueryConnect[i]	= rData.eQueryConnect[i];
547
        bMatchMultiStrValues[i] = rData.bMatchMultiStrValues[i];
548
        aStrValues[i] = rData.aStrValues[i];
547
	}
549
	}
548
	for (i=0; i<MAXSUBTOTAL; i++)
550
	for (i=0; i<MAXSUBTOTAL; i++)
549
	{
551
	{
Lines 812-817 Link Here
812
		*rEntry.pStr = *pQueryStr[i];
814
		*rEntry.pStr = *pQueryStr[i];
813
		rEntry.nVal = nQueryVal[i];
815
		rEntry.nVal = nQueryVal[i];
814
		rEntry.eConnect = eQueryConnect[i];
816
		rEntry.eConnect = eQueryConnect[i];
817
        rEntry.bMatchMultiStrValues = bMatchMultiStrValues[i];
818
        rEntry.aStrValues = aStrValues[i];
815
	}
819
	}
816
}
820
}
817
821
Lines 843-848 Link Here
843
		*pQueryStr[i] = *rEntry.pStr;
847
		*pQueryStr[i] = *rEntry.pStr;
844
		nQueryVal[i] = rEntry.nVal;
848
		nQueryVal[i] = rEntry.nVal;
845
		eQueryConnect[i] = rEntry.eConnect;
849
		eQueryConnect[i] = rEntry.eConnect;
850
        bMatchMultiStrValues[i] = rEntry.bMatchMultiStrValues;
851
        aStrValues[i] = rEntry.aStrValues;
846
	}
852
	}
847
}
853
}
848
854
(-)sc/source/ui/dbgui/filtdlg.cxx (+4 lines)
Lines 586-591 Link Here
586
            rEntry.nField = nField ? (theQueryData.nCol1 +
586
            rEntry.nField = nField ? (theQueryData.nCol1 +
587
                    static_cast<SCCOL>(nField) - 1) : static_cast<SCCOL>(0);
587
                    static_cast<SCCOL>(nField) - 1) : static_cast<SCCOL>(0);
588
			rEntry.eOp	  = eOp;
588
			rEntry.eOp	  = eOp;
589
590
            // Disable multi-string matching until we have the UI implemented.
591
            // TODO: Implement it in the UI (kohei).
592
            rEntry.bMatchMultiStrValues = false;
589
		}
593
		}
590
	}
594
	}
591
595
(-)sc/source/ui/unoobj/datauno.cxx (+21 lines)
Lines 1150-1155 Link Here
1150
		aField.IsNumeric	 = !rEntry.bQueryByString;
1150
		aField.IsNumeric	 = !rEntry.bQueryByString;
1151
		aField.StringValue	 = aStringValue;
1151
		aField.StringValue	 = aStringValue;
1152
		aField.NumericValue	 = rEntry.nVal;
1152
		aField.NumericValue	 = rEntry.nVal;
1153
        aField.MatchMultiStringValues = rEntry.bMatchMultiStrValues;
1153
1154
1154
		switch (rEntry.eOp)				// ScQueryOp
1155
		switch (rEntry.eOp)				// ScQueryOp
1155
		{
1156
		{
Lines 1184-1189 Link Here
1184
				DBG_ERROR("Falscher Filter-enum");
1185
				DBG_ERROR("Falscher Filter-enum");
1185
				aField.Operator = sheet::FilterOperator_EMPTY;
1186
				aField.Operator = sheet::FilterOperator_EMPTY;
1186
		}
1187
		}
1188
1189
        if (rEntry.bMatchMultiStrValues && rEntry.aStrValues.size())
1190
        {
1191
            uno::Sequence<rtl::OUString> aStrList(rEntry.aStrValues.size());
1192
            ScHashOUStringSet::const_iterator itr, itrEnd = rEntry.aStrValues.end();
1193
            sal_Int32 nStrCount = 0;
1194
            for (itr = rEntry.aStrValues.begin(); itr != itrEnd; ++itr, ++nStrCount)
1195
                aStrList[nStrCount] = *itr;
1196
            aField.StringValues = aStrList;
1197
        }
1187
		pAry[i] = aField;
1198
		pAry[i] = aField;
1188
	}
1199
	}
1189
	return aSeq;
1200
	return aSeq;
Lines 1216-1221 Link Here
1216
		rEntry.bQueryByString	= !pAry[i].IsNumeric;
1227
		rEntry.bQueryByString	= !pAry[i].IsNumeric;
1217
		*rEntry.pStr			= String( pAry[i].StringValue );
1228
		*rEntry.pStr			= String( pAry[i].StringValue );
1218
		rEntry.nVal				= pAry[i].NumericValue;
1229
		rEntry.nVal				= pAry[i].NumericValue;
1230
        rEntry.bMatchMultiStrValues = pAry[i].MatchMultiStringValues;
1219
1231
1220
        if (!rEntry.bQueryByString && pDocSh)
1232
        if (!rEntry.bQueryByString && pDocSh)
1221
        {
1233
        {
Lines 1254-1259 Link Here
1254
				DBG_ERROR("Falscher Query-enum");
1266
				DBG_ERROR("Falscher Query-enum");
1255
				rEntry.eOp = SC_EQUAL;
1267
				rEntry.eOp = SC_EQUAL;
1256
		}
1268
		}
1269
1270
        if (pAry[i].MatchMultiStringValues)
1271
        {
1272
            // The option for matching individual string values is set.
1273
            const uno::Sequence<rtl::OUString>& aStrValues = pAry[i].StringValues;
1274
            sal_Int32 nLen = aStrValues.getLength();
1275
            for (sal_Int32 nStrCount = 0; nStrCount < nLen; ++nStrCount)
1276
                rEntry.aStrValues.insert(aStrValues[nStrCount]);
1277
        }
1257
    }
1278
    }
1258
1279
1259
	SCSIZE nParamCount = aParam.GetEntryCount();	// Param wird nicht unter 8 resized
1280
	SCSIZE nParamCount = aParam.GetEntryCount();	// Param wird nicht unter 8 resized
(-)sc/source/ui/view/gridwin.cxx (+4 lines)
Lines 1299-1304 Link Here
1299
		ScQueryParam aParam;
1299
		ScQueryParam aParam;
1300
		pDBData->GetQueryParam( aParam );		// kann nur MAXQUERY Eintraege ergeben
1300
		pDBData->GetQueryParam( aParam );		// kann nur MAXQUERY Eintraege ergeben
1301
1301
1302
        // Disable multi-string match flag until we implement it in the UI.
1303
        for (SCSIZE i = 0; i < MAXQUERY; ++i)
1304
            aParam.GetEntry(i).bMatchMultiStrValues = false;
1305
1302
		if (SC_AUTOFILTER_CUSTOM == nSel)
1306
		if (SC_AUTOFILTER_CUSTOM == nSel)
1303
		{
1307
		{
1304
			pViewData->GetView()->SetCursor(nCol,nRow);		//! auch ueber Slot ??
1308
			pViewData->GetView()->SetCursor(nCol,nRow);		//! auch ueber Slot ??

Return to issue 77677