1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
23 #define _WIN32_WINNT 0x0500
26 #include <osl/diagnose.h>
27 #include "../misc/WinImplHelper.hxx"
28 #include "FileOpenDlg.hxx"
30 //------------------------------------------------------------------------
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
)
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();
73 //------------------------------------------------------------------------
75 //------------------------------------------------------------------------
77 CFileOpenDialog::CFileOpenDialog(
80 sal_uInt32 dwTemplateId
,
81 HINSTANCE hInstance
) :
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
),
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
|
103 OFN_OVERWRITEPROMPT
|
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
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
)
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
;
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
));
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
)
266 m_ofn
.Flags
|= OFN_ALLOWMULTISELECT
;
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()
293 if (m_bFileOpenDialog
)
294 bRet
= m_GetFileNameWrapper
.getOpenFileName(
295 reinterpret_cast<LPOPENFILENAME
>(&m_ofn
));
297 bRet
= m_GetFileNameWrapper
.getSaveFileName(
298 reinterpret_cast<LPOPENFILENAME
>(&m_ofn
));
303 nRC
= (0 == m_GetFileNameWrapper
.commDlgExtendedError()) ? 0 : -1;
312 //------------------------------------------------------------------------
314 //------------------------------------------------------------------------
316 sal_uInt32 SAL_CALL
CFileOpenDialog::getLastDialogError() const
318 return CommDlgExtendedError();
321 //------------------------------------------------------------------------
323 //------------------------------------------------------------------------
325 bool SAL_CALL
CFileOpenDialog::preModal()
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(
358 m_helperBuffer
.getCapacity(),
359 reinterpret_cast<LPARAM
>(m_helperBuffer
.getStr()));
363 m_helperBuffer
.setLength((nLen
* sizeof(sal_Unicode
)) - 1);
364 return OUString(m_helperBuffer
.getStr());
369 //------------------------------------------------------------------------
371 //------------------------------------------------------------------------
373 OUString SAL_CALL
CFileOpenDialog::getCurrentFolderPath() const
375 OSL_ASSERT(IsWindow(m_hwndFileOpenDlg
));
377 LPARAM nLen
= SendMessage(
380 m_helperBuffer
.getCapacity(),
381 reinterpret_cast<LPARAM
>(m_helperBuffer
.getStr()));
385 m_helperBuffer
.setLength((nLen
* sizeof(sal_Unicode
)) - 1);
386 return OUString(m_helperBuffer
.getStr());
391 //------------------------------------------------------------------------
393 //------------------------------------------------------------------------
395 OUString SAL_CALL
CFileOpenDialog::getCurrentFileName() const
397 OSL_ASSERT(IsWindow(m_hwndFileOpenDlg
));
399 LPARAM nLen
= SendMessage(
402 m_helperBuffer
.getCapacity(),
403 reinterpret_cast<LPARAM
>(m_helperBuffer
.getStr()));
407 m_helperBuffer
.setLength((nLen
* sizeof(sal_Unicode
)) - 1);
408 return OUString(m_helperBuffer
.getStr());
413 //------------------------------------------------------------------------
415 //------------------------------------------------------------------------
417 sal_uInt32 SAL_CALL
CFileOpenDialog::onShareViolation(const OUString
&)
422 //------------------------------------------------------------------------
424 //------------------------------------------------------------------------
426 sal_uInt32 SAL_CALL
CFileOpenDialog::onFileOk()
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
)
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
));
496 onSelChanged(lpOfNotify
->hdr
.hwndFrom
);
507 case CDN_FOLDERCHANGE
:
512 m_ofn
.nFilterIndex
= lpOfNotify
->lpOFN
->nFilterIndex
;
513 onTypeChanged(lpOfNotify
->lpOFN
->nFilterIndex
);
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
;
550 _LPOPENFILENAME lpofn
= reinterpret_cast<_LPOPENFILENAME
>(lParam
);
551 pImpl
= reinterpret_cast<CFileOpenDialog
*>(lpofn
->lCustData
);
554 // subclass the base dialog for WM_NCDESTROY processing
555 pImpl
->m_pfnBaseDlgProc
=
556 reinterpret_cast<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
);
569 pImpl
= getCurrentInstance(hwndDlg
);
570 return pImpl
->onWMNotify(
571 hChildDlg
, reinterpret_cast<LPOFNOTIFY
>(lParam
));
576 pImpl
= getCurrentInstance(hwndDlg
);
579 return pImpl
->onCtrlCommand(
580 hChildDlg
, LOWORD(wParam
), HIWORD(lParam
));
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
));
606 pImpl
= getCurrentInstance(hWnd
);
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
));
643 GetWindowRect(hwndParent
, &rcPar
);
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
);
663 else if ((x
+ lDlgW
) > hResol
)
668 else if ((y
+ lDlgH
) > vResol
)
674 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_NOSIZE
);
677 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */