xref: /AOO41X/main/fpicker/source/win32/filepicker/PreviewCtrl.cxx (revision b557fc96600fce3029f73c89748b6c08fd00b34d)
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_BODER_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_BODER_SPACE )  >= aPicSize.m_cx ) &&
155                  ( ( nHeightWnd - VERT_BORDER_SPACE ) >= aPicSize.m_cy ) );
156     }
157 
158     //------------------------------------------------------------
159     // calc the dimemsions 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, "OleInitalize 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 automaticly
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 // occured (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 
611 
612