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