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 <tchar.h>
32 #include "PreviewCtrl.hxx"
33 #include <osl/diagnose.h>
34 
35 #if defined _MSC_VER
36 #pragma warning(push, 1)
37 #endif
38 #include <windows.h>
39 #if defined _MSC_VER
40 #pragma warning(pop)
41 #endif
42 #include <ocidl.h>
43 #include <olectl.h>
44 
45 //------------------------------------------------------------------------
46 // defines
47 //------------------------------------------------------------------------
48 
49 #define PREVIEWWND_CLASS_NAME TEXT("PreviewWnd###")
50 
51 #define HIMETRIC_INCH 2540
52 
53 // means 3 pixel left and 3 pixel right
54 #define HORZ_BORDER_SPACE	6
55 
56 // means 3 pixel top and 3 pixel bottom
57 #define VERT_BORDER_SPACE	6
58 
59 //---------------------------------------------------
60 // static member initialization
61 //---------------------------------------------------
62 
63 CFilePreview* CFilePreview::s_FilePreviewInst = NULL;
64 CFilePreview::FILEPREVIEW_SINGLETON_DESTROYER_T CFilePreview::s_SingletonDestroyer;
65 
66 //---------------------------------------------------
67 // some useful helper functions
68 //---------------------------------------------------
69 
70 namespace // private
71 {
72 	class CPreviewException
73 	{
74 		// used when registering or creation
75 		// of the preview window failed
76 	};
77 
78 	//------------------------------------------------------------
79 	//
80 	//------------------------------------------------------------
81 
82 	inline
SubDiv(sal_Int32 nNumber,sal_Int32 nMinuend,sal_Int32 nDenominator)83 	sal_Int32 SubDiv( sal_Int32	nNumber, sal_Int32 nMinuend, sal_Int32 nDenominator )
84 	{
85 		return ( static_cast<sal_Int32>( ( nNumber - nMinuend ) / nDenominator ) );
86 	}
87 
88 	//------------------------------------------------------------
89 	// convert himetric to pixel
90 	//------------------------------------------------------------
91 
92 	inline
Himetric2Pixel(HDC hDC,sal_Int32 hmSize,sal_Int32 nIndex)93 	sal_Int32 Himetric2Pixel( HDC hDC, sal_Int32 hmSize, sal_Int32 nIndex )
94 	{
95 		return MulDiv( hmSize, GetDeviceCaps( hDC, nIndex), HIMETRIC_INCH );
96 	}
97 
98 	//------------------------------------------------------------
99 	//
100 	//------------------------------------------------------------
101 
102 	inline
_getWidthRect(const RECT & aRect)103 	sal_uInt32 _getWidthRect( const RECT& aRect )
104 	{
105 		return ( aRect.right - aRect.left );
106 	}
107 
108 	//------------------------------------------------------------
109 	//
110 	//------------------------------------------------------------
111 
112 	inline
_getHeightRect(const RECT & aRect)113 	sal_uInt32 _getHeightRect( const RECT& aRect )
114 	{
115 		return ( aRect.bottom - aRect.top );
116 	}
117 
118 	//------------------------------------------------------------
119 	// calc the upper left corner so that a given window will be
120 	// displayed centered within the given window
121 	//------------------------------------------------------------
122 
123 	inline
_calcULCorner(HWND hwnd,const CDimension & aPicSize)124 	POINT _calcULCorner( HWND hwnd, const CDimension& aPicSize )
125 	{
126 		RECT rect;
127 		GetClientRect( hwnd, &rect );
128 
129 		sal_Int32 nWidthWnd  = _getWidthRect( rect );
130 		sal_Int32 nHeightWnd = _getHeightRect( rect );
131 
132 		POINT ulCorner;
133 		ulCorner.x = SubDiv( nWidthWnd,  aPicSize.m_cx, 2 );
134 		ulCorner.y = SubDiv( nHeightWnd, aPicSize.m_cy, 2 );
135 
136 		return ulCorner;
137 	}
138 
139 	//------------------------------------------------------------
140 	// test if a picture with the given dimensions fits into an
141 	// arbitrary window
142 	// we expect the width and height to be in pixel
143 	//------------------------------------------------------------
144 
145 	inline
_pictureSizeFitsWindowSize(HWND hwnd,const CDimension & aPicSize)146 	sal_Bool _pictureSizeFitsWindowSize( HWND hwnd, const CDimension& aPicSize )
147 	{
148 		RECT rect;
149 		GetClientRect( hwnd, &rect );
150 
151 		sal_Int32 nWidthWnd  = _getWidthRect( rect );
152 		sal_Int32 nHeightWnd = _getHeightRect( rect );
153 
154 		return ( ( ( nWidthWnd  - HORZ_BORDER_SPACE ) >= aPicSize.m_cx ) &&
155 				 ( ( nHeightWnd - VERT_BORDER_SPACE ) >= aPicSize.m_cy ) );
156 	}
157 
158 	//------------------------------------------------------------
159 	// calc the dimensions so that a given picture fits into a
160 	// given window, if the picture fits into the given window
161 	// the original CDimension will be returned
162 	//------------------------------------------------------------
163 
164 	inline
_scalePictureSize(HWND hwnd,const CDimension & aPicSize)165 	CDimension _scalePictureSize( HWND hwnd, const CDimension& aPicSize )
166 	{
167 		CDimension scaledPicSize = aPicSize;
168 
169 		if ( !_pictureSizeFitsWindowSize( hwnd, aPicSize ) )
170 		{
171 			RECT rect;
172 			GetClientRect( hwnd, &rect );
173 
174 			// the dimensions of the preview wnd are not equal
175 			// that's why we equalize it
176 			sal_Int32 nHeightWnd = _getHeightRect( rect ) - VERT_BORDER_SPACE;
177 			sal_Int32 nWidthWnd  = nHeightWnd;
178 
179 			if ( aPicSize.m_cx >= aPicSize.m_cy )
180 			{
181 				scaledPicSize.m_cx = nWidthWnd;
182 				scaledPicSize.m_cy =
183 					static_cast< sal_Int32 >(
184                         aPicSize.m_cy * nWidthWnd / aPicSize.m_cx );
185 			}
186 			else
187 			{
188 				scaledPicSize.m_cx =
189 					static_cast< sal_Int32 >(
190                         aPicSize.m_cx * nHeightWnd / aPicSize.m_cy );
191 				scaledPicSize.m_cy = nHeightWnd;
192 			}
193 		}
194 
195 		return scaledPicSize;
196 	}
197 
198 } // end namespace
199 
200 
201 //---------------------------------------------------
202 // to ensure only one instance (singleton)
203 //---------------------------------------------------
204 
createInstance(HWND aParent,POINT ulCorner,const CDimension & aSize,HINSTANCE hInstance,sal_Bool bShow,sal_Bool bEnabled)205 CFilePreview* CFilePreview::createInstance(
206 	HWND aParent,
207 	POINT ulCorner,
208 	const CDimension& aSize,
209 	HINSTANCE hInstance,
210 	sal_Bool bShow,
211 	sal_Bool bEnabled )
212 {
213 	if ( !s_FilePreviewInst )
214 	{
215         try
216         {
217 		    s_FilePreviewInst = new CFilePreview(
218 			    aParent, ulCorner, aSize, hInstance, bShow, bEnabled );
219 		    s_SingletonDestroyer.reset( s_FilePreviewInst );
220         }
221         catch( CPreviewException& )
222         {
223             OSL_ASSERT( !s_FilePreviewInst );
224             OSL_ENSURE( sal_False, "Creation of the preview window failed" );
225         }
226         catch( CAutoOleInit::COleInitException& )
227         {
228             OSL_ASSERT( !s_FilePreviewInst );
229             OSL_ENSURE( sal_False, "OleInitialize failed" );
230         }
231 	}
232 
233 	return s_FilePreviewInst;
234 }
235 
236 //---------------------------------------------------
237 //
238 //---------------------------------------------------
239 
CFilePreview(HWND aParent,POINT ulCorner,const CDimension & aSize,HINSTANCE hInstance,sal_Bool bShow,sal_Bool bEnabled)240 CFilePreview::CFilePreview(
241 	HWND aParent,
242 	POINT ulCorner,
243 	const CDimension& aSize,
244 	HINSTANCE hInstance,
245 	sal_Bool bShow,
246 	sal_Bool bEnabled ) :
247 	m_hInstance( hInstance ),
248 	m_bEnabled( bEnabled )
249 {
250 	// register the preview window class
251 	WNDCLASSEX wndClsEx;
252 	ZeroMemory(&wndClsEx, sizeof(wndClsEx));
253 
254 	wndClsEx.cbSize        = sizeof(wndClsEx);
255 	wndClsEx.style		   = CS_HREDRAW | CS_VREDRAW;
256 	wndClsEx.lpfnWndProc   = CFilePreview::WndProc;
257 	wndClsEx.hInstance     = m_hInstance;
258 	wndClsEx.hbrBackground = (HBRUSH)( COLOR_INACTIVEBORDER + 1 );
259 	wndClsEx.lpszClassName = PREVIEWWND_CLASS_NAME;
260 
261 	// register the preview window class
262 	// !!! Win95 -   the window class will be unregistered automatically
263 	//			     if the dll is unloaded
264 	//     Win2000 - the window class must be unregistered manually
265 	//				 if the dll is unloaded
266 	m_atomPrevWndClass = RegisterClassEx(&wndClsEx);
267     if ( !m_atomPrevWndClass )
268         throw CPreviewException( );
269 
270 	// create the preview window in invisible state
271 	sal_uInt32 dwStyle = bShow ? (WS_CHILD | WS_VISIBLE) : WS_CHILD;
272 	m_hwnd = CreateWindowEx(
273 		WS_EX_CLIENTEDGE,
274 		PREVIEWWND_CLASS_NAME,
275 		TEXT(""),
276 		dwStyle,
277 		ulCorner.x,
278 		ulCorner.y,
279 		aSize.m_cx,
280 		aSize.m_cy,
281 		aParent,
282 		(HMENU)100, // for child windows this will
283 					// be used as child window identifier
284 		m_hInstance,
285 		0 );
286     if (!IsWindow(m_hwnd))
287         throw CPreviewException( );
288 }
289 
290 //---------------------------------------------------
291 //
292 //---------------------------------------------------
293 
~CFilePreview()294 CFilePreview::~CFilePreview( )
295 {
296 	// unregister preview window class
297 	sal_Bool bRet = UnregisterClass(
298 		(LPCTSTR)MAKELONG( m_atomPrevWndClass, 0 ),
299 		m_hInstance );
300 	OSL_POSTCOND( bRet, "Unregister preview window class failed" );
301 }
302 
303 //---------------------------------------------------
304 // sets the size of the preview window
305 //---------------------------------------------------
306 
setSize(const CDimension & aSize)307 sal_Bool SAL_CALL CFilePreview::setSize( const CDimension& aSize )
308 {
309 	OSL_PRECOND( IsWindow( m_hwnd ), "Preview window not initialized" );
310 
311 	// resize the fileopen file listbox
312 	return SetWindowPos(
313 		m_hwnd,
314 		NULL,
315 		0,
316 		0,
317 		aSize.m_cx,
318 		aSize.m_cy,
319 		SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
320 }
321 
322 //---------------------------------------------------
323 // returns the dimension of the preview
324 //---------------------------------------------------
325 
getSize(CDimension & theSize) const326 sal_Bool SAL_CALL CFilePreview::getSize( CDimension& theSize ) const
327 {
328 	OSL_PRECOND( IsWindow( m_hwnd ), "Preview window not initialized" );
329 
330 	RECT rect;
331 	sal_Bool bRet = GetWindowRect( m_hwnd, &rect );
332 
333 	theSize.m_cx = _getWidthRect( rect );
334 	theSize.m_cy = _getHeightRect( rect );
335 
336 	return bRet;
337 }
338 
339 //---------------------------------------------------
340 // sets the position of the upper left corner
341 // of the preview window relative to the
342 // upper left corner of the parent window
343 //---------------------------------------------------
344 
setPos(POINT ulCorner)345 sal_Bool SAL_CALL CFilePreview::setPos( POINT ulCorner )
346 {
347 	OSL_PRECOND( IsWindow( m_hwnd ), "Preview window not initialized" );
348 
349 	// resize the fileopen file listbox
350 	return SetWindowPos(
351 		m_hwnd,
352 		NULL,
353 		ulCorner.x,
354 		ulCorner.y,
355 		0,
356 		0,
357 		SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
358 }
359 
360 //---------------------------------------------------
361 // returns the current position of the preview
362 // relative to the upper left corner of the
363 // parent window
364 //---------------------------------------------------
365 
getPos(POINT & ulCorner) const366 sal_Bool SAL_CALL CFilePreview::getPos( POINT& ulCorner ) const
367 {
368 	OSL_PRECOND( IsWindow( m_hwnd ), "Preview window not initialized" );
369 
370 	POINT pt = { 0, 0 };
371 	RECT rect;
372 
373 	sal_Bool bRet = GetWindowRect( m_hwnd, &rect );
374 
375 	ulCorner.x = rect.left;
376 	ulCorner.y = rect.top;
377 
378 	ScreenToClient( m_hwnd, &ulCorner );
379 
380 	return bRet;
381 }
382 
383 //---------------------------------------------------
384 //
385 //---------------------------------------------------
386 
enable(sal_Bool bEnable)387 void SAL_CALL CFilePreview::enable( sal_Bool bEnable )
388 {
389 	m_bEnabled = bEnable;
390 
391 	// force a redraw
392 	InvalidateRect( m_hwnd, NULL, sal_True );
393 	UpdateWindow( m_hwnd );
394 }
395 
396 //---------------------------------------------------
397 // shows the preview window
398 // possible values see SHOW_STATE
399 // SS_SHOW     - make the window visible
400 // SS_HIDE     - hide the window
401 // SS_ENABLED  - enable the window
402 // SS_DISABLED - disable the window
403 //---------------------------------------------------
404 
show(sal_Bool bShow)405 sal_Bool SAL_CALL CFilePreview::show( sal_Bool bShow )
406 {
407 	OSL_PRECOND( IsWindow( m_hwnd ), "Preview window not initialized" );
408 
409 	sal_Int32 showState = bShow ? SW_SHOW : SW_HIDE;
410 	return ShowWindow( m_hwnd, showState );
411 }
412 
413 //---------------------------------------------------
414 // if the preview is shown and enabled
415 // preview of the given file will be shown
416 // returns true on success or false if an error
417 // occurred (the file in not there or not accessible etc.)
418 //---------------------------------------------------
419 
update(const rtl::OUString & aFileName)420 sal_Bool SAL_CALL CFilePreview::update( const rtl::OUString& aFileName )
421 {
422 	OSL_PRECOND( IsWindow( m_hwnd ), "Preview window not initialized" );
423 
424 	try
425 	{
426 		if ( m_bEnabled )
427 		{
428 			if ( m_IPicture )
429 				m_IPicture.Release( );
430 
431 			loadFile( aFileName );
432 
433 			// force a complete window redraw
434 			InvalidateRect( m_hwnd, NULL, sal_True );
435 			UpdateWindow( m_hwnd );
436 		}
437 	}
438 	catch( _com_error& )
439 	{
440 	}
441 
442 	return sal_True;
443 }
444 
445 //---------------------------------------------------
446 //
447 //---------------------------------------------------
448 
onPaint(HWND hWnd,HDC hDC)449 void SAL_CALL CFilePreview::onPaint( HWND hWnd, HDC hDC )
450 {
451 	OSL_PRECOND( IsWindow( m_hwnd ), "Preview window not initialized" );
452 
453 	try
454 	{
455 		if ( m_bEnabled )
456 		{
457 			// get width and height of picture
458 			long cxPicHIMETRIC;
459 			long cyPicHIMETRIC;
460 
461 			m_IPicture->get_Width( &cxPicHIMETRIC );
462 			m_IPicture->get_Height( &cyPicHIMETRIC );
463 
464 			// convert himetric to pixels
465 			int cxPicPIXEL = Himetric2Pixel( hDC, cxPicHIMETRIC, LOGPIXELSX );
466 			int cyPicPIXEL = Himetric2Pixel( hDC, cyPicHIMETRIC, LOGPIXELSY );
467 
468 			// scale the picture based on the size of the preview window
469 			RECT rcPrevWnd;
470 			GetClientRect(hWnd, &rcPrevWnd);
471 
472 			CDimension scaledPicSize = _scalePictureSize(
473 				hWnd, CDimension( cxPicPIXEL, cyPicPIXEL ) );
474 
475 			// calc the upper left corner so that the picture
476 			// is centered within the window
477 			POINT ulCorner = _calcULCorner( hWnd, scaledPicSize );
478 
479 			// render the picture
480 			HRESULT hr = m_IPicture->Render(
481 				hDC,
482 				ulCorner.x,
483 				ulCorner.y,
484 				scaledPicSize.m_cx,
485 				scaledPicSize.m_cy,
486 				0,
487 				cyPicHIMETRIC,
488 				cxPicHIMETRIC,
489 				-cyPicHIMETRIC,
490 				&rcPrevWnd );
491 		} // end if ( m_bEnabled )
492 	}
493 	catch( _com_error& )
494 	{
495 	}
496 }
497 
498 //---------------------------------------------------
499 //
500 //---------------------------------------------------
501 
loadFile(const rtl::OUString & aFileName)502 sal_Bool CFilePreview::loadFile( const rtl::OUString& aFileName )
503 {
504 	HANDLE		hFile   = 0;
505 	HGLOBAL		hGlobal = 0;
506 	LPVOID		pData   = NULL;
507 	IStreamPtr	pIStream;
508 	HRESULT		hr = E_FAIL;
509 	sal_Bool	bRet;
510 	sal_uInt32	nBytesRead;
511 	sal_uInt32	fszExtra;
512 	sal_uInt32	fsize;
513 
514 	hFile = CreateFile(
515 		aFileName.getStr( ),
516 		GENERIC_READ,
517 		0,
518 		NULL,
519 		OPEN_EXISTING,
520 		0,
521 		NULL );
522 	if ( INVALID_HANDLE_VALUE == hFile )
523 		goto CLEANUP_AND_EXIT;
524 
525 	fszExtra = 0;
526 	fsize = GetFileSize( hFile, &fszExtra );
527 
528 	// empty file, error or file to big
529 	if ( -1 == fsize || 0 == fsize || fszExtra )
530 		goto CLEANUP_AND_EXIT;
531 
532 	hGlobal = GlobalAlloc( GMEM_MOVEABLE, fsize );
533 	if ( !hGlobal )
534 		goto CLEANUP_AND_EXIT;
535 
536 	pData = GlobalLock( hGlobal );
537 	if ( !pData )
538 		goto CLEANUP_AND_EXIT;
539 
540 	bRet = ReadFile(
541 		hFile, pData, fsize, &nBytesRead, NULL );
542 
543 	if ( !bRet )
544 		goto CLEANUP_AND_EXIT;
545 
546 	hr = CreateStreamOnHGlobal(
547 		hGlobal, sal_False, &pIStream );
548 
549 	if ( SUCCEEDED( hr ) )
550 	{
551 		hr = OleLoadPicture(
552 			pIStream, fsize, sal_False,
553 			__uuidof( IPicture ), (LPVOID*)&m_IPicture );
554 	}
555 
556 CLEANUP_AND_EXIT:
557 	if ( hFile )
558 		CloseHandle( hFile );
559 
560 	if ( pData )
561 		GlobalUnlock( hGlobal );
562 
563 	if ( hGlobal )
564 		GlobalFree( hGlobal );
565 
566 	return ( SUCCEEDED( hr ) );
567 }
568 
569 //---------------------------------------------------
570 //
571 //---------------------------------------------------
572 
WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)573 LRESULT CALLBACK CFilePreview::WndProc(
574 	HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
575 {
576 	LRESULT lResult = 0;
577 
578 	switch( uMsg )
579 	{
580 	case WM_PAINT:
581 	{
582 		OSL_PRECOND( s_FilePreviewInst, "Static member not initialized" );
583 
584 		HDC         hDC;
585 		PAINTSTRUCT ps;
586 
587 		hDC = BeginPaint( hWnd, &ps );
588 		s_FilePreviewInst->onPaint( hWnd, hDC );
589 		EndPaint( hWnd, &ps );
590 	}
591 	break;
592 
593 	// under windows 95/98 the creation of the
594 		// hidden target request window fails if
595 		// we don't handle this message ourself
596 		// because the DefWindowProc returns 0 as
597 		// a result of handling WM_NCCREATE what
598 		// leads to a failure of CreateWindow[Ex]!!!
599 	case WM_NCCREATE:
600 		lResult = sal_True;
601 		break;
602 
603 	default:
604 		return DefWindowProc( hWnd, uMsg, wParam, lParam );
605 	}
606 
607 	return lResult;
608 }
609 
610