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 #include <tchar.h>
32 #include "previewadapter.hxx"
33 
34 #ifndef _COM_SUN_STAR_UI_DIALOG_FILEPREVIEWIMAGEFORMATS_HPP_
35 #include <com/sun/star/ui/dialogs/FilePreviewImageFormats.hpp>
36 #endif
37 #include "dibpreview.hxx"
38 #include "../misc/WinImplHelper.hxx"
39 
40 #include <memory>
41 #include <stdexcept>
42 
43 //---------------------------------------------
44 //
45 //---------------------------------------------
46 
47 using namespace ::com::sun::star::uno;
48 using namespace ::com::sun::star::lang;
49 
50 //---------------------------------------------
51 // An impl class to hide implementation details
52 // from clients
53 //---------------------------------------------
54 
55 class CPreviewAdapterImpl
56 {
57 public:
58 	CPreviewAdapterImpl(HINSTANCE instance);
59 
60 	virtual ~CPreviewAdapterImpl();
61 
62 	virtual sal_Int32 SAL_CALL getTargetColorDepth();
63 
64 	virtual sal_Int32 SAL_CALL getAvailableWidth();
65 
66 	virtual sal_Int32 SAL_CALL getAvailableHeight();
67 
68 	virtual void SAL_CALL setImage( sal_Int16 aImageFormat, const Any& aImage )
69 		throw (IllegalArgumentException,RuntimeException);
70 
71     virtual sal_Bool SAL_CALL setShowState(sal_Bool bShowState);
72 
73 	virtual sal_Bool SAL_CALL getShowState();
74 
75 	virtual void SAL_CALL setParent(HWND parent);
76 
77 	virtual HWND SAL_CALL getParent();
78 
79 	//-------------------------------------
80 	// parent notification handler
81 	//-------------------------------------
82 
83 	virtual void SAL_CALL notifyParentShow(sal_Bool bShow);
84 
85 	virtual void SAL_CALL notifyParentSizeChanged();
86 
87 	virtual void SAL_CALL notifyParentWindowPosChanged();
88 
89 protected:
90 	virtual void SAL_CALL calcRightMargin();
91 
92 	virtual void SAL_CALL rearrangeLayout();
93 
94 	void SAL_CALL initializeActivePreview() throw(std::runtime_error);
95 
96 	HWND SAL_CALL findFileListbox() const;
97 
98 // member
99 protected:
100 	HINSTANCE					m_Instance;
101 	std::auto_ptr<PreviewBase>  m_Preview;
102 	HWND						m_FileDialog;
103 	int							m_RightMargin;
104 
105 //prevent copy/assignment
106 private:
107 	CPreviewAdapterImpl(const CPreviewAdapterImpl&);
108 	CPreviewAdapterImpl& operator=(const CPreviewAdapterImpl&);
109 };
110 
111 //-----------------------------------------
112 //
113 //-----------------------------------------
114 
115 CPreviewAdapterImpl::CPreviewAdapterImpl(HINSTANCE instance) :
116 	m_Instance(instance),
117 	m_Preview(new PreviewBase()), // create dummy preview (NULL-Object pattern)
118 	m_FileDialog(0),
119 	m_RightMargin(0)
120 {
121 }
122 
123 //-----------------------------------------
124 //
125 //-----------------------------------------
126 
127 CPreviewAdapterImpl::~CPreviewAdapterImpl()
128 {
129 }
130 
131 //-----------------------------------------
132 //
133 //-----------------------------------------
134 
135 sal_Int32 SAL_CALL CPreviewAdapterImpl::getTargetColorDepth()
136 {
137 	return m_Preview->getTargetColorDepth();
138 }
139 
140 //-----------------------------------------
141 //
142 //-----------------------------------------
143 
144 sal_Int32 SAL_CALL CPreviewAdapterImpl::getAvailableWidth()
145 {
146 	return m_Preview->getAvailableWidth();
147 }
148 
149 //-----------------------------------------
150 //
151 //-----------------------------------------
152 
153 sal_Int32 SAL_CALL CPreviewAdapterImpl::getAvailableHeight()
154 {
155 	return m_Preview->getAvailableHeight();
156 }
157 
158 //-----------------------------------------
159 //
160 //-----------------------------------------
161 
162 void SAL_CALL CPreviewAdapterImpl::setImage( sal_Int16 aImageFormat, const Any& aImage )
163 	throw (IllegalArgumentException,RuntimeException)
164 {
165 	m_Preview->setImage(aImageFormat,aImage);
166 }
167 
168 //-----------------------------------------
169 //
170 //-----------------------------------------
171 
172 sal_Bool SAL_CALL CPreviewAdapterImpl::setShowState( sal_Bool bShowState )
173 {
174 	sal_Bool bRet = m_Preview->setShowState(bShowState);
175 	rearrangeLayout();
176 	return bRet;
177 }
178 
179 //-----------------------------------------
180 //
181 //-----------------------------------------
182 
183 sal_Bool SAL_CALL CPreviewAdapterImpl::getShowState()
184 {
185 	return m_Preview->getShowState();
186 }
187 
188 //-----------------------------------------
189 //
190 //-----------------------------------------
191 
192 void SAL_CALL CPreviewAdapterImpl::setParent(HWND parent)
193 {
194 	OSL_PRECOND(IsWindow(parent),"Invalid FileDialog handle");
195 
196 	m_FileDialog = parent;
197 	calcRightMargin();
198 }
199 
200 //-----------------------------------------
201 //
202 //-----------------------------------------
203 
204 HWND SAL_CALL CPreviewAdapterImpl::getParent()
205 {
206 	return m_FileDialog;
207 }
208 
209 //-----------------------------------------
210 //
211 //-----------------------------------------
212 
213 void SAL_CALL CPreviewAdapterImpl::calcRightMargin()
214 {
215 	// Calculate the right reference margin
216 	//
217 	// Assumtions:
218 	// 1. This method will be called before the dialog becomes
219 	//    visible
220 	// 2. There exist a FileListbox with the id lst1 even
221 	//    if it is not visible like under Win2000/XP
222 	// 3. Initially this FileListbox has the appropriate size
223 	//    to fit within the FileListbox
224 	// 4. The margin between the right edge of the FileListbox
225 	//    and the right edge of the FileDialog will be constant
226 	//    even if the size of the dialog changes
227 
228 	HWND flb = GetDlgItem(m_FileDialog,lst1);
229 
230 	OSL_ENSURE(IsWindow(flb),"Filelistbox not found");
231 
232 	RECT rcFlb;
233 	GetWindowRect(flb,&rcFlb);
234 
235 	RECT rcFileDlg;
236 	GetWindowRect(m_FileDialog,&rcFileDlg);
237 
238 	m_RightMargin = rcFileDlg.right - rcFlb.right;
239 }
240 
241 //-----------------------------------------
242 //
243 //-----------------------------------------
244 
245 void SAL_CALL CPreviewAdapterImpl::notifyParentShow(sal_Bool)
246 {
247 }
248 
249 //-----------------------------------------
250 //
251 //-----------------------------------------
252 
253 void SAL_CALL CPreviewAdapterImpl::notifyParentSizeChanged()
254 {
255 	rearrangeLayout();
256 }
257 
258 //-----------------------------------------
259 //
260 //-----------------------------------------
261 
262 void SAL_CALL CPreviewAdapterImpl::notifyParentWindowPosChanged()
263 {
264 }
265 
266 //-----------------------------------------
267 //
268 //-----------------------------------------
269 
270 void SAL_CALL CPreviewAdapterImpl::rearrangeLayout()
271 {
272 	// try to get a handle to the filelistbox
273 	// if there is no new-style filelistbox like
274 	// in Win2000/XP there should be at least the
275 	// old listbox, so we take this one
276 	// lst1 - identifies the old-style filelistbox
277 	// lst2 - identifies the new-style filelistbox
278 	// see dlgs.h
279 	HWND flb_new = findFileListbox();
280 
281 	// under Windows NT 4.0 the size of the old
282 	// filelistbox will be used as reference for
283 	// sizing the new filelistbox, so we have
284 	// to change the size of it too
285 	HWND flb_old = GetDlgItem(m_FileDialog,lst1);
286 
287 	RECT rcFlbNew;
288 	GetWindowRect(flb_new,&rcFlbNew);
289 
290 	RECT rcFileDlg;
291 	GetWindowRect(m_FileDialog,&rcFileDlg);
292 	rcFileDlg.right -= m_RightMargin;
293 
294 	// the available area for the filelistbox should be
295 	// the left edge of the filelistbox and the right
296 	// edge of the OK button, we take this as reference
297 	int height = rcFlbNew.bottom - rcFlbNew.top;
298 	int width  = rcFileDlg.right - rcFlbNew.left;
299 
300 	HWND prvwnd = m_Preview->getWindowHandle();
301 
302 	// we use GetWindowLong to ask for the visibility
303 	// of the preview window because IsWindowVisible
304 	// only returns true the specified window including
305 	// its parent windows are visible
306 	// this is not the case when we are called in response
307 	// to the WM_SHOWWINDOW message, somehow the WS_VISIBLE
308 	// style bit of the FileOpen dialog must be set after that
309 	// message
310 	LONG lStyle = GetWindowLong(prvwnd,GWL_STYLE);
311 	bool bIsVisible = ((lStyle & WS_VISIBLE) != 0);
312 
313 	int cx = 0;
314 
315 	if (IsWindow(prvwnd) && bIsVisible)
316 	{
317 		cx = width/2;
318 
319 		// resize the filelistbox to the half of the
320 		// available space
321 		bool bRet = SetWindowPos(flb_new,
322 			NULL, 0, 0, cx, height,
323 			SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
324 
325 		bRet = SetWindowPos(flb_old,
326 			NULL, 0, 0, cx, height,
327 			SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
328 
329 		// get the new dimensions of the filelistbox after
330 		// resizing and take the right,top corner as starting
331 		// point for the preview window
332 		GetWindowRect(flb_new,&rcFlbNew);
333 		POINT pt = { rcFlbNew.right, rcFlbNew.top };
334 		ScreenToClient(m_FileDialog,&pt);
335 
336 		// resize the preview window to fit within
337 		// the available space and set the window
338 		// to the top of the z-order else it will
339 		// be invisible
340 		SetWindowPos(prvwnd,
341 			HWND_TOP, pt.x, pt.y, cx, height, SWP_NOACTIVATE);
342 	}
343 	else
344 	{
345 		// resize the filelistbox to the maximum available
346 		// space
347 		cx = rcFileDlg.right - rcFlbNew.left;
348 
349 		// resize the old filelistbox
350 		SetWindowPos(flb_old,
351 			NULL, 0, 0, cx, height,
352 			SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
353 
354 		// resize the new filelistbox
355 		SetWindowPos(flb_new,
356 			NULL, 0, 0, cx, height,
357 			SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
358 	}
359 }
360 
361 //-----------------------------------------
362 //
363 //-----------------------------------------
364 
365 void SAL_CALL CPreviewAdapterImpl::initializeActivePreview() throw(std::runtime_error)
366 {
367 	sal_Bool bShowState = m_Preview->getImaginaryShowState();
368 
369 	sal_Int16 aImgFrmt;
370 	Any aImg;
371 	m_Preview->getImage(aImgFrmt,aImg);
372 
373 	HWND flb = findFileListbox();
374 
375 	PreviewBase* prv = new CDIBPreview(
376 		m_Instance, GetParent(flb), bShowState);
377 
378 	m_Preview.reset(prv);
379 
380 	m_Preview->setImage(aImgFrmt,aImg);
381 }
382 
383 //-----------------------------------------
384 //
385 //-----------------------------------------
386 
387 HWND SAL_CALL CPreviewAdapterImpl::findFileListbox() const
388 {
389 	// try to get a handle to the filelistbox
390 	// if there is no new-style filelistbox like
391 	// in Win2000/XP there should be at least the
392 	// old listbox, so we take this one
393 	// lst1 - identifies the old-style filelistbox
394 	// lst2 - identifies the new-style filelistbox
395 	// see dlgs.h
396 	HWND flb = GetDlgItem(m_FileDialog,lst2);
397 	if (!IsWindow(flb))
398 		flb = GetDlgItem(m_FileDialog,lst1);
399 
400 	return flb;
401 }
402 
403 
404 //##############################################################
405 
406 
407 //-----------------------------------------
408 // Special implementation for Win98
409 // because:
410 //
411 //-----------------------------------------
412 
413 class CWin98PreviewAdapterImpl : public CPreviewAdapterImpl
414 {
415 public:
416 	CWin98PreviewAdapterImpl(HINSTANCE instance);
417 
418 	virtual void SAL_CALL notifyParentWindowPosChanged();
419 
420 protected:
421 	virtual void SAL_CALL rearrangeLayout();
422 
423 	bool isValidToolbarDimension() const;
424 
425 private:
426 	sal_Bool	m_PreviewActive;
427 	int			m_ToolbarPosX;
428 	int			m_ToolbarPosY;
429 	int			m_ToolbarWidth;
430 	int			m_ToolbarHeight;
431 };
432 
433 //--------------------------------------------
434 //
435 //--------------------------------------------
436 
437 CWin98PreviewAdapterImpl::CWin98PreviewAdapterImpl(HINSTANCE instance) :
438 	CPreviewAdapterImpl(instance),
439 	m_PreviewActive(sal_False),
440 	m_ToolbarPosX(0),
441 	m_ToolbarPosY(0),
442 	m_ToolbarWidth(0),
443 	m_ToolbarHeight(0)
444 {
445 }
446 
447 //--------------------------------------------
448 //
449 //--------------------------------------------
450 
451 void SAL_CALL CWin98PreviewAdapterImpl::notifyParentWindowPosChanged()
452 {
453 	try
454 	{
455 		// the reason for this condition is
456 		// Windows 98
457 		// Under Windows 98 the message WM_SHOWWINDOW
458 		// will be sent only the first time the
459 		// GetOpenFileName function is called within
460 		// the same process
461 		// so we must use another message to initialize
462 		// the preview window
463 		if (IsWindow(m_FileDialog) && !m_PreviewActive)
464 		{
465 			initializeActivePreview();
466 			m_PreviewActive = sal_True;
467 			rearrangeLayout();
468 		}
469 
470 		if (IsWindow(m_FileDialog) && !isValidToolbarDimension())
471 		{
472 			RECT rcStc1;
473 			GetWindowRect(GetDlgItem(m_FileDialog,stc1),&rcStc1);
474 
475 			RECT rcCmb2;
476 			GetWindowRect(GetDlgItem(m_FileDialog,cmb2),&rcCmb2);
477 
478 			// Assumption:
479 			// the toolbar position is only valid
480 			// if the left edge is greater or equal
481 			// than the right edge of the drives listbox
482 			// the stc1 static text is invisible at runtime
483 			// but will be used as reference for the position
484 			// and dimension of the toolbar
485 			if (rcStc1.left >= rcCmb2.right)
486 			{
487 				// important: save the upper left corner in
488 				// client coordinates
489 				POINT pt = {rcStc1.left,rcStc1.top};
490 				ScreenToClient(m_FileDialog,&pt);
491 
492 				m_ToolbarPosX   = pt.x;
493 				m_ToolbarPosY   = pt.y;
494 				m_ToolbarWidth  = rcStc1.right - rcStc1.left;
495 				m_ToolbarHeight = rcStc1.bottom - rcStc1.top;
496 			}
497 		}
498 	}
499 	catch(std::runtime_error&)
500 	{
501 	}
502 }
503 
504 //--------------------------------------------
505 //
506 //--------------------------------------------
507 
508 void SAL_CALL CWin98PreviewAdapterImpl::rearrangeLayout()
509 {
510 	CPreviewAdapterImpl::rearrangeLayout();
511 
512 	// fix the position of the upper toolbar
513 	// because the FileDialog moves all windows
514 	// that are to the right of the FileListbox
515 	// so if we have changed the size of the
516 	// FileListbox we would run into trouble else
517 	if (isValidToolbarDimension())
518 	{
519 		HWND hwndTlb = FindWindowEx(
520 			m_FileDialog,NULL,TEXT("ToolbarWindow32"),NULL);
521 
522 		SetWindowPos(hwndTlb,
523 			HWND_TOP,
524 			m_ToolbarPosX,
525 			m_ToolbarPosY,
526 			m_ToolbarWidth,
527 			m_ToolbarHeight,
528 			SWP_NOACTIVATE);
529 	}
530 }
531 
532 //--------------------------------------------
533 //
534 //--------------------------------------------
535 
536 bool CWin98PreviewAdapterImpl::isValidToolbarDimension() const
537 {
538 	return (m_ToolbarPosX   > 0 &&
539 			m_ToolbarPosY   > 0 &&
540 			m_ToolbarWidth  > 0 &&
541 			m_ToolbarHeight > 0);
542 }
543 
544 //##############################################################
545 
546 
547 //--------------------------------------------
548 // Implementation for Windows 95/NT/ME/2000/XP
549 // because:
550 //
551 //--------------------------------------------
552 
553 class CWin95NTPreviewAdapterImpl : public CPreviewAdapterImpl
554 {
555 public:
556 	CWin95NTPreviewAdapterImpl(HINSTANCE instance);
557 
558 	virtual void SAL_CALL notifyParentShow(sal_Bool bShow);
559 };
560 
561 //--------------------------------------------
562 //
563 //--------------------------------------------
564 
565 CWin95NTPreviewAdapterImpl::CWin95NTPreviewAdapterImpl(HINSTANCE instance) :
566 	CPreviewAdapterImpl(instance)
567 {
568 }
569 
570 //--------------------------------------------
571 //
572 //--------------------------------------------
573 
574 void SAL_CALL CWin95NTPreviewAdapterImpl::notifyParentShow(sal_Bool bShow)
575 {
576 	try
577 	{
578 		if (bShow)
579 		{
580 			initializeActivePreview();
581 			rearrangeLayout();
582 		}
583 	}
584 	catch(std::runtime_error&)
585 	{
586 	}
587 }
588 
589 
590 //##############################################################
591 
592 
593 //-------------------------------
594 // ctor
595 //-------------------------------
596 
597 CPreviewAdapter::CPreviewAdapter(HINSTANCE instance)
598 {
599 	if (!IsWindows98())
600 		m_pImpl.reset(new CWin95NTPreviewAdapterImpl(instance));
601 	else
602 		m_pImpl.reset(new CWin98PreviewAdapterImpl(instance));
603 }
604 
605 //-------------------------------
606 //
607 //-------------------------------
608 
609 CPreviewAdapter::~CPreviewAdapter()
610 {
611 }
612 
613 //-------------------------------
614 //
615 //-------------------------------
616 
617 Sequence<sal_Int16> SAL_CALL CPreviewAdapter::getSupportedImageFormats()
618 {
619 	com::sun::star::uno::Sequence<sal_Int16> imgFormats(1);
620     imgFormats[0] = ::com::sun::star::ui::dialogs::FilePreviewImageFormats::BITMAP;
621     return imgFormats;
622 }
623 
624 //-------------------------------
625 //
626 //-------------------------------
627 
628 sal_Int32 SAL_CALL CPreviewAdapter::getTargetColorDepth()
629 {
630 	return m_pImpl->getTargetColorDepth();
631 }
632 
633 //-------------------------------
634 //
635 //-------------------------------
636 
637 sal_Int32 SAL_CALL CPreviewAdapter::getAvailableWidth()
638 {
639 	return m_pImpl->getAvailableWidth();
640 }
641 
642 //-------------------------------
643 //
644 //-------------------------------
645 
646 sal_Int32 SAL_CALL CPreviewAdapter::getAvailableHeight()
647 {
648 	return m_pImpl->getAvailableHeight();
649 }
650 
651 //-------------------------------
652 //
653 //-------------------------------
654 
655 void SAL_CALL CPreviewAdapter::setImage( sal_Int16 aImageFormat, const Any& aImage )
656 	throw (IllegalArgumentException, RuntimeException)
657 {
658 	m_pImpl->setImage(aImageFormat,aImage);
659 }
660 
661 //-------------------------------
662 //
663 //-------------------------------
664 
665 sal_Bool SAL_CALL CPreviewAdapter::setShowState( sal_Bool bShowState )
666 {
667 	return m_pImpl->setShowState(bShowState);
668 }
669 
670 //-------------------------------
671 //
672 //-------------------------------
673 
674 sal_Bool SAL_CALL CPreviewAdapter::getShowState()
675 {
676 	return m_pImpl->getShowState();
677 }
678 
679 //-------------------------------
680 //
681 //-------------------------------
682 
683 void SAL_CALL CPreviewAdapter::setParent(HWND parent)
684 {
685 	m_pImpl->setParent(parent);
686 }
687 
688 //-------------------------------
689 //
690 //-------------------------------
691 
692 void SAL_CALL CPreviewAdapter::notifyParentShow(bool bShow)
693 {
694 	m_pImpl->notifyParentShow(bShow);
695 }
696 
697 //-------------------------------
698 //
699 //-------------------------------
700 
701 void SAL_CALL CPreviewAdapter::notifyParentSizeChanged()
702 {
703 	m_pImpl->notifyParentSizeChanged();
704 }
705 
706 //-------------------------------
707 //
708 //-------------------------------
709 
710 void SAL_CALL CPreviewAdapter::notifyParentWindowPosChanged()
711 {
712 	m_pImpl->notifyParentWindowPosChanged();
713 }
714