1 /* 2 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "common.h" 27 28 #include <ShObjIdl.h> 29 30 #include "CommonDialogs_COM.h" 31 32 #include "com_sun_glass_ui_CommonDialogs_Type.h" 33 34 /***************************** 35 * IFileDialog implementation 36 *****************************/ 37 38 _COM_SMARTPTR_TYPEDEF(IFileDialog, __uuidof(IFileDialog)); 39 _COM_SMARTPTR_TYPEDEF(IFileOpenDialog, __uuidof(IFileOpenDialog)); 40 _COM_SMARTPTR_TYPEDEF(IShellItem, __uuidof(IShellItem)); 41 _COM_SMARTPTR_TYPEDEF(IShellItemArray, __uuidof(IShellItemArray)); 42 43 #if (_WIN32_IE < _WIN32_IE_IE70) 44 SHSTDAPI SHCreateItemFromParsingName(__in PCWSTR pszPath, __in_opt IBindCtx *pbc, __in REFIID riid, __deref_out void **ppv); 45 #endif // (_WIN32_IE < _WIN32_IE_IE70) 46 47 const HRESULT CANCEL_HRT = HRESULT_FROM_WIN32(ERROR_CANCELLED); 48 49 jstring CreateJString(JNIEnv *env, IShellItemPtr pFile) 50 { 51 LPWSTR path = NULL; 52 jstring ret = NULL; 53 54 OLE_TRY 55 OLE_HRT( pFile->GetDisplayName(SIGDN_FILESYSPATH, &path) ); 56 OLE_CATCH 57 58 ret = CreateJString(env, path); 59 CoTaskMemFree(path); 60 return ret; 61 } 62 63 wchar_t *GetDescription(JNIEnv *env, jobject jFilter) 64 { 65 JLString jDesc(env, (jstring)env->CallObjectMethod(jFilter, 66 javaIDs.CommonDialogs.ExtensionFilter.getDescription)); 67 CheckAndClearException(env); 68 JString desc(env, jDesc, false); 69 return desc; 70 } 71 72 wchar_t *GetExtensions(JNIEnv *env, jobject jFilter) 73 { 74 JLObjectArray jExts(env, (jobjectArray)env->CallObjectMethod(jFilter, 75 javaIDs.CommonDialogs.ExtensionFilter.extensionsToArray)); 76 CheckAndClearException(env); 77 78 jsize size = env->GetArrayLength(jExts); 79 BOOL isHeading = TRUE; // extension without semicolon 80 81 JLString jExt(env, CreateJString(env, _T(""))); 82 JLString semicolon(env, CreateJString(env, _T(";"))); 83 84 for (int j = 0; j < size; j++) { 85 if (!isHeading) { 86 jExt.Attach( ConcatJStrings(env, jExt, semicolon) ); 87 } 88 isHeading = FALSE; 89 90 JLString jExtension(env, (jstring)env->GetObjectArrayElement(jExts, j)); 91 jExt.Attach( ConcatJStrings(env, jExt, jExtension) ); 92 } 93 94 JString ext(env, jExt, false); 95 return ext; 96 } 97 98 void SetFilters(IFileDialogPtr pDialog, jobjectArray jFilters, jint defaultFilterIndex) 99 { 100 JNIEnv *env = GetEnv(); 101 102 jsize size = env->GetArrayLength(jFilters); 103 COMDLG_FILTERSPEC *filterSpec = new COMDLG_FILTERSPEC[size]; 104 105 for (int i = 0; i < size; i++) { 106 JLObject jFilter(env, env->GetObjectArrayElement(jFilters, i)); 107 COMDLG_FILTERSPEC c = {GetDescription(env, jFilter), 108 GetExtensions(env, jFilter)}; 109 filterSpec[i] = c; 110 } 111 112 OLE_TRY 113 OLE_HRT( pDialog->SetDefaultExtension(L"") ); 114 OLE_HRT( pDialog->SetFileTypes(size, filterSpec) ); 115 if (size > 0) { 116 OLE_HRT( pDialog->SetFileTypeIndex(defaultFilterIndex + 1) ); // 1-based index required 117 } 118 OLE_CATCH 119 120 for (int i = 0; i < size; i++) { 121 if (filterSpec[i].pszName) { 122 delete[] filterSpec[i].pszName; 123 } 124 if (filterSpec[i].pszSpec) { 125 delete[] filterSpec[i].pszSpec; 126 } 127 } 128 delete[] filterSpec; 129 } 130 131 jobjectArray GetFiles(IFileDialogPtr pDialog, BOOL isCancelled, jint type) 132 { 133 JNIEnv* env = GetEnv(); 134 jclass jc = env->FindClass("java/lang/String"); 135 if (CheckAndClearException(env)) return NULL; 136 JLClass cls(env, jc); 137 138 jobjectArray ret = NULL; 139 140 if (isCancelled) { 141 ret = env->NewObjectArray(0, cls, NULL); 142 if (CheckAndClearException(env)) return NULL; 143 return ret; 144 } 145 146 OLE_TRY 147 if (type == com_sun_glass_ui_CommonDialogs_Type_SAVE) { 148 ret = env->NewObjectArray(1, cls, NULL); 149 if (CheckAndClearException(env)) return NULL; 150 151 IShellItemPtr pFile; 152 OLE_HRT( pDialog->GetResult(&pFile) ); 153 OLE_CHECK_NOTNULLSP(pFile) 154 155 env->SetObjectArrayElement(ret, 0, 156 jstring(JLString(env, CreateJString(env, pFile)))); 157 CheckAndClearException(env); 158 return ret; 159 } 160 161 IFileOpenDialogPtr pOpenDialog(pDialog); 162 OLE_CHECK_NOTNULLSP(pOpenDialog) 163 164 IShellItemArrayPtr pFiles; 165 OLE_HRT( pOpenDialog->GetResults(&pFiles) ); 166 OLE_CHECK_NOTNULLSP(pFiles) 167 168 DWORD count = 0; 169 OLE_HRT( pFiles->GetCount(&count) ); 170 171 ret = env->NewObjectArray(count, cls, NULL); 172 if (CheckAndClearException(env)) return NULL; 173 174 for (DWORD i = 0; i < count; i++) { 175 IShellItemPtr pFile; 176 OLE_HRT( pFiles->GetItemAt(i, &pFile) ); 177 OLE_CHECK_NOTNULLSP(pFile) 178 179 env->SetObjectArrayElement(ret, i, 180 jstring(JLString(env, CreateJString(env, pFile)))); 181 CheckAndClearException(env); 182 } 183 OLE_CATCH 184 185 return ret; 186 } 187 188 jobject COMFileChooser_Show(HWND owner, LPCTSTR folder, LPCTSTR filename, LPCTSTR title, jint type, 189 jboolean multipleMode, jobjectArray jFilters, jint defaultFilterIndex) 190 { 191 OLEHolder _ole_; 192 IFileDialogPtr pDialog; 193 194 OLE_TRY 195 196 switch(type) { 197 case com_sun_glass_ui_CommonDialogs_Type_OPEN: 198 OLE_HRT( ::CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL, 199 IID_IFileOpenDialog, (void**)&pDialog) ); 200 201 if (multipleMode == TRUE) { 202 DWORD dwOptions = 0; 203 OLE_HRT( pDialog->GetOptions(&dwOptions) ); 204 dwOptions |= FOS_ALLOWMULTISELECT; 205 OLE_HRT( pDialog->SetOptions(dwOptions) ); 206 } 207 208 break; 209 case com_sun_glass_ui_CommonDialogs_Type_SAVE: 210 OLE_HRT( ::CoCreateInstance(CLSID_FileSaveDialog, NULL, CLSCTX_ALL, 211 IID_IFileSaveDialog, (void**)&pDialog) ); 212 break; 213 } 214 215 if (folder) { 216 IShellItemPtr pItem; 217 OLE_HRT( SHCreateItemFromParsingName((PCWSTR)folder, NULL, 218 IID_IShellItem, (void **)&pItem) ); 219 if (pItem) { 220 OLE_HRT( pDialog->SetFolder( pItem ) ); 221 } 222 } 223 224 if (type == com_sun_glass_ui_CommonDialogs_Type_SAVE && filename && *filename) { 225 OLE_HRT( pDialog->SetFileName(filename); ); 226 } 227 228 if (title) { 229 OLE_HRT( pDialog->SetTitle(title) ); 230 } 231 232 if (jFilters != NULL) { 233 SetFilters(pDialog, jFilters, defaultFilterIndex); 234 } 235 236 OLE_HR = pDialog->Show(owner); 237 if (OLE_HR != CANCEL_HRT && FAILED(OLE_HR)) { 238 OLE_THROW_LASTERROR(_T("pDialog->Show(NULL)")) 239 } 240 OLE_CATCH 241 242 jobjectArray ret = GetFiles(pDialog, OLE_HR == CANCEL_HRT, type); 243 244 UINT index = 0; 245 pDialog->GetFileTypeIndex(&index); 246 247 JNIEnv* env = GetEnv(); 248 jclass jc = env->FindClass("com/sun/glass/ui/CommonDialogs"); 249 if (CheckAndClearException(env)) return NULL; 250 JLClass cls(env, jc); 251 jobject jobj = env->CallStaticObjectMethod(cls, javaIDs.CommonDialogs.createFileChooserResult, 252 ret, jFilters, (jint)(index - 1)); 253 if (CheckAndClearException(env)) return NULL; 254 return jobj; 255 } 256 257 /***************************** 258 * IFileDialog implementation 259 *****************************/ 260 261 jstring GetFolder(IFileDialogPtr pDialog, BOOL isCancelled) 262 { 263 if (isCancelled) { 264 return NULL; 265 } 266 267 JNIEnv* env = GetEnv(); 268 IShellItemPtr pFile; 269 270 OLE_TRY 271 OLE_HRT( pDialog->GetResult(&pFile) ); 272 OLE_CATCH 273 274 return CreateJString(env, pFile); 275 } 276 277 jstring COMFolderChooser_Show(HWND owner, LPCTSTR folder, LPCTSTR title) 278 { 279 OLEHolder _ole_; 280 IFileDialogPtr pDialog; 281 282 OLE_TRY 283 OLE_HRT( ::CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL, 284 IID_IFileOpenDialog, (void**)&pDialog) ); 285 286 DWORD dwOptions = 0; 287 OLE_HRT( pDialog->GetOptions(&dwOptions) ); 288 dwOptions |= FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM; 289 OLE_HRT( pDialog->SetOptions(dwOptions) ); 290 291 if (folder) { 292 IShellItemPtr pItem; 293 OLE_HRT( SHCreateItemFromParsingName((PCWSTR)folder, NULL, 294 IID_IShellItem, (void **)&pItem) ); 295 if (pItem) { 296 OLE_HRT( pDialog->SetFolder( pItem ) ); 297 } 298 } 299 300 if (title) { 301 OLE_HRT( pDialog->SetTitle(title) ); 302 } 303 304 OLE_HR = pDialog->Show(owner); 305 if (OLE_HR != CANCEL_HRT && FAILED(OLE_HR)) { 306 OLE_THROW_LASTERROR(_T("pDialog->Show(NULL)")) 307 } 308 OLE_CATCH 309 310 return GetFolder(pDialog, OLE_HR == CANCEL_HRT); 311 }