bump product version to 4.1.6.2
[LibreOffice.git] / fpicker / source / win32 / filepicker / FileOpenDlg.cxx
blob17c81520b33d541d8c916ac6bd3fc8738700ceda
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #if defined _WIN32_WINNT
21 # undef _WIN32_WINNT
22 #endif
23 #define _WIN32_WINNT 0x0500
25 #include <tchar.h>
26 #include <osl/diagnose.h>
27 #include "../misc/WinImplHelper.hxx"
28 #include "FileOpenDlg.hxx"
30 //------------------------------------------------------------------------
31 // constants
32 //------------------------------------------------------------------------
34 namespace /* private */
36 // we choose such large buffers because the size of
37 // an single line edit field can be up to 32k; if
38 // a user has a multi selection FilePicker and selects
39 // a lot of files in a large directory we may reach this
40 // limit and don't want to get out of memory;
41 // another much more elegant way would be to subclass the
42 // FileOpen dialog and overload the BM_CLICK event of the
43 // OK button so that we determine the size of the text
44 // currently in the edit field and resize our buffer
45 // appropriately - in the future we will do this
46 const size_t MAX_FILENAME_BUFF_SIZE = 32000;
47 const size_t MAX_FILETITLE_BUFF_SIZE = 32000;
48 const size_t MAX_FILTER_BUFF_SIZE = 4096;
50 const LPCTSTR CURRENT_INSTANCE = TEXT("CurrInst");
52 //------------------------------------------
53 // find an appropriate parent window
54 //------------------------------------------
56 inline bool is_current_process_window(HWND hwnd)
58 DWORD pid;
59 GetWindowThreadProcessId(hwnd, &pid);
60 return (pid == GetCurrentProcessId());
63 HWND choose_parent_window()
65 HWND hwnd_parent = GetForegroundWindow();
66 if (!is_current_process_window(hwnd_parent))
67 hwnd_parent = GetDesktopWindow();
69 return hwnd_parent;
73 //------------------------------------------------------------------------
75 //------------------------------------------------------------------------
77 CFileOpenDialog::CFileOpenDialog(
78 bool bFileOpenDialog,
79 sal_uInt32 dwFlags,
80 sal_uInt32 dwTemplateId,
81 HINSTANCE hInstance) :
82 m_hwndFileOpenDlg(0),
83 m_hwndFileOpenDlgChild(0),
84 m_bFileOpenDialog(bFileOpenDialog),
85 m_filterBuffer(MAX_FILTER_BUFF_SIZE),
86 m_fileTitleBuffer(MAX_FILETITLE_BUFF_SIZE),
87 m_helperBuffer(MAX_FILENAME_BUFF_SIZE),
88 m_fileNameBuffer(MAX_FILENAME_BUFF_SIZE),
89 m_pfnBaseDlgProc(0)
91 // initialize the OPENFILENAME struct
92 ZeroMemory(&m_ofn, sizeof(m_ofn));
93 m_ofn.lStructSize = sizeof(m_ofn);
95 // 0x02000000 for #97681, sfx will make the entry into
96 // the recent document list
97 m_ofn.Flags |= dwFlags |
98 OFN_EXPLORER |
99 OFN_ENABLEHOOK |
100 OFN_HIDEREADONLY |
101 OFN_PATHMUSTEXIST |
102 OFN_FILEMUSTEXIST |
103 OFN_OVERWRITEPROMPT |
104 OFN_ENABLESIZING |
105 OFN_DONTADDTORECENT; // 0x02000000 -> OFN_DONTADDTORECENT only available with new platform sdk
107 // it is a little hack but how else could
108 // we get a parent window (using a vcl window?)
109 m_ofn.hwndOwner = choose_parent_window();
111 m_ofn.lpstrFile = reinterpret_cast<LPTSTR>(const_cast<sal_Unicode*>(m_fileNameBuffer.getStr()));
112 m_ofn.nMaxFile = m_fileNameBuffer.getCapacity();
114 m_ofn.lpstrFileTitle = reinterpret_cast<LPTSTR>(const_cast<sal_Unicode*>(m_fileTitleBuffer.getStr()));
115 m_ofn.nMaxFileTitle = m_fileTitleBuffer.getCapacity();
117 m_ofn.lpfnHook = CFileOpenDialog::ofnHookProc;
119 // set a custom template
121 if (dwTemplateId)
123 OSL_ASSERT(hInstance);
125 m_ofn.Flags |= OFN_ENABLETEMPLATE;
126 m_ofn.lpTemplateName = MAKEINTRESOURCE(dwTemplateId);
127 m_ofn.hInstance = hInstance;
130 // set a pointer to myself as ofn parameter
131 m_ofn.lCustData = reinterpret_cast<long>(this);
134 //------------------------------------------------------------------------
136 //------------------------------------------------------------------------
138 CFileOpenDialog::~CFileOpenDialog()
142 //------------------------------------------------------------------------
144 //------------------------------------------------------------------------
146 void SAL_CALL CFileOpenDialog::setTitle(const OUString& aTitle)
148 m_dialogTitle = aTitle;
149 m_ofn.lpstrTitle = reinterpret_cast<LPCTSTR>(m_dialogTitle.getStr());
152 //------------------------------------------------------------------------
154 //------------------------------------------------------------------------
156 void CFileOpenDialog::setFilter(const OUString& aFilter)
158 // Format is like
159 // "*.TXT" or multiple separate by ';' like "*.TXT;*.DOC;*.SXW"
160 // Do not include spaces in the pattern string
161 m_filterBuffer.ensureCapacity(aFilter.getLength());
162 m_filterBuffer.setLength(0);
163 m_filterBuffer.append(aFilter);
164 m_ofn.lpstrFilter = reinterpret_cast<LPCTSTR>(m_filterBuffer.getStr());
167 //------------------------------------------------------------------------
169 //------------------------------------------------------------------------
171 bool CFileOpenDialog::setFilterIndex(sal_uInt32 aIndex)
173 OSL_ASSERT(aIndex > 0);
174 m_ofn.nFilterIndex = aIndex;
175 return sal_True;
178 //------------------------------------------------------------------------
180 //------------------------------------------------------------------------
182 sal_uInt32 CFileOpenDialog::getSelectedFilterIndex() const
184 return m_ofn.nFilterIndex;
187 //------------------------------------------------------------------------
189 //------------------------------------------------------------------------
191 void SAL_CALL CFileOpenDialog::setDefaultName(const OUString& aName)
193 m_fileNameBuffer.setLength(0);
194 m_fileNameBuffer.append(aName);
195 m_ofn.lpstrFile = reinterpret_cast<LPTSTR>(const_cast<sal_Unicode*>(m_fileNameBuffer.getStr()));
198 //------------------------------------------------------------------------
200 //------------------------------------------------------------------------
202 void SAL_CALL CFileOpenDialog::setDisplayDirectory(const OUString& aDirectory)
204 m_displayDirectory = aDirectory;
205 m_ofn.lpstrInitialDir = reinterpret_cast<LPCTSTR>(m_displayDirectory.getStr());
208 //------------------------------------------------------------------------
210 //------------------------------------------------------------------------
212 OUString SAL_CALL CFileOpenDialog::getLastDisplayDirectory() const
214 return m_displayDirectory;
217 //------------------------------------------------------------------------
219 //------------------------------------------------------------------------
221 OUString SAL_CALL CFileOpenDialog::getFullFileName() const
223 return OUString(m_fileNameBuffer.getStr(),
224 _wcslenex(m_fileNameBuffer.getStr()));
227 //------------------------------------------------------------------------
229 //------------------------------------------------------------------------
231 OUString SAL_CALL CFileOpenDialog::getFileName() const
233 return OUString(m_fileTitleBuffer.getStr());
236 //------------------------------------------------------------------------
238 //------------------------------------------------------------------------
240 OUString CFileOpenDialog::getFileExtension()
242 if (m_ofn.nFileExtension)
243 return OUString(m_fileNameBuffer.getStr() + m_ofn.nFileExtension,
244 rtl_ustr_getLength(m_fileNameBuffer.getStr() + m_ofn.nFileExtension));
246 return OUString();
249 //------------------------------------------------------------------------
251 //------------------------------------------------------------------------
253 void CFileOpenDialog::setDefaultFileExtension(const OUString& aExtension)
255 m_defaultExtension = aExtension;
256 m_ofn.lpstrDefExt = reinterpret_cast<LPCTSTR>(m_defaultExtension.getStr());
259 //------------------------------------------------------------------------
261 //------------------------------------------------------------------------
263 void SAL_CALL CFileOpenDialog::setMultiSelectionMode(bool bMode)
265 if (bMode)
266 m_ofn.Flags |= OFN_ALLOWMULTISELECT;
267 else
268 m_ofn.Flags &= ~OFN_ALLOWMULTISELECT;
271 //------------------------------------------------------------------------
273 //------------------------------------------------------------------------
275 bool SAL_CALL CFileOpenDialog::getMultiSelectionMode() const
277 return ((m_ofn.Flags & OFN_ALLOWMULTISELECT) > 0);
280 //------------------------------------------------------------------------
282 //------------------------------------------------------------------------
284 sal_Int16 SAL_CALL CFileOpenDialog::doModal()
286 sal_Int16 nRC = -1;
288 // pre-processing
289 if (preModal())
291 bool bRet;
293 if (m_bFileOpenDialog)
294 bRet = m_GetFileNameWrapper.getOpenFileName(
295 reinterpret_cast<LPOPENFILENAME>(&m_ofn));
296 else
297 bRet = m_GetFileNameWrapper.getSaveFileName(
298 reinterpret_cast<LPOPENFILENAME>(&m_ofn));
300 nRC = 1;
302 if (!bRet)
303 nRC = (0 == m_GetFileNameWrapper.commDlgExtendedError()) ? 0 : -1;
305 // post-processing
306 postModal(nRC);
309 return nRC;
312 //------------------------------------------------------------------------
314 //------------------------------------------------------------------------
316 sal_uInt32 SAL_CALL CFileOpenDialog::getLastDialogError() const
318 return CommDlgExtendedError();
321 //------------------------------------------------------------------------
323 //------------------------------------------------------------------------
325 bool SAL_CALL CFileOpenDialog::preModal()
327 return sal_True;
330 //------------------------------------------------------------------------
332 //------------------------------------------------------------------------
334 void SAL_CALL CFileOpenDialog::postModal(sal_Int16 nDialogResult)
336 OSL_ASSERT((-1 <= nDialogResult) && (nDialogResult <= 1));
338 if (1 == nDialogResult)
340 // Attention: assuming that nFileOffset is always greater 0 because under
341 // Windows there is always a drive letter or a server in a complete path
342 // the OPENFILENAME docu never says that nFileOffset can be 0
343 m_displayDirectory = OUString(reinterpret_cast<const sal_Unicode*>(m_ofn.lpstrFile),m_ofn.nFileOffset);
347 //------------------------------------------------------------------------
349 //------------------------------------------------------------------------
351 OUString SAL_CALL CFileOpenDialog::getCurrentFilePath() const
353 OSL_ASSERT(IsWindow(m_hwndFileOpenDlg));
355 LPARAM nLen = SendMessage(
356 m_hwndFileOpenDlg,
357 CDM_GETFILEPATH,
358 m_helperBuffer.getCapacity(),
359 reinterpret_cast<LPARAM>(m_helperBuffer.getStr()));
361 if (nLen > 0)
363 m_helperBuffer.setLength((nLen * sizeof(sal_Unicode)) - 1);
364 return OUString(m_helperBuffer.getStr());
366 return OUString();
369 //------------------------------------------------------------------------
371 //------------------------------------------------------------------------
373 OUString SAL_CALL CFileOpenDialog::getCurrentFolderPath() const
375 OSL_ASSERT(IsWindow(m_hwndFileOpenDlg));
377 LPARAM nLen = SendMessage(
378 m_hwndFileOpenDlg,
379 CDM_GETFOLDERPATH,
380 m_helperBuffer.getCapacity(),
381 reinterpret_cast<LPARAM>(m_helperBuffer.getStr()));
383 if (nLen > 0)
385 m_helperBuffer.setLength((nLen * sizeof(sal_Unicode)) - 1);
386 return OUString(m_helperBuffer.getStr());
388 return OUString();
391 //------------------------------------------------------------------------
393 //------------------------------------------------------------------------
395 OUString SAL_CALL CFileOpenDialog::getCurrentFileName() const
397 OSL_ASSERT(IsWindow(m_hwndFileOpenDlg));
399 LPARAM nLen = SendMessage(
400 m_hwndFileOpenDlg,
401 CDM_GETSPEC,
402 m_helperBuffer.getCapacity(),
403 reinterpret_cast<LPARAM>(m_helperBuffer.getStr()));
405 if (nLen > 0)
407 m_helperBuffer.setLength((nLen * sizeof(sal_Unicode)) - 1);
408 return OUString(m_helperBuffer.getStr());
410 return OUString();
413 //------------------------------------------------------------------------
415 //------------------------------------------------------------------------
417 sal_uInt32 SAL_CALL CFileOpenDialog::onShareViolation(const OUString&)
419 return 0;
422 //------------------------------------------------------------------------
424 //------------------------------------------------------------------------
426 sal_uInt32 SAL_CALL CFileOpenDialog::onFileOk()
428 return 0;
431 //------------------------------------------------------------------------
433 //------------------------------------------------------------------------
435 void SAL_CALL CFileOpenDialog::onSelChanged(HWND)
439 //------------------------------------------------------------------------
441 //------------------------------------------------------------------------
443 void SAL_CALL CFileOpenDialog::onHelp()
447 //------------------------------------------------------------------------
449 //------------------------------------------------------------------------
451 void SAL_CALL CFileOpenDialog::onInitDone()
453 centerPositionToParent();
456 //------------------------------------------------------------------------
458 //------------------------------------------------------------------------
460 void SAL_CALL CFileOpenDialog::onFolderChanged()
464 //------------------------------------------------------------------------
466 //------------------------------------------------------------------------
468 void SAL_CALL CFileOpenDialog::onTypeChanged(sal_uInt32)
472 //------------------------------------------------------------------------
474 //------------------------------------------------------------------------
476 sal_uInt32 SAL_CALL CFileOpenDialog::onCtrlCommand(HWND, sal_uInt16, sal_uInt16)
478 return 0;
481 //------------------------------------------------------------------------
483 //------------------------------------------------------------------------
485 sal_uInt32 SAL_CALL CFileOpenDialog::onWMNotify( HWND, LPOFNOTIFY lpOfNotify )
487 switch(lpOfNotify->hdr.code)
489 case CDN_SHAREVIOLATION:
490 return onShareViolation(reinterpret_cast<const sal_Unicode*>(lpOfNotify->pszFile));
492 case CDN_FILEOK:
493 return onFileOk();
495 case CDN_SELCHANGE:
496 onSelChanged(lpOfNotify->hdr.hwndFrom);
497 break;
499 case CDN_HELP:
500 onHelp();
501 break;
503 case CDN_INITDONE:
504 onInitDone();
505 break;
507 case CDN_FOLDERCHANGE:
508 onFolderChanged();
509 break;
511 case CDN_TYPECHANGE:
512 m_ofn.nFilterIndex = lpOfNotify->lpOFN->nFilterIndex;
513 onTypeChanged(lpOfNotify->lpOFN->nFilterIndex);
514 break;
517 return 0;
520 //------------------------------------------------------------------------
522 //------------------------------------------------------------------------
524 void SAL_CALL CFileOpenDialog::handleInitDialog(HWND hwndDlg, HWND hwndChild)
526 m_hwndFileOpenDlg = hwndDlg;
527 m_hwndFileOpenDlgChild = hwndChild;
529 OSL_ASSERT(GetParent(hwndChild) == hwndDlg);
531 // calling virtual function which the
532 // client can overload
533 onInitDialog(hwndDlg);
536 //------------------------------------------------------------------------
538 //------------------------------------------------------------------------
540 UINT_PTR CALLBACK CFileOpenDialog::ofnHookProc(
541 HWND hChildDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
543 HWND hwndDlg = GetParent(hChildDlg);
544 CFileOpenDialog* pImpl = NULL;
546 switch( uiMsg )
548 case WM_INITDIALOG:
550 _LPOPENFILENAME lpofn = reinterpret_cast<_LPOPENFILENAME>(lParam);
551 pImpl = reinterpret_cast<CFileOpenDialog*>(lpofn->lCustData);
552 OSL_ASSERT(pImpl);
554 // subclass the base dialog for WM_NCDESTROY processing
555 pImpl->m_pfnBaseDlgProc =
556 reinterpret_cast<WNDPROC>(
557 SetWindowLongPtr(
558 hwndDlg,
559 GWLP_WNDPROC,
560 reinterpret_cast<LONG_PTR>(CFileOpenDialog::BaseDlgProc)));
561 // connect the instance handle to the window
562 SetProp(hwndDlg, CURRENT_INSTANCE, pImpl);
563 pImpl->handleInitDialog(hwndDlg, hChildDlg);
565 return 0;
567 case WM_NOTIFY:
569 pImpl = getCurrentInstance(hwndDlg);
570 return pImpl->onWMNotify(
571 hChildDlg, reinterpret_cast<LPOFNOTIFY>(lParam));
574 case WM_COMMAND:
576 pImpl = getCurrentInstance(hwndDlg);
577 OSL_ASSERT(pImpl);
579 return pImpl->onCtrlCommand(
580 hChildDlg, LOWORD(wParam), HIWORD(lParam));
584 return 0;
587 //------------------------------------------------------------------------
589 //------------------------------------------------------------------------
591 LRESULT CALLBACK CFileOpenDialog::BaseDlgProc(
592 HWND hWnd, UINT wMessage, WPARAM wParam, LPARAM lParam)
594 CFileOpenDialog* pImpl = 0;
596 if (WM_NCDESTROY == wMessage)
598 pImpl = reinterpret_cast<CFileOpenDialog*>(
599 RemoveProp(hWnd,CURRENT_INSTANCE));
601 SetWindowLongPtr(hWnd, GWLP_WNDPROC,
602 reinterpret_cast<LONG_PTR>(pImpl->m_pfnBaseDlgProc));
604 else
606 pImpl = getCurrentInstance(hWnd);
609 OSL_ASSERT(pImpl);
611 return CallWindowProc(
612 reinterpret_cast<WNDPROC>(pImpl->m_pfnBaseDlgProc),
613 hWnd,wMessage,wParam,lParam);
616 //------------------------------------------------------------------------
618 //------------------------------------------------------------------------
620 CFileOpenDialog* SAL_CALL CFileOpenDialog::getCurrentInstance(HWND hwnd)
622 OSL_ASSERT(IsWindow( hwnd));
623 return reinterpret_cast<CFileOpenDialog*>(
624 GetProp(hwnd, CURRENT_INSTANCE));
627 //------------------------------------------------------------------------
629 //------------------------------------------------------------------------
631 void SAL_CALL CFileOpenDialog::centerPositionToParent() const
633 OSL_PRECOND(IsWindow(m_hwndFileOpenDlg), "no dialog window, call method only after or in onInitDone");
635 HWND hwndParent = m_ofn.hwndOwner;
637 if (!IsWindow(hwndParent))
638 hwndParent = GetDesktopWindow();
640 OSL_ASSERT(IsWindow(hwndParent));
642 RECT rcPar;
643 GetWindowRect(hwndParent, &rcPar);
645 RECT rcDlg;
646 GetWindowRect(m_hwndFileOpenDlg, &rcDlg);
648 int lDlgW = rcDlg.right - rcDlg.left;
649 int lDlgH = rcDlg.bottom - rcDlg.top;
651 int x = (rcPar.left + rcPar.right - lDlgW) / 2;
652 int y = (rcPar.top + rcPar.bottom - lDlgH) / 2;
654 HDC hdc = GetDC(m_hwndFileOpenDlg);
656 int hResol = GetDeviceCaps(hdc, HORZRES);
657 int vResol = GetDeviceCaps(hdc, VERTRES);
659 ReleaseDC(m_hwndFileOpenDlg, hdc);
661 if (x < 0)
662 x = 0;
663 else if ((x + lDlgW) > hResol)
664 x = hResol - lDlgW;
666 if (y < 0)
667 y = 0;
668 else if ((y + lDlgH) > vResol)
669 y = vResol - lDlgH;
671 SetWindowPos(
672 m_hwndFileOpenDlg,
673 NULL, x, y, 0, 0,
674 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE );
677 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */