merged tag ooo/DEV300_m102
[LibreOffice.git] / fpicker / source / win32 / filepicker / FileOpenDlg.cxx
blob73a757058e2831c929397967886e38a3df677dd3
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_fpicker.hxx"
31 //------------------------------------------------------------------------
32 // includes
33 //------------------------------------------------------------------------
35 #include <tchar.h>
36 #include <osl/diagnose.h>
37 #include "../misc/WinImplHelper.hxx"
38 #include "FileOpenDlg.hxx"
40 //------------------------------------------------------------------------
41 // constants
42 //------------------------------------------------------------------------
44 namespace /* private */
46 // we choose such large buffers because the size of
47 // an single line edit field can be up to 32k; if
48 // a user has a multi selection FilePicker and selects
49 // a lot of files in a large directory we may reach this
50 // limit and don't want to get out of memory;
51 // another much more elegant way would be to subclass the
52 // FileOpen dialog and overload the BM_CLICK event of the
53 // OK button so that we determine the size of the text
54 // currently in the edit field and resize our buffer
55 // appropriately - in the future we will do this
56 const size_t MAX_FILENAME_BUFF_SIZE = 32000;
57 const size_t MAX_FILETITLE_BUFF_SIZE = 32000;
58 const size_t MAX_FILTER_BUFF_SIZE = 4096;
60 const LPTSTR CURRENT_INSTANCE = TEXT("CurrInst");
62 //------------------------------------------
63 // find an appropriate parent window
64 //------------------------------------------
66 inline bool is_current_process_window(HWND hwnd)
68 DWORD pid;
69 GetWindowThreadProcessId(hwnd, &pid);
70 return (pid == GetCurrentProcessId());
73 HWND choose_parent_window()
75 HWND hwnd_parent = GetForegroundWindow();
76 if (!is_current_process_window(hwnd_parent))
77 hwnd_parent = GetDesktopWindow();
79 return hwnd_parent;
83 //------------------------------------------------------------------------
85 //------------------------------------------------------------------------
87 CFileOpenDialog::CFileOpenDialog(
88 bool bFileOpenDialog,
89 sal_uInt32 dwFlags,
90 sal_uInt32 dwTemplateId,
91 HINSTANCE hInstance) :
92 m_hwndFileOpenDlg(0),
93 m_hwndFileOpenDlgChild(0),
94 m_bFileOpenDialog(bFileOpenDialog),
95 m_filterBuffer(MAX_FILTER_BUFF_SIZE),
96 m_fileTitleBuffer(MAX_FILETITLE_BUFF_SIZE),
97 m_helperBuffer(MAX_FILENAME_BUFF_SIZE),
98 m_fileNameBuffer(MAX_FILENAME_BUFF_SIZE),
99 m_pfnBaseDlgProc(0)
101 // initialize the OPENFILENAME struct
102 if (IsWindows2000Platform() || IsWindowsME())
104 ZeroMemory(&m_ofn, sizeof(m_ofn));
105 m_ofn.lStructSize = sizeof(m_ofn);
107 else // OSVER < Win2000
109 // the size of the OPENFILENAME structure is different
110 // under windows < win2000
111 ZeroMemory(&m_ofn, _OPENFILENAME_SIZE_VERSION_400);
112 m_ofn.lStructSize = _OPENFILENAME_SIZE_VERSION_400;
115 // 0x02000000 for #97681, sfx will make the entry into
116 // the recent document list
117 m_ofn.Flags |= dwFlags |
118 OFN_EXPLORER |
119 OFN_ENABLEHOOK |
120 OFN_HIDEREADONLY |
121 OFN_PATHMUSTEXIST |
122 OFN_FILEMUSTEXIST |
123 OFN_OVERWRITEPROMPT |
124 OFN_ENABLESIZING |
125 OFN_DONTADDTORECENT; // 0x02000000 -> OFN_DONTADDTORECENT only available with new platform sdk
127 // it is a little hack but how else could
128 // we get a parent window (using a vcl window?)
129 m_ofn.hwndOwner = choose_parent_window();
131 m_ofn.lpstrFile = reinterpret_cast<LPTSTR>(const_cast<sal_Unicode*>(m_fileNameBuffer.getStr()));
132 m_ofn.nMaxFile = m_fileNameBuffer.getCapacity();
134 m_ofn.lpstrFileTitle = reinterpret_cast<LPTSTR>(const_cast<sal_Unicode*>(m_fileTitleBuffer.getStr()));
135 m_ofn.nMaxFileTitle = m_fileTitleBuffer.getCapacity();
137 m_ofn.lpfnHook = CFileOpenDialog::ofnHookProc;
139 // set a custom template
141 if (dwTemplateId)
143 OSL_ASSERT(hInstance);
145 m_ofn.Flags |= OFN_ENABLETEMPLATE;
146 m_ofn.lpTemplateName = MAKEINTRESOURCE(dwTemplateId);
147 m_ofn.hInstance = hInstance;
150 // set a pointer to myself as ofn parameter
151 m_ofn.lCustData = reinterpret_cast<long>(this);
154 //------------------------------------------------------------------------
156 //------------------------------------------------------------------------
158 CFileOpenDialog::~CFileOpenDialog()
162 //------------------------------------------------------------------------
164 //------------------------------------------------------------------------
166 void SAL_CALL CFileOpenDialog::setTitle(const rtl::OUString& aTitle)
168 m_dialogTitle = aTitle;
169 m_ofn.lpstrTitle = reinterpret_cast<LPCTSTR>(m_dialogTitle.getStr());
172 //------------------------------------------------------------------------
174 //------------------------------------------------------------------------
176 void CFileOpenDialog::setFilter(const rtl::OUString& aFilter)
178 // Format is like
179 // "*.TXT" or multiple separate by ';' like "*.TXT;*.DOC;*.SXW"
180 // Do not include spaces in the pattern string
181 m_filterBuffer.ensureCapacity(aFilter.getLength());
182 m_filterBuffer.setLength(0);
183 m_filterBuffer.append(aFilter);
184 m_ofn.lpstrFilter = reinterpret_cast<LPCTSTR>(m_filterBuffer.getStr());
187 //------------------------------------------------------------------------
189 //------------------------------------------------------------------------
191 bool CFileOpenDialog::setFilterIndex(sal_uInt32 aIndex)
193 OSL_ASSERT(aIndex > 0);
194 m_ofn.nFilterIndex = aIndex;
195 return sal_True;
198 //------------------------------------------------------------------------
200 //------------------------------------------------------------------------
202 sal_uInt32 CFileOpenDialog::getSelectedFilterIndex() const
204 return m_ofn.nFilterIndex;
207 //------------------------------------------------------------------------
209 //------------------------------------------------------------------------
211 void SAL_CALL CFileOpenDialog::setDefaultName(const rtl::OUString& aName)
213 m_fileNameBuffer.setLength(0);
214 m_fileNameBuffer.append(aName);
215 m_ofn.lpstrFile = reinterpret_cast<LPTSTR>(const_cast<sal_Unicode*>(m_fileNameBuffer.getStr()));
218 //------------------------------------------------------------------------
220 //------------------------------------------------------------------------
222 void SAL_CALL CFileOpenDialog::setDisplayDirectory(const rtl::OUString& aDirectory)
224 m_displayDirectory = aDirectory;
225 m_ofn.lpstrInitialDir = reinterpret_cast<LPCTSTR>(m_displayDirectory.getStr());
228 //------------------------------------------------------------------------
230 //------------------------------------------------------------------------
232 rtl::OUString SAL_CALL CFileOpenDialog::getLastDisplayDirectory() const
234 return m_displayDirectory;
237 //------------------------------------------------------------------------
239 //------------------------------------------------------------------------
241 rtl::OUString SAL_CALL CFileOpenDialog::getFullFileName() const
243 return rtl::OUString(m_fileNameBuffer.getStr(),
244 _wcslenex(m_fileNameBuffer.getStr()));
247 //------------------------------------------------------------------------
249 //------------------------------------------------------------------------
251 rtl::OUString SAL_CALL CFileOpenDialog::getFileName() const
253 return rtl::OUString(m_fileTitleBuffer);
256 //------------------------------------------------------------------------
258 //------------------------------------------------------------------------
260 rtl::OUString CFileOpenDialog::getFileExtension()
262 if (m_ofn.nFileExtension)
263 return rtl::OUString(m_fileNameBuffer.getStr() + m_ofn.nFileExtension,
264 rtl_ustr_getLength(m_fileNameBuffer.getStr() + m_ofn.nFileExtension));
266 return rtl::OUString();
269 //------------------------------------------------------------------------
271 //------------------------------------------------------------------------
273 void CFileOpenDialog::setDefaultFileExtension(const rtl::OUString& aExtension)
275 m_defaultExtension = aExtension;
276 m_ofn.lpstrDefExt = reinterpret_cast<LPCTSTR>(m_defaultExtension.getStr());
279 //------------------------------------------------------------------------
281 //------------------------------------------------------------------------
283 void SAL_CALL CFileOpenDialog::setMultiSelectionMode(bool bMode)
285 if (bMode)
286 m_ofn.Flags |= OFN_ALLOWMULTISELECT;
287 else
288 m_ofn.Flags &= ~OFN_ALLOWMULTISELECT;
291 //------------------------------------------------------------------------
293 //------------------------------------------------------------------------
295 bool SAL_CALL CFileOpenDialog::getMultiSelectionMode() const
297 return ((m_ofn.Flags & OFN_ALLOWMULTISELECT) > 0);
300 //------------------------------------------------------------------------
302 //------------------------------------------------------------------------
304 sal_Int16 SAL_CALL CFileOpenDialog::doModal()
306 sal_Int16 nRC = -1;
308 // pre-processing
309 if (preModal())
311 bool bRet;
313 if (m_bFileOpenDialog)
314 bRet = m_GetFileNameWrapper.getOpenFileName(
315 reinterpret_cast<LPOPENFILENAME>(&m_ofn));
316 else
317 bRet = m_GetFileNameWrapper.getSaveFileName(
318 reinterpret_cast<LPOPENFILENAME>(&m_ofn));
320 nRC = 1;
322 if (!bRet)
323 nRC = (0 == m_GetFileNameWrapper.commDlgExtendedError()) ? 0 : -1;
325 // post-processing
326 postModal(nRC);
329 return nRC;
332 //------------------------------------------------------------------------
334 //------------------------------------------------------------------------
336 sal_uInt32 SAL_CALL CFileOpenDialog::getLastDialogError() const
338 return CommDlgExtendedError();
341 //------------------------------------------------------------------------
343 //------------------------------------------------------------------------
345 bool SAL_CALL CFileOpenDialog::preModal()
347 return sal_True;
350 //------------------------------------------------------------------------
352 //------------------------------------------------------------------------
354 void SAL_CALL CFileOpenDialog::postModal(sal_Int16 nDialogResult)
356 OSL_ASSERT((-1 <= nDialogResult) && (nDialogResult <= 1));
358 if (1 == nDialogResult)
360 // Attention: assuming that nFileOffset is always greater 0 because under
361 // Windows there is always a drive letter or a server in a complete path
362 // the OPENFILENAME docu never says that nFileOffset can be 0
363 m_displayDirectory = rtl::OUString(reinterpret_cast<const sal_Unicode*>(m_ofn.lpstrFile),m_ofn.nFileOffset);
367 //------------------------------------------------------------------------
369 //------------------------------------------------------------------------
371 rtl::OUString SAL_CALL CFileOpenDialog::getCurrentFilePath() const
373 OSL_ASSERT(IsWindow(m_hwndFileOpenDlg));
375 LPARAM nLen = SendMessage(
376 m_hwndFileOpenDlg,
377 CDM_GETFILEPATH,
378 m_helperBuffer.getCapacity(),
379 reinterpret_cast<LPARAM>(m_helperBuffer.getStr()));
381 if (nLen > 0)
383 m_helperBuffer.setLength((nLen * sizeof(sal_Unicode)) - 1);
384 return rtl::OUString(m_helperBuffer);
386 return rtl::OUString();
389 //------------------------------------------------------------------------
391 //------------------------------------------------------------------------
393 rtl::OUString SAL_CALL CFileOpenDialog::getCurrentFolderPath() const
395 OSL_ASSERT(IsWindow(m_hwndFileOpenDlg));
397 LPARAM nLen = SendMessage(
398 m_hwndFileOpenDlg,
399 CDM_GETFOLDERPATH,
400 m_helperBuffer.getCapacity(),
401 reinterpret_cast<LPARAM>(m_helperBuffer.getStr()));
403 if (nLen > 0)
405 m_helperBuffer.setLength((nLen * sizeof(sal_Unicode)) - 1);
406 return rtl::OUString(m_helperBuffer);
408 return rtl::OUString();
411 //------------------------------------------------------------------------
413 //------------------------------------------------------------------------
415 rtl::OUString SAL_CALL CFileOpenDialog::getCurrentFileName() const
417 OSL_ASSERT(IsWindow(m_hwndFileOpenDlg));
419 LPARAM nLen = SendMessage(
420 m_hwndFileOpenDlg,
421 CDM_GETSPEC,
422 m_helperBuffer.getCapacity(),
423 reinterpret_cast<LPARAM>(m_helperBuffer.getStr()));
425 if (nLen > 0)
427 m_helperBuffer.setLength((nLen * sizeof(sal_Unicode)) - 1);
428 return rtl::OUString(m_helperBuffer);
430 return rtl::OUString();
433 //------------------------------------------------------------------------
435 //------------------------------------------------------------------------
437 sal_uInt32 SAL_CALL CFileOpenDialog::onShareViolation(const rtl::OUString&)
439 return 0;
442 //------------------------------------------------------------------------
444 //------------------------------------------------------------------------
446 sal_uInt32 SAL_CALL CFileOpenDialog::onFileOk()
448 return 0;
451 //------------------------------------------------------------------------
453 //------------------------------------------------------------------------
455 void SAL_CALL CFileOpenDialog::onSelChanged(HWND)
459 //------------------------------------------------------------------------
461 //------------------------------------------------------------------------
463 void SAL_CALL CFileOpenDialog::onHelp()
467 //------------------------------------------------------------------------
469 //------------------------------------------------------------------------
471 void SAL_CALL CFileOpenDialog::onInitDone()
473 centerPositionToParent();
476 //------------------------------------------------------------------------
478 //------------------------------------------------------------------------
480 void SAL_CALL CFileOpenDialog::onFolderChanged()
484 //------------------------------------------------------------------------
486 //------------------------------------------------------------------------
488 void SAL_CALL CFileOpenDialog::onTypeChanged(sal_uInt32)
492 //------------------------------------------------------------------------
494 //------------------------------------------------------------------------
496 sal_uInt32 SAL_CALL CFileOpenDialog::onCtrlCommand(HWND, sal_uInt16, sal_uInt16)
498 return 0;
501 //------------------------------------------------------------------------
503 //------------------------------------------------------------------------
505 sal_uInt32 SAL_CALL CFileOpenDialog::onWMNotify( HWND, LPOFNOTIFY lpOfNotify )
507 switch(lpOfNotify->hdr.code)
509 case CDN_SHAREVIOLATION:
510 return onShareViolation(reinterpret_cast<const sal_Unicode*>(lpOfNotify->pszFile));
512 case CDN_FILEOK:
513 return onFileOk();
515 case CDN_SELCHANGE:
516 onSelChanged(lpOfNotify->hdr.hwndFrom);
517 break;
519 case CDN_HELP:
520 onHelp();
521 break;
523 case CDN_INITDONE:
524 onInitDone();
525 break;
527 case CDN_FOLDERCHANGE:
528 onFolderChanged();
529 break;
531 case CDN_TYPECHANGE:
532 m_ofn.nFilterIndex = lpOfNotify->lpOFN->nFilterIndex;
533 onTypeChanged(lpOfNotify->lpOFN->nFilterIndex);
534 break;
537 return 0;
540 //------------------------------------------------------------------------
542 //------------------------------------------------------------------------
544 void SAL_CALL CFileOpenDialog::handleInitDialog(HWND hwndDlg, HWND hwndChild)
546 m_hwndFileOpenDlg = hwndDlg;
547 m_hwndFileOpenDlgChild = hwndChild;
549 OSL_ASSERT(GetParent(hwndChild) == hwndDlg);
551 // calling virtual function which the
552 // client can overload
553 onInitDialog(hwndDlg);
556 //------------------------------------------------------------------------
558 //------------------------------------------------------------------------
560 unsigned int CALLBACK CFileOpenDialog::ofnHookProc(
561 HWND hChildDlg, unsigned int uiMsg, WPARAM wParam, LPARAM lParam)
563 HWND hwndDlg = GetParent(hChildDlg);
564 CFileOpenDialog* pImpl = NULL;
566 switch( uiMsg )
568 case WM_INITDIALOG:
570 _LPOPENFILENAME lpofn = reinterpret_cast<_LPOPENFILENAME>(lParam);
571 pImpl = reinterpret_cast<CFileOpenDialog*>(lpofn->lCustData);
572 OSL_ASSERT(pImpl);
574 // subclass the base dialog for WM_NCDESTROY processing
575 pImpl->m_pfnBaseDlgProc =
576 reinterpret_cast<WNDPROC>(
577 SetWindowLong(
578 hwndDlg,
579 GWL_WNDPROC,
580 reinterpret_cast<LONG>(CFileOpenDialog::BaseDlgProc)));
581 // connect the instance handle to the window
582 SetProp(hwndDlg, CURRENT_INSTANCE, pImpl);
583 pImpl->handleInitDialog(hwndDlg, hChildDlg);
585 return 0;
587 case WM_NOTIFY:
589 pImpl = getCurrentInstance(hwndDlg);
590 return pImpl->onWMNotify(
591 hChildDlg, reinterpret_cast<LPOFNOTIFY>(lParam));
594 case WM_COMMAND:
596 pImpl = getCurrentInstance(hwndDlg);
597 OSL_ASSERT(pImpl);
599 return pImpl->onCtrlCommand(
600 hChildDlg, LOWORD(wParam), HIWORD(lParam));
604 return 0;
607 //------------------------------------------------------------------------
609 //------------------------------------------------------------------------
611 LRESULT CALLBACK CFileOpenDialog::BaseDlgProc(
612 HWND hWnd, UINT wMessage, WPARAM wParam, LPARAM lParam)
614 CFileOpenDialog* pImpl = 0;
616 if (WM_NCDESTROY == wMessage)
618 pImpl = reinterpret_cast<CFileOpenDialog*>(
619 RemoveProp(hWnd,CURRENT_INSTANCE));
621 SetWindowLong(hWnd, GWL_WNDPROC,
622 reinterpret_cast<LONG>(pImpl->m_pfnBaseDlgProc));
624 else
626 pImpl = getCurrentInstance(hWnd);
629 OSL_ASSERT(pImpl);
631 return CallWindowProc(
632 reinterpret_cast<WNDPROC>(pImpl->m_pfnBaseDlgProc),
633 hWnd,wMessage,wParam,lParam);
636 //------------------------------------------------------------------------
638 //------------------------------------------------------------------------
640 CFileOpenDialog* SAL_CALL CFileOpenDialog::getCurrentInstance(HWND hwnd)
642 OSL_ASSERT(IsWindow( hwnd));
643 return reinterpret_cast<CFileOpenDialog*>(
644 GetProp(hwnd, CURRENT_INSTANCE));
647 //------------------------------------------------------------------------
649 //------------------------------------------------------------------------
651 void SAL_CALL CFileOpenDialog::centerPositionToParent() const
653 OSL_PRECOND(IsWindow(m_hwndFileOpenDlg), "no dialog window, call method only after or in onInitDone");
655 HWND hwndParent = m_ofn.hwndOwner;
657 if (!IsWindow(hwndParent))
658 hwndParent = GetDesktopWindow();
660 OSL_ASSERT(IsWindow(hwndParent));
662 RECT rcPar;
663 GetWindowRect(hwndParent, &rcPar);
665 RECT rcDlg;
666 GetWindowRect(m_hwndFileOpenDlg, &rcDlg);
668 int lDlgW = rcDlg.right - rcDlg.left;
669 int lDlgH = rcDlg.bottom - rcDlg.top;
671 int x = (rcPar.left + rcPar.right - lDlgW) / 2;
672 int y = (rcPar.top + rcPar.bottom - lDlgH) / 2;
674 HDC hdc = GetDC(m_hwndFileOpenDlg);
676 int hResol = GetDeviceCaps(hdc, HORZRES);
677 int vResol = GetDeviceCaps(hdc, VERTRES);
679 ReleaseDC(m_hwndFileOpenDlg, hdc);
681 if (x < 0)
682 x = 0;
683 else if ((x + lDlgW) > hResol)
684 x = hResol - lDlgW;
686 if (y < 0)
687 y = 0;
688 else if ((y + lDlgH) > vResol)
689 y = vResol - lDlgH;
691 SetWindowPos(
692 m_hwndFileOpenDlg,
693 NULL, x, y, 0, 0,
694 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE );