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