1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_fpicker.hxx"
30 
31 //------------------------------------------------------------------------
32 // includes
33 //------------------------------------------------------------------------
34 #include <osl/diagnose.h>
35 #include <rtl/ustrbuf.hxx>
36 #include "AutoBuffer.hxx"
37 #include "WinImplHelper.hxx"
38 #include <com/sun/star/uno/Sequence.hxx>
39 
40 //------------------------------------------------------------
41 // namespace directives
42 //------------------------------------------------------------
43 
44 using rtl::OUString;
45 using rtl::OUStringBuffer;
46 using ::com::sun::star::lang::IllegalArgumentException;
47 using ::com::sun::star::uno::Reference;
48 using ::com::sun::star::uno::XInterface;
49 using ::com::sun::star::uno::Any;
50 using ::com::sun::star::uno::Sequence;
51 
52 //------------------------------------------------------------
53 //
54 //------------------------------------------------------------
55 
56 const rtl::OUString TILDE = OUString::createFromAscii( "~" );
57 const sal_Unicode   TILDE_SIGN = L'~';
58 const rtl::OUString AMPERSAND = OUString::createFromAscii( "&" );
59 const sal_Unicode   AMPERSAND_SIGN = L'&';
60 
61 //------------------------------------------------------------
62 // OS NAME			Platform					Major	Minor
63 //
64 // Windows NT 3.51	VER_PLATFORM_WIN32_NT		3		51
65 // Windows NT 4.0	VER_PLATFORM_WIN32_NT		4		0
66 // Windows 2000		VER_PLATFORM_WIN32_NT		5		0
67 // Windows XP		VER_PLATFORM_WIN32_NT		5		1
68 // Windows Vista    VER_PLATFORM_WIN32_NT		6		0
69 // Windows 7		VER_PLATFORM_WIN32_NT		6		1
70 // Windows 95		VER_PLATFORM_WIN32_WINDOWS	4		0
71 // Windows 98		VER_PLATFORM_WIN32_WINDOWS	4		10
72 // Windows ME		VER_PLATFORM_WIN32_WINDOWS	4		90
73 //------------------------------------------------------------
74 
75 bool SAL_CALL IsWindowsVersion(unsigned int PlatformId, unsigned int MajorVersion, int MinorVersion = -1)
76 {
77 	OSVERSIONINFO osvi;
78 	osvi.dwOSVersionInfoSize = sizeof(osvi);
79 
80 	if(!GetVersionEx(&osvi))
81 		return false;
82 
83 	bool bRet = (PlatformId == osvi.dwPlatformId) &&
84 				(MajorVersion == osvi.dwMajorVersion);
85 
86 	if (MinorVersion > -1)
87 		bRet = bRet &&
88             (sal::static_int_cast< unsigned int >(MinorVersion) ==
89              osvi.dwMinorVersion);
90 
91 	return bRet;
92 }
93 
94 //------------------------------------------------------------
95 // determine if we are running under Vista or newer OS
96 //------------------------------------------------------------
97 
98 bool SAL_CALL IsWindowsVistaOrNewer()
99 {
100 	OSVERSIONINFO osvi;
101 	osvi.dwOSVersionInfoSize = sizeof(osvi);
102 
103 	if(!GetVersionEx(&osvi))
104 		return false;
105 
106 	bool bRet = (VER_PLATFORM_WIN32_NT == osvi.dwPlatformId) &&
107 				(osvi.dwMajorVersion >= 6);
108 
109 	bRet = bRet &&
110         (osvi.dwMinorVersion >=
111 		 sal::static_int_cast< unsigned int >(0));
112 
113 	return bRet;
114 }
115 
116 //------------------------------------------------------------
117 // determine if we are running under Windows 7
118 //------------------------------------------------------------
119 
120 bool SAL_CALL IsWindows7()
121 {
122 	return IsWindowsVersion(VER_PLATFORM_WIN32_NT, 6, 1);
123 }
124 
125 //------------------------------------------------------------
126 // determine if we are running under Windows Vista
127 //------------------------------------------------------------
128 
129 bool SAL_CALL IsWindowsVista()
130 {
131 	return IsWindowsVersion(VER_PLATFORM_WIN32_NT, 6, 0);
132 }
133 
134 //------------------------------------------------------------
135 // determine if we are running under Windows XP
136 //------------------------------------------------------------
137 
138 bool SAL_CALL IsWindowsXP()
139 {
140 	return IsWindowsVersion(VER_PLATFORM_WIN32_NT, 5, 1);
141 }
142 
143 //------------------------------------------------------------
144 // determine if we are running under Windows 2000
145 //------------------------------------------------------------
146 
147 bool SAL_CALL IsWindows2000()
148 {
149 	return IsWindowsVersion(VER_PLATFORM_WIN32_NT, 5, 0);
150 }
151 
152 //------------------------------------------------------------
153 //
154 //------------------------------------------------------------
155 
156 bool SAL_CALL IsWindows98()
157 {
158 	return IsWindowsVersion(VER_PLATFORM_WIN32_WINDOWS, 4, 10);
159 }
160 
161 //------------------------------------------------------------
162 //
163 //------------------------------------------------------------
164 
165 bool SAL_CALL IsWindowsME()
166 {
167 	return 	IsWindowsVersion(VER_PLATFORM_WIN32_WINDOWS, 4, 90);
168 }
169 
170 //------------------------------------------------------------
171 //
172 //------------------------------------------------------------
173 
174 bool SAL_CALL IsWindows2000Platform()
175 {
176     // POST: return true if we are at least on Windows 2000
177 
178     // WRONG!: return IsWindowsVersion(VER_PLATFORM_WIN32_NT, 5);
179 
180     OSVERSIONINFO osvi;
181     ZeroMemory(&osvi, sizeof(osvi));
182     osvi.dwOSVersionInfoSize = sizeof(osvi);
183     GetVersionEx(&osvi);
184     if ( osvi.dwMajorVersion >= 5 )
185     {
186         return true;
187     }
188     return false;
189 }
190 
191 //------------------------------------------------------------
192 //
193 //------------------------------------------------------------
194 
195 void SAL_CALL ListboxAddString( HWND hwnd, const OUString& aString )
196 {
197     LRESULT rc = SendMessageW(
198         hwnd, CB_ADDSTRING, 0, reinterpret_cast< LPARAM >(aString.getStr( )) );
199     (void) rc; // avoid warning
200     OSL_ASSERT( (CB_ERR != rc) && (CB_ERRSPACE != rc) );
201 }
202 
203 //------------------------------------------------------------
204 //
205 //------------------------------------------------------------
206 
207 OUString SAL_CALL ListboxGetString( HWND hwnd, sal_Int32 aPosition )
208 {
209     OSL_ASSERT( IsWindow( hwnd ) );
210 
211     OUString aString;
212 
213 	LRESULT lItem =
214         SendMessageW( hwnd, CB_GETLBTEXTLEN, aPosition, 0 );
215 
216 	if ( (CB_ERR != lItem) && (lItem > 0) )
217 	{
218 	    // message returns the len of a combobox item
219 		// without trailing '\0' that's why += 1
220 		lItem++;
221 
222         CAutoUnicodeBuffer aBuff( lItem );
223 
224 		LRESULT lRet =
225             SendMessageW(
226                 hwnd, CB_GETLBTEXT, aPosition,
227                 reinterpret_cast<LPARAM>(&aBuff) );
228 
229         OSL_ASSERT( lRet != CB_ERR );
230 
231 	    if ( CB_ERR != lRet )
232             aString = OUString( aBuff, lRet );
233     }
234 
235     return aString;
236 }
237 
238 //------------------------------------------------------------
239 //
240 //------------------------------------------------------------
241 
242 void SAL_CALL ListboxAddItem( HWND hwnd, const Any& aItem, const Reference< XInterface >& rXInterface, sal_Int16 aArgPos )
243     throw( IllegalArgumentException )
244 {
245     OSL_ASSERT( IsWindow( hwnd ) );
246 
247     if ( !aItem.hasValue( ) ||
248          aItem.getValueType( ) != getCppuType((OUString*)0) )
249          throw IllegalArgumentException(
250             OUString::createFromAscii( "invalid value type or any has no value" ),
251             rXInterface,
252             aArgPos );
253 
254     OUString cbItem;
255     aItem >>= cbItem;
256 
257     ListboxAddString( hwnd, cbItem );
258 }
259 
260 //------------------------------------------------------------
261 //
262 //------------------------------------------------------------
263 
264 void SAL_CALL ListboxAddItems( HWND hwnd, const Any& aItemList, const Reference< XInterface >& rXInterface, sal_Int16 aArgPos )
265     throw( IllegalArgumentException )
266 {
267     OSL_ASSERT( IsWindow( hwnd ) );
268 
269     if ( !aItemList.hasValue( ) ||
270          aItemList.getValueType( ) != getCppuType((Sequence<OUString>*)0) )
271          throw IllegalArgumentException(
272             OUString::createFromAscii( "invalid value type or any has no value" ),
273             rXInterface,
274             aArgPos );
275 
276     Sequence< OUString > aStringList;
277     aItemList >>= aStringList;
278 
279     sal_Int32 nItemCount = aStringList.getLength( );
280     for( sal_Int32 i = 0; i < nItemCount; i++ )
281     {
282         ListboxAddString( hwnd, aStringList[i] );
283     }
284 }
285 
286 //------------------------------------------------------------
287 //
288 //------------------------------------------------------------
289 
290 void SAL_CALL ListboxDeleteItem( HWND hwnd, const Any& aPosition, const Reference< XInterface >& rXInterface, sal_Int16 aArgPos )
291     throw( IllegalArgumentException )
292 {
293     OSL_ASSERT( IsWindow( hwnd ) );
294 
295     if ( !aPosition.hasValue( ) ||
296          ( (aPosition.getValueType( ) != getCppuType((sal_Int32*)0)) &&
297            (aPosition.getValueType( ) != getCppuType((sal_Int16*)0)) &&
298            (aPosition.getValueType( ) != getCppuType((sal_Int8*)0)) ) )
299          throw IllegalArgumentException(
300             OUString::createFromAscii( "invalid value type or any has no value" ),
301             rXInterface,
302             aArgPos );
303 
304     sal_Int32 nPos;
305     aPosition >>= nPos;
306 
307     LRESULT lRet = SendMessage( hwnd, CB_DELETESTRING, nPos, 0 );
308 
309     // if the return value is CB_ERR the given
310     // index was not correct
311     if ( CB_ERR == lRet )
312         throw IllegalArgumentException(
313             OUString::createFromAscii( "inavlid item position" ),
314             rXInterface,
315             aArgPos );
316 }
317 
318 //------------------------------------------------------------
319 //
320 //------------------------------------------------------------
321 
322 void SAL_CALL ListboxDeleteItems( HWND hwnd, const Any&, const Reference< XInterface >&, sal_Int16 )
323     throw( IllegalArgumentException )
324 {
325     OSL_ASSERT( IsWindow( hwnd ) );
326 
327     LRESULT lRet = 0;
328 
329     do
330     {
331         // the return value on success is the number
332         // of remaining elements in the listbox
333         lRet = SendMessageW( hwnd, CB_DELETESTRING, 0, 0 );
334     }
335     while ( (lRet != CB_ERR) && (lRet > 0) );
336 }
337 
338 //------------------------------------------------------------
339 //
340 //------------------------------------------------------------
341 
342 void SAL_CALL ListboxSetSelectedItem( HWND hwnd, const Any& aPosition, const Reference< XInterface >& rXInterface, sal_Int16 aArgPos )
343     throw( IllegalArgumentException )
344 {
345     OSL_ASSERT( IsWindow( hwnd ) );
346 
347      if ( !aPosition.hasValue( ) ||
348          ( (aPosition.getValueType( ) != getCppuType((sal_Int32*)0)) &&
349            (aPosition.getValueType( ) != getCppuType((sal_Int16*)0)) &&
350            (aPosition.getValueType( ) != getCppuType((sal_Int8*)0)) ) )
351          throw IllegalArgumentException(
352             OUString::createFromAscii( "invalid value type or any has no value" ),
353             rXInterface,
354             aArgPos );
355 
356     sal_Int32 nPos;
357     aPosition >>= nPos;
358 
359     if ( nPos < -1 )
360         throw IllegalArgumentException(
361             OUString::createFromAscii("invalid index"),
362             rXInterface,
363             aArgPos );
364 
365     LRESULT lRet = SendMessageW( hwnd, CB_SETCURSEL, nPos, 0 );
366 
367     if ( (CB_ERR == lRet) && (-1 != nPos) )
368         throw IllegalArgumentException(
369             OUString::createFromAscii("invalid index"),
370             rXInterface,
371             aArgPos );
372 }
373 
374 //------------------------------------------------------------
375 //
376 //------------------------------------------------------------
377 
378 Any SAL_CALL ListboxGetItems( HWND hwnd )
379 {
380     OSL_ASSERT( IsWindow( hwnd ) );
381 
382     LRESULT nItemCount = SendMessageW( hwnd, CB_GETCOUNT, 0, 0 );
383 
384     Sequence< OUString > aItemList;
385 
386     if ( CB_ERR != nItemCount )
387     {
388         aItemList.realloc( nItemCount );
389 
390         for ( sal_Int32 i = 0; i < nItemCount; i++ )
391         {
392             aItemList[i] = ListboxGetString( hwnd, i );
393         }
394     }
395 
396     Any aAny;
397     aAny <<= aItemList;
398 
399     return aAny;
400 }
401 
402 //------------------------------------------------------------
403 //
404 //------------------------------------------------------------
405 
406 Any SAL_CALL ListboxGetSelectedItem( HWND hwnd )
407 {
408     OSL_ASSERT( IsWindow( hwnd ) );
409 
410     LRESULT idxItem = SendMessageW( hwnd, CB_GETCURSEL, 0, 0 );
411 
412     Any aAny;
413     aAny <<= ListboxGetString( hwnd, idxItem );
414 
415     return aAny;
416 }
417 
418 //------------------------------------------------------------
419 //
420 //------------------------------------------------------------
421 
422 Any SAL_CALL ListboxGetSelectedItemIndex( HWND hwnd )
423 {
424     OSL_ASSERT( IsWindow( hwnd ) );
425 
426     LRESULT idxItem = SendMessageW( hwnd, CB_GETCURSEL, 0, 0 );
427 
428     Any aAny;
429     aAny <<= static_cast< sal_Int32 >( idxItem );
430 
431     return aAny;
432 }
433 
434 //------------------------------------------------------------
435 //
436 //------------------------------------------------------------
437 
438 Any SAL_CALL CheckboxGetState( HWND hwnd )
439 {
440     OSL_ASSERT( IsWindow( hwnd ) );
441 
442     LRESULT lChkState = SendMessageW( hwnd, BM_GETCHECK, 0, 0 );
443     sal_Bool bChkState = (lChkState == BST_CHECKED) ? sal_True : sal_False;
444     Any aAny;
445     aAny.setValue( &bChkState, getCppuType((sal_Bool*)0) );
446     return aAny;
447 }
448 
449 //------------------------------------------------------------
450 //
451 //------------------------------------------------------------
452 
453 void SAL_CALL CheckboxSetState(
454     HWND hwnd, const ::com::sun::star::uno::Any& aState, const Reference< XInterface >& rXInterface, sal_Int16 aArgPos )
455     throw( IllegalArgumentException )
456 {
457     OSL_ASSERT( IsWindow( hwnd ) );
458 
459     if ( !aState.hasValue( ) ||
460          aState.getValueType( ) != getCppuType((sal_Bool*)0) )
461          throw IllegalArgumentException(
462             OUString::createFromAscii( "invalid value type or any has no value" ),
463             rXInterface,
464             aArgPos );
465 
466     sal_Bool bCheckState = *reinterpret_cast< const sal_Bool* >( aState.getValue( ) );
467     WPARAM wParam = bCheckState ? BST_CHECKED : BST_UNCHECKED;
468     SendMessageW( hwnd, BM_SETCHECK, wParam, 0 );
469 }
470 
471 //------------------------------------------------------------
472 //
473 //------------------------------------------------------------
474 
475 sal_uInt32 SAL_CALL _wcslenex( const sal_Unicode* pStr )
476 {
477     if ( !pStr )
478         return 0;
479 
480     const sal_Unicode* pTemp = pStr;
481     sal_uInt32 strLen = 0;
482     while( *pTemp || *(pTemp + 1) )
483     {
484         pTemp++;
485         strLen++;
486     }
487 
488     return strLen;
489 }
490 
491 //------------------------------------------------------------
492 //
493 //------------------------------------------------------------
494 
495 void Replace( const OUString& aLabel, sal_Unicode OldChar, sal_Unicode NewChar, OUStringBuffer& aBuffer )
496 {
497     OSL_ASSERT( aLabel.getLength( ) );
498     OSL_ASSERT( aBuffer.getCapacity( ) >= (aLabel.getLength( )) );
499 
500     sal_Int32 i = 0;
501     const sal_Unicode* pCurrent  = aLabel.getStr( );
502     const sal_Unicode* pNext     = aLabel.getStr( ) + 1;
503     const sal_Unicode* pEnd      = aLabel.getStr( ) + aLabel.getLength( );
504 
505     while( pCurrent < pEnd )
506     {
507         OSL_ASSERT( pNext <= pEnd );
508         OSL_ASSERT( (i >= 0) && (i < aBuffer.getCapacity( )) );
509 
510         if ( OldChar == *pCurrent )
511         {
512             if ( OldChar == *pNext )
513             {
514                 // two OldChars in line will
515                 // be replaced by one
516                 // e.g. ~~ -> ~
517                 aBuffer.insert( i, *pCurrent );
518 
519                 // skip the next one
520                 pCurrent++;
521                 pNext++;
522             }
523             else
524             {
525                 // one OldChar will be replace
526                 // by NexChar
527                 aBuffer.insert( i, NewChar );
528             }
529          }
530          else if ( *pCurrent == NewChar )
531          {
532             // a NewChar will be replaced by
533              // two NewChars
534              // e.g. & -> &&
535             aBuffer.insert( i++, *pCurrent );
536             aBuffer.insert( i, *pCurrent );
537          }
538          else
539          {
540             aBuffer.insert( i, *pCurrent );
541          }
542 
543          pCurrent++;
544          pNext++;
545          i++;
546     }
547 }
548 
549 //------------------------------------------------------------
550 // converts a soffice label to a windows label
551 // the following rules for character replacements
552 // will be done:
553 // '~'  -> '&'
554 // '~~' -> '~'
555 // '&'  -> '&&'
556 //------------------------------------------------------------
557 
558 OUString SOfficeToWindowsLabel( const rtl::OUString& aSOLabel )
559 {
560     OUString aWinLabel = aSOLabel;
561 
562     if ( (aWinLabel.indexOf( TILDE ) > -1) || (aWinLabel.indexOf( AMPERSAND ) > -1) )
563     {
564         sal_Int32 nStrLen = aWinLabel.getLength( );
565 
566         // in the worst case the new string is
567         // doubled in length, maybe some waste
568         // of memory but how long is a label
569         // normaly(?)
570         rtl::OUStringBuffer aBuffer( nStrLen * 2 );
571 
572         Replace( aWinLabel, TILDE_SIGN, AMPERSAND_SIGN, aBuffer );
573 
574         aWinLabel = aBuffer.makeStringAndClear( );
575     }
576 
577     return aWinLabel;
578 }
579 
580 //------------------------------------------------------------
581 // converts a windows label to a soffice label
582 // the following rules for character replacements
583 // will be done:
584 // '&'  -> '~'
585 // '&&' -> '&'
586 // '~'  -> '~~'
587 //------------------------------------------------------------
588 
589 OUString WindowsToSOfficeLabel( const rtl::OUString& aWinLabel )
590 {
591     OUString aSOLabel = aWinLabel;
592 
593     if ( (aSOLabel.indexOf( TILDE ) > -1) || (aSOLabel.indexOf( AMPERSAND ) > -1) )
594     {
595         sal_Int32 nStrLen = aSOLabel.getLength( );
596 
597         // in the worst case the new string is
598         // doubled in length, maybe some waste
599         // of memory but how long is a label
600         // normaly(?)
601         rtl::OUStringBuffer aBuffer( nStrLen * 2 );
602 
603         Replace( aSOLabel, AMPERSAND_SIGN, TILDE_SIGN, aBuffer );
604 
605         aSOLabel = aBuffer.makeStringAndClear( );
606     }
607 
608     return aSOLabel;
609 }
610 
611