xref: /trunk/main/fpicker/source/win32/filepicker/PreviewCtrl.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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