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