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