/* ============================================================================== This file is part of the JUCE library - "Jules' Utility Class Extensions" Copyright 2004-7 by Raw Material Software ltd. ------------------------------------------------------------------------------ JUCE can be redistributed and/or modified under the terms of the GNU General Public License, as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with JUCE; if not, visit www.gnu.org/licenses or write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ------------------------------------------------------------------------------ If you'd like to release a closed-source product which uses JUCE, commercial licenses are also available: visit www.rawmaterialsoftware.com/juce for more information. ============================================================================== */ #ifdef _MSC_VER #pragma warning (disable: 4514) #pragma warning (push) #endif #include "win32_headers.h" #include #include "../../../src/juce_core/basics/juce_StandardHeader.h" BEGIN_JUCE_NAMESPACE #include "../../../src/juce_appframework/gui/components/filebrowser/juce_FileChooser.h" #include "../../../src/juce_appframework/gui/components/juce_Desktop.h" #include "../../../src/juce_core/basics/juce_SystemStats.h" #ifdef _MSC_VER #pragma warning (pop) #endif //============================================================================== static const void* defaultDirPath = 0; static String returnedString; // need this to get non-existent pathnames from the directory chooser static Component* currentExtraFileWin = 0; static bool areThereAnyAlwaysOnTopWindows() { for (int i = Desktop::getInstance().getNumComponents(); --i >= 0;) { Component* c = Desktop::getInstance().getComponent (i); if (c != 0 && c->isAlwaysOnTop() && c->isShowing()) return true; } return false; } static int CALLBACK browseCallbackProc (HWND hWnd, UINT msg, LPARAM lParam, LPARAM /*lpData*/) { if (msg == BFFM_INITIALIZED) { SendMessage (hWnd, BFFM_SETSELECTIONW, TRUE, (LPARAM) defaultDirPath); } else if (msg == BFFM_VALIDATEFAILEDW) { returnedString = (LPCWSTR) lParam; } else if (msg == BFFM_VALIDATEFAILEDA) { returnedString = (const char*) lParam; } return 0; } void juce_setWindowStyleBit (HWND h, int styleType, int feature, bool bitIsSet); static UINT_PTR CALLBACK openCallback (HWND hdlg, UINT uiMsg, WPARAM /*wParam*/, LPARAM lParam) { if (currentExtraFileWin != 0) { if (uiMsg == WM_INITDIALOG) { 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, currentExtraFileWin->getWidth() + jmax (150, r.right - r.left), jmax (150, r.bottom - r.top), SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER); currentExtraFileWin->setBounds (cr.right, cr.top, currentExtraFileWin->getWidth(), cr.bottom - cr.top); currentExtraFileWin->getChildComponent(0)->setBounds (0, 0, currentExtraFileWin->getWidth(), currentExtraFileWin->getHeight()); SetParent ((HWND) currentExtraFileWin->getWindowHandle(), (HWND) dialogH); juce_setWindowStyleBit ((HWND)currentExtraFileWin->getWindowHandle(), GWL_STYLE, WS_CHILD, (dialogH != 0)); juce_setWindowStyleBit ((HWND)currentExtraFileWin->getWindowHandle(), GWL_STYLE, WS_POPUP, (dialogH == 0)); } else if (uiMsg == WM_NOTIFY) { LPOFNOTIFY ofn = (LPOFNOTIFY) lParam; if (ofn->hdr.code == CDN_SELCHANGE) { FilePreviewComponent* comp = (FilePreviewComponent*) currentExtraFileWin->getChildComponent(0); if (comp != 0) { TCHAR path [MAX_PATH * 2]; path[0] = 0; CommDlg_OpenSave_GetFilePath (GetParent (hdlg), (LPARAM) &path, MAX_PATH); const String fn ((const WCHAR*) path); comp->selectedFileChanged (File (fn)); } } } } return 0; } class FPComponentHolder : public Component { public: FPComponentHolder() { setVisible (true); setOpaque (true); } ~FPComponentHolder() { } void paint (Graphics& g) { g.fillAll (Colours::lightgrey); } private: FPComponentHolder (const FPComponentHolder&); const FPComponentHolder& operator= (const FPComponentHolder&); }; //============================================================================== void FileChooser::showPlatformDialog (OwnedArray& results, const String& title, const File& currentFileOrDirectory, const String& filter, bool selectsDirectory, bool isSaveDialogue, bool warnAboutOverwritingExistingFiles, bool selectMultipleFiles, FilePreviewComponent* extraInfoComponent) { const int numCharsAvailable = 32768; MemoryBlock filenameSpace ((numCharsAvailable + 1) * sizeof (WCHAR), true); WCHAR* const fname = (WCHAR*) filenameSpace.getData(); int fnameIdx = 0; JUCE_TRY { // use a modal window as the parent for this dialog box // to block input from other app windows const Rectangle mainMon (Desktop::getInstance().getMainMonitorArea()); Component w (String::empty); w.setBounds (mainMon.getX() + mainMon.getWidth() / 4, mainMon.getY() + mainMon.getHeight() / 4, 0, 0); w.setOpaque (true); w.setAlwaysOnTop (areThereAnyAlwaysOnTopWindows()); w.addToDesktop (0); if (extraInfoComponent == 0) w.enterModalState(); String initialDir; if (currentFileOrDirectory.isDirectory()) { initialDir = currentFileOrDirectory.getFullPathName(); } else { currentFileOrDirectory.getFileName().copyToBuffer (fname, numCharsAvailable); initialDir = currentFileOrDirectory.getParentDirectory().getFullPathName(); } if (currentExtraFileWin->isValidComponent()) { jassertfalse return; } if (selectsDirectory) { LPITEMIDLIST list = 0; filenameSpace.fillWith (0); { BROWSEINFO bi; zerostruct (bi); bi.hwndOwner = (HWND) w.getWindowHandle(); bi.pszDisplayName = fname; bi.lpszTitle = title; bi.lpfn = browseCallbackProc; #ifdef BIF_USENEWUI bi.ulFlags = BIF_USENEWUI | BIF_VALIDATE; #else bi.ulFlags = 0x50; #endif defaultDirPath = (const WCHAR*) initialDir; list = SHBrowseForFolder (&bi); if (! SHGetPathFromIDListW (list, fname)) { fname[0] = 0; returnedString = String::empty; } } LPMALLOC al; if (list != 0 && SUCCEEDED (SHGetMalloc (&al))) al->Free (list); defaultDirPath = 0; if (returnedString.isNotEmpty()) { const String stringFName (fname); results.add (new File (File (stringFName).getSiblingFile (returnedString))); returnedString = String::empty; return; } } else { DWORD flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR | OFN_HIDEREADONLY; if (warnAboutOverwritingExistingFiles) flags |= OFN_OVERWRITEPROMPT; if (selectMultipleFiles) flags |= OFN_ALLOWMULTISELECT; if (extraInfoComponent != 0) { flags |= OFN_ENABLEHOOK; currentExtraFileWin = new FPComponentHolder(); currentExtraFileWin->addAndMakeVisible (extraInfoComponent); currentExtraFileWin->setSize (jlimit (20, 800, extraInfoComponent->getWidth()), extraInfoComponent->getHeight()); currentExtraFileWin->addToDesktop (0); currentExtraFileWin->enterModalState(); } { WCHAR filters [1024]; zeromem (filters, sizeof (filters)); filter.copyToBuffer (filters, 1024); filter.copyToBuffer (filters + filter.length() + 1, 1022 - filter.length()); OPENFILENAMEW of; zerostruct (of); #ifdef OPENFILENAME_SIZE_VERSION_400W of.lStructSize = OPENFILENAME_SIZE_VERSION_400W; #else of.lStructSize = sizeof (of); #endif of.hwndOwner = (HWND) w.getWindowHandle(); of.lpstrFilter = filters; of.nFilterIndex = 1; of.lpstrFile = fname; of.nMaxFile = numCharsAvailable; of.lpstrInitialDir = initialDir; of.lpstrTitle = title; of.Flags = flags; if (extraInfoComponent != 0) of.lpfnHook = &openCallback; if (isSaveDialogue) { if (! GetSaveFileName (&of)) fname[0] = 0; else fnameIdx = of.nFileOffset; } else { if (! GetOpenFileName (&of)) fname[0] = 0; else fnameIdx = of.nFileOffset; } } } } #if JUCE_CATCH_UNHANDLED_EXCEPTIONS catch (...) { fname[0] = 0; } #endif deleteAndZero (currentExtraFileWin); const WCHAR* const files = fname; if (selectMultipleFiles && fnameIdx > 0 && files [fnameIdx - 1] == 0) { const WCHAR* filename = files + fnameIdx; while (*filename != 0) { const String filepath (String (files) + T("\\") + String (filename)); results.add (new File (filepath)); filename += CharacterFunctions::length (filename) + 1; } } else if (files[0] != 0) { results.add (new File (files)); } } END_JUCE_NAMESPACE