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