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