xref: /trunk/main/fpicker/source/win32/filepicker/WinFileOpenImpl.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_fpicker.hxx"
26 
27 //------------------------------------------------------------------------
28 // includes
29 //------------------------------------------------------------------------
30 
31 #include "shared.hxx"
32 #include "WinFileOpenImpl.hxx"
33 #include <osl/diagnose.h>
34 #include <osl/file.hxx>
35 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
36 #include <com/sun/star/ui/dialogs/FilePickerEvent.hpp>
37 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
38 #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
39 #include <com/sun/star/ui/dialogs/FilePreviewImageFormats.hpp>
40 #include <com/sun/star/ui/dialogs/ListBoxControlActions.hpp>
41 #include "..\misc\WinImplHelper.hxx"
42 
43 #ifndef _FILEPICKER_HXX_
44 #include "filepicker.hxx"
45 #endif
46 #include "controlaccess.hxx"
47 #include <rtl/ustrbuf.hxx>
48 #include <rtl/string.hxx>
49 #include <osl/thread.hxx>
50 #include "filepickerstate.hxx"
51 
52 //------------------------------------------------------------------------
53 // namespace directives
54 //------------------------------------------------------------------------
55 
56 using namespace com::sun::star;
57 
58 using com::sun::star::ui::dialogs::FilePickerEvent;
59 using com::sun::star::lang::IllegalArgumentException;
60 using com::sun::star::ui::dialogs::XFilePicker2;
61 
62 using namespace ::com::sun::star::ui::dialogs::ExtendedFilePickerElementIds;
63 using namespace ::com::sun::star::ui::dialogs::CommonFilePickerElementIds;
64 using namespace ::com::sun::star::ui::dialogs::ListboxControlActions;
65 
66 //-------------------------------------------------------------------------
67 // to distinguish what to do in the enum child window callback function
68 //-------------------------------------------------------------------------
69 
70 enum ECW_ACTION_T
71 {
72     INIT_CUSTOM_CONTROLS,
73     CACHE_CONTROL_VALUES
74 };
75 
76 struct EnumParam
77 {
78     ECW_ACTION_T        m_action;
79     CWinFileOpenImpl*   m_instance;
80 
EnumParamEnumParam81     EnumParam( ECW_ACTION_T action, CWinFileOpenImpl* instance ):
82         m_action( action ),
83         m_instance( instance )
84     {}
85 };
86 
87 //-------------------------------------------------------------------------
88 // ctor
89 //-------------------------------------------------------------------------
90 
CWinFileOpenImpl(CFilePicker * aFilePicker,sal_Bool bFileOpenDialog,sal_uInt32 dwFlags,sal_uInt32 dwTemplateId,HINSTANCE hInstance)91 CWinFileOpenImpl::CWinFileOpenImpl(
92     CFilePicker* aFilePicker,
93     sal_Bool bFileOpenDialog,
94     sal_uInt32 dwFlags,
95     sal_uInt32 dwTemplateId,
96     HINSTANCE hInstance) :
97     CFileOpenDialog(bFileOpenDialog, dwFlags, dwTemplateId, hInstance),
98     m_filterContainer(new CFilterContainer()),
99     m_Preview(new CPreviewAdapter(hInstance)),
100     m_CustomControlFactory(new CCustomControlFactory()),
101     m_CustomControls(m_CustomControlFactory->CreateCustomControlContainer()),
102     m_FilePicker(aFilePicker),
103     m_bInitialSelChanged(sal_True),
104     m_HelpPopupWindow(hInstance, m_hwndFileOpenDlg),
105     m_ExecuteFilePickerState(new CExecuteFilePickerState()),
106     m_NonExecuteFilePickerState(new CNonExecuteFilePickerState())
107 {
108     m_FilePickerState = m_NonExecuteFilePickerState;
109 }
110 
111 //------------------------------------------------------------------------
112 // dtor
113 //------------------------------------------------------------------------
114 
~CWinFileOpenImpl()115 CWinFileOpenImpl::~CWinFileOpenImpl()
116 {
117     delete m_ExecuteFilePickerState;
118     delete m_NonExecuteFilePickerState;
119 }
120 
121 //------------------------------------------------------------------------
122 // we expect the directory in URL format
123 //------------------------------------------------------------------------
124 
setDisplayDirectory(const rtl::OUString & aDirectory)125 void CWinFileOpenImpl::setDisplayDirectory(const rtl::OUString& aDirectory)
126 {
127     rtl::OUString aSysDirectory;
128     if( aDirectory.getLength() > 0)
129     {
130         if ( ::osl::FileBase::E_None !=
131              ::osl::FileBase::getSystemPathFromFileURL(aDirectory,aSysDirectory))
132             throw IllegalArgumentException(
133                 rtl::OUString::createFromAscii("Invalid directory"),
134                 static_cast<XFilePicker2*>(m_FilePicker), 1);
135 
136         // we ensure that there is a trailing '/' at the end of
137         // he given file url, because the windows functions only
138         // works correctly when providing "c:\" or an environment
139         // variable like "=c:=c:\.." etc. is set, else the
140         // FolderPicker would stand in the root of the shell
141         // hierarchie which is the desktop folder
142         if ( aSysDirectory.lastIndexOf(BACKSLASH) != (aSysDirectory.getLength() - 1))
143             aSysDirectory += BACKSLASH;
144     }
145 
146     // call base class method
147     CFileOpenDialog::setDisplayDirectory(aSysDirectory);
148 }
149 
150 //------------------------------------------------------------------------
151 // we return the directory in URL format
152 //------------------------------------------------------------------------
153 
getDisplayDirectory()154 rtl::OUString CWinFileOpenImpl::getDisplayDirectory()
155 {
156     return m_FilePickerState->getDisplayDirectory(this);
157 }
158 
159 //-----------------------------------------------------------------------------------------
160 //
161 //-----------------------------------------------------------------------------------------
162 
setDefaultName(const rtl::OUString & aName)163 void SAL_CALL CWinFileOpenImpl::setDefaultName(const rtl::OUString& aName)
164 {
165     // we don't set the default name directly
166     // because this influences how the file open
167     // dialog sets the initial path when it is about
168     // to open (see MSDN: OPENFILENAME)
169     // so we save the default name which should
170     // appear in the file-name-box and set
171     // this name when processing onInitDone
172     m_defaultName = aName;
173 }
174 
175 //-----------------------------------------------------------------------------------------
176 // return format: URL
177 // if multiselection is allowed there are two different cases
178 // 1. one file selected: the sequence contains one entry path\filename.ext
179 // 2. multiple files selected: the sequence contains multiple entries
180 //    the first entry is the path url, all other entries are file names
181 //-----------------------------------------------------------------------------------------
182 
getFiles()183 uno::Sequence<rtl::OUString> SAL_CALL CWinFileOpenImpl::getFiles()
184 {
185     return m_FilePickerState->getFiles(this);
186 }
187 
188 //-----------------------------------------------------------------------------------------
189 // shows the FileOpen/FileSave dialog
190 //-----------------------------------------------------------------------------------------
191 
execute()192 sal_Int16 SAL_CALL CWinFileOpenImpl::execute(  )
193 {
194     sal_Int16 rc = CFileOpenDialog::doModal();
195 
196     if (1 == rc)
197         rc = ::com::sun::star::ui::dialogs::ExecutableDialogResults::OK;
198     else if (0 == rc)
199         rc = ::com::sun::star::ui::dialogs::ExecutableDialogResults::CANCEL;
200     else
201         throw uno::RuntimeException(
202             rtl::OUString::createFromAscii("Error executing dialog"),
203             static_cast<XFilePicker2*>(m_FilePicker));
204 
205     return rc;
206 }
207 
208 //-----------------------------------------------------------------------------------------
209 // appends a new filter
210 // returns false if the title (aTitle) was already added or the title or the filter are
211 // empty
212 //-----------------------------------------------------------------------------------------
213 
appendFilter(const rtl::OUString & aTitle,const rtl::OUString & aFilter)214 void SAL_CALL CWinFileOpenImpl::appendFilter(const rtl::OUString& aTitle, const rtl::OUString& aFilter)
215 {
216     sal_Bool bRet = m_filterContainer->addFilter(aTitle, aFilter);
217 
218     if (!bRet)
219         throw IllegalArgumentException(
220             rtl::OUString::createFromAscii("filter already exists"),
221             static_cast<XFilePicker2*>(m_FilePicker), 1);
222 
223     // #95345# see MSDN OPENFILENAME
224     // If nFilterIndex is zero and lpstrCustomFilter is NULL,
225     // the system uses the first filter in the lpstrFilter buffer.
226     // to reflect this we must set the filter index so that calls
227     // to getSelectedFilterIndex without explicitly calling
228     // setFilterIndex before does not return 0 which leads to a
229     // false state
230     if (0 == getSelectedFilterIndex())
231         CFileOpenDialog::setFilterIndex(1);
232 }
233 
234 //-----------------------------------------------------------------------------------------
235 // sets a current filter
236 //-----------------------------------------------------------------------------------------
237 
setCurrentFilter(const rtl::OUString & aTitle)238 void SAL_CALL CWinFileOpenImpl::setCurrentFilter(const rtl::OUString& aTitle)
239 {
240     sal_Int32 filterPos = m_filterContainer->getFilterPos(aTitle);
241 
242     if (filterPos < 0)
243         throw IllegalArgumentException(
244             rtl::OUString::createFromAscii("filter doesn't exist"),
245             static_cast<XFilePicker2*>(m_FilePicker), 1);
246 
247     // filter index of the base class starts with 1
248     CFileOpenDialog::setFilterIndex(filterPos + 1);
249 }
250 
251 //-----------------------------------------------------------------------------------------
252 // returns the currently selected filter
253 //-----------------------------------------------------------------------------------------
254 
getCurrentFilter()255 rtl::OUString SAL_CALL CWinFileOpenImpl::getCurrentFilter()
256 {
257     sal_uInt32 nIndex = getSelectedFilterIndex();
258 
259     rtl::OUString currentFilter;
260     if (nIndex > 0)
261     {
262         // filter index of the base class starts with 1
263         if (!m_filterContainer->getFilter(nIndex - 1, currentFilter)) {
264             OSL_ASSERT(false);
265         }
266     }
267 
268     return currentFilter;
269 }
270 
271 //-----------------------------------------------------------------------------------------
272 //
273 //-----------------------------------------------------------------------------------------
274 
appendFilterGroupSeparator()275 inline void SAL_CALL CWinFileOpenImpl::appendFilterGroupSeparator()
276 {
277     m_filterContainer->addFilter(FILTER_SEPARATOR, ALL_FILES_WILDCARD, ALLOW_DUPLICATES);
278 }
279 
280 //-----------------------------------------------------------------------------------------
281 // XFilterGroupManager
282 //-----------------------------------------------------------------------------------------
283 
appendFilterGroup(const rtl::OUString & sGroupTitle,const uno::Sequence<beans::StringPair> & aFilters)284 void SAL_CALL CWinFileOpenImpl::appendFilterGroup(const rtl::OUString& sGroupTitle, const uno::Sequence<beans::StringPair>& aFilters)
285 {
286     (void) sGroupTitle; // avoid warning
287     OSL_ENSURE(0 == sGroupTitle.getLength(), "appendFilterGroup: Parameter 'GroupTitle' currently ignored");
288 
289     sal_Int32 nFilters = aFilters.getLength();
290 
291     OSL_PRECOND(nFilters > 0, "Empty filter list");
292 
293     if (nFilters > 0)
294     {
295         // append a separator before the next group if
296         // there is already a group of filters
297         if (m_filterContainer->numFilter() > 0)
298             appendFilterGroupSeparator();
299 
300         for (int i = 0; i < nFilters; i++)
301             appendFilter(aFilters[i].First, aFilters[i].Second);
302     }
303 }
304 
305 //=================================================================================================================
306 // XExtendedFilePicker
307 //=================================================================================================================
308 
309 // #i90917: Due to a different feature set for the system-dependent file pickers
310 // it's possible that generic code (e.g. sfx2) provides control ids
311 // (see ExtendedFilePickerElementIds::LISTBOX_FILTER_SELECTOR) which are NOT
312 // available on all platforms. This filter function should filter out control ids
313 // which are only available on KDE/GTK file pickers.
filterControlCommand(sal_Int16 nControlId)314 static bool filterControlCommand( sal_Int16 nControlId )
315 {
316     if ( nControlId == LISTBOX_FILTER_SELECTOR )
317         return true;
318     return false;
319 }
320 
setValue(sal_Int16 aControlId,sal_Int16 aControlAction,const uno::Any & aValue)321 void SAL_CALL CWinFileOpenImpl::setValue(sal_Int16 aControlId, sal_Int16 aControlAction, const uno::Any& aValue)
322 {
323     OSL_ASSERT(m_FilePickerState);
324     if ( !filterControlCommand( aControlId ))
325         m_FilePickerState->setValue(aControlId, aControlAction, aValue);
326 }
327 
328 //-----------------------------------------------------------------------------------------
329 // returns the value of an custom template element
330 // we assume that there are only checkboxes or comboboxes
331 //-----------------------------------------------------------------------------------------
332 
getValue(sal_Int16 aControlId,sal_Int16 aControlAction)333 uno::Any SAL_CALL CWinFileOpenImpl::getValue(sal_Int16 aControlId, sal_Int16 aControlAction)
334 {
335     OSL_ASSERT(m_FilePickerState);
336     if ( !filterControlCommand( aControlId ))
337         return m_FilePickerState->getValue(aControlId, aControlAction);
338     else
339         return uno::Any();
340 }
341 
342 //-----------------------------------------------------------------------------------------
343 // enables a custom template element
344 //-----------------------------------------------------------------------------------------
345 
enableControl(sal_Int16 ControlID,sal_Bool bEnable)346 void SAL_CALL CWinFileOpenImpl::enableControl(sal_Int16 ControlID, sal_Bool bEnable)
347 {
348     OSL_ASSERT(m_FilePickerState);
349     if ( !filterControlCommand( ControlID ))
350         m_FilePickerState->enableControl(ControlID, bEnable);
351 }
352 
353 //-----------------------------------------------------------------------------------------
354 //
355 //-----------------------------------------------------------------------------------------
356 
setLabel(sal_Int16 aControlId,const rtl::OUString & aLabel)357 void SAL_CALL CWinFileOpenImpl::setLabel( sal_Int16 aControlId, const rtl::OUString& aLabel )
358 {
359     OSL_ASSERT(m_FilePickerState);
360     if ( !filterControlCommand( aControlId ))
361         m_FilePickerState->setLabel(aControlId, aLabel);
362 }
363 
364 //-----------------------------------------------------------------------------------------
365 //
366 //-----------------------------------------------------------------------------------------
367 
getLabel(sal_Int16 aControlId)368 rtl::OUString SAL_CALL CWinFileOpenImpl::getLabel( sal_Int16 aControlId )
369 {
370     OSL_ASSERT(m_FilePickerState);
371     if ( !filterControlCommand( aControlId ))
372         return m_FilePickerState->getLabel(aControlId);
373     else
374         return rtl::OUString();
375 }
376 
377 //-----------------------------------------------------------------------------------------
378 //
379 //-----------------------------------------------------------------------------------------
380 
getSupportedImageFormats()381 uno::Sequence<sal_Int16> SAL_CALL CWinFileOpenImpl::getSupportedImageFormats()
382 {
383     return m_Preview->getSupportedImageFormats();
384 }
385 
386 //-----------------------------------------------------------------------------------------
387 //
388 //-----------------------------------------------------------------------------------------
389 
getTargetColorDepth()390 sal_Int32 SAL_CALL CWinFileOpenImpl::getTargetColorDepth()
391 {
392     return m_Preview->getTargetColorDepth();
393 }
394 
395 //-----------------------------------------------------------------------------------------
396 //
397 //-----------------------------------------------------------------------------------------
398 
getAvailableWidth()399 sal_Int32 SAL_CALL CWinFileOpenImpl::getAvailableWidth()
400 {
401     return m_Preview->getAvailableWidth();
402 }
403 
404 //-----------------------------------------------------------------------------------------
405 //
406 //-----------------------------------------------------------------------------------------
407 
getAvailableHeight()408 sal_Int32 SAL_CALL CWinFileOpenImpl::getAvailableHeight()
409 {
410     return m_Preview->getAvailableHeight();
411 }
412 
413 //-----------------------------------------------------------------------------------------
414 //
415 //-----------------------------------------------------------------------------------------
416 
setImage(sal_Int16 aImageFormat,const uno::Any & aImage)417 void SAL_CALL CWinFileOpenImpl::setImage(sal_Int16 aImageFormat, const uno::Any& aImage)
418 {
419     m_Preview->setImage(aImageFormat,aImage);
420 }
421 
422 //-----------------------------------------------------------------------------------------
423 //
424 //-----------------------------------------------------------------------------------------
425 
setShowState(sal_Bool bShowState)426 sal_Bool SAL_CALL CWinFileOpenImpl::setShowState(sal_Bool bShowState)
427 {
428     return m_Preview->setShowState(bShowState);
429 }
430 
431 //-----------------------------------------------------------------------------------------
432 //
433 //-----------------------------------------------------------------------------------------
434 
getShowState()435 sal_Bool SAL_CALL CWinFileOpenImpl::getShowState()
436 {
437     return m_Preview->getShowState();
438 }
439 
440 //-----------------------------------------------------------------------------------------
441 //
442 //-----------------------------------------------------------------------------------------
443 
cancel()444 void SAL_CALL CWinFileOpenImpl::cancel()
445 {
446     if (IsWindow(m_hwndFileOpenDlg))
447     {
448         // simulate a mouse click to the
449         // cancel button
450         PostMessage(
451             m_hwndFileOpenDlg,
452             WM_COMMAND,
453             MAKEWPARAM(IDCANCEL,BN_CLICKED),
454             (LPARAM)GetDlgItem(m_hwndFileOpenDlg, IDCANCEL));
455     }
456 }
457 
458 //-----------------------------------------------------------------------------------------
459 // returns the id of a custom template element
460 //-----------------------------------------------------------------------------------------
461 
getFocused()462 sal_Int16 SAL_CALL CWinFileOpenImpl::getFocused()
463 {
464     int nID = GetDlgCtrlID(GetFocus());
465 
466     // we don't forward id's of standard file open
467     // dialog elements (ctlFirst is defined in dlgs.h
468     // in MS Platform SDK)
469     if (nID >= ctlFirst)
470         nID = 0;
471 
472     return sal::static_int_cast< sal_Int16 >(nID);
473 }
474 
475 //-----------------------------------------------------------------------------------------
476 //
477 //-----------------------------------------------------------------------------------------
478 
IsCustomControlHelpRequested(LPHELPINFO lphi) const479 inline sal_Bool SAL_CALL CWinFileOpenImpl::IsCustomControlHelpRequested(LPHELPINFO lphi) const
480 {
481     return ((lphi->iCtrlId != IDOK) && (lphi->iCtrlId != IDCANCEL) && (lphi->iCtrlId < ctlFirst));
482 }
483 
484 //-----------------------------------------------------------------------------------------
485 // our own DlgProc because we do subclass the dialog
486 // we catch the WM_NCDESTROY message in order to erase an entry in our static map
487 // if one instance dies
488 //-----------------------------------------------------------------------------------------
489 
SubClassFunc(HWND hWnd,UINT wMessage,WPARAM wParam,LPARAM lParam)490 LRESULT CALLBACK CWinFileOpenImpl::SubClassFunc(
491     HWND hWnd, UINT wMessage, WPARAM wParam, LPARAM lParam)
492 {
493     LRESULT lResult = 0;
494 
495     CWinFileOpenImpl* pImpl = dynamic_cast<CWinFileOpenImpl*>(getCurrentInstance(hWnd));
496 
497     switch(wMessage)
498     {
499     case WM_HELP:
500     {
501         LPHELPINFO lphi = reinterpret_cast<LPHELPINFO>(lParam);
502 
503         if (pImpl->IsCustomControlHelpRequested(lphi))
504             pImpl->onCustomControlHelpRequest(lphi);
505         else
506             lResult = CallWindowProc(
507                 reinterpret_cast<WNDPROC>(pImpl->m_pfnOldDlgProc),
508                 hWnd,wMessage,wParam,lParam);
509     }
510     break;
511 
512     case WM_SIZE:
513         lResult = CallWindowProc(
514             reinterpret_cast<WNDPROC>(pImpl->m_pfnOldDlgProc),
515             hWnd,wMessage,wParam,lParam);
516 
517         pImpl->onWMSize();
518         break;
519 
520     case WM_WINDOWPOSCHANGED:
521         lResult = CallWindowProc(
522             reinterpret_cast<WNDPROC>(pImpl->m_pfnOldDlgProc),
523             hWnd,wMessage,wParam,lParam);
524 
525         pImpl->onWMWindowPosChanged();
526         break;
527 
528     case WM_SHOWWINDOW:
529         lResult = CallWindowProc(
530             reinterpret_cast<WNDPROC>(pImpl->m_pfnOldDlgProc),
531             hWnd,wMessage,wParam,lParam);
532 
533         pImpl->onWMShow((sal_Bool)wParam);
534         break;
535 
536     case WM_NCDESTROY:
537         // restore the old window proc
538         SetWindowLongPtr(hWnd, GWLP_WNDPROC,
539             reinterpret_cast<LONG_PTR>(pImpl->m_pfnOldDlgProc));
540 
541         lResult = CallWindowProc(
542             reinterpret_cast<WNDPROC>(pImpl->m_pfnOldDlgProc),
543             hWnd,wMessage,wParam,lParam);
544         break;
545 
546     default:
547         lResult = CallWindowProc(
548             reinterpret_cast<WNDPROC>(pImpl->m_pfnOldDlgProc),
549             hWnd,wMessage,wParam,lParam);
550     break;
551 
552     } // switch
553 
554     return lResult;
555 }
556 
557 //-----------------------------------------------------------------
558 //
559 //-----------------------------------------------------------------
560 
InitControlLabel(HWND hWnd)561 void SAL_CALL CWinFileOpenImpl::InitControlLabel(HWND hWnd)
562 {
563     //-----------------------------------------
564     // set the labels for all extendet controls
565     //-----------------------------------------
566 
567     sal_Int16 aCtrlId = sal::static_int_cast< sal_Int16 >(GetDlgCtrlID(hWnd));
568     rtl::OUString aLabel = m_ResProvider.getResString(aCtrlId);
569     if (aLabel.getLength())
570         setLabel(aCtrlId, aLabel);
571 }
572 
573 //-----------------------------------------------------------------
574 // There may be problems with the layout of our custom controls,
575 // so that they are not aligned with the standard controls of the
576 // FileOpen dialog.
577 // We use a simple algorithm to move the custom controls to their
578 // proper position and resize them.
579 // Our approach is to align all static text controls with the
580 // static text control "File name" of the FileOpen dialog,
581 // all checkboxes and all list/comboboxes will be left aligned with
582 // the standard combobox edt1 (defined in MS platform sdk dlgs.h)
583 // and all push buttons will be left aligned with the standard
584 // "OK" button
585 //-----------------------------------------------------------------
586 
InitCustomControlContainer(HWND hCustomControl)587 void SAL_CALL CWinFileOpenImpl::InitCustomControlContainer(HWND hCustomControl)
588 {
589     m_CustomControls->AddControl(
590         m_CustomControlFactory->CreateCustomControl(hCustomControl,m_hwndFileOpenDlg));
591 }
592 
593 //-----------------------------------------------------------------
594 //
595 //-----------------------------------------------------------------
596 
CacheControlState(HWND hWnd)597 void SAL_CALL CWinFileOpenImpl::CacheControlState(HWND hWnd)
598 {
599     OSL_ASSERT(m_FilePickerState && m_NonExecuteFilePickerState);
600     m_ExecuteFilePickerState->cacheControlState(hWnd, m_NonExecuteFilePickerState);
601 }
602 
603 //-----------------------------------------------------------------
604 //
605 //-----------------------------------------------------------------
606 
EnumChildWndProc(HWND hWnd,LPARAM lParam)607 BOOL CALLBACK CWinFileOpenImpl::EnumChildWndProc(HWND hWnd, LPARAM lParam)
608 {
609     EnumParam* enumParam    = (EnumParam*)lParam;
610     CWinFileOpenImpl* pImpl = enumParam->m_instance;
611 
612     OSL_ASSERT(pImpl);
613 
614     sal_Bool bRet = sal_True;
615 
616     switch(enumParam->m_action)
617     {
618     case INIT_CUSTOM_CONTROLS:
619         pImpl->InitControlLabel(hWnd);
620         pImpl->InitCustomControlContainer(hWnd);
621         break;
622 
623     case CACHE_CONTROL_VALUES:
624         pImpl->CacheControlState(hWnd);
625     break;
626 
627     default:
628         // should not end here
629         OSL_ASSERT(sal_False);
630     }
631 
632     return bRet;
633 }
634 
635 //-----------------------------------------------------------------
636 //
637 //-----------------------------------------------------------------
638 
onFileOk()639 UINT_PTR SAL_CALL CWinFileOpenImpl::onFileOk()
640 {
641     m_NonExecuteFilePickerState->reset();
642 
643     EnumParam enumParam(CACHE_CONTROL_VALUES,this);
644 
645     EnumChildWindows(
646         m_hwndFileOpenDlgChild,
647         CWinFileOpenImpl::EnumChildWndProc,
648         (LPARAM)&enumParam);
649 
650     return 0;
651 }
652 
653 //-----------------------------------------------------------------
654 //
655 //-----------------------------------------------------------------
656 
onSelChanged(HWND)657 void SAL_CALL CWinFileOpenImpl::onSelChanged(HWND)
658 {
659     // the windows file open dialog sends an initial
660     // SelChanged message after the InitDone message
661     // when the dialog is about to be opened
662     // if the lpstrFile buffer of the OPENFILENAME is
663     // empty (zero length string) the windows file open
664     // dialog sends a WM_SETTEXT message with an empty
665     // string to the file name edit line
666     // this would overwritte our text when we would set
667     // the default name in onInitDone, so we have to
668     // remember that this is the first SelChanged message
669     // and set the default name here to overwrite the
670     // windows setting
671     InitialSetDefaultName();
672 
673     FilePickerEvent evt;
674     m_FilePicker->fileSelectionChanged(evt);
675 }
676 
677 // #i40865# The size of the standard labels 'File name'
678 // and 'File type' is to short in some cases when the
679 // label will be changed (e.g. in the Brazil version).
680 // We just make sure that the labels are using the maximum
681 // available space.
EnlargeStdControlLabels() const682 void CWinFileOpenImpl::EnlargeStdControlLabels() const
683 {
684     HWND hFilterBoxLabel = GetDlgItem(m_hwndFileOpenDlg, stc2);
685     HWND hFileNameBoxLabel = GetDlgItem(m_hwndFileOpenDlg, stc3);
686     HWND hFileNameBox = GetDlgItem(m_hwndFileOpenDlg, cmb13);
687     if (!hFileNameBox)
688         hFileNameBox = GetDlgItem(m_hwndFileOpenDlg, edt1); // under Win98 it is edt1 instead of cmb13
689 
690     HWND hFilterBox = GetDlgItem(m_hwndFileOpenDlg, cmb1);
691     HWND hOkButton = GetDlgItem(m_hwndFileOpenDlg, IDOK);
692 
693     // Move filter and file name box nearer to OK and Cancel button
694     RECT rcOkButton;
695     GetWindowRect(hOkButton, &rcOkButton);
696 
697     const int MAX_GAP = IsWindows98() ? 5 : 10;
698     const int OFFSET = IsWindows98() ? 10 : 0;
699 
700     RECT rcFileNameBox;
701     GetWindowRect(hFileNameBox, &rcFileNameBox);
702     int w = rcFileNameBox.right - rcFileNameBox.left;
703     int h = rcFileNameBox.bottom - rcFileNameBox.top;
704 
705     int gap = rcOkButton.left - rcFileNameBox.right;
706     gap = (gap > MAX_GAP) ? gap - MAX_GAP : gap;
707 
708     ScreenToClient(m_hwndFileOpenDlg, (LPPOINT)&rcFileNameBox);
709     MoveWindow(hFileNameBox, rcFileNameBox.left + gap + OFFSET, rcFileNameBox.top, w - OFFSET, h, true);
710 
711     RECT rcFilterBox;
712     GetWindowRect(hFilterBox, &rcFilterBox);
713     w = rcFilterBox.right - rcFilterBox.left;
714     h = rcFilterBox.bottom - rcFilterBox.top;
715     ScreenToClient(m_hwndFileOpenDlg, (LPPOINT)&rcFilterBox);
716     MoveWindow(hFilterBox, rcFilterBox.left + gap + OFFSET, rcFilterBox.top, w - OFFSET, h, true);
717 
718     // get the new window rect
719     GetWindowRect(hFileNameBox, &rcFileNameBox);
720 
721     RECT rcFilterBoxLabel;
722     GetWindowRect(hFilterBoxLabel, &rcFilterBoxLabel);
723     int offset = rcFileNameBox.left - rcFilterBoxLabel.right - 1;
724 
725     w = rcFilterBoxLabel.right - rcFilterBoxLabel.left + offset;
726     h = rcFilterBoxLabel.bottom - rcFilterBoxLabel.top;
727     ScreenToClient(m_hwndFileOpenDlg, (LPPOINT)&rcFilterBoxLabel);
728     MoveWindow(hFilterBoxLabel, rcFilterBoxLabel.left, rcFilterBoxLabel.top, w, h, true);
729 
730     RECT rcFileNameBoxLabel;
731     GetWindowRect(hFileNameBoxLabel, &rcFileNameBoxLabel);
732     w = rcFileNameBoxLabel.right - rcFileNameBoxLabel.left + offset;
733     h = rcFileNameBoxLabel.bottom - rcFileNameBoxLabel.top;
734     ScreenToClient(m_hwndFileOpenDlg, (LPPOINT)&rcFileNameBoxLabel);
735     MoveWindow(hFileNameBoxLabel, rcFileNameBoxLabel.left, rcFileNameBoxLabel.top, w, h, true);
736 }
737 
onInitDone()738 void SAL_CALL CWinFileOpenImpl::onInitDone()
739 {
740     m_Preview->setParent(m_hwndFileOpenDlg);
741 
742     // but now we have a valid parent handle
743     m_HelpPopupWindow.setParent(m_hwndFileOpenDlg);
744 
745     EnlargeStdControlLabels();
746 
747     // #99826
748     // Set the online filepicker state before initializing
749     // the control labels from the resource else we are
750     // overriding the offline settings
751     m_ExecuteFilePickerState->setHwnd(m_hwndFileOpenDlgChild);
752 
753     m_FilePickerState = m_ExecuteFilePickerState;
754 
755     // initialize controls from cache
756 
757     EnumParam enumParam(INIT_CUSTOM_CONTROLS,this);
758 
759     EnumChildWindows(
760         m_hwndFileOpenDlgChild,
761         CWinFileOpenImpl::EnumChildWndProc,
762         (LPARAM)&enumParam);
763 
764     m_ExecuteFilePickerState->initFilePickerControls(
765         m_NonExecuteFilePickerState->getControlCommand());
766 
767     SetDefaultExtension();
768 
769     m_CustomControls->Align();
770 
771     m_CustomControls->SetFont(
772         reinterpret_cast<HFONT>(SendMessage(m_hwndFileOpenDlg, WM_GETFONT, 0, 0)));
773 
774     // resume event notification that was
775     // defered in onInitDialog
776     m_FilePicker->resumeEventNotification();
777 
778     //#105996 let vcl know that now a system window is active
779     PostMessage(
780         HWND_BROADCAST,
781         RegisterWindowMessage(TEXT("SYSTEM_WINDOW_ACTIVATED")),
782         0,
783         0);
784 
785     // call the parent function to center the
786     // dialog to it's parent
787     CFileOpenDialog::onInitDone();
788 }
789 
790 //-----------------------------------------------------------------
791 //
792 //-----------------------------------------------------------------
793 
onFolderChanged()794 void SAL_CALL CWinFileOpenImpl::onFolderChanged()
795 {
796     FilePickerEvent evt;
797     m_FilePicker->directoryChanged(evt);
798 }
799 
800 //-----------------------------------------------------------------
801 //
802 //-----------------------------------------------------------------
803 
onTypeChanged(sal_uInt32)804 void SAL_CALL CWinFileOpenImpl::onTypeChanged(sal_uInt32)
805 {
806     SetDefaultExtension();
807 
808     FilePickerEvent evt;
809     evt.ElementId = LISTBOX_FILTER;
810     m_FilePicker->controlStateChanged(evt);
811 }
812 
813 //-----------------------------------------------------------------------------------------
814 // onMessageCommand handler
815 //-----------------------------------------------------------------------------------------
816 
onCtrlCommand(HWND,sal_uInt16 ctrlId,sal_uInt16)817 UINT_PTR SAL_CALL CWinFileOpenImpl::onCtrlCommand(
818     HWND, sal_uInt16 ctrlId, sal_uInt16)
819 {
820     SetDefaultExtension();
821 
822     if (ctrlId < ctlFirst)
823     {
824         FilePickerEvent evt;
825         evt.ElementId = ctrlId;
826         m_FilePicker->controlStateChanged(evt);
827     }
828 
829     return 0;
830 }
831 
832 //-----------------------------------------------------------------------------------------
833 //
834 //-----------------------------------------------------------------------------------------
835 
onWMSize()836 void CWinFileOpenImpl::onWMSize()
837 {
838     m_Preview->notifyParentSizeChanged();
839     m_CustomControls->Align();
840     m_FilePicker->dialogSizeChanged();
841 }
842 
843 //-----------------------------------------------------------------------------------------
844 //
845 //-----------------------------------------------------------------------------------------
846 
onWMShow(sal_Bool bShow)847 void CWinFileOpenImpl::onWMShow(sal_Bool bShow)
848 {
849     m_Preview->notifyParentShow(bShow);
850 }
851 
852 //-----------------------------------------------------------------------------------------
853 //
854 //-----------------------------------------------------------------------------------------
855 
onWMWindowPosChanged()856 void CWinFileOpenImpl::onWMWindowPosChanged()
857 {
858     m_Preview->notifyParentWindowPosChanged();
859 }
860 
861 //-----------------------------------------------------------------------------------------
862 //
863 //-----------------------------------------------------------------------------------------
864 
onCustomControlHelpRequest(LPHELPINFO lphi)865 void CWinFileOpenImpl::onCustomControlHelpRequest(LPHELPINFO lphi)
866 {
867     FilePickerEvent evt;
868     evt.ElementId = sal::static_int_cast< sal_Int16 >(lphi->iCtrlId);
869 
870     rtl::OUString aPopupHelpText = m_FilePicker->helpRequested(evt);
871 
872     if (aPopupHelpText.getLength())
873     {
874         m_HelpPopupWindow.setText(aPopupHelpText);
875 
876         DWORD dwMsgPos = GetMessagePos();
877         m_HelpPopupWindow.show(LOWORD(dwMsgPos),HIWORD(dwMsgPos));
878     }
879 }
880 
881 //-----------------------------------------------------------------------------------------
882 //
883 //-----------------------------------------------------------------------------------------
884 
onInitDialog(HWND hwndDlg)885 void SAL_CALL CWinFileOpenImpl::onInitDialog(HWND hwndDlg)
886 {
887     // subclass the dialog window
888     m_pfnOldDlgProc =
889         reinterpret_cast<WNDPROC>(
890             SetWindowLongPtr( hwndDlg, GWLP_WNDPROC,
891             reinterpret_cast<LONG_PTR>(SubClassFunc)));
892 }
893 
894 //-----------------------------------------------------------------------------------------
895 // processing before showing the dialog
896 //-----------------------------------------------------------------------------------------
897 
preModal()898 bool SAL_CALL CWinFileOpenImpl::preModal()
899 {
900     CFileOpenDialog::setFilter(
901         makeWinFilterBuffer(*m_filterContainer.get()));
902 
903     return true;
904 }
905 
906 //-----------------------------------------------------------------------------------------
907 // processing after showing the dialog
908 //-----------------------------------------------------------------------------------------
909 
postModal(sal_Int16 nDialogResult)910 void CWinFileOpenImpl::postModal(sal_Int16 nDialogResult)
911 {
912     CFileOpenDialog::postModal(nDialogResult);
913 
914     // empty the container in order to get rid off
915     // invalid controls in case someone calls execute
916     // twice in sequence with the same instance
917     m_CustomControls->RemoveAllControls();
918 
919     m_FilePickerState = m_NonExecuteFilePickerState;
920 }
921 
922 //-----------------------------------------------------------------------------------------
923 //
924 //-----------------------------------------------------------------------------------------
925 
SetDefaultExtension()926 void SAL_CALL CWinFileOpenImpl::SetDefaultExtension()
927 {
928     HWND hwndChkSaveWithExt = GetDlgItem(m_hwndFileOpenDlgChild, 100);
929 
930     if (hwndChkSaveWithExt)
931     {
932         uno::Any aAny = CheckboxGetState(hwndChkSaveWithExt);
933         sal_Bool bChecked = *reinterpret_cast<const sal_Bool*>(aAny.getValue());
934 
935         if (bChecked)
936         {
937             sal_uInt32 nIndex = getSelectedFilterIndex();
938 
939             rtl::OUString currentFilter;
940             if (nIndex > 0)
941             {
942                 // filter index of the base class starts with 1
943                 m_filterContainer->getFilter(nIndex - 1, currentFilter);
944 
945                 if (currentFilter.getLength())
946                 {
947                     rtl::OUString FilterExt;
948                     m_filterContainer->getFilter(currentFilter, FilterExt);
949 
950                     sal_Int32 posOfPoint = FilterExt.indexOf(L'.');
951                     const sal_Unicode* pFirstExtStart = FilterExt.getStr() + posOfPoint + 1;
952 
953                     sal_Int32 posOfSemiColon = FilterExt.indexOf(L';') - 1;
954                     if (posOfSemiColon < 0)
955                         posOfSemiColon = FilterExt.getLength() - 1;
956 
957                     FilterExt = rtl::OUString(pFirstExtStart, posOfSemiColon - posOfPoint);
958 
959                     SendMessage(m_hwndFileOpenDlg, CDM_SETDEFEXT, 0, reinterpret_cast<LPARAM>(FilterExt.getStr()));
960                  }
961             }
962         }
963         else
964         {
965             SendMessage(m_hwndFileOpenDlg, CDM_SETDEFEXT, 0, reinterpret_cast<LPARAM>(TEXT("")));
966         }
967     }
968 
969     // !!! HACK !!!
970 }
971 
972 //-----------------------------------------------------------------------------------------
973 //
974 //-----------------------------------------------------------------------------------------
975 
InitialSetDefaultName()976 void SAL_CALL CWinFileOpenImpl::InitialSetDefaultName()
977 {
978     // manually setting the file name that appears
979     // initially in the file-name-box of the file
980     // open dialog (reason: see above setDefaultName)
981     if (m_bInitialSelChanged && m_defaultName.getLength())
982     {
983         sal_Int32 edt1Id = edt1;
984 
985         // under W2k the there is a combobox instead
986         // of an edit field for the file name edit field
987         // the control id of this box is cmb13 and not
988         // edt1 as before so we must use this id
989         if (IsWindows2000Platform())
990             edt1Id = cmb13;
991 
992         HWND hwndEdt1 = GetDlgItem(m_hwndFileOpenDlg, edt1Id);
993         SetWindowText(hwndEdt1, reinterpret_cast<LPCTSTR>(m_defaultName.getStr()));
994     }
995 
996     m_bInitialSelChanged = sal_False;
997 }
998