bump product version to 4.1.6.2
[LibreOffice.git] / fpicker / source / win32 / filepicker / filepickerstate.cxx
blobf178de5839736d367b022e5d3b9a20186a97170e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <boost/scoped_ptr.hpp>
22 #include "filepickerstate.hxx"
23 #include <osl/diagnose.h>
24 #include "controlaccess.hxx"
25 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
26 #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp>
27 #include <com/sun/star/ui/dialogs/ListboxControlActions.hpp>
28 #include <com/sun/star/ui/dialogs/ControlActions.hpp>
29 #include "controlcommandrequest.hxx"
30 #include "controlcommandresult.hxx"
31 #include <com/sun/star/uno/Reference.hxx>
32 #include <com/sun/star/uno/XInterface.hpp>
33 #include <osl/file.hxx>
34 #include "FileOpenDlg.hxx"
36 #include "../misc/WinImplHelper.hxx"
37 //---------------------------------------------
39 //---------------------------------------------
41 using com::sun::star::uno::Any;
42 using com::sun::star::uno::Sequence;
43 using com::sun::star::uno::Reference;
44 using com::sun::star::uno::XInterface;
46 using namespace ::com::sun::star::ui::dialogs::ExtendedFilePickerElementIds;
47 using namespace ::com::sun::star::ui::dialogs::CommonFilePickerElementIds;
48 using namespace ::com::sun::star::ui::dialogs::ListboxControlActions;
50 //---------------------------------------------
52 //---------------------------------------------
54 const sal_Int32 MAX_LABEL = 256;
55 const sal_Int16 LISTBOX_LABEL_OFFSET = 100;
57 //---------------------------------------------
58 // declaration
59 //---------------------------------------------
61 CFilePickerState::~CFilePickerState( )
65 //---------------------------------------------
67 //---------------------------------------------
69 CNonExecuteFilePickerState::CNonExecuteFilePickerState( ) :
70 m_FirstControlCommand( NULL )
74 //---------------------------------------------
76 //---------------------------------------------
78 CNonExecuteFilePickerState::~CNonExecuteFilePickerState( )
80 reset( );
83 //---------------------------------------------
85 //---------------------------------------------
87 void SAL_CALL CNonExecuteFilePickerState::setValue( sal_Int16 aControlId, sal_Int16 aControlAction, const Any& aValue )
89 CValueControlCommand* value_command = new CValueControlCommand(
90 aControlId, aControlAction, aValue );
92 addControlCommand( value_command );
95 //---------------------------------------------
97 //---------------------------------------------
99 Any SAL_CALL CNonExecuteFilePickerState::getValue( sal_Int16 aControlId, sal_Int16 aControlAction )
101 CValueControlCommandRequest value_request( aControlId, aControlAction );
102 Any aAny;
104 if (m_FirstControlCommand)
106 // pass the request along the command-chain
107 boost::scoped_ptr< CControlCommandResult > result( m_FirstControlCommand->handleRequest( &value_request ) );
109 OSL_ENSURE( result.get(), "invalid getValue request" );
111 if ( result.get() )
113 // #101753 must remove assertion else running into deadlock
114 // because getValue may be called asynchronously from main thread
115 // with locked SOLAR_MUTEX but we also need SOLAR_MUTEX in
116 // WinFileOpenDialog::onInitDone ... but we cannot dismiss the
117 // assertion dialog because at this point the FileOpen Dialog
118 // has aleady the focus but is not yet visible :-(
119 // The real cure is to remove the VCL/SOLAR_MUTEX dependency
120 // cause by the use of our resource manager and not being able to
121 // generate native windows resources
122 //OSL_ENSURE( result->hasResult( ), "invalid getValue request" );
124 if ( result->hasResult( ) )
126 CValueCommandResult* value_result = dynamic_cast< CValueCommandResult* >( result.get( ) );
127 OSL_ENSURE( value_result, "should have be a CValueCommandResult" );
129 aAny = value_result->getValue( );
130 OSL_ENSURE( aAny.hasValue( ), "empty any" );
135 return aAny;
138 //---------------------------------------------
140 //---------------------------------------------
142 void SAL_CALL CNonExecuteFilePickerState::enableControl( sal_Int16 aControlId, sal_Bool bEnable )
144 CEnableControlCommand* enable_command = new CEnableControlCommand(
145 aControlId, bEnable );
147 addControlCommand( enable_command );
150 //---------------------------------------------
152 //---------------------------------------------
154 void SAL_CALL CNonExecuteFilePickerState::setLabel( sal_Int16 aControlId, const OUString& aLabel )
156 CLabelControlCommand* label_command = new CLabelControlCommand(
157 aControlId, aLabel );
159 addControlCommand( label_command );
162 //---------------------------------------------
164 //---------------------------------------------
166 OUString SAL_CALL CNonExecuteFilePickerState::getLabel( sal_Int16 aControlId )
168 CControlCommandRequest label_request( aControlId );
170 // pass the request along the command-chain
171 boost::scoped_ptr< CControlCommandResult > result( m_FirstControlCommand->handleRequest( &label_request ) );
173 OSL_ENSURE( result->hasResult( ), "invalid getValue request" );
175 OUString aLabel;
177 if ( result->hasResult( ) )
179 CLabelCommandResult* label_result = dynamic_cast< CLabelCommandResult* >( result.get( ) );
180 OSL_ENSURE( label_result, "should have be a CLabelCommandResult" );
182 aLabel = label_result->getLabel( );
185 return aLabel;
188 /* #i26224#
189 When typing file names with drive letter but without '\'
190 in the "File name" box of the FileOpen dialog the FileOpen
191 dialog makes strange paths out of them e.g. "d:.\test.sxw".
192 Such file names will not be accepted by sal so we fix these
193 somehow broken paths here. */
194 OUString MatchFixBrokenPath(const OUString& path)
196 OSL_ASSERT(path.getLength() >= 4);
198 if (path[1] == ':' && path[2] == '.' && path[3] == '\\')
200 // skip the '.'
201 return OUString(path.getStr(), 2) + path.copy(3, path.getLength() - 3);
203 return path;
206 //-----------------------------------------------------------------------------------------
208 //-----------------------------------------------------------------------------------------
209 static OUString trimTrailingSpaces(const OUString& rString)
211 OUString aResult(rString);
213 sal_Int32 nIndex = rString.lastIndexOf(' ');
214 if (nIndex == rString.getLength()-1)
216 while (nIndex >= 0 && rString[nIndex] == ' ')
217 nIndex--;
218 if (nIndex >= 0)
219 aResult = rString.copy(0,nIndex+1);
220 else
221 aResult = OUString();
223 return aResult;
226 Sequence< OUString > SAL_CALL CNonExecuteFilePickerState::getFiles( CFileOpenDialog* aFileOpenDialog )
228 OSL_PRECOND( aFileOpenDialog, "invalid parameter" );
230 Sequence< OUString > aFilePathList;
231 OUString aFilePathURL;
232 OUString aFilePath;
233 ::osl::FileBase::RC rc;
235 aFilePath = aFileOpenDialog->getFullFileName( );
237 if ( aFilePath.getLength( ) )
239 // tokenize the returned string and copy the
240 // sub-strings separately into a sequence
241 const sal_Unicode* pTemp = aFilePath.getStr();
242 const sal_Unicode* pStrEnd = pTemp + aFilePath.getLength();
243 sal_uInt32 lSubStr;
245 while (pTemp < pStrEnd)
247 // detect the length of the next sub string
248 lSubStr = rtl_ustr_getLength(pTemp);
250 aFilePathList.realloc(aFilePathList.getLength() + 1);
252 aFilePathList[aFilePathList.getLength() - 1] =
253 MatchFixBrokenPath(OUString(pTemp, lSubStr));
255 pTemp += (lSubStr + 1);
258 // change all entries to file URLs
259 sal_Int32 lenFileList = aFilePathList.getLength( );
260 OSL_ASSERT( lenFileList >= 1 );
262 for ( sal_Int32 i = 0; i < lenFileList; i++ )
264 aFilePath = trimTrailingSpaces(aFilePathList[i]);
265 rc = ::osl::FileBase::getFileURLFromSystemPath(
266 aFilePath, aFilePathURL );
268 // we do return all or nothing, that means
269 // in case of failures we destroy the sequence
270 // and return an empty sequence
271 if ( rc != ::osl::FileBase::E_None )
273 aFilePathList.realloc( 0 );
274 break;
277 aFilePathList[i] = aFilePathURL;
281 return aFilePathList;
284 //---------------------------------------------
286 //---------------------------------------------
288 OUString SAL_CALL CNonExecuteFilePickerState::getDisplayDirectory( CFileOpenDialog* aFileOpenDialog )
290 OSL_PRECOND( aFileOpenDialog, "invalid parameter" );
292 OUString pathURL;
293 OUString displayDir;
295 displayDir = aFileOpenDialog->getLastDisplayDirectory( );
297 if ( displayDir.getLength( ) )
298 ::osl::FileBase::getFileURLFromSystemPath( displayDir, pathURL );
300 return pathURL;
303 //---------------------------------------------
305 //---------------------------------------------
307 void SAL_CALL CNonExecuteFilePickerState::reset( )
309 CControlCommand* nextCommand;
310 CControlCommand* currentCommand = m_FirstControlCommand;
312 while( currentCommand )
314 nextCommand = currentCommand->getNextCommand( );
315 delete currentCommand;
316 currentCommand = nextCommand;
319 m_FirstControlCommand = NULL;
322 //---------------------------------------------
324 //---------------------------------------------
326 CControlCommand* SAL_CALL CNonExecuteFilePickerState::getControlCommand( ) const
328 return m_FirstControlCommand;
331 //---------------------------------------------
332 // we append new control commands to the end
333 // of the list so that we are sure the commands
334 // will be executed as the client issued it
335 //---------------------------------------------
337 void SAL_CALL CNonExecuteFilePickerState::addControlCommand( CControlCommand* aControlCommand )
339 OSL_ASSERT( aControlCommand );
341 if ( NULL == m_FirstControlCommand )
343 m_FirstControlCommand = aControlCommand;
345 else
347 CControlCommand* pNextControlCommand = m_FirstControlCommand;
349 while ( pNextControlCommand->getNextCommand( ) != NULL )
350 pNextControlCommand = pNextControlCommand->getNextCommand( );
352 pNextControlCommand->setNextCommand( aControlCommand );
356 //#######################################################################
358 //---------------------------------------------
360 //---------------------------------------------
362 CExecuteFilePickerState::CExecuteFilePickerState( HWND hwndDlg ) :
363 m_hwndDlg( hwndDlg )
367 //---------------------------------------------
369 //---------------------------------------------
371 void SAL_CALL CExecuteFilePickerState::setValue( sal_Int16 aControlId, sal_Int16 aControlAction, const Any& aValue )
373 // we do not support SET_HELP_URL/GET_HELP_URL
374 if ( com::sun::star::ui::dialogs::ControlActions::SET_HELP_URL == aControlAction )
375 return;
377 HWND hwndCtrl = GetHwndDlgItem( aControlId );
379 // the filter listbox can be manipulated via this
380 // method the caller should use XFilterManager
381 if ( !hwndCtrl || (aControlId == LISTBOX_FILTER) )
383 OSL_FAIL( "invalid control id" );
384 return;
387 CTRL_CLASS aCtrlClass = GetCtrlClass( hwndCtrl );
388 if ( UNKNOWN == aCtrlClass )
390 OSL_FAIL( "unsupported control class" );
391 return;
394 CTRL_SETVALUE_FUNCTION_T lpfnSetValue =
395 GetCtrlSetValueFunction( aCtrlClass, aControlAction );
397 if ( !lpfnSetValue )
399 OSL_FAIL( "unsupported control action" );
400 return;
403 // the function that we call should throw an IllegalArgumentException if
404 // the given value is invalid or empty, that's why we provide a Reference
405 // to an XInterface and a argument position
406 lpfnSetValue( hwndCtrl, aValue, Reference< XInterface >( ), 3 );
409 //---------------------------------------------
411 //---------------------------------------------
413 Any SAL_CALL CExecuteFilePickerState::getValue( sal_Int16 aControlId, sal_Int16 aControlAction )
415 // we do not support SET_HELP_URL/GET_HELP_URL
416 if ( com::sun::star::ui::dialogs::ControlActions::GET_HELP_URL == aControlAction )
417 return Any( );
419 HWND hwndCtrl = GetHwndDlgItem( aControlId );
421 // the filter listbox can be manipulated via this
422 // method the caller should use XFilterManager
423 if ( !hwndCtrl || (aControlId == LISTBOX_FILTER) )
425 OSL_FAIL( "invalid control id" );
426 return Any( );
429 CTRL_CLASS aCtrlClass = GetCtrlClass( hwndCtrl );
430 if ( UNKNOWN == aCtrlClass )
432 OSL_FAIL( "unsupported control class" );
433 return Any( );
436 CTRL_GETVALUE_FUNCTION_T lpfnGetValue =
437 GetCtrlGetValueFunction( aCtrlClass, aControlAction );
439 if ( !lpfnGetValue )
441 OSL_FAIL( "unsupported control action" );
442 return Any( );
445 return lpfnGetValue( hwndCtrl );
448 //---------------------------------------------
450 //---------------------------------------------
452 void SAL_CALL CExecuteFilePickerState::enableControl( sal_Int16 aControlId, sal_Bool bEnable )
454 HWND hwndCtrl = GetHwndDlgItem( aControlId );
456 OSL_ENSURE( IsWindow( hwndCtrl ), "invalid element id");
458 EnableWindow( hwndCtrl, bEnable );
461 //---------------------------------------------
463 //---------------------------------------------
465 void SAL_CALL CExecuteFilePickerState::setLabel( sal_Int16 aControlId, const OUString& aLabel )
467 HWND hwndCtrl = GetHwndDlgItem( aControlId );
469 OSL_ENSURE( IsWindow( hwndCtrl ), "invalid element id");
471 if ( IsListboxControl( hwndCtrl ) )
472 hwndCtrl = GetListboxLabelItem( aControlId );
474 OUString aWinLabel = SOfficeToWindowsLabel( aLabel );
476 // somewhat risky because we don't know if OUString
477 // has a terminating '\0'
478 SetWindowText( hwndCtrl, reinterpret_cast<LPCTSTR>(aWinLabel.getStr( )) );
481 //---------------------------------------------
483 //---------------------------------------------
485 OUString SAL_CALL CExecuteFilePickerState::getLabel( sal_Int16 aControlId )
487 HWND hwndCtrl = GetHwndDlgItem( aControlId );
489 OSL_ENSURE( IsWindow( hwndCtrl ), "invalid element id");
491 if ( IsListboxControl( hwndCtrl ) )
492 hwndCtrl = GetListboxLabelItem( aControlId );
494 sal_Unicode aLabel[MAX_LABEL];
495 int nRet = GetWindowText( hwndCtrl, reinterpret_cast<LPTSTR>(aLabel), MAX_LABEL );
497 OUString ctrlLabel;
498 if ( nRet )
500 ctrlLabel = WindowsToSOfficeLabel( aLabel );
503 return ctrlLabel;
506 //---------------------------------------------
508 //---------------------------------------------
510 Sequence< OUString > SAL_CALL CExecuteFilePickerState::getFiles( CFileOpenDialog* aFileOpenDialog )
512 OSL_POSTCOND( aFileOpenDialog, "invalid parameter" );
514 Sequence< OUString > aFilePathList;
515 OUString aFilePathURL;
516 OUString aFilePath;
517 ::osl::FileBase::RC rc;
519 // in execution mode getFullFileName doesn't
520 // return anything, so we must use another way
522 // returns the currently selected file(s)
523 // including path information
524 aFilePath = aFileOpenDialog->getCurrentFilePath( );
526 // if multiple files are selected or the user
527 // typed anything that doesn't seem to be a valid
528 // file name getFileURLFromSystemPath fails
529 // and we return an empty file list
530 rc = ::osl::FileBase::getFileURLFromSystemPath(
531 aFilePath, aFilePathURL );
533 if ( ::osl::FileBase::E_None == rc )
535 aFilePathList.realloc( 1 );
536 aFilePathList[0] = aFilePathURL;
539 return aFilePathList;
542 //---------------------------------------------
544 //---------------------------------------------
546 OUString SAL_CALL CExecuteFilePickerState::getDisplayDirectory( CFileOpenDialog* aFileOpenDialog )
548 OSL_POSTCOND( aFileOpenDialog, "invalid parameter" );
550 OUString pathURL;
551 OUString displayDir;
553 displayDir = aFileOpenDialog->getCurrentFolderPath( );
555 if ( displayDir.getLength( ) )
556 ::osl::FileBase::getFileURLFromSystemPath( displayDir, pathURL );
558 return pathURL;
561 //---------------------------------------------
563 //---------------------------------------------
565 void SAL_CALL CExecuteFilePickerState::initFilePickerControls( CControlCommand* firstControlCommand )
567 CControlCommand* aControlCommand = firstControlCommand;
569 while ( aControlCommand )
571 aControlCommand->exec( this );
572 aControlCommand = aControlCommand->getNextCommand( );
576 //---------------------------------------------
578 //---------------------------------------------
580 void SAL_CALL CExecuteFilePickerState::cacheControlState( HWND hwndControl, CFilePickerState* aNonExecFilePickerState )
582 OSL_ENSURE( hwndControl && aNonExecFilePickerState, "invalid parameters" );
584 CTRL_CLASS aCtrlClass = GetCtrlClass( hwndControl );
586 sal_Int16 aControlAction;
587 CTRL_GETVALUE_FUNCTION_T lpfnGetValue;
589 if ( CHECKBOX == aCtrlClass )
591 aControlAction = 0;
593 lpfnGetValue = GetCtrlGetValueFunction( aCtrlClass, aControlAction );
595 OSL_ASSERT( lpfnGetValue );
597 aNonExecFilePickerState->setValue(
598 sal::static_int_cast< sal_Int16 >( GetDlgCtrlID( hwndControl ) ),
599 aControlAction,
600 lpfnGetValue( hwndControl ) );
602 aNonExecFilePickerState->setLabel(
603 sal::static_int_cast< sal_Int16 >( GetDlgCtrlID( hwndControl ) ),
604 getLabel(
605 sal::static_int_cast< sal_Int16 >(
606 GetDlgCtrlID( hwndControl ) ) ) );
608 else if ( LISTBOX == aCtrlClass )
610 // for listboxes we save only the
611 // last selected item and the last
612 // selected item index
614 aControlAction = GET_SELECTED_ITEM;
616 lpfnGetValue = GetCtrlGetValueFunction( aCtrlClass, aControlAction );
618 aNonExecFilePickerState->setValue(
619 sal::static_int_cast< sal_Int16 >( GetDlgCtrlID( hwndControl ) ),
620 aControlAction,
621 lpfnGetValue( hwndControl ) );
623 aControlAction = ::com::sun::star::ui::dialogs::ControlActions::GET_SELECTED_ITEM_INDEX;
625 lpfnGetValue = GetCtrlGetValueFunction( aCtrlClass, aControlAction );
627 aNonExecFilePickerState->setValue(
628 sal::static_int_cast< sal_Int16 >( GetDlgCtrlID( hwndControl ) ),
629 aControlAction,
630 lpfnGetValue( hwndControl ) );
634 //---------------------------------------------
636 //---------------------------------------------
638 void SAL_CALL CExecuteFilePickerState::setHwnd( HWND hwndDlg )
640 m_hwndDlg = hwndDlg;
643 //---------------------------------------------
645 //---------------------------------------------
647 inline sal_Bool SAL_CALL CExecuteFilePickerState::IsListboxControl( HWND hwndControl ) const
649 OSL_PRECOND( IsWindow( hwndControl ), "invalid parameter" );
651 CTRL_CLASS aCtrlClass = GetCtrlClass( hwndControl );
652 return ( LISTBOX == aCtrlClass );
655 //---------------------------------------------
656 // because listboxes (comboboxes) and their labels
657 // are separated we have to translate the listbox
658 // id to their corresponding label id
659 // the convention is that the label id of a listbox
660 // is the id of the listbox + 100
661 //---------------------------------------------
663 inline sal_Int16 SAL_CALL CExecuteFilePickerState::ListboxIdToListboxLabelId( sal_Int16 aListboxId ) const
665 return ( aListboxId + LISTBOX_LABEL_OFFSET );
668 //---------------------------------------------
670 //---------------------------------------------
672 inline HWND SAL_CALL CExecuteFilePickerState::GetListboxLabelItem( sal_Int16 aControlId ) const
674 sal_Int16 aLabelId = ListboxIdToListboxLabelId( aControlId );
675 HWND hwndCtrl = GetHwndDlgItem( aLabelId );
677 OSL_ASSERT( IsWindow( hwndCtrl ) );
679 return hwndCtrl;
682 //---------------------------------------------
684 //---------------------------------------------
686 HWND SAL_CALL CExecuteFilePickerState::GetHwndDlgItem( sal_Int16 aControlId, sal_Bool bIncludeStdCtrls ) const
688 OSL_ENSURE( IsWindow( m_hwndDlg ), "no valid parent window set before" );
690 HWND hwndCtrl = GetDlgItem( m_hwndDlg, aControlId );
692 // maybe it's a control of the dialog itself for instance
693 // the ok and cancel button
694 if ( !hwndCtrl && bIncludeStdCtrls )
696 hwndCtrl = GetDlgItem(
697 GetParent( m_hwndDlg ),
698 CommonFilePickerCtrlIdToWinFileOpenCtrlId( aControlId ) );
701 return hwndCtrl;
704 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */