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_BODER_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,"Coud 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 it's 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() throw (RuntimeException)
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() throw (RuntimeException)
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() throw (RuntimeException)
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 throw (IllegalArgumentException, RuntimeException)
193 {
194 PreviewBase::setImage(aImageFormat,aImage);
195
196 // if the any has no value we have an
197 // empty Sequence which clears the
198 // preview window
199 osl::ClearableMutexGuard aGuard(m_PaintLock);
200
201 m_Image.realloc(0);
202 m_ImageData >>= m_Image;
203
204 aGuard.clear();
205
206 InvalidateRect(m_Hwnd,NULL,sal_False);
207 UpdateWindow(m_Hwnd);
208 }
209
210 //-------------------------------
211 //
212 //-------------------------------
213
setShowState(sal_Bool bShowState)214 sal_Bool SAL_CALL CDIBPreview::setShowState(sal_Bool bShowState) throw (RuntimeException)
215 {
216 PreviewBase::setShowState(bShowState);
217 ShowWindow(m_Hwnd, m_bShowState ? SW_SHOW : SW_HIDE);
218 return sal_True;
219 }
220
221 //-------------------------------
222 //
223 //-------------------------------
224
getShowState()225 sal_Bool SAL_CALL CDIBPreview::getShowState() throw (RuntimeException)
226 {
227 return (sal_Bool)IsWindowVisible(m_Hwnd);
228 }
229
230 //-------------------------------
231 //
232 //-------------------------------
233
getWindowHandle() const234 HWND SAL_CALL CDIBPreview::getWindowHandle() const
235 {
236 return m_Hwnd;
237 }
238
239 //---------------------------------------------------
240 //
241 //---------------------------------------------------
242
onPaint(HWND hWnd,HDC hDC)243 void SAL_CALL CDIBPreview::onPaint(HWND hWnd, HDC hDC)
244 {
245 BITMAPFILEHEADER* pbmfh;
246 BITMAPINFO * pbmi;
247 sal_uInt8 * pBits;
248 int cxDib;
249 int cyDib;
250
251 osl::MutexGuard aGuard(m_PaintLock);
252
253 try
254 {
255 pbmfh = reinterpret_cast<BITMAPFILEHEADER*>(m_Image.getArray());
256
257 if ( !IsBadReadPtr( pbmfh, sizeof(BITMAPFILEHEADER)) &&
258 (pbmfh->bfType == ('B' | ('M' << 8))) )
259 {
260 pbmi = reinterpret_cast<BITMAPINFO*>((pbmfh + 1));
261 pBits = reinterpret_cast<sal_uInt8*>(((DWORD)pbmfh) + pbmfh->bfOffBits);
262
263 cxDib = pbmi->bmiHeader.biWidth;
264 cyDib = abs (pbmi->bmiHeader.biHeight);
265
266 SetStretchBltMode(hDC, COLORONCOLOR);
267
268 int nWidth = getAvailableWidth();
269 int nHeight = getAvailableHeight();
270
271 int nX = abs(nWidth - cxDib) / 2;
272 int nY = abs(nHeight - cyDib) / 2;
273
274 int GDIError = GDI_ERROR;
275 GDIError = StretchDIBits(
276 hDC, nX, nY, cxDib, cyDib,
277 0, 0, cxDib, cyDib, pBits, pbmi,
278 DIB_RGB_COLORS, SRCCOPY);
279
280 OSL_ASSERT(GDI_ERROR != GDIError);
281
282 // paint the border
283 RECT rc;
284
285 if (nY > 0)
286 {
287 // top
288 rc.left = 0;
289 rc.top = 0;
290 rc.right = nWidth;
291 rc.bottom = nY;
292 FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1));
293
294 // bottom
295 rc.left = 0;
296 rc.top = nHeight - nY - 1;
297 rc.right = nWidth;
298 rc.bottom = nHeight;
299 FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1));
300 }
301
302 if (nX > 0)
303 {
304 // left
305 rc.left = 0;
306 rc.top = nY;
307 rc.right = nX;
308 rc.bottom = nHeight - nY;
309 FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1));
310
311 // right
312 rc.left = nWidth - nX - 1;
313 rc.top = nY;
314 rc.right = nWidth;
315 rc.bottom = nHeight - nY;
316 FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1));
317 }
318 }
319 else // clear background
320 {
321 RECT rc;
322 GetClientRect(hWnd,&rc);
323 FillRect(hDC,&rc,(HBRUSH)(COLOR_INACTIVEBORDER + 1));
324 }
325 }
326 catch(...)
327 {
328 OSL_ASSERT(sal_False);
329 }
330 }
331
332 //---------------------------------------------------
333 //
334 //---------------------------------------------------
335
WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)336 LRESULT CALLBACK CDIBPreview::WndProc(
337 HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
338 {
339 LRESULT lResult = 0;
340
341 switch(uMsg)
342 {
343
344 // we connect a pointer to the current instance
345 // with a window instance via SetProp
346 case WM_CREATE:
347 {
348 LPCREATESTRUCT lpcs =
349 reinterpret_cast< LPCREATESTRUCT >(lParam);
350
351 OSL_ASSERT(lpcs->lpCreateParams);
352
353 // connect the instance handle to the window
354 SetProp(hWnd, CURRENT_INSTANCE, lpcs->lpCreateParams);
355 }
356 break;
357
358 // we remove the window property which connects
359 // a class instance with a window class
360 case WM_NCDESTROY:
361 {
362 // RemoveProp returns the saved value on success
363 if (reinterpret_cast<CDIBPreview*>(
364 RemoveProp(hWnd, CURRENT_INSTANCE)) == NULL)
365 {
366 OSL_ASSERT(false);
367 }
368 }
369 break;
370
371 case WM_PAINT:
372 {
373 CDIBPreview* pImpl = reinterpret_cast<CDIBPreview*>(
374 GetProp(hWnd, CURRENT_INSTANCE));
375
376 OSL_ASSERT(pImpl);
377
378 HDC hDC;
379 PAINTSTRUCT ps;
380
381 hDC = BeginPaint(hWnd,&ps);
382 pImpl->onPaint(hWnd,hDC);
383 EndPaint(hWnd,&ps);
384 }
385 break;
386
387 // ignore this message in order to
388 // avoid flickering during paint
389 case WM_ERASEBKGND:
390 lResult = 1;
391 break;
392
393 default:
394 return DefWindowProc(hWnd, uMsg, wParam, lParam);
395 }
396
397 return lResult;
398 }
399
400 //---------------------------------------------------
401 //
402 //---------------------------------------------------
403
RegisterDibPreviewWindowClass()404 ATOM SAL_CALL CDIBPreview::RegisterDibPreviewWindowClass()
405 {
406 osl::MutexGuard aGuard( s_Mutex );
407
408 if (0 == s_ClassAtom)
409 {
410 // register the preview window class
411 WNDCLASSEX wndClsEx;
412 ZeroMemory(&wndClsEx, sizeof(wndClsEx));
413
414 wndClsEx.cbSize = sizeof(wndClsEx);
415 wndClsEx.style = CS_HREDRAW | CS_VREDRAW;
416 wndClsEx.lpfnWndProc = CDIBPreview::WndProc;
417 wndClsEx.hInstance = m_Instance;
418 wndClsEx.hbrBackground = (HBRUSH)(COLOR_INACTIVEBORDER + 1);
419 wndClsEx.lpszClassName = PREVIEWWND_CLASS_NAME;
420
421 // register the preview window class
422 // !!! Win95 - the window class will be unregistered automaticly
423 // if the dll is unloaded
424 // Win2000 - the window class must be unregistered manually
425 // if the dll is unloaded
426 s_ClassAtom = RegisterClassEx(&wndClsEx);
427
428 OSL_POSTCOND(s_ClassAtom,"Could not register preview window class");
429
430 if (0 == s_ClassAtom)
431 throw std::runtime_error("Preview window class could not be registered");
432 }
433
434 // increment the register class counter
435 // so that we keep track of the number
436 // of class registrations
437 //if ( 0 != s_ClassAtom )
438 s_RegisterDibPreviewWndCount++;
439
440 return s_ClassAtom;
441 }
442
443 //---------------------------------------------------
444 //
445 //---------------------------------------------------
446
UnregisterDibPreviewWindowClass()447 void SAL_CALL CDIBPreview::UnregisterDibPreviewWindowClass()
448 {
449 osl::MutexGuard aGuard( s_Mutex );
450
451 OSL_ASSERT( ( (0 != s_ClassAtom) && (s_RegisterDibPreviewWndCount > 0)) ||
452 ( (0 == s_ClassAtom) && (0 == s_RegisterDibPreviewWndCount) ) );
453
454 // update the register class counter
455 // and unregister the window class if
456 // counter drops to zero
457 if (0 != s_ClassAtom)
458 {
459 s_RegisterDibPreviewWndCount--;
460 OSL_ASSERT(s_RegisterDibPreviewWndCount >= 0);
461 }
462
463 if (0 == s_RegisterDibPreviewWndCount)
464 {
465 UnregisterClass((LPCTSTR)MAKELONG(s_ClassAtom,0),m_Instance);
466 s_ClassAtom = 0;
467 }
468 }
469