| /******************************************************************************* |
| * Copyright (c) 2011 Tasktop Technologies. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Tasktop Technologies - initial API and implementation |
| *******************************************************************************/ |
| #include "stdafx.h" |
| #include "Windows7Search.h" |
| #include "Windows7SearchProvider.h" |
| |
| #include <sstream> |
| #include <list> |
| |
| |
| #import "C:/Program Files/Common Files/System/ado/msado15.dll" rename("EOF", "ADOEOF") |
| |
| void InvokeCallback(JNIEnv *env, jobject obj, jobject callback, std::wstring filename) |
| { |
| jstring j_filename = env->NewString((const jchar *)filename.c_str(), filename.length()); |
| |
| jclass fileClass = env->FindClass("java/io/File"); |
| jmethodID fileConstructor = env->GetMethodID(fileClass, "<init>", "(Ljava/lang/String;)V"); |
| jobject fileObj = env->NewObject(fileClass, fileConstructor, j_filename); |
| |
| jclass resultClass = env->FindClass("org/eclipse/mylyn/sandbox/search/ui/SearchResult"); |
| jmethodID resultConstructor = env->GetMethodID(resultClass, "<init>", "(Ljava/io/File;)V"); |
| jobject resultObj = env->NewObject(resultClass, resultConstructor, fileObj); |
| |
| jclass jc = env->GetObjectClass(callback); |
| jmethodID mid = env->GetMethodID(jc, "searchResult","(Lorg/eclipse/mylyn/sandbox/search/ui/SearchResult;)V"); |
| env->CallObjectMethod(callback, mid, resultObj); |
| } |
| |
| bool IsProgressMonitorCancelled(JNIEnv *env,jobject monitor) { |
| jclass monitorClass = env->FindClass("org/eclipse/core/runtime/IProgressMonitor"); |
| jmethodID isCanceledMethod = env->GetMethodID(monitorClass,"isCanceled","()Z"); |
| |
| jboolean result = env->CallBooleanMethod(monitor,isCanceledMethod); |
| return result == JNI_TRUE; |
| } |
| |
| std::wstring ReplaceCharWithString(std::wstring source, const wchar_t replaceChar, std::wstring replaceString) |
| { |
| size_t posn = source.find(&replaceChar); |
| while (posn != std::wstring::npos) |
| { |
| source.replace(posn, 1, replaceString); |
| posn = source.find(&replaceChar, posn + replaceString.length()); |
| } |
| return source; |
| } |
| |
| std::wstring IntToString(int value) { |
| std::wstringstream sstream; |
| sstream << value; |
| return sstream.str(); |
| } |
| |
| |
| void PerformSearch(JNIEnv *env, jobject obj, jobject callback, std::wstring searchText, std::list<std::wstring>& patterns,int maximumResults, jobject monitor) |
| { |
| |
| ADODB::_ConnectionPtr connection = NULL; |
| ADODB::_RecordsetPtr recordset = NULL; |
| try { |
| HRESULT hr = ::CoInitialize(NULL); |
| if (!SUCCEEDED(hr)) |
| return; |
| |
| hr = connection.CreateInstance(__uuidof(ADODB::Connection)); |
| if (!SUCCEEDED(hr)) |
| return; |
| |
| hr = recordset.CreateInstance(__uuidof(ADODB::Recordset)); |
| if (!SUCCEEDED(hr)) |
| return; |
| |
| connection->CursorLocation = ADODB::adUseClient; |
| hr = connection->Open(L"Provider=Search.CollatorDSO;Extended Properties='Application=Windows';", L"", L"", ADODB::adConnectUnspecified); |
| if (!SUCCEEDED(hr)) |
| return; |
| |
| |
| searchText = ReplaceCharWithString(searchText, '\'', L"''"); |
| |
| std::wstring filenameMatcher = searchText; |
| filenameMatcher = ReplaceCharWithString(filenameMatcher, '%', L"\\%"); |
| filenameMatcher = ReplaceCharWithString(filenameMatcher, '*', L"%"); |
| |
| // see FREETEXT http://msdn.microsoft.com/en-us/library/bb231268(v=vs.85).aspx |
| // see CONTAINS http://msdn.microsoft.com/en-us/library/bb231270(v=vs.85).aspx |
| |
| std::wstring query = L"SELECT TOP "; |
| query += IntToString(maximumResults); |
| query += L" System.ItemPathDisplay from SystemIndex WHERE "; |
| // limit to documents, pictures and video |
| query += L"(System.Kind = 'document' or System.Kind = 'picture' or System.Kind = 'video' or System.Kind is null) AND "; |
| // content search |
| query += L"(FREETEXT('\""; |
| query += searchText; |
| query += L"\"') OR "; |
| // filename search |
| query += L"(System.ItemName LIKE '%"; |
| query += filenameMatcher; |
| query += L"%'))"; |
| |
| if (patterns.size() > 0) { |
| bool hasFilenameSearch = true; |
| std::wstring anyFile(L"*"); |
| |
| for(std::list<std::wstring>::iterator iterator = patterns.begin(); iterator != patterns.end(); iterator++) { |
| std::wstring pattern = *iterator; |
| if (pattern == anyFile) { |
| hasFilenameSearch = false; |
| break; |
| } |
| } |
| if (hasFilenameSearch) { |
| query += L" AND ("; |
| for(std::list<std::wstring>::iterator iterator = patterns.begin(); iterator != patterns.end(); iterator++) { |
| std::wstring pattern = *iterator; |
| if (pattern.size() == 0) { |
| continue; |
| } |
| pattern = ReplaceCharWithString(pattern, '*', L"%"); |
| if (iterator != patterns.begin()) { |
| query += L" OR "; |
| } |
| query += L"(System.ItemName LIKE '"; |
| if (pattern[0] != '%') { |
| query += L"%"; |
| } |
| query += pattern; |
| query += L"')"; |
| } |
| query += L")"; |
| } |
| } |
| |
| //std::cout << "Query:\n"; |
| //std::cout << query; |
| //std::cout << "\n"; |
| //std::cout << std::flush; |
| |
| hr = recordset->Open(query.c_str(), connection.GetInterfacePtr(), ADODB::adOpenForwardOnly, ADODB::adLockReadOnly, ADODB::adCmdText); |
| if (!SUCCEEDED(hr)) { |
| std::cout << "Open Failed\n" << std::flush; |
| return; |
| } |
| |
| int count = maximumResults; |
| |
| |
| while(!recordset->ADOEOF) |
| { |
| _variant_t var = recordset->Fields->GetItem(L"System.ItemPathDisplay")->GetValue(); |
| std::wstring filename = (const wchar_t*)_bstr_t(var.bstrVal); |
| InvokeCallback(env, obj, callback, filename); |
| |
| if (IsProgressMonitorCancelled(env,monitor)) { |
| break; |
| } |
| |
| if (--count < 0) { |
| break; |
| } |
| |
| hr = recordset->MoveNext(); |
| if (!SUCCEEDED(hr)) { |
| std::cout << "Move Next Failed\n" << std::flush; |
| break; |
| } |
| } |
| } catch (_com_error &e) { |
| _tprintf(_T("\tCOM Error code = %08lx\n"), e.Error()); |
| } |
| |
| |
| if (recordset != NULL && recordset->State == ADODB::adStateOpen) |
| recordset->Close(); |
| if (connection != NULL && connection->State == ADODB::adStateOpen) |
| connection->Close(); |
| |
| ::CoUninitialize(); |
| } |
| |
| std::wstring JStringToWString (JNIEnv *env, jstring javaString) |
| { |
| const jchar *javaChars = env->GetStringChars(javaString, NULL); |
| jsize length = env->GetStringLength(javaString); |
| std::wstring wideString((wchar_t *)javaChars, length); |
| env->ReleaseStringChars(javaString, javaChars); |
| return wideString; |
| } |
| |
| JNIEXPORT void JNICALL Java_org_eclipse_mylyn_internal_sandbox_search_ui_windows_WindowsSearchProvider_performNativeSearch (JNIEnv *env, jobject obj, jobject criteria, jobject callback, jobject monitor) |
| { |
| |
| jclass jc = env->GetObjectClass(criteria); |
| jmethodID mid = env->GetMethodID(jc, "getText","()Ljava/lang/String;"); |
| jstring jSearchText = (jstring)env->CallObjectMethod(criteria, mid); |
| std::wstring searchText = JStringToWString(env, jSearchText); |
| |
| jmethodID getPatternId = env->GetMethodID(jc, "getFilenamePatterns","()[Ljava/lang/String;"); |
| jobjectArray patternArray = (jobjectArray)env->CallObjectMethod(criteria, getPatternId); |
| unsigned int patternCount = env->GetArrayLength(patternArray); |
| |
| |
| // FIXME FIXME FIXME |
| jmethodID getMaximumResultsId = env->GetMethodID(jc,"getMaximumResults","()I"); |
| jint maximumResults = (jint) env->CallIntMethod(criteria,getMaximumResultsId); |
| |
| |
| std::list<std::wstring> patterns; |
| for (unsigned int i=0; i<patternCount; i++) { |
| jstring jPattern = (jstring)env->GetObjectArrayElement(patternArray, i); |
| std::wstring pattern = JStringToWString(env, jPattern); |
| patterns.push_back(pattern); |
| } |
| |
| PerformSearch(env, obj, callback, searchText, patterns,(int) maximumResults, monitor); |
| } |