Update ooo320-m1
[ooovba.git] / fpicker / source / win32 / filepicker / FileOpenDlg.cxx
blobf28a18c56a009f1ac7a8a8c3d73eacb14433a4f8
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: FileOpenDlg.cxx,v $
10 * $Revision: 1.17 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_fpicker.hxx"
34 //------------------------------------------------------------------------
35 // includes
36 //------------------------------------------------------------------------
38 #include <tchar.h>
39 #include <osl/diagnose.h>
40 #include "../misc/WinImplHelper.hxx"
41 #include "FileOpenDlg.hxx"
43 //------------------------------------------------------------------------
44 // constants
45 //------------------------------------------------------------------------
47 namespace /* private */
49 // we choose such large buffers because the size of
50 // an single line edit field can be up to 32k; if
51 // a user has a multi selection FilePicker and selects
52 // a lot of files in a large directory we may reach this
53 // limit and don't want to get out of memory;
54 // another much more elegant way would be to subclass the
55 // FileOpen dialog and overload the BM_CLICK event of the
56 // OK button so that we determine the size of the text
57 // currently in the edit field and resize our buffer
58 // appropriately - in the future we will do this
59 const size_t MAX_FILENAME_BUFF_SIZE = 32000;
60 const size_t MAX_FILETITLE_BUFF_SIZE = 32000;
61 const size_t MAX_FILTER_BUFF_SIZE = 4096;
63 const LPTSTR CURRENT_INSTANCE = TEXT("CurrInst");
65 //------------------------------------------
66 // find an appropriate parent window
67 //------------------------------------------
69 inline bool is_current_process_window(HWND hwnd)
71 DWORD pid;
72 GetWindowThreadProcessId(hwnd, &pid);
73 return (pid == GetCurrentProcessId());
76 HWND choose_parent_window()
78 HWND hwnd_parent = GetForegroundWindow();
79 if (!is_current_process_window(hwnd_parent))
80 hwnd_parent = GetDesktopWindow();
82 return hwnd_parent;
86 //------------------------------------------------------------------------
87 //
88 //------------------------------------------------------------------------
90 CFileOpenDialog::CFileOpenDialog(
91 bool bFileOpenDialog,
92 sal_uInt32 dwFlags,
93 sal_uInt32 dwTemplateId,
94 HINSTANCE hInstance) :
95 m_hwndFileOpenDlg(0),
96 m_hwndFileOpenDlgChild(0),
97 m_bFileOpenDialog(bFileOpenDialog),
98 m_filterBuffer(MAX_FILTER_BUFF_SIZE),
99 m_fileTitleBuffer(MAX_FILETITLE_BUFF_SIZE),
100 m_helperBuffer(MAX_FILENAME_BUFF_SIZE),
101 m_fileNameBuffer(MAX_FILENAME_BUFF_SIZE),
102 m_pfnBaseDlgProc(0)
104 // initialize the OPENFILENAME struct
105 if (IsWindows2000Platform() || IsWindowsME())
107 ZeroMemory(&m_ofn, sizeof(m_ofn));
108 m_ofn.lStructSize = sizeof(m_ofn);
110 else // OSVER < Win2000
112 // the size of the OPENFILENAME structure is different
113 // under windows < win2000
114 ZeroMemory(&m_ofn, _OPENFILENAME_SIZE_VERSION_400);
115 m_ofn.lStructSize = _OPENFILENAME_SIZE_VERSION_400;
118 // 0x02000000 for #97681, sfx will make the entry into
119 // the recent document list
120 m_ofn.Flags |= dwFlags |
121 OFN_EXPLORER |
122 OFN_ENABLEHOOK |
123 OFN_HIDEREADONLY |
124 OFN_PATHMUSTEXIST |
125 OFN_FILEMUSTEXIST |
126 OFN_OVERWRITEPROMPT |
127 OFN_ENABLESIZING |
128 OFN_DONTADDTORECENT; // 0x02000000 -> OFN_DONTADDTORECENT only available with new platform sdk
130 // it is a little hack but how else could
131 // we get a parent window (using a vcl window?)
132 m_ofn.hwndOwner = choose_parent_window();
134 m_ofn.lpstrFile = reinterpret_cast<LPTSTR>(const_cast<sal_Unicode*>(m_fileNameBuffer.getStr()));
135 m_ofn.nMaxFile = m_fileNameBuffer.getCapacity();
137 m_ofn.lpstrFileTitle = reinterpret_cast<LPTSTR>(const_cast<sal_Unicode*>(m_fileTitleBuffer.getStr()));
138 m_ofn.nMaxFileTitle = m_fileTitleBuffer.getCapacity();
140 m_ofn.lpfnHook = CFileOpenDialog::ofnHookProc;
142 // set a custom template
144 if (dwTemplateId)
146 OSL_ASSERT(hInstance);
148 m_ofn.Flags |= OFN_ENABLETEMPLATE;
149 m_ofn.lpTemplateName = MAKEINTRESOURCE(dwTemplateId);
150 m_ofn.hInstance = hInstance;
153 // set a pointer to myself as ofn parameter
154 m_ofn.lCustData = reinterpret_cast<long>(this);
157 //------------------------------------------------------------------------
159 //------------------------------------------------------------------------
161 CFileOpenDialog::~CFileOpenDialog()
165 //------------------------------------------------------------------------
167 //------------------------------------------------------------------------
169 void SAL_CALL CFileOpenDialog::setTitle(const rtl::OUString& aTitle)
171 m_dialogTitle = aTitle;
172 m_ofn.lpstrTitle = reinterpret_cast<LPCTSTR>(m_dialogTitle.getStr());
175 //------------------------------------------------------------------------
177 //------------------------------------------------------------------------
179 void CFileOpenDialog::setFilter(const rtl::OUString& aFilter)
181 // Format is like
182 // "*.TXT" or multiple separate by ';' like "*.TXT;*.DOC;*.SXW"
183 // Do not include spaces in the pattern string
184 m_filterBuffer.ensureCapacity(aFilter.getLength());
185 m_filterBuffer.setLength(0);
186 m_filterBuffer.append(aFilter);
187 m_ofn.lpstrFilter = reinterpret_cast<LPCTSTR>(m_filterBuffer.getStr());
190 //------------------------------------------------------------------------
192 //------------------------------------------------------------------------
194 bool CFileOpenDialog::setFilterIndex(sal_uInt32 aIndex)
196 OSL_ASSERT(aIndex > 0);
197 m_ofn.nFilterIndex = aIndex;
198 return sal_True;
201 //------------------------------------------------------------------------
203 //------------------------------------------------------------------------
205 sal_uInt32 CFileOpenDialog::getSelectedFilterIndex() const
207 return m_ofn.nFilterIndex;
210 //------------------------------------------------------------------------
212 //------------------------------------------------------------------------
214 void SAL_CALL CFileOpenDialog::setDefaultName(const rtl::OUString& aName)
216 m_fileNameBuffer.setLength(0);
217 m_fileNameBuffer.append(aName);
218 m_ofn.lpstrFile = reinterpret_cast<LPTSTR>(const_cast<sal_Unicode*>(m_fileNameBuffer.getStr()));
221 //------------------------------------------------------------------------
223 //------------------------------------------------------------------------
225 void SAL_CALL CFileOpenDialog::setDisplayDirectory(const rtl::OUString& aDirectory)
227 m_displayDirectory = aDirectory;
228 m_ofn.lpstrInitialDir = reinterpret_cast<LPCTSTR>(m_displayDirectory.getStr());
231 //------------------------------------------------------------------------
233 //------------------------------------------------------------------------
235 rtl::OUString SAL_CALL CFileOpenDialog::getLastDisplayDirectory() const
237 return m_displayDirectory;
240 //------------------------------------------------------------------------
242 //------------------------------------------------------------------------
244 rtl::OUString SAL_CALL CFileOpenDialog::getFullFileName() const
246 return rtl::OUString(m_fileNameBuffer.getStr(),
247 _wcslenex(m_fileNameBuffer.getStr()));
250 //------------------------------------------------------------------------
252 //------------------------------------------------------------------------
254 rtl::OUString SAL_CALL CFileOpenDialog::getFileName() const
256 return rtl::OUString(m_fileTitleBuffer);
259 //------------------------------------------------------------------------
261 //------------------------------------------------------------------------
263 rtl::OUString CFileOpenDialog::getFileExtension()
265 if (m_ofn.nFileExtension)
266 return rtl::OUString(m_fileNameBuffer.getStr() + m_ofn.nFileExtension,
267 rtl_ustr_getLength(m_fileNameBuffer.getStr() + m_ofn.nFileExtension));
269 return rtl::OUString();
272 //------------------------------------------------------------------------
274 //------------------------------------------------------------------------
276 void CFileOpenDialog::setDefaultFileExtension(const rtl::OUString& aExtension)
278 m_defaultExtension = aExtension;
279 m_ofn.lpstrDefExt = reinterpret_cast<LPCTSTR>(m_defaultExtension.getStr());
282 //------------------------------------------------------------------------
284 //------------------------------------------------------------------------
286 void SAL_CALL CFileOpenDialog::setMultiSelectionMode(bool bMode)
288 if (bMode)
289 m_ofn.Flags |= OFN_ALLOWMULTISELECT;
290 else
291 m_ofn.Flags &= ~OFN_ALLOWMULTISELECT;
294 //------------------------------------------------------------------------
296 //------------------------------------------------------------------------
298 bool SAL_CALL CFileOpenDialog::getMultiSelectionMode() const
300 return ((m_ofn.Flags & OFN_ALLOWMULTISELECT) > 0);
303 //------------------------------------------------------------------------
305 //------------------------------------------------------------------------
307 sal_Int16 SAL_CALL CFileOpenDialog::doModal()
309 sal_Int16 nRC = -1;
311 // pre-processing
312 if (preModal())
314 bool bRet;
316 if (m_bFileOpenDialog)
317 bRet = m_GetFileNameWrapper.getOpenFileName(
318 reinterpret_cast<LPOPENFILENAME>(&m_ofn));
319 else
320 bRet = m_GetFileNameWrapper.getSaveFileName(
321 reinterpret_cast<LPOPENFILENAME>(&m_ofn));
323 nRC = 1;
325 if (!bRet)
326 nRC = (0 == m_GetFileNameWrapper.commDlgExtendedError()) ? 0 : -1;
328 // post-processing
329 postModal(nRC);
332 return nRC;
335 //------------------------------------------------------------------------
337 //------------------------------------------------------------------------
339 sal_uInt32 SAL_CALL CFileOpenDialog::getLastDialogError() const
341 return CommDlgExtendedError();
344 //------------------------------------------------------------------------
346 //------------------------------------------------------------------------
348 bool SAL_CALL CFileOpenDialog::preModal()
350 return sal_True;
353 //------------------------------------------------------------------------
355 //------------------------------------------------------------------------
357 void SAL_CALL CFileOpenDialog::postModal(sal_Int16 nDialogResult)
359 OSL_ASSERT((-1 <= nDialogResult) && (nDialogResult <= 1));
361 if (1 == nDialogResult)
363 // Attention: assuming that nFileOffset is always greater 0 because under
364 // Windows there is always a drive letter or a server in a complete path
365 // the OPENFILENAME docu never says that nFileOffset can be 0
366 m_displayDirectory = rtl::OUString(reinterpret_cast<const sal_Unicode*>(m_ofn.lpstrFile),m_ofn.nFileOffset);
370 //------------------------------------------------------------------------
372 //------------------------------------------------------------------------
374 rtl::OUString SAL_CALL CFileOpenDialog::getCurrentFilePath() const
376 OSL_ASSERT(IsWindow(m_hwndFileOpenDlg));
378 LPARAM nLen = SendMessage(
379 m_hwndFileOpenDlg,
380 CDM_GETFILEPATH,
381 m_helperBuffer.getCapacity(),
382 reinterpret_cast<LPARAM>(m_helperBuffer.getStr()));
384 if (nLen > 0)
386 m_helperBuffer.setLength((nLen * sizeof(sal_Unicode)) - 1);
387 return rtl::OUString(m_helperBuffer);
389 return rtl::OUString();
392 //------------------------------------------------------------------------
394 //------------------------------------------------------------------------
396 rtl::OUString SAL_CALL CFileOpenDialog::getCurrentFolderPath() const
398 OSL_ASSERT(IsWindow(m_hwndFileOpenDlg));
400 LPARAM nLen = SendMessage(
401 m_hwndFileOpenDlg,
402 CDM_GETFOLDERPATH,
403 m_helperBuffer.getCapacity(),
404 reinterpret_cast<LPARAM>(m_helperBuffer.getStr()));
406 if (nLen > 0)
408 m_helperBuffer.setLength((nLen * sizeof(sal_Unicode)) - 1);
409 return rtl::OUString(m_helperBuffer);
411 return rtl::OUString();
414 //------------------------------------------------------------------------
416 //------------------------------------------------------------------------
418 rtl::OUString SAL_CALL CFileOpenDialog::getCurrentFileName() const
420 OSL_ASSERT(IsWindow(m_hwndFileOpenDlg));
422 LPARAM nLen = SendMessage(
423 m_hwndFileOpenDlg,
424 CDM_GETSPEC,
425 m_helperBuffer.getCapacity(),
426 reinterpret_cast<LPARAM>(m_helperBuffer.getStr()));
428 if (nLen > 0)
430 m_helperBuffer.setLength((nLen * sizeof(sal_Unicode)) - 1);
431 return rtl::OUString(m_helperBuffer);
433 return rtl::OUString();
436 //------------------------------------------------------------------------
438 //------------------------------------------------------------------------
440 sal_uInt32 SAL_CALL CFileOpenDialog::onShareViolation(const rtl::OUString&)
442 return 0;
445 //------------------------------------------------------------------------
447 //------------------------------------------------------------------------
449 sal_uInt32 SAL_CALL CFileOpenDialog::onFileOk()
451 return 0;
454 //------------------------------------------------------------------------
456 //------------------------------------------------------------------------
458 void SAL_CALL CFileOpenDialog::onSelChanged(HWND)
462 //------------------------------------------------------------------------
464 //------------------------------------------------------------------------
466 void SAL_CALL CFileOpenDialog::onHelp()
470 //------------------------------------------------------------------------
472 //------------------------------------------------------------------------
474 void SAL_CALL CFileOpenDialog::onInitDone()
476 centerPositionToParent();
479 //------------------------------------------------------------------------
481 //------------------------------------------------------------------------
483 void SAL_CALL CFileOpenDialog::onFolderChanged()
487 //------------------------------------------------------------------------
489 //------------------------------------------------------------------------
491 void SAL_CALL CFileOpenDialog::onTypeChanged(sal_uInt32)
495 //------------------------------------------------------------------------
497 //------------------------------------------------------------------------
499 sal_uInt32 SAL_CALL CFileOpenDialog::onCtrlCommand(HWND, sal_uInt16, sal_uInt16)
501 return 0;
504 //------------------------------------------------------------------------
506 //------------------------------------------------------------------------
508 sal_uInt32 SAL_CALL CFileOpenDialog::onWMNotify( HWND, LPOFNOTIFY lpOfNotify )
510 switch(lpOfNotify->hdr.code)
512 case CDN_SHAREVIOLATION:
513 return onShareViolation(reinterpret_cast<const sal_Unicode*>(lpOfNotify->pszFile));
515 case CDN_FILEOK:
516 return onFileOk();
518 case CDN_SELCHANGE:
519 onSelChanged(lpOfNotify->hdr.hwndFrom);
520 break;
522 case CDN_HELP:
523 onHelp();
524 break;
526 case CDN_INITDONE:
527 onInitDone();
528 break;
530 case CDN_FOLDERCHANGE:
531 onFolderChanged();
532 break;
534 case CDN_TYPECHANGE:
535 m_ofn.nFilterIndex = lpOfNotify->lpOFN->nFilterIndex;
536 onTypeChanged(lpOfNotify->lpOFN->nFilterIndex);
537 break;
540 return 0;
543 //------------------------------------------------------------------------
545 //------------------------------------------------------------------------
547 void SAL_CALL CFileOpenDialog::handleInitDialog(HWND hwndDlg, HWND hwndChild)
549 m_hwndFileOpenDlg = hwndDlg;
550 m_hwndFileOpenDlgChild = hwndChild;
552 OSL_ASSERT(GetParent(hwndChild) == hwndDlg);
554 // calling virtual function which the
555 // client can overload
556 onInitDialog(hwndDlg);
559 //------------------------------------------------------------------------
561 //------------------------------------------------------------------------
563 unsigned int CALLBACK CFileOpenDialog::ofnHookProc(
564 HWND hChildDlg, unsigned int uiMsg, WPARAM wParam, LPARAM lParam)
566 HWND hwndDlg = GetParent(hChildDlg);
567 CFileOpenDialog* pImpl = NULL;
569 switch( uiMsg )
571 case WM_INITDIALOG:
573 _LPOPENFILENAME lpofn = reinterpret_cast<_LPOPENFILENAME>(lParam);
574 pImpl = reinterpret_cast<CFileOpenDialog*>(lpofn->lCustData);
575 OSL_ASSERT(pImpl);
577 // subclass the base dialog for WM_NCDESTROY processing
578 pImpl->m_pfnBaseDlgProc =
579 reinterpret_cast<WNDPROC>(
580 SetWindowLong(
581 hwndDlg,
582 GWL_WNDPROC,
583 reinterpret_cast<LONG>(CFileOpenDialog::BaseDlgProc)));
584 // connect the instance handle to the window
585 SetProp(hwndDlg, CURRENT_INSTANCE, pImpl);
586 pImpl->handleInitDialog(hwndDlg, hChildDlg);
588 return 0;
590 case WM_NOTIFY:
592 pImpl = getCurrentInstance(hwndDlg);
593 return pImpl->onWMNotify(
594 hChildDlg, reinterpret_cast<LPOFNOTIFY>(lParam));
597 case WM_COMMAND:
599 pImpl = getCurrentInstance(hwndDlg);
600 OSL_ASSERT(pImpl);
602 return pImpl->onCtrlCommand(
603 hChildDlg, LOWORD(wParam), HIWORD(lParam));
607 return 0;
610 //------------------------------------------------------------------------
612 //------------------------------------------------------------------------
614 LRESULT CALLBACK CFileOpenDialog::BaseDlgProc(
615 HWND hWnd, UINT wMessage, WPARAM wParam, LPARAM lParam)
617 CFileOpenDialog* pImpl = 0;
619 if (WM_NCDESTROY == wMessage)
621 pImpl = reinterpret_cast<CFileOpenDialog*>(
622 RemoveProp(hWnd,CURRENT_INSTANCE));
624 SetWindowLong(hWnd, GWL_WNDPROC,
625 reinterpret_cast<LONG>(pImpl->m_pfnBaseDlgProc));
627 else
629 pImpl = getCurrentInstance(hWnd);
632 OSL_ASSERT(pImpl);
634 return CallWindowProc(
635 reinterpret_cast<WNDPROC>(pImpl->m_pfnBaseDlgProc),
636 hWnd,wMessage,wParam,lParam);
639 //------------------------------------------------------------------------
641 //------------------------------------------------------------------------
643 CFileOpenDialog* SAL_CALL CFileOpenDialog::getCurrentInstance(HWND hwnd)
645 OSL_ASSERT(IsWindow( hwnd));
646 return reinterpret_cast<CFileOpenDialog*>(
647 GetProp(hwnd, CURRENT_INSTANCE));
650 //------------------------------------------------------------------------
652 //------------------------------------------------------------------------
654 void SAL_CALL CFileOpenDialog::centerPositionToParent() const
656 OSL_PRECOND(IsWindow(m_hwndFileOpenDlg), "no dialog window, call method only after or in onInitDone");
658 HWND hwndParent = m_ofn.hwndOwner;
660 if (!IsWindow(hwndParent))
661 hwndParent = GetDesktopWindow();
663 OSL_ASSERT(IsWindow(hwndParent));
665 RECT rcPar;
666 GetWindowRect(hwndParent, &rcPar);
668 RECT rcDlg;
669 GetWindowRect(m_hwndFileOpenDlg, &rcDlg);
671 int lDlgW = rcDlg.right - rcDlg.left;
672 int lDlgH = rcDlg.bottom - rcDlg.top;
674 int x = (rcPar.left + rcPar.right - lDlgW) / 2;
675 int y = (rcPar.top + rcPar.bottom - lDlgH) / 2;
677 HDC hdc = GetDC(m_hwndFileOpenDlg);
679 int hResol = GetDeviceCaps(hdc, HORZRES);
680 int vResol = GetDeviceCaps(hdc, VERTRES);
682 ReleaseDC(m_hwndFileOpenDlg, hdc);
684 if (x < 0)
685 x = 0;
686 else if ((x + lDlgW) > hResol)
687 x = hResol - lDlgW;
689 if (y < 0)
690 y = 0;
691 else if ((y + lDlgH) > vResol)
692 y = vResol - lDlgH;
694 SetWindowPos(
695 m_hwndFileOpenDlg,
696 NULL, x, y, 0, 0,
697 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE );