xref: /AOO41X/main/fpicker/source/win32/filepicker/dibpreview.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 "dibpreview.hxx"
37 #include <osl/diagnose.h>
38 
39 #ifndef _COM_SUN_STAR_UI_DIALOG_FILEPREVIEWIMAGEFORMATS_HPP_
40 #include <com/sun/star/ui/dialogs/FilePreviewImageFormats.hpp>
41 #endif
42 
43 #ifndef _USTRING_HXX_
44 #include <rtl/ustring.hxx>
45 #endif
46 
47 #include <stdexcept>
48 #include <string>
49 
50 //------------------------------------------------------------------------
51 //
52 //------------------------------------------------------------------------
53 
54 using ::com::sun::star::uno::Sequence;
55 using ::com::sun::star::uno::RuntimeException;
56 using ::com::sun::star::uno::Any;
57 using ::com::sun::star::lang::IllegalArgumentException;
58 using rtl::OUString;
59 
60 //------------------------------------------------------------------------
61 //
62 //------------------------------------------------------------------------
63 
64 namespace /* private */
65 {
66     const LPTSTR CURRENT_INSTANCE = TEXT("CurrInst");
67 };
68 
69 //------------------------------------------------------------------------
70 // defines
71 //------------------------------------------------------------------------
72 
73 #define PREVIEWWND_CLASS_NAME TEXT("DIBPreviewWnd###")
74 
75 // means 3 pixel left and 3 pixel right
76 #define HORZ_BODER_SPACE    6
77 
78 // means 3 pixel top and 3 pixel bottom
79 #define VERT_BORDER_SPACE   6
80 
81 //---------------------------------------------------
82 // static member initialization
83 //---------------------------------------------------
84 
85 osl::Mutex CDIBPreview::s_Mutex;
86 ATOM CDIBPreview::s_ClassAtom = 0;
87 sal_Int32 CDIBPreview::s_RegisterDibPreviewWndCount = 0;
88 
89 //---------------------------------------------------
90 //
91 //---------------------------------------------------
92 
93 CDIBPreview::CDIBPreview(HINSTANCE instance,HWND parent,sal_Bool bShowWindow) :
94 	m_Instance(instance)
95 {
96 	RegisterDibPreviewWindowClass();
97 
98 	DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
99 
100 	if (bShowWindow)
101 		dwStyle |= WS_VISIBLE;
102 
103 	m_Hwnd = CreateWindowEx(
104 		WS_EX_CLIENTEDGE,
105 		PREVIEWWND_CLASS_NAME,
106 		TEXT(""),
107 		dwStyle,
108 		0, 0, 0, 0,
109         parent,
110 		(HMENU)0x0, // for child windows this will
111 					// be used as child window identifier
112 		m_Instance,
113         (LPVOID)this // pass a pointer to the current
114                      // instance of this class
115     );
116 
117 	bool bSuccess = IsWindow(m_Hwnd);
118 
119 	OSL_POSTCOND(bSuccess,"Coud not create preview window");
120 
121 	if (!bSuccess)
122 	{
123 		UnregisterDibPreviewWindowClass();
124 		throw std::runtime_error("Could not create preview window");
125 	}
126 }
127 
128 //---------------------------------------------------
129 //
130 //---------------------------------------------------
131 
132 CDIBPreview::~CDIBPreview( )
133 {
134     // remember: we don't have to destroy the
135     // preview window because it will be destroyed
136     // by it's parent window (the FileOpen dialog)
137     // but we have to unregister the window class
138     //if ( m_bWndClassRegistered )
139     UnregisterDibPreviewWindowClass();
140 }
141 
142 //-------------------------------
143 //
144 //-------------------------------
145 
146 sal_Int32 SAL_CALL CDIBPreview::getTargetColorDepth() throw (RuntimeException)
147 {
148 	HDC hdc = GetDC(m_Hwnd);
149     int clrRes = 0;
150 
151     if (hdc)
152         clrRes = GetDeviceCaps(hdc, COLORRES);
153 
154     return clrRes;
155 }
156 
157 //-------------------------------
158 //
159 //-------------------------------
160 
161 sal_Int32 SAL_CALL CDIBPreview::getAvailableWidth() throw (RuntimeException)
162 {
163 	RECT rect;
164 	bool bRet = GetClientRect(m_Hwnd,&rect);
165 
166 	sal_Int32 cx = 0;
167 
168     if ( bRet )
169         cx = rect.right;
170 
171 	return cx;
172 }
173 
174 //-------------------------------
175 //
176 //-------------------------------
177 
178 sal_Int32 SAL_CALL CDIBPreview::getAvailableHeight() throw (RuntimeException)
179 {
180 	RECT rect;
181 	bool bRet = GetClientRect(m_Hwnd,&rect);
182 
183 	sal_Int32 cy = 0;
184 
185     if ( bRet )
186         cy = rect.bottom;
187 
188 	return cy;
189 }
190 
191 //-------------------------------
192 //
193 //-------------------------------
194 
195 void SAL_CALL CDIBPreview::setImage(sal_Int16 aImageFormat, const Any& aImage)
196 	throw (IllegalArgumentException, RuntimeException)
197 {
198 	PreviewBase::setImage(aImageFormat,aImage);
199 
200 	// if the any has no value we have an
201 	// empty Sequence which clears the
202 	// preview window
203 	osl::ClearableMutexGuard aGuard(m_PaintLock);
204 
205 	m_Image.realloc(0);
206 	m_ImageData >>= m_Image;
207 
208 	aGuard.clear();
209 
210 	InvalidateRect(m_Hwnd,NULL,sal_False);
211 	UpdateWindow(m_Hwnd);
212 }
213 
214 //-------------------------------
215 //
216 //-------------------------------
217 
218 sal_Bool SAL_CALL CDIBPreview::setShowState(sal_Bool bShowState) throw (RuntimeException)
219 {
220 	PreviewBase::setShowState(bShowState);
221 	ShowWindow(m_Hwnd, m_bShowState ? SW_SHOW : SW_HIDE);
222     return sal_True;
223 }
224 
225 //-------------------------------
226 //
227 //-------------------------------
228 
229 sal_Bool SAL_CALL CDIBPreview::getShowState() throw (RuntimeException)
230 {
231 	return (sal_Bool)IsWindowVisible(m_Hwnd);
232 }
233 
234 //-------------------------------
235 //
236 //-------------------------------
237 
238 HWND SAL_CALL CDIBPreview::getWindowHandle() const
239 {
240 	return m_Hwnd;
241 }
242 
243 //---------------------------------------------------
244 //
245 //---------------------------------------------------
246 
247 void SAL_CALL CDIBPreview::onPaint(HWND hWnd, HDC hDC)
248 {
249 	BITMAPFILEHEADER*  pbmfh;
250     BITMAPINFO      *  pbmi;
251     sal_uInt8            *  pBits;
252     int                cxDib;
253     int                cyDib;
254 
255 	osl::MutexGuard aGuard(m_PaintLock);
256 
257 	try
258 	{
259 		pbmfh = reinterpret_cast<BITMAPFILEHEADER*>(m_Image.getArray());
260 
261 		if ( !IsBadReadPtr( pbmfh, sizeof(BITMAPFILEHEADER)) &&
262 			 (pbmfh->bfType == ('B' | ('M' << 8))) )
263 		{
264 			pbmi  = reinterpret_cast<BITMAPINFO*>((pbmfh + 1));
265 			pBits = reinterpret_cast<sal_uInt8*>(((DWORD)pbmfh) + pbmfh->bfOffBits);
266 
267 			cxDib =      pbmi->bmiHeader.biWidth;
268 			cyDib = abs (pbmi->bmiHeader.biHeight);
269 
270 			SetStretchBltMode(hDC, COLORONCOLOR);
271 
272 			int nWidth  = getAvailableWidth();
273 			int nHeight = getAvailableHeight();
274 
275 			int nX = abs(nWidth - cxDib) / 2;
276 			int nY = abs(nHeight - cyDib) / 2;
277 
278 			int GDIError = GDI_ERROR;
279             GDIError = StretchDIBits(
280 				hDC, nX, nY, cxDib, cyDib,
281 				0, 0, cxDib, cyDib, pBits, pbmi,
282 				DIB_RGB_COLORS, SRCCOPY);
283 
284             OSL_ASSERT(GDI_ERROR != GDIError);
285 
286 			// paint the border
287 			RECT rc;
288 
289 			if (nY > 0)
290 			{
291 				// top
292 				rc.left	  = 0;
293 				rc.top	  = 0;
294 				rc.right  = nWidth;
295 				rc.bottom = nY;
296 				FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1));
297 
298 				// bottom
299 				rc.left	  = 0;
300 				rc.top	  = nHeight - nY - 1;
301 				rc.right  = nWidth;
302 				rc.bottom = nHeight;
303 				FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1));
304 			}
305 
306 			if (nX > 0)
307 			{
308 				// left
309 				rc.left	  = 0;
310 				rc.top	  = nY;
311 				rc.right  = nX;
312 				rc.bottom = nHeight - nY;
313 				FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1));
314 
315 				// right
316 				rc.left	  = nWidth - nX - 1;
317 				rc.top	  = nY;
318 				rc.right  = nWidth;
319 				rc.bottom = nHeight - nY;
320 				FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1));
321 			}
322 		}
323 		else // clear background
324 		{
325 			RECT rc;
326 			GetClientRect(hWnd,&rc);
327 			FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1));
328 		}
329 	}
330 	catch(...)
331 	{
332 		OSL_ASSERT(sal_False);
333 	}
334 }
335 
336 //---------------------------------------------------
337 //
338 //---------------------------------------------------
339 
340 LRESULT CALLBACK CDIBPreview::WndProc(
341     HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
342 {
343 	LRESULT lResult = 0;
344 
345 	switch(uMsg)
346 	{
347 
348     // we connect a pointer to the current instance
349     // with a window instance via SetProp
350     case WM_CREATE:
351         {
352             LPCREATESTRUCT lpcs =
353                 reinterpret_cast< LPCREATESTRUCT >(lParam);
354 
355             OSL_ASSERT(lpcs->lpCreateParams);
356 
357             // connect the instance handle to the window
358             SetProp(hWnd, CURRENT_INSTANCE, lpcs->lpCreateParams);
359         }
360         break;
361 
362     // we remove the window property which connects
363     // a class instance with a window class
364     case WM_NCDESTROY:
365         {
366             // RemoveProp returns the saved value on success
367             if (reinterpret_cast<CDIBPreview*>(
368                     RemoveProp(hWnd, CURRENT_INSTANCE)) == NULL)
369             {
370                 OSL_ASSERT(false);
371             }
372         }
373         break;
374 
375 	case WM_PAINT:
376 	{
377 		CDIBPreview* pImpl = reinterpret_cast<CDIBPreview*>(
378             GetProp(hWnd, CURRENT_INSTANCE));
379 
380         OSL_ASSERT(pImpl);
381 
382 		HDC         hDC;
383 		PAINTSTRUCT ps;
384 
385 		hDC = BeginPaint(hWnd,&ps);
386 		pImpl->onPaint(hWnd,hDC);
387 		EndPaint(hWnd,&ps);
388 	}
389 	break;
390 
391 	// ignore this message in order to
392 	// avoid flickering during paint
393 	case WM_ERASEBKGND:
394 		lResult = 1;
395 		break;
396 
397 	default:
398 		return DefWindowProc(hWnd, uMsg, wParam, lParam);
399 	}
400 
401 	return lResult;
402 }
403 
404 //---------------------------------------------------
405 //
406 //---------------------------------------------------
407 
408 ATOM SAL_CALL CDIBPreview::RegisterDibPreviewWindowClass()
409 {
410     osl::MutexGuard aGuard( s_Mutex );
411 
412     if (0 == s_ClassAtom)
413     {
414         // register the preview window class
415 	    WNDCLASSEX wndClsEx;
416 	    ZeroMemory(&wndClsEx, sizeof(wndClsEx));
417 
418 	    wndClsEx.cbSize        = sizeof(wndClsEx);
419 	    wndClsEx.style		   = CS_HREDRAW | CS_VREDRAW;
420 	    wndClsEx.lpfnWndProc   = CDIBPreview::WndProc;
421 	    wndClsEx.hInstance     = m_Instance;
422 	    wndClsEx.hbrBackground = (HBRUSH)(COLOR_INACTIVEBORDER + 1);
423 	    wndClsEx.lpszClassName = PREVIEWWND_CLASS_NAME;
424 
425 	    // register the preview window class
426 	    // !!! Win95 -   the window class will be unregistered automaticly
427 	    //			     if the dll is unloaded
428 	    //     Win2000 - the window class must be unregistered manually
429 	    //				 if the dll is unloaded
430 	    s_ClassAtom = RegisterClassEx(&wndClsEx);
431 
432 		OSL_POSTCOND(s_ClassAtom,"Could  not register preview window class");
433 
434 		if (0 == s_ClassAtom)
435 			throw std::runtime_error("Preview window class could not be registered");
436     }
437 
438     // increment the register class counter
439     // so that we keep track of the number
440     // of class registrations
441     //if ( 0 != s_ClassAtom )
442     s_RegisterDibPreviewWndCount++;
443 
444     return s_ClassAtom;
445 }
446 
447 //---------------------------------------------------
448 //
449 //---------------------------------------------------
450 
451 void SAL_CALL CDIBPreview::UnregisterDibPreviewWindowClass()
452 {
453     osl::MutexGuard aGuard( s_Mutex );
454 
455     OSL_ASSERT( ( (0 != s_ClassAtom) && (s_RegisterDibPreviewWndCount > 0)) ||
456                 ( (0 == s_ClassAtom) && (0 == s_RegisterDibPreviewWndCount) ) );
457 
458     // update the register class counter
459     // and unregister the window class if
460     // counter drops to zero
461     if (0 != s_ClassAtom)
462     {
463         s_RegisterDibPreviewWndCount--;
464         OSL_ASSERT(s_RegisterDibPreviewWndCount >= 0);
465     }
466 
467     if (0 == s_RegisterDibPreviewWndCount)
468     {
469         UnregisterClass((LPCTSTR)MAKELONG(s_ClassAtom,0),m_Instance);
470         s_ClassAtom = 0;
471     }
472 }
473