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