|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2017 - ROLI Ltd.
-
- JUCE is an open source library subject to commercial or open-source
- licensing.
-
- By using JUCE, you agree to the terms of both the JUCE 5 End-User License
- Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
- 27th April 2017).
-
- End User License Agreement: www.juce.com/juce-5-licence
- Privacy Policy: www.juce.com/juce-5-privacy-policy
-
- Or: You may also use this code under the terms of the GPL v3 (see
- www.gnu.org/licenses).
-
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
-
- ==============================================================================
- */
-
- namespace juce
- {
-
- namespace FileChooserHelpers
- {
- struct FileChooserCallbackInfo
- {
- String initialPath;
- String returnedString; // need this to get non-existent pathnames from the directory chooser
- ScopedPointer<Component> customComponent;
- };
-
- static int CALLBACK browseCallbackProc (HWND hWnd, UINT msg, LPARAM lParam, LPARAM lpData)
- {
- FileChooserCallbackInfo* info = (FileChooserCallbackInfo*) lpData;
-
- if (msg == BFFM_INITIALIZED)
- SendMessage (hWnd, BFFM_SETSELECTIONW, TRUE, (LPARAM) info->initialPath.toWideCharPointer());
- else if (msg == BFFM_VALIDATEFAILEDW)
- info->returnedString = (LPCWSTR) lParam;
- else if (msg == BFFM_VALIDATEFAILEDA)
- info->returnedString = (const char*) lParam;
-
- return 0;
- }
-
- static UINT_PTR CALLBACK openCallback (HWND hdlg, UINT uiMsg, WPARAM /*wParam*/, LPARAM lParam)
- {
- if (uiMsg == WM_INITDIALOG)
- {
- Component* customComp = ((FileChooserCallbackInfo*) (((OPENFILENAMEW*) lParam)->lCustData))->customComponent;
-
- HWND dialogH = GetParent (hdlg);
- jassert (dialogH != 0);
- if (dialogH == 0)
- dialogH = hdlg;
-
- RECT r, cr;
- GetWindowRect (dialogH, &r);
- GetClientRect (dialogH, &cr);
-
- SetWindowPos (dialogH, 0,
- r.left, r.top,
- customComp->getWidth() + jmax (150, (int) (r.right - r.left)),
- jmax (150, (int) (r.bottom - r.top)),
- SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
-
- customComp->setBounds (cr.right, cr.top, customComp->getWidth(), cr.bottom - cr.top);
- customComp->addToDesktop (0, dialogH);
- }
- else if (uiMsg == WM_NOTIFY)
- {
- LPOFNOTIFY ofn = (LPOFNOTIFY) lParam;
-
- if (ofn->hdr.code == CDN_SELCHANGE)
- {
- FileChooserCallbackInfo* info = (FileChooserCallbackInfo*) ofn->lpOFN->lCustData;
-
- if (FilePreviewComponent* comp = dynamic_cast<FilePreviewComponent*> (info->customComponent->getChildComponent(0)))
- {
- WCHAR path [MAX_PATH * 2] = { 0 };
- if (CommDlg_OpenSave_GetFilePath (GetParent (hdlg), (LPARAM) &path, MAX_PATH) < 0)
- return 0;
-
- comp->selectedFileChanged (File (path));
- }
- }
- }
-
- return 0;
- }
-
- class CustomComponentHolder : public Component
- {
- public:
- CustomComponentHolder (Component* const customComp)
- {
- setVisible (true);
- setOpaque (true);
- addAndMakeVisible (customComp);
- setSize (jlimit (20, 800, customComp->getWidth()), customComp->getHeight());
- }
-
- void paint (Graphics& g) override
- {
- g.fillAll (Colours::lightgrey);
- }
-
- void resized() override
- {
- if (Component* const c = getChildComponent(0))
- c->setBounds (getLocalBounds());
- }
-
- private:
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CustomComponentHolder)
- };
- }
-
- //==============================================================================
- bool FileChooser::isPlatformDialogAvailable()
- {
- #if JUCE_DISABLE_NATIVE_FILECHOOSERS
- return false;
- #else
- return true;
- #endif
- }
-
- void FileChooser::showPlatformDialog (Array<File>& results, const String& title_, const File& currentFileOrDirectory,
- const String& filter, bool selectsDirectory, bool /*selectsFiles*/,
- bool isSaveDialogue, bool warnAboutOverwritingExistingFiles,
- bool selectMultipleFiles, bool /*treatFilePackagesAsDirs*/,
- FilePreviewComponent* extraInfoComponent)
- {
- using namespace FileChooserHelpers;
-
- const String title (title_);
- String defaultExtension; // scope of these strings must extend beyond dialog's lifetime.
-
- HeapBlock<WCHAR> files;
- const size_t charsAvailableForResult = 32768;
- files.calloc (charsAvailableForResult + 1);
- int filenameOffset = 0;
-
- FileChooserCallbackInfo info;
-
- // use a modal window as the parent for this dialog box
- // to block input from other app windows
- Component parentWindow;
- const Rectangle<int> mainMon (Desktop::getInstance().getDisplays().getMainDisplay().userArea);
- parentWindow.setBounds (mainMon.getX() + mainMon.getWidth() / 4,
- mainMon.getY() + mainMon.getHeight() / 4,
- 0, 0);
- parentWindow.setOpaque (true);
- parentWindow.setAlwaysOnTop (juce_areThereAnyAlwaysOnTopWindows());
- parentWindow.addToDesktop (0);
-
- if (extraInfoComponent == nullptr)
- parentWindow.enterModalState();
-
- auto parentDirectory = currentFileOrDirectory.getParentDirectory();
-
- // Handle nonexistent root directories in the same way as existing ones
- if (currentFileOrDirectory.isDirectory() || currentFileOrDirectory.isRoot())
- {
- info.initialPath = currentFileOrDirectory.getFullPathName();
- }
- else
- {
- currentFileOrDirectory.getFileName().copyToUTF16 (files, charsAvailableForResult * sizeof (WCHAR));
- info.initialPath = parentDirectory.getFullPathName();
- }
-
- if (selectsDirectory)
- {
- BROWSEINFO bi = { 0 };
- bi.hwndOwner = (HWND) parentWindow.getWindowHandle();
- bi.pszDisplayName = files;
- bi.lpszTitle = title.toWideCharPointer();
- bi.lParam = (LPARAM) &info;
- bi.lpfn = browseCallbackProc;
- #ifdef BIF_USENEWUI
- bi.ulFlags = BIF_USENEWUI | BIF_VALIDATE;
- #else
- bi.ulFlags = 0x50;
- #endif
-
- LPITEMIDLIST list = SHBrowseForFolder (&bi);
-
- if (! SHGetPathFromIDListW (list, files))
- {
- files[0] = 0;
- info.returnedString.clear();
- }
-
- LPMALLOC al;
- if (list != nullptr && SUCCEEDED (SHGetMalloc (&al)))
- al->Free (list);
-
- if (info.returnedString.isNotEmpty())
- {
- results.add (File (String (files.get())).getSiblingFile (info.returnedString));
- return;
- }
- }
- else
- {
- DWORD flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_ENABLESIZING;
-
- if (warnAboutOverwritingExistingFiles)
- flags |= OFN_OVERWRITEPROMPT;
-
- if (selectMultipleFiles)
- flags |= OFN_ALLOWMULTISELECT;
-
- if (extraInfoComponent != nullptr)
- {
- flags |= OFN_ENABLEHOOK;
-
- info.customComponent = new CustomComponentHolder (extraInfoComponent);
- info.customComponent->enterModalState (false);
- }
-
- const size_t filterSpaceNumChars = 2048;
- HeapBlock<WCHAR> filters;
- filters.calloc (filterSpaceNumChars);
- const size_t bytesWritten = filter.copyToUTF16 (filters.getData(), filterSpaceNumChars * sizeof (WCHAR));
- filter.copyToUTF16 (filters + (bytesWritten / sizeof (WCHAR)),
- ((filterSpaceNumChars - 1) * sizeof (WCHAR) - bytesWritten));
-
- for (size_t i = 0; i < filterSpaceNumChars; ++i)
- if (filters[i] == '|')
- filters[i] = 0;
-
- OPENFILENAMEW of = { 0 };
- String localPath (info.initialPath);
-
- #ifdef OPENFILENAME_SIZE_VERSION_400W
- of.lStructSize = OPENFILENAME_SIZE_VERSION_400W;
- #else
- of.lStructSize = sizeof (of);
- #endif
- of.hwndOwner = (HWND) parentWindow.getWindowHandle();
- of.lpstrFilter = filters.getData();
- of.nFilterIndex = 1;
- of.lpstrFile = files;
- of.nMaxFile = (DWORD) charsAvailableForResult;
- of.lpstrInitialDir = localPath.toWideCharPointer();
- of.lpstrTitle = title.toWideCharPointer();
- of.Flags = flags;
- of.lCustData = (LPARAM) &info;
-
- if (extraInfoComponent != nullptr)
- of.lpfnHook = &openCallback;
-
- if (isSaveDialogue)
- {
- StringArray tokens;
- tokens.addTokens (filter, ";,", "\"'");
- tokens.trim();
- tokens.removeEmptyStrings();
-
- if (tokens.size() == 1 && tokens[0].removeCharacters ("*.").isNotEmpty())
- {
- defaultExtension = tokens[0].fromFirstOccurrenceOf (".", false, false);
- of.lpstrDefExt = defaultExtension.toWideCharPointer();
- }
-
- if (! GetSaveFileName (&of))
- return;
- }
- else
- {
- if (! GetOpenFileName (&of))
- return;
- }
-
- filenameOffset = of.nFileOffset;
- }
-
- if (selectMultipleFiles && filenameOffset > 0 && files [filenameOffset - 1] == 0)
- {
- const WCHAR* filename = files + filenameOffset;
-
- while (*filename != 0)
- {
- results.add (File (String (files.get())).getChildFile (String (filename)));
- filename += wcslen (filename) + 1;
- }
- }
- else if (files[0] != 0)
- {
- results.add (File (String (files.get())));
- }
- }
-
- } // namespace juce
|