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