| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_fpicker.hxx" |
| |
| //------------------------------------------------------------------------ |
| // includes |
| //------------------------------------------------------------------------ |
| |
| #include <tchar.h> |
| #include <osl/diagnose.h> |
| #include "../misc/WinImplHelper.hxx" |
| #include "FileOpenDlg.hxx" |
| |
| //------------------------------------------------------------------------ |
| // constants |
| //------------------------------------------------------------------------ |
| |
| namespace /* private */ |
| { |
| // we choose such large buffers because the size of |
| // an single line edit field can be up to 32k; if |
| // a user has a multi selection FilePicker and selects |
| // a lot of files in a large directory we may reach this |
| // limit and don't want to get out of memory; |
| // another much more elegant way would be to subclass the |
| // FileOpen dialog and overload the BM_CLICK event of the |
| // OK button so that we determine the size of the text |
| // currently in the edit field and resize our buffer |
| // appropriately - in the future we will do this |
| const size_t MAX_FILENAME_BUFF_SIZE = 32000; |
| const size_t MAX_FILETITLE_BUFF_SIZE = 32000; |
| const size_t MAX_FILTER_BUFF_SIZE = 4096; |
| |
| const LPTSTR CURRENT_INSTANCE = TEXT("CurrInst"); |
| |
| //------------------------------------------ |
| // find an appropriate parent window |
| //------------------------------------------ |
| |
| inline bool is_current_process_window(HWND hwnd) |
| { |
| DWORD pid; |
| GetWindowThreadProcessId(hwnd, &pid); |
| return (pid == GetCurrentProcessId()); |
| } |
| |
| HWND choose_parent_window() |
| { |
| HWND hwnd_parent = GetForegroundWindow(); |
| if (!is_current_process_window(hwnd_parent)) |
| hwnd_parent = GetDesktopWindow(); |
| |
| return hwnd_parent; |
| } |
| }; |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| CFileOpenDialog::CFileOpenDialog( |
| bool bFileOpenDialog, |
| sal_uInt32 dwFlags, |
| sal_uInt32 dwTemplateId, |
| HINSTANCE hInstance) : |
| m_hwndFileOpenDlg(0), |
| m_hwndFileOpenDlgChild(0), |
| m_bFileOpenDialog(bFileOpenDialog), |
| m_filterBuffer(MAX_FILTER_BUFF_SIZE), |
| m_fileTitleBuffer(MAX_FILETITLE_BUFF_SIZE), |
| m_helperBuffer(MAX_FILENAME_BUFF_SIZE), |
| m_fileNameBuffer(MAX_FILENAME_BUFF_SIZE), |
| m_pfnBaseDlgProc(0) |
| { |
| // initialize the OPENFILENAME struct |
| if (IsWindows2000Platform() || IsWindowsME()) |
| { |
| ZeroMemory(&m_ofn, sizeof(m_ofn)); |
| m_ofn.lStructSize = sizeof(m_ofn); |
| } |
| else // OSVER < Win2000 |
| { |
| // the size of the OPENFILENAME structure is different |
| // under windows < win2000 |
| ZeroMemory(&m_ofn, _OPENFILENAME_SIZE_VERSION_400); |
| m_ofn.lStructSize = _OPENFILENAME_SIZE_VERSION_400; |
| } |
| |
| // 0x02000000 for #97681, sfx will make the entry into |
| // the recent document list |
| m_ofn.Flags |= dwFlags | |
| OFN_EXPLORER | |
| OFN_ENABLEHOOK | |
| OFN_HIDEREADONLY | |
| OFN_PATHMUSTEXIST | |
| OFN_FILEMUSTEXIST | |
| OFN_OVERWRITEPROMPT | |
| OFN_ENABLESIZING | |
| OFN_DONTADDTORECENT; // 0x02000000 -> OFN_DONTADDTORECENT only available with new platform sdk |
| |
| // it is a little hack but how else could |
| // we get a parent window (using a vcl window?) |
| m_ofn.hwndOwner = choose_parent_window(); |
| |
| m_ofn.lpstrFile = reinterpret_cast<LPTSTR>(const_cast<sal_Unicode*>(m_fileNameBuffer.getStr())); |
| m_ofn.nMaxFile = m_fileNameBuffer.getCapacity(); |
| |
| m_ofn.lpstrFileTitle = reinterpret_cast<LPTSTR>(const_cast<sal_Unicode*>(m_fileTitleBuffer.getStr())); |
| m_ofn.nMaxFileTitle = m_fileTitleBuffer.getCapacity(); |
| |
| m_ofn.lpfnHook = CFileOpenDialog::ofnHookProc; |
| |
| // set a custom template |
| |
| if (dwTemplateId) |
| { |
| OSL_ASSERT(hInstance); |
| |
| m_ofn.Flags |= OFN_ENABLETEMPLATE; |
| m_ofn.lpTemplateName = MAKEINTRESOURCE(dwTemplateId); |
| m_ofn.hInstance = hInstance; |
| } |
| |
| // set a pointer to myself as ofn parameter |
| m_ofn.lCustData = reinterpret_cast<long>(this); |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| CFileOpenDialog::~CFileOpenDialog() |
| { |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| void SAL_CALL CFileOpenDialog::setTitle(const rtl::OUString& aTitle) |
| { |
| m_dialogTitle = aTitle; |
| m_ofn.lpstrTitle = reinterpret_cast<LPCTSTR>(m_dialogTitle.getStr()); |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| void CFileOpenDialog::setFilter(const rtl::OUString& aFilter) |
| { |
| // Format is like |
| // "*.TXT" or multiple separate by ';' like "*.TXT;*.DOC;*.SXW" |
| // Do not include spaces in the pattern string |
| m_filterBuffer.ensureCapacity(aFilter.getLength()); |
| m_filterBuffer.setLength(0); |
| m_filterBuffer.append(aFilter); |
| m_ofn.lpstrFilter = reinterpret_cast<LPCTSTR>(m_filterBuffer.getStr()); |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| bool CFileOpenDialog::setFilterIndex(sal_uInt32 aIndex) |
| { |
| OSL_ASSERT(aIndex > 0); |
| m_ofn.nFilterIndex = aIndex; |
| return sal_True; |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| sal_uInt32 CFileOpenDialog::getSelectedFilterIndex() const |
| { |
| return m_ofn.nFilterIndex; |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| void SAL_CALL CFileOpenDialog::setDefaultName(const rtl::OUString& aName) |
| { |
| m_fileNameBuffer.setLength(0); |
| m_fileNameBuffer.append(aName); |
| m_ofn.lpstrFile = reinterpret_cast<LPTSTR>(const_cast<sal_Unicode*>(m_fileNameBuffer.getStr())); |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| void SAL_CALL CFileOpenDialog::setDisplayDirectory(const rtl::OUString& aDirectory) |
| { |
| m_displayDirectory = aDirectory; |
| m_ofn.lpstrInitialDir = reinterpret_cast<LPCTSTR>(m_displayDirectory.getStr()); |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| rtl::OUString SAL_CALL CFileOpenDialog::getLastDisplayDirectory() const |
| { |
| return m_displayDirectory; |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| rtl::OUString SAL_CALL CFileOpenDialog::getFullFileName() const |
| { |
| return rtl::OUString(m_fileNameBuffer.getStr(), |
| _wcslenex(m_fileNameBuffer.getStr())); |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| rtl::OUString SAL_CALL CFileOpenDialog::getFileName() const |
| { |
| return rtl::OUString(m_fileTitleBuffer); |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| rtl::OUString CFileOpenDialog::getFileExtension() |
| { |
| if (m_ofn.nFileExtension) |
| return rtl::OUString(m_fileNameBuffer.getStr() + m_ofn.nFileExtension, |
| rtl_ustr_getLength(m_fileNameBuffer.getStr() + m_ofn.nFileExtension)); |
| |
| return rtl::OUString(); |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| void CFileOpenDialog::setDefaultFileExtension(const rtl::OUString& aExtension) |
| { |
| m_defaultExtension = aExtension; |
| m_ofn.lpstrDefExt = reinterpret_cast<LPCTSTR>(m_defaultExtension.getStr()); |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| void SAL_CALL CFileOpenDialog::setMultiSelectionMode(bool bMode) |
| { |
| if (bMode) |
| m_ofn.Flags |= OFN_ALLOWMULTISELECT; |
| else |
| m_ofn.Flags &= ~OFN_ALLOWMULTISELECT; |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| bool SAL_CALL CFileOpenDialog::getMultiSelectionMode() const |
| { |
| return ((m_ofn.Flags & OFN_ALLOWMULTISELECT) > 0); |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| sal_Int16 SAL_CALL CFileOpenDialog::doModal() |
| { |
| sal_Int16 nRC = -1; |
| |
| // pre-processing |
| if (preModal()) |
| { |
| bool bRet; |
| |
| if (m_bFileOpenDialog) |
| bRet = m_GetFileNameWrapper.getOpenFileName( |
| reinterpret_cast<LPOPENFILENAME>(&m_ofn)); |
| else |
| bRet = m_GetFileNameWrapper.getSaveFileName( |
| reinterpret_cast<LPOPENFILENAME>(&m_ofn)); |
| |
| nRC = 1; |
| |
| if (!bRet) |
| nRC = (0 == m_GetFileNameWrapper.commDlgExtendedError()) ? 0 : -1; |
| |
| // post-processing |
| postModal(nRC); |
| } |
| |
| return nRC; |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| sal_uInt32 SAL_CALL CFileOpenDialog::getLastDialogError() const |
| { |
| return CommDlgExtendedError(); |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| bool SAL_CALL CFileOpenDialog::preModal() |
| { |
| return sal_True; |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| void SAL_CALL CFileOpenDialog::postModal(sal_Int16 nDialogResult) |
| { |
| OSL_ASSERT((-1 <= nDialogResult) && (nDialogResult <= 1)); |
| |
| if (1 == nDialogResult) |
| { |
| // Attention: assuming that nFileOffset is always greater 0 because under |
| // Windows there is always a drive letter or a server in a complete path |
| // the OPENFILENAME docu never says that nFileOffset can be 0 |
| m_displayDirectory = rtl::OUString(reinterpret_cast<const sal_Unicode*>(m_ofn.lpstrFile),m_ofn.nFileOffset); |
| } |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| rtl::OUString SAL_CALL CFileOpenDialog::getCurrentFilePath() const |
| { |
| OSL_ASSERT(IsWindow(m_hwndFileOpenDlg)); |
| |
| LPARAM nLen = SendMessage( |
| m_hwndFileOpenDlg, |
| CDM_GETFILEPATH, |
| m_helperBuffer.getCapacity(), |
| reinterpret_cast<LPARAM>(m_helperBuffer.getStr())); |
| |
| if (nLen > 0) |
| { |
| m_helperBuffer.setLength((nLen * sizeof(sal_Unicode)) - 1); |
| return rtl::OUString(m_helperBuffer); |
| } |
| return rtl::OUString(); |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| rtl::OUString SAL_CALL CFileOpenDialog::getCurrentFolderPath() const |
| { |
| OSL_ASSERT(IsWindow(m_hwndFileOpenDlg)); |
| |
| LPARAM nLen = SendMessage( |
| m_hwndFileOpenDlg, |
| CDM_GETFOLDERPATH, |
| m_helperBuffer.getCapacity(), |
| reinterpret_cast<LPARAM>(m_helperBuffer.getStr())); |
| |
| if (nLen > 0) |
| { |
| m_helperBuffer.setLength((nLen * sizeof(sal_Unicode)) - 1); |
| return rtl::OUString(m_helperBuffer); |
| } |
| return rtl::OUString(); |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| rtl::OUString SAL_CALL CFileOpenDialog::getCurrentFileName() const |
| { |
| OSL_ASSERT(IsWindow(m_hwndFileOpenDlg)); |
| |
| LPARAM nLen = SendMessage( |
| m_hwndFileOpenDlg, |
| CDM_GETSPEC, |
| m_helperBuffer.getCapacity(), |
| reinterpret_cast<LPARAM>(m_helperBuffer.getStr())); |
| |
| if (nLen > 0) |
| { |
| m_helperBuffer.setLength((nLen * sizeof(sal_Unicode)) - 1); |
| return rtl::OUString(m_helperBuffer); |
| } |
| return rtl::OUString(); |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| sal_uInt32 SAL_CALL CFileOpenDialog::onShareViolation(const rtl::OUString&) |
| { |
| return 0; |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| sal_uInt32 SAL_CALL CFileOpenDialog::onFileOk() |
| { |
| return 0; |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| void SAL_CALL CFileOpenDialog::onSelChanged(HWND) |
| { |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| void SAL_CALL CFileOpenDialog::onHelp() |
| { |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| void SAL_CALL CFileOpenDialog::onInitDone() |
| { |
| centerPositionToParent(); |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| void SAL_CALL CFileOpenDialog::onFolderChanged() |
| { |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| void SAL_CALL CFileOpenDialog::onTypeChanged(sal_uInt32) |
| { |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| sal_uInt32 SAL_CALL CFileOpenDialog::onCtrlCommand(HWND, sal_uInt16, sal_uInt16) |
| { |
| return 0; |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| sal_uInt32 SAL_CALL CFileOpenDialog::onWMNotify( HWND, LPOFNOTIFY lpOfNotify ) |
| { |
| switch(lpOfNotify->hdr.code) |
| { |
| case CDN_SHAREVIOLATION: |
| return onShareViolation(reinterpret_cast<const sal_Unicode*>(lpOfNotify->pszFile)); |
| |
| case CDN_FILEOK: |
| return onFileOk(); |
| |
| case CDN_SELCHANGE: |
| onSelChanged(lpOfNotify->hdr.hwndFrom); |
| break; |
| |
| case CDN_HELP: |
| onHelp(); |
| break; |
| |
| case CDN_INITDONE: |
| onInitDone(); |
| break; |
| |
| case CDN_FOLDERCHANGE: |
| onFolderChanged(); |
| break; |
| |
| case CDN_TYPECHANGE: |
| m_ofn.nFilterIndex = lpOfNotify->lpOFN->nFilterIndex; |
| onTypeChanged(lpOfNotify->lpOFN->nFilterIndex); |
| break; |
| } |
| |
| return 0; |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| void SAL_CALL CFileOpenDialog::handleInitDialog(HWND hwndDlg, HWND hwndChild) |
| { |
| m_hwndFileOpenDlg = hwndDlg; |
| m_hwndFileOpenDlgChild = hwndChild; |
| |
| OSL_ASSERT(GetParent(hwndChild) == hwndDlg); |
| |
| // calling virtual function which the |
| // client can overload |
| onInitDialog(hwndDlg); |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| unsigned int CALLBACK CFileOpenDialog::ofnHookProc( |
| HWND hChildDlg, unsigned int uiMsg, WPARAM wParam, LPARAM lParam) |
| { |
| HWND hwndDlg = GetParent(hChildDlg); |
| CFileOpenDialog* pImpl = NULL; |
| |
| switch( uiMsg ) |
| { |
| case WM_INITDIALOG: |
| { |
| _LPOPENFILENAME lpofn = reinterpret_cast<_LPOPENFILENAME>(lParam); |
| pImpl = reinterpret_cast<CFileOpenDialog*>(lpofn->lCustData); |
| OSL_ASSERT(pImpl); |
| |
| // subclass the base dialog for WM_NCDESTROY processing |
| pImpl->m_pfnBaseDlgProc = |
| reinterpret_cast<WNDPROC>( |
| SetWindowLong( |
| hwndDlg, |
| GWL_WNDPROC, |
| reinterpret_cast<LONG>(CFileOpenDialog::BaseDlgProc))); |
| // connect the instance handle to the window |
| SetProp(hwndDlg, CURRENT_INSTANCE, pImpl); |
| pImpl->handleInitDialog(hwndDlg, hChildDlg); |
| } |
| return 0; |
| |
| case WM_NOTIFY: |
| { |
| pImpl = getCurrentInstance(hwndDlg); |
| return pImpl->onWMNotify( |
| hChildDlg, reinterpret_cast<LPOFNOTIFY>(lParam)); |
| } |
| |
| case WM_COMMAND: |
| { |
| pImpl = getCurrentInstance(hwndDlg); |
| OSL_ASSERT(pImpl); |
| |
| return pImpl->onCtrlCommand( |
| hChildDlg, LOWORD(wParam), HIWORD(lParam)); |
| } |
| } |
| |
| return 0; |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| LRESULT CALLBACK CFileOpenDialog::BaseDlgProc( |
| HWND hWnd, UINT wMessage, WPARAM wParam, LPARAM lParam) |
| { |
| CFileOpenDialog* pImpl = 0; |
| |
| if (WM_NCDESTROY == wMessage) |
| { |
| pImpl = reinterpret_cast<CFileOpenDialog*>( |
| RemoveProp(hWnd,CURRENT_INSTANCE)); |
| |
| SetWindowLong(hWnd, GWL_WNDPROC, |
| reinterpret_cast<LONG>(pImpl->m_pfnBaseDlgProc)); |
| } |
| else |
| { |
| pImpl = getCurrentInstance(hWnd); |
| } |
| |
| OSL_ASSERT(pImpl); |
| |
| return CallWindowProc( |
| reinterpret_cast<WNDPROC>(pImpl->m_pfnBaseDlgProc), |
| hWnd,wMessage,wParam,lParam); |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| CFileOpenDialog* SAL_CALL CFileOpenDialog::getCurrentInstance(HWND hwnd) |
| { |
| OSL_ASSERT(IsWindow( hwnd)); |
| return reinterpret_cast<CFileOpenDialog*>( |
| GetProp(hwnd, CURRENT_INSTANCE)); |
| } |
| |
| //------------------------------------------------------------------------ |
| // |
| //------------------------------------------------------------------------ |
| |
| void SAL_CALL CFileOpenDialog::centerPositionToParent() const |
| { |
| OSL_PRECOND(IsWindow(m_hwndFileOpenDlg), "no dialog window, call method only after or in onInitDone"); |
| |
| HWND hwndParent = m_ofn.hwndOwner; |
| |
| if (!IsWindow(hwndParent)) |
| hwndParent = GetDesktopWindow(); |
| |
| OSL_ASSERT(IsWindow(hwndParent)); |
| |
| RECT rcPar; |
| GetWindowRect(hwndParent, &rcPar); |
| |
| RECT rcDlg; |
| GetWindowRect(m_hwndFileOpenDlg, &rcDlg); |
| |
| int lDlgW = rcDlg.right - rcDlg.left; |
| int lDlgH = rcDlg.bottom - rcDlg.top; |
| |
| int x = (rcPar.left + rcPar.right - lDlgW) / 2; |
| int y = (rcPar.top + rcPar.bottom - lDlgH) / 2; |
| |
| HDC hdc = GetDC(m_hwndFileOpenDlg); |
| |
| int hResol = GetDeviceCaps(hdc, HORZRES); |
| int vResol = GetDeviceCaps(hdc, VERTRES); |
| |
| ReleaseDC(m_hwndFileOpenDlg, hdc); |
| |
| if (x < 0) |
| x = 0; |
| else if ((x + lDlgW) > hResol) |
| x = hResol - lDlgW; |
| |
| if (y < 0) |
| y = 0; |
| else if ((y + lDlgH) > vResol) |
| y = vResol - lDlgH; |
| |
| SetWindowPos( |
| m_hwndFileOpenDlg, |
| NULL, x, y, 0, 0, |
| SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE ); |
| } |